Skip to content

Commit

Permalink
Merge pull request #92 from rogers-obrien-rad/feature/no-ref/create-t…
Browse files Browse the repository at this point in the history
…imecards

Feature/no ref/create timecards
  • Loading branch information
HagenFritz authored Feb 5, 2025
2 parents ea1a300 + 34dc08c commit 099efad
Show file tree
Hide file tree
Showing 11 changed files with 1,094 additions and 134 deletions.
21 changes: 18 additions & 3 deletions ProPyCore/access/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ def get_request(self, api_url, additional_headers=None, params=None):
headers[key] = value

response = requests.get(url, headers=headers)
'''
print(f"Request URL: {response.request.url}")
print(f"Request Headers: {response.request.headers}")
print(f"Request Response: {response.json()}")
'''

if response.ok:
return response.json()
Expand Down Expand Up @@ -91,13 +96,21 @@ def post_request(self, api_url, additional_headers=None, params=None, data=None,

# Make the request with file if necessary
if files is None:
response = requests.post(
headers["Content-Type"] = "application/json"
response = requests.request(
"POST",
url,
headers=headers,
data=data
json=data # Use json parameter instead of data to properly serialize
)
'''
print(f"Request URL: {response.request.url}")
print(f"Request Headers: {response.request.headers}")
print(f"Request Data: {response.request.body}")
'''
elif data is None:
response = requests.post(
response = requests.request(
"POST",
url,
headers=headers,
files=files # use files for multipart/form-data
Expand All @@ -108,8 +121,10 @@ def post_request(self, api_url, additional_headers=None, params=None, data=None,
if response.ok:
return response.json()
else:
'''
print("Response Status Code:", response.status_code)
print("Response Text:", response.text)
'''
raise_exception(response)

def patch_request(self, api_url, additional_headers=None, params=None, data=None, files=False):
Expand Down
13 changes: 8 additions & 5 deletions ProPyCore/access/cost_codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,14 @@ def show(self, company_id, project_id, cost_code_id):
"project_id": project_id
}

cost_code_info = self.get_request(
api_url=f"{self.endpoint}/cost_codes/{cost_code_id}",
additional_headers=headers,
params=params
)
try:
cost_code_info = self.get_request(
api_url=f"{self.endpoint}/{cost_code_id}",
additional_headers=headers,
params=params
)
except Exception as e:
raise NotFoundItemError(f"Could not find Cost Code {identifier}")

return cost_code_info

Expand Down
4 changes: 3 additions & 1 deletion ProPyCore/access/directory/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
from .users import Users
from .vendors import Vendors
from .roles import Roles
from .people import People

class Directory:
def __init__(self, access_token, server_url):
self.trades = Trades(access_token, server_url)
self.users = Users(access_token, server_url)
self.vendors = Vendors(access_token, server_url)
self.roles = Roles(access_token, server_url)
self.roles = Roles(access_token, server_url)
self.people = People(access_token, server_url)
118 changes: 118 additions & 0 deletions ProPyCore/access/directory/people.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
from ..base import Base
from ...exceptions import NotFoundItemError

class People(Base):
"""Access user information on a Company and Project Level"""

def __init__(self, access_token, server_url) -> None:
super().__init__(access_token, server_url)

def get_url(self, company_id, project_id=None):
"""
Returns the url specific to People at company or project level
Parameters
----------
company_id : int
unique identifier for the company
project_id : int, default None
unique identifier for the project
None specifies company-level
Returns
-------
<get_url> : str
url for People request
"""
if project_id is None:
return f"/rest/v1.0/companies/{company_id}/people"
else:
return f"/rest/v1.0/projects/{project_id}/people"

def get(self, company_id, project_id=None, per_page=1000):
"""
Gets a list of all people from the company or project level
Parameters
----------
company_id : int
unique identifier for the company
project_id : int, default None
unique identifier for the project
None specifies company-level
per_page : int, default 100
number of companies to include
Returns
-------
people : list of dict
list where each value is a dict with a person's information
"""
people = []
n_people = 1
page = 1
while n_people > 0:
params = {
"page": page,
"per_page": per_page,
"company_id": company_id # this parameter is only used in Company Vendors, but including it for other requests does not seem to create any issues
}

headers = {
"Procore-Company-Id": f"{company_id}"
}

url = self.get_url(
company_id=company_id,
project_id=project_id
)

people_per_page = self.get_request(
api_url=url,
additional_headers=headers,
params=params
)
n_people = len(people_per_page)

people += people_per_page
page += 1

return people

def find(self, company_id, person_id, project_id=None,):
"""
Finds a person based on their Procore identifier
Parameters
----------
company_id : int
company id that the project is under
person_id : int or str
if int, search by person id
if str with @, search by person email
else, search by person name
project_id : int, default None
unique identifier for the project
None specifies company-level
Returns
-------
person : dict
person-specific dictionary
"""
if isinstance(person_id, int):
key = "id"
elif isinstance(person_id, str) and "@" in person_id:
key = "contact"
subkey = "email"
else:
raise TypeError(f"Invalid person_id type or format: {person_id}. Must be an integer ID or email string.")

for person in self.get(company_id=company_id, project_id=project_id):
if key == "contact":
if person.get(key, {}).get(subkey) == person_id:
return person
elif person[key] == person_id:
return person

raise NotFoundItemError(f"Could not find Person {person_id}")
31 changes: 5 additions & 26 deletions ProPyCore/access/directory/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,9 @@ def find(self, company_id, user_id, project_id=None,):
company_id : int
company id that the project is under
user_id : int or str
user id number - can be in an integer or string format
if int, search by user id
if str with @, search by user email
else, search by user name
project_id : int, default None
unique identifier for the project
None specifies company-level
Expand All @@ -134,6 +136,8 @@ def find(self, company_id, user_id, project_id=None,):
"""
if isinstance(user_id, int):
key = "id"
elif "@" in user_id:
key = "email_address"
else:
key = "name"

Expand All @@ -142,31 +146,6 @@ def find(self, company_id, user_id, project_id=None,):
return user

raise NotFoundItemError(f"Could not find User {user_id}")

def find_by_email(self, company_id, email, project_id=None,):
"""
Finds a user based on their email
Parameters
----------
company_id : int
company id that the project is under
email : str
user's email address
project_id : int, default None
unique identifier for the project
None specifies company-level
Returns
-------
user : dict
user-specific dictionary
"""
for user in self.get(company_id=company_id, project_id=project_id):
if user["email_address"] == email:
return user

raise NotFoundItemError(f"Could not find User with email {email}")

def add(self, company_id, project_id, user_id, permission_template_id=None):
"""
Expand Down
Loading

0 comments on commit 099efad

Please sign in to comment.