python-exact-online


Namepython-exact-online JSON
Version 1.0.0 PyPI version JSON
download
home_pagehttps://github.com/alexanderlhsglobal/python-exact-online
SummaryBasic wrapper for the Exact Online REST API (v1)
upload_time2022-12-07 08:22:34
maintainer
docs_urlNone
authorAlexander Schillemans
requires_python
licenseGPL-3.0-or-later
keywords exact exact online api
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # python-exact-online
Basic wrapper for the Exact Online REST API (v1)

## Limitations
Only functionalities that I need are worked out. No intention to develop any further.

# Getting started

### Install

Install with pip.

```python
pip install python-exact-online
```

### Import

Import the package and the ExactOnlineAPI.

```python
from exactonline.api import ExactOnlineAPI
```

### Setup connection

Make the connection with your provided CLIENTID and CLIENTSECRET.

```python
api = ExactOnlineAPI(CLIENTID, CLIENTSECRET)
```

Exact Online authentication is build on OAuth2. A basic script to obtain your first tokens can be found below. After you've obtained your tokens, the refresh tokens are automatically used to renew the token if needed. No manual action is required after that.

```python
from exactonline.api import ExactOnlineAPI

REDIRECT_URI = 'https://any-url-will-do.com/callback/'

api = ExactOnlineAPI(CLIENTID, CLIENTSECRET)

authUrl = api.authHandler.getAuthURL(REDIRECT_URI)
print('visit url: ', authUrl)

response = input('paste response: ')
token = api.authHandler.retrieveToken(response, redirectUri=REDIRECT_URI)
```

When using the script above, any REDIRECT_URI will do. Simply copy and paste the response URI so the handler can obtain the right tokens. 

!! The Redirect URI has to be registered in your Exact App Center.

# Available functionalities

| Object        | Endpoint | Actions       |
| ------------- | ------------- | ------------- |
| SalesEntry/SalesEntryLine  | salesEntries | List, Get, Filter, Create, Update, Delete |
| Documents/Attachments  | documents | List, Get, Filter, Create, Update, Delete  |
| Journals  | journals | List, Get, Filter, Create, Update, Delete  |
| GLAccounts  | glAccounts | List, Get, Filter, Create, Update, Delete  |
| Accounts  | accounts | List, Get, Filter, Create, Update, Delete  |
| Contacts  | contacts | List, Get, Filter, Create, Update, Delete  |
| VATCodes  | vatCodes | List, Get, Filter, Create, Update, Delete  |

## Basic setup

The above endpoints can be used together with their actions. The way to use them are similar to each other.
The examples below are used with the 'accounts' endpoint. Replace them with their respective endpoints in the table above to call other objects.

### List

```python
journals = api.journals.list()

for journal in journals.items():
    print(journal.ID)
```

Some endpoints require you to use a filter. If you do not filter, it will return an error.

```python
# raises ValueError
accounts = api.accounts.list()

# uses mandatory filtering
accounts = api.accounts.list(filter={ 'Blocked' : 'false' })

for account in accounts.items():
    print(account.ID)
```


### Get
```python
accounts = api.accounts.get('uid')
```

Specific fields can be selected while using the get function. This function takes an optional array which contains the fields that need to be returned.

```python
accounts = api.accounts.get('uid', select=['Name', 'Email'])
```

### Filter

Filter on field and value. Returns a list always.

```python
accounts = api.accounts.filter('Email', 'test@test.com')

for account in accounts.items():
    print(account.ID, account.Name)
```

This function also supports the optional select parameter.

```python
accounts = api.accounts.filter('Email', 'test@test.com', select=['Name', 'Email'])
```

### Create

Before creating an object in Exact Online, you need to create the object within Python itself.

```python
account = Account(
    Name='New Account',
    Status='C'
)

exactAccount = api.accounts.create(account)
```

### Update

You can retrieve an object, update its attributes and then push it back to Exact Online.

```python
account = api.accounts.get('uid')
account.Name = 'Updated Account'
api.account.update(acc)
```

