diff --git a/.idea/akaunting-py.iml b/.idea/akaunting-py.iml index 60b03b1..d6db46e 100644 --- a/.idea/akaunting-py.iml +++ b/.idea/akaunting-py.iml @@ -4,6 +4,7 @@ + diff --git a/akauntingpy/api.py b/akauntingpy/api.py index 5797247..3848a88 100644 --- a/akauntingpy/api.py +++ b/akauntingpy/api.py @@ -4,7 +4,7 @@ from requests.auth import HTTPBasicAuth from akauntingpy import exceptions from akauntingpy.helpers import * -__version__ = "1.0.2" +__version__ = "1.0.3" class Client(object): @@ -18,16 +18,21 @@ class Client(object): username, password, company_id, + ssl_verify=True, currency_code="NZD", currency_rate="1.0"): """ Create a new instance. Args: - url (str): The URL to the Akaunting api. - username (str): The username of the Akaunting credentials. - password (str): The password of the Akaunting credentials. + url (str): The URL to the Akaunting api. ** required ** + username (str): The username of the Akaunting credentials. ** required ** + password (str): The password of the Akaunting credentials. ** required ** + company_id (str): The company ID from Akaunting + currency_code (str): The currency code. default is NZD + currency_rate (str): The currency rate. default is "1.0" """ self.url = url + self.ssl_verify = ssl_verify self.authentication = HTTPBasicAuth(username, password) self.headers = { 'User-Agent': 'AkauntingPy v' + __version__, @@ -44,7 +49,8 @@ class Client(object): url=self.url + "/" + endpoint, headers=self.headers, auth=self.authentication, - params=MergeDict(self.default_params, params) + params=MergeDict(self.default_params, params), + verify=self.ssl_verify ) response_ = response.json() @@ -73,17 +79,45 @@ class Client(object): if params.get('search', False): # Check if there is an account returned - if data['meta']['pagination'].get('count') == 0: - # No account found - raise exceptions.AccountNotFound("Sorry, account not found matching search parameters: %s".format( - params.get('search') - )) + try: + if data['meta']['pagination'].get('count') == 0: + # No account found + raise exceptions.AccountNotFound("Sorry, account not found matching search parameters: %s".format( + params.get('search') + )) + except KeyError as e: + # New API 3.0 + if data['meta']['total'] == 0: + raise exceptions.AccountNotFound("Sorry, account not found matching search parameters: %s".format( + params.get('search') + )) + + return data['data'] + + def get_contact(self, **params): + data = self.call(endpoint="contacts", **params) + print(data) + if params.get('search', False): + try: + # Check if there is an account returned + if data['meta']['pagination'].get('count') == 0: + # No account found + raise exceptions.AccountNotFound("Sorry, contact not found matching search parameters: %s".format( + params.get('search') + )) + except KeyError as e: + # New API 3.0 + if data['meta']['total'] == 0: + raise exceptions.AccountNotFound("Sorry, contact not found matching search parameters: %s".format( + params.get('search') + )) return data['data'] def create_transaction(self, transaction_type='income', # Payment method type account_id=None, # Account ID to assign + number="NULL", # Transaction number category_id=None, # Category ID to assign contact_id=None, # Contact ID/Client to assign description=None, # Description @@ -106,6 +140,7 @@ class Client(object): data = self.call(endpoint="transactions", method="POST", search="type:" + transaction_type, + number=number, type=transaction_type, account_id=account_id, category_id=category_id, @@ -121,18 +156,17 @@ class Client(object): ) return data - def create_transfer(self, - from_account_id=None, # Account ID to create transfer from - to_account_id=None, # Account ID to create transfer to - transferred_at=None, # Date of expense/transfer or income - payment_method="Bank Transfer", # Payment method - amount=None, # Amount received/paid - **params # Any additional parameters - ): - - data = self.call(endpoint="transfers", - method="POST", + from_account_id=None, # Account ID to create transfer from + to_account_id=None, # Account ID to create transfer to + transferred_at=None, # Date of expense/transfer or income + payment_method="Bank Transfer", # Payment method + amount=None, # Amount received/paid + **params # Any additional parameters + ): + + data = self.call(endpoint="transfers", + method="POST", from_account_id=from_account_id, to_account_id=to_account_id, transferred_at=transferred_at, @@ -140,4 +174,4 @@ class Client(object): amount=EnsurePositiveInteger(amount), **params ) - return data \ No newline at end of file + return data diff --git a/akauntingpy/exceptions.py b/akauntingpy/exceptions.py index 7f101ca..ec738b1 100644 --- a/akauntingpy/exceptions.py +++ b/akauntingpy/exceptions.py @@ -23,6 +23,14 @@ class AccountNotFound(Error): """ Account not found + Args: + Error (_type_): _description_ + """ + +class ContactNotFound(Error): + """ + Account not found + Args: Error (_type_): _description_ """ \ No newline at end of file diff --git a/tests/api_test.py b/tests/api_test.py index 3b55e15..e827fe0 100644 --- a/tests/api_test.py +++ b/tests/api_test.py @@ -11,24 +11,24 @@ from requests.auth import HTTPBasicAuth class TestAPI: @pytest.fixture() def setUp(self): - c = akauntingpy.Client("https://akaunting.guise.net.nz/api", - "aaron@guise.net.nz", - "L3Tm31N0w", + c = akauntingpy.Client("https://someakaunting-url/api", + "some-emailaddress@somewhere.com", + "aPassWord", 1) yield c @pytest.fixture() def setUpFailed(self): - c = akauntingpy.Client("https://akaunting.guise.net.nz/api", - "aaron@guise.net.nz", - "L3Tm31N0w1", + c = akauntingpy.Client("https://someakaunting-url/api", + "some-emailaddress@somewhere.com", + "aWrongPassWord", 1) yield c def test_init(self, setUp): c = setUp assert isinstance(c, akauntingpy.Client) - assert c.url == "https://akaunting.guise.net.nz/api" + assert c.url == "https://someakaunting-url/api" assert isinstance(c.authentication, HTTPBasicAuth) def test_ping_success(self, setUp, requests_mock): @@ -55,19 +55,32 @@ class TestAPI: json=RetrieveJSONFromFile("data/GetAccountsList.json")) data = c.get_accounts(params={'page': 1, 'limit': 200}) - def test_get_account_search(self, setUp, requests_mock): + def test_get_account_search_v2(self, setUp, requests_mock): c = setUp - requests_mock.get(c.url + "/accounts?search=number%3A38-9011-0510023-03¶ms=page¶ms=limit&company_id=1", - json=RetrieveJSONFromFile("data/GetAccountsSearch.json")) - data = c.get_accounts(search="number:38-9011-0510023-03", params={'page': 1, 'limit': 200}) + requests_mock.get(c.url + "/accounts?search=number%3A00-0000-0000000-00¶ms=page¶ms=limit&company_id=1", + json=RetrieveJSONFromFile("data/v2/GetAccountsSearch.json")) + data = c.get_accounts(search="number:00-0000-0000000-00", params={'page': 1, 'limit': 200}) - def test_get_account_search_not_found(self, setUp, requests_mock): + def test_get_account_search_v3(self, setUp, requests_mock): + c = setUp + requests_mock.get(c.url + "/accounts?search=number%3A00-0000-0000000-00¶ms=page¶ms=limit&company_id=1", + json=RetrieveJSONFromFile("data/v3/GetAccountsSearch.json")) + data = c.get_accounts(search="number:00-0000-0000000-00", params={'page': 1, 'limit': 200}) + + def test_get_account_search_not_found_v2(self, setUp, requests_mock): c = setUp requests_mock.get(c.url + "/accounts?search=number%3Aarandomvalue&company_id=1", - json=RetrieveJSONFromFile("data/GetAccountsSearchNotFound.json")) + json=RetrieveJSONFromFile("data/v2/GetAccountsSearchNotFound.json")) with pytest.raises(AccountNotFound): data = c.get_accounts(search="number:arandomvalue") + def test_get_account_search_not_found_v3(self, setUp, requests_mock): + c = setUp + requests_mock.get(c.url + "/accounts?search=number%3Aarandomvalue&company_id=1", + json=RetrieveJSONFromFile("data/v3/GetAccountsSearchNotFound.json")) + with pytest.raises(AccountNotFound): + data = c.get_accounts(search="number:arandomvalue") + def test_create_transaction_income_success(self, setUp, requests_mock, transaction_type='income', # Payment method type account_id=2, # Account ID to assign