Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add QuickBooks connector #922

Open
wants to merge 42 commits into
base: main
Choose a base branch
from

Conversation

mkrausse-ggtx
Copy link
Contributor

This pull request adds a QuickBooks connector to the Parsons library, which allows users to pull time tracking data from QuickBooks Time.

This includes methods for getting data out of the software like users, groups, jobcodes, timesheets, schedules.

@mkrausse-ggtx mkrausse-ggtx changed the title Add QuickBooks connector and related updates Add QuickBooks connector Nov 14, 2023
@mkrausse-ggtx
Copy link
Contributor Author

I am running all the linting commands and it's still not passing the linting tests. Not sure what to do at this point.

@mkrausse-ggtx
Copy link
Contributor Author

Success! I had pasted in the API docs from QB Time and they had all these problems with line length and trailing whitespaces that took forever to fix. But there is a vscode extension for flake8 that highlights all the issues. That helped as opposed to reading that long list of lines in the flake8 output.

Copy link
Collaborator

@shaunagm shaunagm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Matthew! So sorry this ended up taking so long to review, we didn't end up communicating well about who was reviewing what. Overall looks great, just a few minor changes need to merge.

"""
Instantiate the QuickBooks class.

TODO: Add information about the difference between accounting vs time
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a huge deal, but would be nice not to publish the docs with a 'todo' in them. You can always link to a guide distinguishing the two if you don't want to have to write up the distinction yourself.

token: str
A valid QuickBooks Auth Token. Not required if ``QB_AUTH_TOKEN`` env
variable set. Find instructions to create yours here:
https://developer.intuit.com/app/developer/qbo/docs/develop/authentication-and-authorization/oauth-2.0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use the restructured text to markup docstrings to (ie https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#external-links). Here's an example of someone doing this in a Parsons connector: https://github.com/move-coop/parsons/blob/main/parsons/aws/aws_async.py#L30

variable set. Find instructions to create yours here:
https://developer.intuit.com/app/developer/qbo/docs/develop/authentication-and-authorization/oauth-2.0

Quickbooks API Documentation: https://tsheetsteam.github.io/api_docs/#introduction
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, if you can reformat so this is just a link with text "Quickbooks API Documentation" that'd be great - much easier for the docs reader

Only jobcodes with a parent_id set to one of these values will be returned.
Additionally you can use 0 to get only the top-level jobcodes.

Then get the id of any results with has_children=yes
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The formatting of this looks a little weird. Have you built the docs and checked that it looks okay?

@requests_mock.Mocker()
def test_get_jobcodes_with_params(self, mock_request):
# Arrange
mock_request.get(requests_mock.ANY, json=mock_jobcodes_data)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused why this data is here and not in test_quickbooks_data.py. It's not so much data as to make the tests unreadable, but it is inconsistent.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not necesarily the data but the parameters to test that this method works.

result = self.qb.get_groups()

# Assert
self.assertIsInstance(result, Table)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests only test whether the result is a Table, but you return an empty table for most of the methods. So you might also want to test the number of rows > 0 for all of these, and/or test the specific data being returned for each test.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added.

@shaunagm shaunagm assigned shaunagm and unassigned KasiaHinkson Feb 8, 2024
Copy link

github-actions bot commented Feb 12, 2025

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  parsons/quickbooks
  __init__.py
  quickbookstime.py 40, 151, 251, 363, 471, 667, 737
  test/test_quickbooks
  test_quickbookstime.py
  test_quickbookstime_data.py
Project Total  

This report was generated by python-coverage-comment-action

@matthewkrausse
Copy link
Contributor

@shaunagm Guess what?! Got these tests passing.

@shaunagm shaunagm removed their assignment Feb 13, 2025
@shaunagm shaunagm self-assigned this Feb 13, 2025
Copy link
Collaborator

@shaunagm shaunagm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good, just a minor indentation issue and then a possible bug with those parameters - whether or not you want to implement the design of switching out explicit paremters for **kwargs is up to you.

All Args are optional.

`Args:`
ids: Int
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like there might be an indentation issue here? Can you fix it so all args are at the same level of indentation?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

"modified_before": modified_before,
"modified_since": modified_since,
"supplemental_data": supplemental_data,
"per_page": per_page,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like the querystring dict is missing the "page" parameter listed in the docstring?

You could maybe do something programmatic with these functions, where you accept **kwargs and then pass them along to qb_get_request (if there are any functions where there's a param that doesn't go into the querystring, you could pop it in that function). That would decrease the size of the functions and also prevent accidentally missing parameters.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the page param to all the functions that were missing it. Not sure I want to refactor all that but if you think I should, I can.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @matthewkrausse I'm still confused. The default is 0 but is there any way to override the default? The page parameter getting passed in here seems to be overwritten in qb_get_request.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you are saying. I made a change in the qb_get_request method to address that.

Copy link
Contributor

@matthewkrausse matthewkrausse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @matthewkrausse I'm still confused. The default is 0 but is there any way to override the default? The page parameter getting passed in here seems to be overwritten in qb_get_request.

I see what you are saying. I went ahead and fixed the issue in the qb_get_request method and did a little bit of refactoring to make it a bit more clear.

result = self.qb.get_groups()

# Assert
self.assertIsInstance(result, Table)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added.

@requests_mock.Mocker()
def test_get_jobcodes_with_params(self, mock_request):
# Arrange
mock_request.get(requests_mock.ANY, json=mock_jobcodes_data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not necesarily the data but the parameters to test that this method works.

All Args are optional.

`Args:`
ids: Int
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

"modified_before": modified_before,
"modified_since": modified_since,
"supplemental_data": supplemental_data,
"per_page": per_page,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the page param to all the functions that were missing it. Not sure I want to refactor all that but if you think I should, I can.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: In Review
Development

Successfully merging this pull request may close these issues.

4 participants