Returns True if succeeded.

### Delete
```python
accounts = api.accounts.delete('uid')
```

Returns True if succeeded.


## Creating documents

Creating documents has a slightly different approach, because it allows you to also upload files directly to Exact, linked to the document. Multiple files are supported.

```python
doc = Document(
    Account='uid',
    Type=10,
    Subject='New Document',
)

exactDocument = api.documents.create(doc, ['/path/to/pdf/file.pdf'])
```

## Creating sales entries

When creating sales entries, the corresponding sales lines are expected to be given as well.

```python
salesEntry = SalesEntry(
    Customer='uid',
    Journal='700',
    YourRef='MyREF',
)

lines = SalesEntryLineList()
line1 = SalesEntryLine(AmountFC=100, GLAccount='uid')
line2 = SalesEntryLine(AmountFC=150, GLAccount='uid')

lines.add(line1)
lines.add(line2)

salesEntry.SalesEntryLines = lines

exactEntry = api.salesEntries.create(salesEntry)

print(exactEntry.EntryID, exactEntry.InvoiceNumber, exactEntry.AmountDC)
```

## Retrieving VATPercentages

VATCodes have VATPercentages linked to them. By default, these percentages are not given when requesting a list of VAT Codes.

```python
vatCodes = api.vatCodes.list()

for entry in vatCodes.items():
    for perc in entry.VATPercentages.items():
        # This will contain an empty VATPercentage object
        print(vars(perc))
```

To get the VATPercentages for a VATCode, you need to make a new GET request for that specific VATCode. You can then loop over all the available percentages.

```python
entry = api.vatCodes.get(UID)

for perc in entry.VATPercentages.items():
    print(vars(perc))
```

## Error handling

Basic error handling has been added.
You can check if an error has occured during a call by checking the hasError attribute on the object.
If the hasError attribute has been set to True, an Error object will be attached to the error attribute of the same object.
The Error object contains two attributes: code and message. Usually code will be empty. Message is the error message.

```python
account = api.accounts.get('uid')

if account.hasError:
    print(account.error.message)
else:
    print(account.ID)
```

## Documentation

Find the official Exact Online documentation here: https://start.exactonline.nl/docs/HlpRestAPIResources.aspx?SourceAction=10

