brynq-sdk-vplan 2.0.1__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.
- brynq_sdk_vplan/__init__.py +46 -0
- brynq_sdk_vplan/activity.py +132 -0
- brynq_sdk_vplan/get_data.py +86 -0
- brynq_sdk_vplan/item.py +141 -0
- brynq_sdk_vplan/leave.py +109 -0
- brynq_sdk_vplan/order.py +166 -0
- brynq_sdk_vplan/project.py +129 -0
- brynq_sdk_vplan/resource.py +142 -0
- brynq_sdk_vplan/time_tracking.py +144 -0
- brynq_sdk_vplan/user.py +141 -0
- brynq_sdk_vplan-2.0.1.dist-info/METADATA +17 -0
- brynq_sdk_vplan-2.0.1.dist-info/RECORD +14 -0
- brynq_sdk_vplan-2.0.1.dist-info/WHEEL +5 -0
- brynq_sdk_vplan-2.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from brynq_sdk_brynq import BrynQ
|
|
2
|
+
from typing import List, Union, Literal, Optional
|
|
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, system_type: Optional[Literal['source', 'target']] = None, 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.timeout = 3600
|
|
21
|
+
self.headers = self._get_credentials(system_type)
|
|
22
|
+
self.post_headers = {**self.headers, 'Content-Type': 'application/json'}
|
|
23
|
+
self.base_url = 'https://api.vplan.com/v1/'
|
|
24
|
+
self.get = GetData(self)
|
|
25
|
+
self.activity = Activity(self)
|
|
26
|
+
self.item = Item(self)
|
|
27
|
+
self.order = Order(self)
|
|
28
|
+
self.project = Project(self)
|
|
29
|
+
self.resource = Resource(self)
|
|
30
|
+
self.time_tracking = TimeTracking(self)
|
|
31
|
+
self.user = User(self)
|
|
32
|
+
self.leave = Leave(self)
|
|
33
|
+
|
|
34
|
+
def _get_credentials(self, system_type) -> dict:
|
|
35
|
+
"""
|
|
36
|
+
Retrieve API key and env from the system credentials.
|
|
37
|
+
Args: label (Union[str, List]): The label or list of labels to get the credentials.
|
|
38
|
+
Returns: str: The authorization headers
|
|
39
|
+
"""
|
|
40
|
+
credentials = self.interfaces.credentials.get(system="vplan", system_type=system_type)
|
|
41
|
+
credentials = credentials.get('data')
|
|
42
|
+
headers = {
|
|
43
|
+
'X-Api-Key': credentials['X-Api-Key'],
|
|
44
|
+
'X-Api-Env': credentials['X-Api-Env']
|
|
45
|
+
}
|
|
46
|
+
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, timeout=self.vplan.timeout)
|
|
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, timeout=self.vplan.timeout)
|
|
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, timeout=self.vplan.timeout)
|
|
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
|
brynq_sdk_vplan/item.py
ADDED
|
@@ -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, timeout=self.vplan.timeout)
|
|
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, data=json.dumps(base_body), timeout=self.vplan.timeout)
|
|
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, timeout=self.vplan.timeout)
|
|
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)))
|
brynq_sdk_vplan/leave.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
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
|
+
Get leave data for a specific resource.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
resource_id (str): The id of the resource to get the leave from.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
requests.Response: The response from the vPlan API containing schedule deviations.
|
|
26
|
+
"""
|
|
27
|
+
url = f"{self.vplan.base_url}resource/{resource_id}?with=schedule_deviations"
|
|
28
|
+
response = requests.request('GET', url, headers=self.vplan.headers)
|
|
29
|
+
return response
|
|
30
|
+
|
|
31
|
+
def post_leave(self, resource_id: str, data: dict) -> requests.Response:
|
|
32
|
+
"""
|
|
33
|
+
There is no documentation for this method available
|
|
34
|
+
|
|
35
|
+
This method constructs a request URL based on the endpoint and sends a POST request
|
|
36
|
+
to the vPlan API with the provided data.
|
|
37
|
+
|
|
38
|
+
Args: resource_id (str): The resource id of the employee to add the leave to
|
|
39
|
+
data (dict): The data to create the new order with.
|
|
40
|
+
|
|
41
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
42
|
+
"""
|
|
43
|
+
required_fields = ['type', 'time', 'description', 'start_date', 'end_date']
|
|
44
|
+
allowed_fields = []
|
|
45
|
+
self.__check_fields(data=data, required_fields=required_fields, allowed_fields=allowed_fields)
|
|
46
|
+
|
|
47
|
+
url = f"{self.vplan.base_url}resource/{resource_id}/schedule_deviation"
|
|
48
|
+
base_body = json.dumps({
|
|
49
|
+
"type": data['type'],
|
|
50
|
+
"time": data['time'],
|
|
51
|
+
"description": data['description'],
|
|
52
|
+
"start_date": data['start_date'],
|
|
53
|
+
"end_date": data['end_date']
|
|
54
|
+
})
|
|
55
|
+
response = requests.request('POST', url, headers=self.vplan.post_headers, data=base_body, timeout=self.vplan.timeout)
|
|
56
|
+
return response
|
|
57
|
+
|
|
58
|
+
def update_leave(self, resource_id: str, leave_id: str, data: dict) -> requests.Response:
|
|
59
|
+
"""
|
|
60
|
+
There is no documentation for this method available
|
|
61
|
+
|
|
62
|
+
This method constructs a request URL based on the endpoint and sends a POST request
|
|
63
|
+
to the vPlan API with the provided data.
|
|
64
|
+
|
|
65
|
+
Args: resource_id (str): The resource id of the employee to add the leave to
|
|
66
|
+
leave_id (str): The id of the leave to update
|
|
67
|
+
data (dict): The data to create the new order with.
|
|
68
|
+
|
|
69
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
70
|
+
"""
|
|
71
|
+
required_fields = ['type', 'time', 'description', 'start_date', 'end_date']
|
|
72
|
+
allowed_fields = []
|
|
73
|
+
self.__check_fields(data=data, required_fields=required_fields, allowed_fields=allowed_fields)
|
|
74
|
+
|
|
75
|
+
url = f"{self.vplan.base_url}resource/{resource_id}/schedule_deviation/{leave_id}"
|
|
76
|
+
base_body = json.dumps({
|
|
77
|
+
"type": data['type'],
|
|
78
|
+
"time": data['time'],
|
|
79
|
+
"description": data['description'],
|
|
80
|
+
"start_date": data['start_date'],
|
|
81
|
+
"end_date": data['end_date']
|
|
82
|
+
})
|
|
83
|
+
response = requests.request('PUT', url, headers=self.vplan.post_headers, data=base_body, timeout=self.vplan.timeout)
|
|
84
|
+
return response
|
|
85
|
+
|
|
86
|
+
def delete_leave(self, resource_id: str, leave_id: str):
|
|
87
|
+
"""
|
|
88
|
+
There is no documentation for this method available
|
|
89
|
+
This method constructs a request URL based on the endpoint and sends a DELETE request to the vPlan API.
|
|
90
|
+
:param resource_id: The resource id of the employee to delete the the leave to
|
|
91
|
+
:param leave_id: The id of the leave to delete
|
|
92
|
+
"""
|
|
93
|
+
url = f"{self.vplan.base_url}resource/{resource_id}/schedule_deviation/{leave_id}"
|
|
94
|
+
response = requests.request('DELETE', url, headers=self.vplan.headers, timeout=self.vplan.timeout)
|
|
95
|
+
return response
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@staticmethod
|
|
99
|
+
def __check_fields(data: Union[dict, List], required_fields: List, allowed_fields: List):
|
|
100
|
+
if isinstance(data, dict):
|
|
101
|
+
data = data.keys()
|
|
102
|
+
|
|
103
|
+
for field in data:
|
|
104
|
+
if field not in allowed_fields and field not in required_fields:
|
|
105
|
+
warnings.warn('Field {field} is not implemented. Optional fields are: {allowed_fields}'.format(field=field, allowed_fields=tuple(allowed_fields)))
|
|
106
|
+
|
|
107
|
+
for field in required_fields:
|
|
108
|
+
if field not in data:
|
|
109
|
+
raise ValueError('Field {field} is required. Required fields are: {required_fields}'.format(field=field, required_fields=tuple(required_fields)))
|
brynq_sdk_vplan/order.py
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
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 Order:
|
|
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_order_list(self, filter: str = None, with_array: str = None, show: str = None, hide: str = None):
|
|
18
|
+
"""
|
|
19
|
+
Get all the orders from vPlan: https://developer.vplan.com/documentation/#tag/Order/paths/~1order/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
|
+
with_array (list, optional): object(s) included in the dataset, Possible options are: address, item, order_rows, collection, project, relation, warehouse, board, contact, user, activity, order, item, project, relation, warehouse, supplies_order_rows
|
|
43
|
+
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
|
|
44
|
+
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
|
|
45
|
+
|
|
46
|
+
Returns: pd.DataFrame: The fetched data as a pandas DataFrame.
|
|
47
|
+
"""
|
|
48
|
+
df = self.get_data.get_data(endpoint='order', filter=filter, with_array=with_array, show=show, hide=hide)
|
|
49
|
+
return df
|
|
50
|
+
|
|
51
|
+
def post_order(self, data: dict) -> requests.Response:
|
|
52
|
+
"""
|
|
53
|
+
Create a new order in vPlan: https://developer.vplan.com/documentation/#tag/order/paths/~1order/post
|
|
54
|
+
|
|
55
|
+
This method constructs a request URL based on the endpoint and sends a POST request
|
|
56
|
+
to the vPlan API with the provided data.
|
|
57
|
+
|
|
58
|
+
Args: endpoint (str): The name of the endpoint to create a new order in.
|
|
59
|
+
data (dict): The data to create the new order with.
|
|
60
|
+
|
|
61
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
62
|
+
"""
|
|
63
|
+
required_fields = ['type', 'code', 'description']
|
|
64
|
+
allowed_fields = ['quantity', 'external_url', 'sub_type', 'status', 'note', 'contact', 'relation_ref', 'date', 'desired_date', 'promised_date',
|
|
65
|
+
'delivered_date', 'collection_id', 'item_id', 'project_id', 'relation_id', 'warehouse_id', 'external_ref', 'board_id']
|
|
66
|
+
self.__check_fields(data=data, required_fields=required_fields, allowed_fields=allowed_fields)
|
|
67
|
+
|
|
68
|
+
url = f"{self.vplan.base_url}order"
|
|
69
|
+
|
|
70
|
+
base_body = {
|
|
71
|
+
"type": data['type'],
|
|
72
|
+
"code": data['code'],
|
|
73
|
+
"description": data['description']
|
|
74
|
+
}
|
|
75
|
+
# Add fields that you want to update a dict (adding to body itself is too much text)
|
|
76
|
+
base_body.update({"quantity": data['quantity']}) if 'quantity' in data else base_body
|
|
77
|
+
base_body.update({"external_url": data['external_url']}) if 'external_url' in data else base_body
|
|
78
|
+
base_body.update({"sub_type": data['sub_type']}) if 'sub_type' in data else base_body
|
|
79
|
+
base_body.update({"status": data['status']}) if 'status' in data else base_body
|
|
80
|
+
base_body.update({"note": data['note']}) if 'note' in data else base_body
|
|
81
|
+
base_body.update({"contact": data['contact']}) if 'contact' in data else base_body
|
|
82
|
+
base_body.update({"relation_ref": data['relation_ref']}) if 'relation_ref' in data else base_body
|
|
83
|
+
base_body.update({"date": data['date']}) if 'date' in data else base_body
|
|
84
|
+
base_body.update({"desired_date": data['desired_date']}) if 'desired_date' in data else base_body
|
|
85
|
+
base_body.update({"promised_date": data['promised_date']}) if 'promised_date' in data else base_body
|
|
86
|
+
base_body.update({"delivered_date": data['delivered_date']}) if 'delivered_date' in data else base_body
|
|
87
|
+
base_body.update({"collection_id": data['collection_id']}) if 'collection_id' in data else base_body
|
|
88
|
+
base_body.update({"item_id": data['item_id']}) if 'item_id' in data else base_body
|
|
89
|
+
base_body.update({"project_id": data['project_id']}) if 'project_id' in data else base_body
|
|
90
|
+
base_body.update({"relation_id": data['relation_id']}) if 'relation_id' in data else base_body
|
|
91
|
+
base_body.update({"warehouse_id": data['warehouse_id']}) if 'warehouse_id' in data else base_body
|
|
92
|
+
base_body.update({"external_ref": data['external_ref']}) if 'external_ref' in data else base_body
|
|
93
|
+
base_body.update({"board_id": data['board_id']}) if 'board_id' in data else base_body
|
|
94
|
+
|
|
95
|
+
response = requests.request('POST', url, headers=self.vplan.post_headers, data=json.dumps(base_body), timeout=self.vplan.timeout)
|
|
96
|
+
return response
|
|
97
|
+
|
|
98
|
+
def update_order(self, order_id: str, data: dict) -> requests.Response:
|
|
99
|
+
"""
|
|
100
|
+
Update an existing order in vPlan: https://developer.vplan.com/documentation/#tag/order/paths/~1order~1%7Border_id%7D/put
|
|
101
|
+
|
|
102
|
+
This method constructs a request URL based on the endpoint and sends a POST request
|
|
103
|
+
to the vPlan API with the provided data.
|
|
104
|
+
|
|
105
|
+
Args: endpoint (str): The name of the endpoint to create a new order in.
|
|
106
|
+
data (dict): The data to create the new order with.
|
|
107
|
+
|
|
108
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
109
|
+
"""
|
|
110
|
+
required_fields = []
|
|
111
|
+
allowed_fields = ['description' 'type', 'code', 'quantity', 'external_url', 'sub_type', 'status', 'note', 'contact', 'relation_ref', 'date', 'desired_date',
|
|
112
|
+
'promised_date', 'delivered_date', 'collection_id', 'item_id', 'project_id', 'relation_id', 'warehouse_id', 'external_ref', 'board_id']
|
|
113
|
+
self.__check_fields(data=data, required_fields=required_fields, allowed_fields=allowed_fields)
|
|
114
|
+
|
|
115
|
+
url = f"{self.vplan.base_url}order/{order_id}"
|
|
116
|
+
|
|
117
|
+
base_body = {
|
|
118
|
+
}
|
|
119
|
+
# Add fields that you want to update a dict (adding to body itself is too much text)
|
|
120
|
+
base_body.update({"code": data['code']}) if 'code' in data else base_body
|
|
121
|
+
base_body.update({"description": data['description']}) if 'description' in data else base_body
|
|
122
|
+
base_body.update({"type": data['type']}) if 'type' in data else base_body
|
|
123
|
+
base_body.update({"quantity": data['quantity']}) if 'quantity' in data else base_body
|
|
124
|
+
base_body.update({"external_url": data['external_url']}) if 'external_url' in data else base_body
|
|
125
|
+
base_body.update({"sub_type": data['sub_type']}) if 'sub_type' in data else base_body
|
|
126
|
+
base_body.update({"status": data['status']}) if 'status' in data else base_body
|
|
127
|
+
base_body.update({"note": data['note']}) if 'note' in data else base_body
|
|
128
|
+
base_body.update({"contact": data['contact']}) if 'contact' in data else base_body
|
|
129
|
+
base_body.update({"relation_ref": data['relation_ref']}) if 'relation_ref' in data else base_body
|
|
130
|
+
base_body.update({"date": data['date']}) if 'date' in data else base_body
|
|
131
|
+
base_body.update({"desired_date": data['desired_date']}) if 'desired_date' in data else base_body
|
|
132
|
+
base_body.update({"promised_date": data['promised_date']}) if 'promised_date' in data else base_body
|
|
133
|
+
base_body.update({"delivered_date": data['delivered_date']}) if 'delivered_date' in data else base_body
|
|
134
|
+
base_body.update({"collection_id": data['collection_id']}) if 'collection_id' in data else base_body
|
|
135
|
+
base_body.update({"item_id": data['item_id']}) if 'item_id' in data else base_body
|
|
136
|
+
base_body.update({"project_id": data['project_id']}) if 'project_id' in data else base_body
|
|
137
|
+
base_body.update({"relation_id": data['relation_id']}) if 'relation_id' in data else base_body
|
|
138
|
+
base_body.update({"warehouse_id": data['warehouse_id']}) if 'warehouse_id' in data else base_body
|
|
139
|
+
base_body.update({"external_ref": data['external_ref']}) if 'external_ref' in data else base_body
|
|
140
|
+
base_body.update({"board_id": data['board_id']}) if 'board_id' in data else base_body
|
|
141
|
+
|
|
142
|
+
response = requests.request('PUT', url, headers=self.vplan.post_headers, data=json.dumps(base_body), timeout=self.vplan.timeout)
|
|
143
|
+
return response
|
|
144
|
+
|
|
145
|
+
def delete_order(self, order_id):
|
|
146
|
+
"""
|
|
147
|
+
Delete an existing order in vPlan: https://developer.vplan.com/documentation/#tag/order/paths/~1order~1%7Border_id%7D/delete
|
|
148
|
+
This method constructs a request URL based on the endpoint and sends a DELETE request to the vPlan API.
|
|
149
|
+
"""
|
|
150
|
+
url = f"{self.vplan.base_url}order/{order_id}"
|
|
151
|
+
response = requests.request('DELETE', url, headers=self.vplan.headers, timeout=self.vplan.timeout)
|
|
152
|
+
return response
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@staticmethod
|
|
156
|
+
def __check_fields(data: Union[dict, List], required_fields: List, allowed_fields: List):
|
|
157
|
+
if isinstance(data, dict):
|
|
158
|
+
data = data.keys()
|
|
159
|
+
|
|
160
|
+
for field in data:
|
|
161
|
+
if field not in allowed_fields and field not in required_fields:
|
|
162
|
+
warnings.warn('Field {field} is not implemented. Optional fields are: {allowed_fields}'.format(field=field, allowed_fields=tuple(allowed_fields)))
|
|
163
|
+
|
|
164
|
+
for field in required_fields:
|
|
165
|
+
if field not in data:
|
|
166
|
+
raise ValueError('Field {field} is required. Required fields are: {required_fields}'.format(field=field, required_fields=tuple(required_fields)))
|
|
@@ -0,0 +1,129 @@
|
|
|
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 Project:
|
|
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_project_list(self, filter: str = None, show: str = None, hide: str = None):
|
|
18
|
+
"""
|
|
19
|
+
Get all the projects from vPlan: https://developer.vplan.com/documentation/#tag/Project/paths/~1project/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='project', filter=filter, show=show, hide=hide)
|
|
48
|
+
return df
|
|
49
|
+
|
|
50
|
+
def post_project(self, data: dict) -> requests.Response:
|
|
51
|
+
"""
|
|
52
|
+
Create a new project in vPlan: https://developer.vplan.com/documentation/#tag/Project/paths/~1project/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 project in.
|
|
58
|
+
data (dict): The data to create the new project with.
|
|
59
|
+
|
|
60
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
61
|
+
"""
|
|
62
|
+
required_fields = ['name']
|
|
63
|
+
allowed_fields = ['code', 'description', 'external_ref']
|
|
64
|
+
self.__check_fields(data=data, required_fields=required_fields, allowed_fields=allowed_fields)
|
|
65
|
+
|
|
66
|
+
url = f"{self.vplan.base_url}project"
|
|
67
|
+
|
|
68
|
+
base_body = {
|
|
69
|
+
"name": data['name']
|
|
70
|
+
}
|
|
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({"external_ref": data['external_ref']}) if 'external_ref' in data else base_body
|
|
76
|
+
|
|
77
|
+
response = requests.request('POST', url, headers=self.vplan.post_headers, data=json.dumps(base_body), timeout=self.vplan.timeout)
|
|
78
|
+
return response
|
|
79
|
+
|
|
80
|
+
def update_project(self, project_id: str, data: dict) -> requests.Response:
|
|
81
|
+
"""
|
|
82
|
+
Update an existing project in vPlan: https://developer.vplan.com/documentation/#tag/Project/paths/~1project~1%7Bproject_id%7D/put
|
|
83
|
+
|
|
84
|
+
This method constructs a request URL based on the endpoint and sends a POST request
|
|
85
|
+
to the vPlan API with the provided data.
|
|
86
|
+
|
|
87
|
+
Args: endpoint (str): The name of the endpoint to create a new project in.
|
|
88
|
+
data (dict): The data to create the new project with.
|
|
89
|
+
|
|
90
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
91
|
+
"""
|
|
92
|
+
required_fields = ['name']
|
|
93
|
+
allowed_fields = ['code', 'description', 'external_ref']
|
|
94
|
+
self.__check_fields(data=data, required_fields=required_fields, allowed_fields=allowed_fields)
|
|
95
|
+
|
|
96
|
+
url = f"{self.vplan.base_url}project/{project_id}"
|
|
97
|
+
|
|
98
|
+
base_body = {
|
|
99
|
+
"name": data['name']
|
|
100
|
+
}
|
|
101
|
+
# Add fields that you want to update a dict (adding to body itself is too much text)
|
|
102
|
+
base_body.update({"code": data['code']}) if 'code' in data else base_body
|
|
103
|
+
base_body.update({"description": data['description']}) if 'description' in data else base_body
|
|
104
|
+
base_body.update({"external_ref": data['external_ref']}) if 'external_ref' in data else base_body
|
|
105
|
+
|
|
106
|
+
response = requests.request('PUT', url, headers=self.vplan.post_headers, data=json.dumps(base_body), timeout=self.vplan.timeout)
|
|
107
|
+
return response
|
|
108
|
+
|
|
109
|
+
def delete_project(self, project_id):
|
|
110
|
+
"""
|
|
111
|
+
Delete an existing project in vPlan: https://developer.vplan.com/documentation/#tag/Project/paths/~1project~1%7Bproject_id%7D/delete
|
|
112
|
+
This method constructs a request URL based on the endpoint and sends a DELETE request to the vPlan API.
|
|
113
|
+
"""
|
|
114
|
+
url = f"{self.vplan.base_url}project/{project_id}"
|
|
115
|
+
response = requests.request('DELETE', url, headers=self.vplan.headers, timeout=self.vplan.timeout)
|
|
116
|
+
return response
|
|
117
|
+
|
|
118
|
+
@staticmethod
|
|
119
|
+
def __check_fields(data: Union[dict, List], required_fields: List, allowed_fields: List):
|
|
120
|
+
if isinstance(data, dict):
|
|
121
|
+
data = data.keys()
|
|
122
|
+
|
|
123
|
+
for field in data:
|
|
124
|
+
if field not in allowed_fields and field not in required_fields:
|
|
125
|
+
warnings.warn('Field {field} is not implemented. Optional fields are: {allowed_fields}'.format(field=field, allowed_fields=tuple(allowed_fields)))
|
|
126
|
+
|
|
127
|
+
for field in required_fields:
|
|
128
|
+
if field not in data:
|
|
129
|
+
raise ValueError('Field {field} is required. Required fields are: {required_fields}'.format(field=field, required_fields=tuple(required_fields)))
|
|
@@ -0,0 +1,142 @@
|
|
|
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 Resource:
|
|
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_resource_list(self, filter: str = None, show: str = None, hide: str = None, archived: bool = False):
|
|
18
|
+
"""
|
|
19
|
+
Get all the resources from vPlan: https://developer.vplan.com/documentation/#tag/Resource/paths/~1resource/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='resource', filter=filter, show=show, hide=hide, archived=archived)
|
|
48
|
+
return df
|
|
49
|
+
|
|
50
|
+
def post_resource(self, data: dict) -> requests.Response:
|
|
51
|
+
"""
|
|
52
|
+
Create a new resource in vPlan: https://developer.vplan.com/documentation/#tag/Resource/paths/~1resource/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 resource in.
|
|
58
|
+
data (dict): The data to create the new resource with.
|
|
59
|
+
|
|
60
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
61
|
+
"""
|
|
62
|
+
required_fields = ['name']
|
|
63
|
+
allowed_fields = ['type', 'start_date', 'workdays', 'description', 'end_date', 'integration_schedule', 'avatar', 'color_hex', '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}resource"
|
|
67
|
+
|
|
68
|
+
base_body = {
|
|
69
|
+
"name": data['name']
|
|
70
|
+
}
|
|
71
|
+
# Add fields that you want to update a dict (adding to body itself is too much text)
|
|
72
|
+
base_body.update({"type": data['type']}) if 'type' in data else base_body
|
|
73
|
+
base_body.update({"start_date": data['start_date']}) if 'start_date' in data else base_body
|
|
74
|
+
base_body.update({"workdays": eval(data['workdays'])}) if 'workdays' in data else base_body
|
|
75
|
+
base_body.update({"description": data['description']}) if 'description' in data else base_body
|
|
76
|
+
base_body.update({"end_date": data['end_date']}) if 'end_date' in data else base_body
|
|
77
|
+
base_body.update({"integration_schedule": data['integration_schedule']}) if 'integration_schedule' in data else base_body
|
|
78
|
+
base_body.update({"avatar": data['avatar']}) if 'avatar' in data else base_body
|
|
79
|
+
base_body.update({"color_hex": data['color_hex']}) if 'color_hex' in data else base_body
|
|
80
|
+
base_body.update({"external_ref": data['external_ref']}) if 'external_ref' in data else base_body
|
|
81
|
+
base_body.update({"archive": data['archive']}) if 'archive' in data else base_body
|
|
82
|
+
|
|
83
|
+
response = requests.request('POST', url, headers=self.vplan.post_headers, data=json.dumps(base_body), timeout=self.vplan.timeout)
|
|
84
|
+
return response
|
|
85
|
+
|
|
86
|
+
def update_resource(self, resource_id: str, data: dict) -> requests.Response:
|
|
87
|
+
"""
|
|
88
|
+
Update an existing resource in vPlan: https://developer.vplan.com/documentation/#tag/Resource/paths/~1resource/put
|
|
89
|
+
|
|
90
|
+
This method constructs a request URL based on the endpoint and sends a POST request
|
|
91
|
+
to the vPlan API with the provided data.
|
|
92
|
+
|
|
93
|
+
Args: endpoint (str): The name of the endpoint to create a new resource in.
|
|
94
|
+
data (dict): The data to create the new resource with.
|
|
95
|
+
|
|
96
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
97
|
+
"""
|
|
98
|
+
required_fields = []
|
|
99
|
+
allowed_fields = ['name', 'type', 'start_date', 'workdays', 'description', 'end_date', 'integration_schedule', 'avatar', 'color_hex', 'external_ref', 'archive']
|
|
100
|
+
self.__check_fields(data=data, required_fields=required_fields, allowed_fields=allowed_fields)
|
|
101
|
+
|
|
102
|
+
url = f"{self.vplan.base_url}resource/{resource_id}"
|
|
103
|
+
|
|
104
|
+
base_body = {}
|
|
105
|
+
|
|
106
|
+
# Add fields that you want to update a dict (adding to body itself is too much text)
|
|
107
|
+
base_body.update({"name": data['name']}) if 'name' in data else base_body
|
|
108
|
+
base_body.update({"type": data['type']}) if 'type' in data else base_body
|
|
109
|
+
base_body.update({"start_date": data['start_date']}) if 'start_date' in data else base_body
|
|
110
|
+
base_body.update({"workdays": eval(data['workdays'])}) if 'workdays' in data else base_body
|
|
111
|
+
base_body.update({"description": data['description']}) if 'description' in data else base_body
|
|
112
|
+
base_body.update({"end_date": data['end_date']}) if 'end_date' in data else base_body
|
|
113
|
+
base_body.update({"integration_schedule": data['integration_schedule']}) if 'integration_schedule' in data else base_body
|
|
114
|
+
base_body.update({"avatar": data['avatar']}) if 'avatar' in data else base_body
|
|
115
|
+
base_body.update({"color_hex": data['color_hex']}) if 'color_hex' in data else base_body
|
|
116
|
+
base_body.update({"external_ref": data['external_ref']}) if 'external_ref' in data else base_body
|
|
117
|
+
base_body.update({"archive": data['archive']}) if 'archive' in data else base_body
|
|
118
|
+
|
|
119
|
+
response = requests.request('PUT', url, headers=self.vplan.post_headers, data=json.dumps(base_body), timeout=self.vplan.timeout)
|
|
120
|
+
return response
|
|
121
|
+
|
|
122
|
+
def delete_resource(self, resource_id):
|
|
123
|
+
"""
|
|
124
|
+
Delete an existing resource in vPlan: https://developer.vplan.com/documentation/#tag/Resource/paths/~1resource~1%7Bresource_id%7D/delete
|
|
125
|
+
This method constructs a request URL based on the endpoint and sends a DELETE request to the vPlan API.
|
|
126
|
+
"""
|
|
127
|
+
url = f"{self.vplan.base_url}resource/{resource_id}"
|
|
128
|
+
response = requests.request('DELETE', url, headers=self.vplan.headers, timeout=self.vplan.timeout)
|
|
129
|
+
return response
|
|
130
|
+
|
|
131
|
+
@staticmethod
|
|
132
|
+
def __check_fields(data: Union[dict, List], required_fields: List, allowed_fields: List):
|
|
133
|
+
if isinstance(data, dict):
|
|
134
|
+
data = data.keys()
|
|
135
|
+
|
|
136
|
+
for field in data:
|
|
137
|
+
if field not in allowed_fields and field not in required_fields:
|
|
138
|
+
warnings.warn('Field {field} is not implemented. Optional fields are: {allowed_fields}'.format(field=field, allowed_fields=tuple(allowed_fields)))
|
|
139
|
+
|
|
140
|
+
for field in required_fields:
|
|
141
|
+
if field not in data:
|
|
142
|
+
raise ValueError('Field {field} is required. Required fields are: {required_fields}'.format(field=field, required_fields=tuple(required_fields)))
|
|
@@ -0,0 +1,144 @@
|
|
|
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 TimeTracking:
|
|
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_time_tracking_list(self, filter: str = None, show: str = None, hide: str = None):
|
|
18
|
+
"""
|
|
19
|
+
Get all the time records from vPlan: https://developer.vplan.com/documentation/#tag/Time-Tracking/paths/~1time_tracking/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='time_tracking', filter=filter, show=show, hide=hide)
|
|
48
|
+
return df
|
|
49
|
+
|
|
50
|
+
def post_time_tracking(self, data: dict) -> requests.Response:
|
|
51
|
+
"""
|
|
52
|
+
Create a new time record in vPlan: https://developer.vplan.com/documentation/#tag/Time-Tracking/paths/~1time_tracking/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 time record in.
|
|
58
|
+
data (dict): The data to create the new time record with.
|
|
59
|
+
|
|
60
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
61
|
+
"""
|
|
62
|
+
required_fields = ['activity_id', 'start']
|
|
63
|
+
allowed_fields = ['card_id', 'end', 'duration', 'status', 'user_id', 'note', 'locked', 'synchronized_at', 'external_ref', 'external_note', 'external_failed']
|
|
64
|
+
self.__check_fields(data=data, required_fields=required_fields, allowed_fields=allowed_fields)
|
|
65
|
+
|
|
66
|
+
url = f"{self.vplan.base_url}time_tracking"
|
|
67
|
+
|
|
68
|
+
base_body = {
|
|
69
|
+
"activity_id": data['activity_id'],
|
|
70
|
+
"start": data['start']
|
|
71
|
+
}
|
|
72
|
+
# Add fields that you want to update a dict (adding to body itself is too much text)
|
|
73
|
+
base_body.update({"card_id": data['card_id']}) if 'card_id' in data else base_body
|
|
74
|
+
base_body.update({"end": data['end']}) if 'end' in data else base_body
|
|
75
|
+
base_body.update({"duration": data['duration']}) if 'duration' in data else base_body
|
|
76
|
+
base_body.update({"status": data['status']}) if 'status' in data else base_body
|
|
77
|
+
base_body.update({"user_id": data['user_id']}) if 'user_id' in data else base_body
|
|
78
|
+
base_body.update({"note": data['note']}) if 'note' in data else base_body
|
|
79
|
+
base_body.update({"locked": data['locked']}) if 'locked' in data else base_body
|
|
80
|
+
base_body.update({"synchronized_at": data['synchronized_at']}) if 'synchronized_at' in data else base_body
|
|
81
|
+
base_body.update({"external_ref": data['external_ref']}) if 'external_ref' in data else base_body
|
|
82
|
+
base_body.update({"external_note": data['external_note']}) if 'external_note' in data else base_body
|
|
83
|
+
base_body.update({"external_failed": data['external_failed']}) if 'external_failed' in data else base_body
|
|
84
|
+
|
|
85
|
+
response = requests.request('POST', url, headers=self.vplan.post_headers, data=base_body, timeout=self.vplan.timeout)
|
|
86
|
+
return response
|
|
87
|
+
|
|
88
|
+
def update_time_tracking(self, time_tracking_id: str, data: dict) -> requests.Response:
|
|
89
|
+
"""
|
|
90
|
+
Update an existing time record in vPlan: https://developer.vplan.com/documentation/#tag/Time-Tracking/paths/~1time_tracking~1%7Btime_tracking_id%7D/put
|
|
91
|
+
|
|
92
|
+
This method constructs a request URL based on the endpoint and sends a POST request
|
|
93
|
+
to the vPlan API with the provided data.
|
|
94
|
+
|
|
95
|
+
Args: endpoint (str): The name of the endpoint to create a new time record in.
|
|
96
|
+
data (dict): The data to create the new time record with.
|
|
97
|
+
|
|
98
|
+
Returns: requests.Response: The response from the vPlan API.
|
|
99
|
+
"""
|
|
100
|
+
required_fields = []
|
|
101
|
+
allowed_fields = ['activity_id', 'start', 'card_id', 'end', 'duration', 'status', 'user_id', 'note', 'locked', 'synchronized_at', 'external_ref', 'external_note', 'external_failed']
|
|
102
|
+
self.__check_fields(data=data, required_fields=required_fields, allowed_fields=allowed_fields)
|
|
103
|
+
|
|
104
|
+
url = f"{self.vplan.base_url}time_tracking/{time_tracking_id}"
|
|
105
|
+
|
|
106
|
+
base_body = {
|
|
107
|
+
}
|
|
108
|
+
# Add fields that you want to update a dict (adding to body itself is too much text)
|
|
109
|
+
base_body.update({"activity_id": data['activity_id']}) if 'activity_id' in data else base_body
|
|
110
|
+
base_body.update({"start": data['start']}) if 'start' in data else base_body
|
|
111
|
+
base_body.update({"code": data['code']}) if 'code' in data else base_body
|
|
112
|
+
base_body.update({"description": data['description']}) if 'description' in data else base_body
|
|
113
|
+
base_body.update({"stock_management": data['stock_management']}) if 'stock_management' in data else base_body
|
|
114
|
+
base_body.update({"unit": data['unit']}) if 'unit' in data else base_body
|
|
115
|
+
base_body.update({"type": data['type']}) if 'type' in data else base_body
|
|
116
|
+
base_body.update({"location": data['location']}) if 'location' in data else base_body
|
|
117
|
+
base_body.update({"note": data['note']}) if 'note' in data else base_body
|
|
118
|
+
base_body.update({"external_ref": data['external_ref']}) if 'external_ref' in data else base_body
|
|
119
|
+
|
|
120
|
+
response = requests.request('PUT', url, headers=self.vplan.post_headers, json=base_body, timeout=self.vplan.timeout)
|
|
121
|
+
return response
|
|
122
|
+
|
|
123
|
+
def delete_time_tracking(self, time_tracking_id):
|
|
124
|
+
"""
|
|
125
|
+
Delete an existing time record in vPlan: https://developer.vplan.com/documentation/#tag/Time-Tracking/paths/~1time_tracking~1%7Btime_tracking_id%7D/delete
|
|
126
|
+
This method constructs a request URL based on the endpoint and sends a DELETE request to the vPlan API.
|
|
127
|
+
"""
|
|
128
|
+
url = f"{self.vplan.base_url}time_tracking/{time_tracking_id}"
|
|
129
|
+
response = requests.request('DELETE', url, headers=self.vplan.headers, timeout=self.vplan.timeout)
|
|
130
|
+
return response
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@staticmethod
|
|
134
|
+
def __check_fields(data: Union[dict, List], required_fields: List, allowed_fields: List):
|
|
135
|
+
if isinstance(data, dict):
|
|
136
|
+
data = data.keys()
|
|
137
|
+
|
|
138
|
+
for field in data:
|
|
139
|
+
if field not in allowed_fields and field not in required_fields:
|
|
140
|
+
warnings.warn('Field {field} is not implemented. Optional fields are: {allowed_fields}'.format(field=field, allowed_fields=tuple(allowed_fields)))
|
|
141
|
+
|
|
142
|
+
for field in required_fields:
|
|
143
|
+
if field not in data:
|
|
144
|
+
raise ValueError('Field {field} is required. Required fields are: {required_fields}'.format(field=field, required_fields=tuple(required_fields)))
|
brynq_sdk_vplan/user.py
ADDED
|
@@ -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 User:
|
|
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_user_list(self, filter: str = None, show: str = None, hide: str = None):
|
|
18
|
+
"""
|
|
19
|
+
Get all the users from vPlan: https://developer.vplan.com/documentation/#tag/user/paths/~1user/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='user', filter=filter, show=show, hide=hide)
|
|
48
|
+
return df
|
|
49
|
+
|
|
50
|
+
def post_user(self, data: dict) -> requests.Response:
|
|
51
|
+
"""
|
|
52
|
+
Create a new user in vPlan: https://developer.vplan.com/documentation/#tag/user/paths/~1user/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 user in.
|
|
58
|
+
data (dict): The data to create the new user 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}user"
|
|
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, timeout=self.vplan.timeout)
|
|
83
|
+
return response
|
|
84
|
+
|
|
85
|
+
def update_user(self, user_id: str, data: dict) -> requests.Response:
|
|
86
|
+
"""
|
|
87
|
+
Update an existing user in vPlan: https://developer.vplan.com/documentation/#tag/user/paths/~1user~1%7Buser_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 user in.
|
|
93
|
+
data (dict): The data to create the new user 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}user/{user_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, timeout=self.vplan.timeout)
|
|
118
|
+
return response
|
|
119
|
+
|
|
120
|
+
def delete_user(self, user_id):
|
|
121
|
+
"""
|
|
122
|
+
Delete an existing user in vPlan: https://developer.vplan.com/documentation/#tag/user/paths/~1user~1%7Buser_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}user/{user_id}"
|
|
126
|
+
response = requests.request('DELETE', url, headers=self.vplan.headers, timeout=self.vplan.timeout)
|
|
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,17 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: brynq_sdk_vplan
|
|
3
|
+
Version: 2.0.1
|
|
4
|
+
Summary: vPlan 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,>=2
|
|
10
|
+
Dynamic: author
|
|
11
|
+
Dynamic: author-email
|
|
12
|
+
Dynamic: description
|
|
13
|
+
Dynamic: license
|
|
14
|
+
Dynamic: requires-dist
|
|
15
|
+
Dynamic: summary
|
|
16
|
+
|
|
17
|
+
vPlan wrapper from BrynQ
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
brynq_sdk_vplan/__init__.py,sha256=MrarXte0hUoGsw4qYVKiOMOvfv0ysgs9a3b1Oy_yfL4,1766
|
|
2
|
+
brynq_sdk_vplan/activity.py,sha256=Obnobz9-3TLbSF4YCrqo4yr8lUqrX_3FJEKoU657gzc,7399
|
|
3
|
+
brynq_sdk_vplan/get_data.py,sha256=jCc4l4l9ORcCebB_Trxm5Scju-HaB8Vy3BEcbf6NViw,4157
|
|
4
|
+
brynq_sdk_vplan/item.py,sha256=fY-xveKAwtSFiVzybDsAaMfVbay7YhZu2L1GyZ4qUq4,7954
|
|
5
|
+
brynq_sdk_vplan/leave.py,sha256=p72zg5XDiq5RYJflXph91QM0lyPcRE5Q5_G0g9G0l-Y,4729
|
|
6
|
+
brynq_sdk_vplan/order.py,sha256=3hM9I56Eq-cHo6N1_ZaPitcauSv0eUnJDgW-s4HVlN0,11010
|
|
7
|
+
brynq_sdk_vplan/project.py,sha256=oWgLBELcSAy8wSW6CuBlunWEkB3pI1pCdSIe9CR_xJw,6951
|
|
8
|
+
brynq_sdk_vplan/resource.py,sha256=siBSdRsR907ZHt9cB4NFz06yybSORLcixWn8_y8Qs98,8641
|
|
9
|
+
brynq_sdk_vplan/time_tracking.py,sha256=UXFl4mg_3M6a0Q3P5N77AlCLWyqmNib5yw5OfD_qYx4,8762
|
|
10
|
+
brynq_sdk_vplan/user.py,sha256=Gdc6XFxhCSEwilDiNdeQTo5gd_CsVKgM4H6yk3IDFxI,7942
|
|
11
|
+
brynq_sdk_vplan-2.0.1.dist-info/METADATA,sha256=DuOwWXCTiYd4zePph4aW4pvDMNuLCyAog7urOECzx_o,369
|
|
12
|
+
brynq_sdk_vplan-2.0.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
13
|
+
brynq_sdk_vplan-2.0.1.dist-info/top_level.txt,sha256=XPJLb-gXBFxypv8aGn2jSIj3z9ltI6c_ZMZaLsZzhBk,16
|
|
14
|
+
brynq_sdk_vplan-2.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
brynq_sdk_vplan
|