You can find what is expected and required for each call.


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/alexanderlhsglobal/python-exact-online",
    "name": "python-exact-online",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "exact,exact online,api",
    "author": "Alexander Schillemans",
    "author_email": "alexander.schillemans@lhs.global",
    "download_url": "https://files.pythonhosted.org/packages/97/6c/4ccb4228bbc50b0d2b76bb0786c5aae116969270dbe63f3455daf2b9dfac/python-exact-online-1.0.0.tar.gz",
    "platform": null,
    "description": "# python-exact-online\r\nBasic wrapper for the Exact Online REST API (v1)\r\n\r\n## Limitations\r\nOnly functionalities that I need are worked out. No intention to develop any further.\r\n\r\n# Getting started\r\n\r\n### Install\r\n\r\nInstall with pip.\r\n\r\n```python\r\npip install python-exact-online\r\n```\r\n\r\n### Import\r\n\r\nImport the package and the ExactOnlineAPI.\r\n\r\n```python\r\nfrom exactonline.api import ExactOnlineAPI\r\n```\r\n\r\n### Setup connection\r\n\r\nMake the connection with your provided CLIENTID and CLIENTSECRET.\r\n\r\n```python\r\napi = ExactOnlineAPI(CLIENTID, CLIENTSECRET)\r\n```\r\n\r\nExact Online authentication is build on OAuth2. A basic script to obtain your first tokens can be found below. After you've obtained your tokens, the refresh tokens are automatically used to renew the token if needed. No manual action is required after that.\r\n\r\n```python\r\nfrom exactonline.api import ExactOnlineAPI\r\n\r\nREDIRECT_URI = 'https://any-url-will-do.com/callback/'\r\n\r\napi = ExactOnlineAPI(CLIENTID, CLIENTSECRET)\r\n\r\nauthUrl = api.authHandler.getAuthURL(REDIRECT_URI)\r\nprint('visit url: ', authUrl)\r\n\r\nresponse = input('paste response: ')\r\ntoken = api.authHandler.retrieveToken(response, redirectUri=REDIRECT_URI)\r\n```\r\n\r\nWhen using the script above, any REDIRECT_URI will do. Simply copy and paste the response URI so the handler can obtain the right tokens. \r\n\r\n!! The Redirect URI has to be registered in your Exact App Center.\r\n\r\n# Available functionalities\r\n\r\n| Object        | Endpoint | Actions       |\r\n| ------------- | ------------- | ------------- |\r\n| SalesEntry/SalesEntryLine  | salesEntries | List, Get, Filter, Create, Update, Delete |\r\n| Documents/Attachments  | documents | List, Get, Filter, Create, Update, Delete  |\r\n| Journals  | journals | List, Get, Filter, Create, Update, Delete  |\r\n| GLAccounts  | glAccounts | List, Get, Filter, Create, Update, Delete  |\r\n| Accounts  | accounts | List, Get, Filter, Create, Update, Delete  |\r\n| Contacts  | contacts | List, Get, Filter, Create, Update, Delete  |\r\n| VATCodes  | vatCodes | List, Get, Filter, Create, Update, Delete  |\r\n\r\n## Basic setup\r\n\r\nThe above endpoints can be used together with their actions. The way to use them are similar to each other.\r\nThe examples below are used with the 'accounts' endpoint. Replace them with their respective endpoints in the table above to call other objects.\r\n\r\n### List\r\n\r\n```python\r\njournals = api.journals.list()\r\n\r\nfor journal in journals.items():\r\n    print(journal.ID)\r\n```\r\n\r\nSome endpoints require you to use a filter. If you do not filter, it will return an error.\r\n\r\n```python\r\n# raises ValueError\r\naccounts = api.accounts.list()\r\n\r\n# uses mandatory filtering\r\naccounts = api.accounts.list(filter={ 'Blocked' : 'false' })\r\n\r\nfor account in accounts.items():\r\n    print(account.ID)\r\n```\r\n\r\n\r\n### Get\r\n```python\r\naccounts = api.accounts.get('uid')\r\n```\r\n\r\nSpecific fields can be selected while using the get function. This function takes an optional array which contains the fields that need to be returned.\r\n\r\n```python\r\naccounts = api.accounts.get('uid', select=['Name', 'Email'])\r\n```\r\n\r\n### Filter\r\n\r\nFilter on field and value. Returns a list always.\r\n\r\n```python\r\naccounts = api.accounts.filter('Email', 'test@test.com')\r\n\r\nfor account in accounts.items():\r\n    print(account.ID, account.Name)\r\n```\r\n\r\nThis function also supports the optional select parameter.\r\n\r\n```python\r\naccounts = api.accounts.filter('Email', 'test@test.com', select=['Name', 'Email'])\r\n```\r\n\r\n### Create\r\n\r\nBefore creating an object in Exact Online, you need to create the object within Python itself.\r\n\r\n```python\r\naccount = Account(\r\n    Name='New Account',\r\n    Status='C'\r\n)\r\n\r\nexactAccount = api.accounts.create(account)\r\n```\r\n\r\n### Update\r\n\r\nYou can retrieve an object, update its attributes and then push it back to Exact Online.\r\n\r\n```python\r\naccount = api.accounts.get('uid')\r\naccount.Name = 'Updated Account'\r\napi.account.update(acc)\r\n```\r\n\r\nReturns True if succeeded.\r\n\r\n### Delete\r\n```python\r\naccounts = api.accounts.delete('uid')\r\n```\r\n\r\nReturns True if succeeded.\r\n\r\n\r\n## Creating documents\r\n\r\nCreating documents has a slightly different approach, because it allows you to also upload files directly to Exact, linked to the document. Multiple files are supported.\r\n\r\n```python\r\ndoc = Document(\r\n    Account='uid',\r\n    Type=10,\r\n    Subject='New Document',\r\n)\r\n\r\nexactDocument = api.documents.create(doc, ['/path/to/pdf/file.pdf'])\r\n```\r\n\r\n## Creating sales entries\r\n\r\nWhen creating sales entries, the corresponding sales lines are expected to be given as well.\r\n\r\n```python\r\nsalesEntry = SalesEntry(\r\n    Customer='uid',\r\n    Journal='700',\r\n    YourRef='MyREF',\r\n)\r\n\r\nlines = SalesEntryLineList()\r\nline1 = SalesEntryLine(AmountFC=100, GLAccount='uid')\r\nline2 = SalesEntryLine(AmountFC=150, GLAccount='uid')\r\n\r\nlines.add(line1)\r\nlines.add(line2)\r\n\r\nsalesEntry.SalesEntryLines = lines\r\n\r\nexactEntry = api.salesEntries.create(salesEntry)\r\n\r\nprint(exactEntry.EntryID, exactEntry.InvoiceNumber, exactEntry.AmountDC)\r\n```\r\n\r\n## Retrieving VATPercentages\r\n\r\nVATCodes have VATPercentages linked to them. By default, these percentages are not given when requesting a list of VAT Codes.\r\n\r\n```python\r\nvatCodes = api.vatCodes.list()\r\n\r\nfor entry in vatCodes.items():\r\n    for perc in entry.VATPercentages.items():\r\n        # This will contain an empty VATPercentage object\r\n        print(vars(perc))\r\n```\r\n\r\nTo get the VATPercentages for a VATCode, you need to make a new GET request for that specific VATCode. You can then loop over all the available percentages.\r\n\r\n```python\r\nentry = api.vatCodes.get(UID)\r\n\r\nfor perc in entry.VATPercentages.items():\r\n    print(vars(perc))\r\n```\r\n\r\n## Error handling\r\n\r\nBasic error handling has been added.\r\nYou can check if an error has occured during a call by checking the hasError attribute on the object.\r\nIf the hasError attribute has been set to True, an Error object will be attached to the error attribute of the same object.\r\nThe Error object contains two attributes: code and message. Usually code will be empty. Message is the error message.\r\n\r\n```python\r\naccount = api.accounts.get('uid')\r\n\r\nif account.hasError:\r\n    print(account.error.message)\r\nelse:\r\n    print(account.ID)\r\n```\r\n\r\n## Documentation\r\n\r\nFind the official Exact Online documentation here: https://start.exactonline.nl/docs/HlpRestAPIResources.aspx?SourceAction=10\r\n\r\nYou can find what is expected and required for each call.\r\n\r\n",
    "bugtrack_url": null,
    "license": "GPL-3.0-or-later",
    "summary": "Basic wrapper for the Exact Online REST API (v1)",
    "version": "1.0.0",
    "split_keywords": [
        "exact",
        "exact online",
        "api"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "md5": "75d54cfc06102d1f0a23df9414b5746e",
                "sha256": "3fd70d9833f236cd057d4691da46496888e564218f966211459c7f20eefde420"
            },
            "downloads": -1,
            "filename": "python-exact-online-1.0.0.tar.gz",
            "has_sig": false,
            "md5_digest": "75d54cfc06102d1f0a23df9414b5746e",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 27995,
            "upload_time": "2022-12-07T08:22:34",
            "upload_time_iso_8601": "2022-12-07T08:22:34.469224Z",
            "url": "https://files.pythonhosted.org/packages/97/6c/4ccb4228bbc50b0d2b76bb0786c5aae116969270dbe63f3455daf2b9dfac/python-exact-online-1.0.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2022-12-07 08:22:34",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "alexanderlhsglobal",
    "github_project": "python-exact-online",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "python-exact-online"
}
        
Elapsed time: 0.03872s