removed lru_cache, made get_all_invoices_for_org_name faster, started revising readme

This commit is contained in:
2022-04-23 18:25:31 +02:00
parent 0dc6e84727
commit 43aaddedaa
2 changed files with 23 additions and 27 deletions

View File

@@ -1,23 +1,18 @@
# AVT Fresh! # AVT Fresh!
This is a wrapper of [the Freshbooks web API](https://www.freshbooks.com/api/start). It is far from comprehensive: It was created for the specific client- and invoice-related needs of [Averbach Transcription](https://avtranscription.com). This is a wrapper of [the Freshbooks web API](https://www.freshbooks.com/api/start). It is far from comprehensive: It was created for the specific client- and invoice-related needs of [Averbach Transcription](https://avtranscription.com). However, there are "band-aids" here to work around some of the API's shortcomings. For example, you don't have to deal with pagination at all. 🎉
There are "band-aids" here to work around some of the API's shortcomings. For example, you don't have to deal with pagination at all. 🎉 Install it with `pip install avt-fresh`.
# Installation Here's how you use it:
```
pip install avt-fresh
```
# Usage
Instantiate the avt_fresh `Client` like so, and you're off to the races:
```python ```python
from avt_fresh import ApiClient from avt_fresh import ApiClient
client = ApiClient(client_secret="...", client_id="...", redirect_uri="https://...", account_id="...") client = ApiClient(client_secret="...", client_id="...", redirect_uri="https://...", account_id="...")
monster_invoices = client.get_all_invoices_for_org_name("Monsters Inc") monster_invoices = client.get_all_invoices_for_org_name("Monsters Inc")
client.get_one_invoice(12345)
``` ```
You can get and set the required arguments to `ApiClient` [here](https://my.freshbooks.com/#/developer). Well, all of them except `FRESHBOOKS_ACCOUNT_ID`, which you can see (there's got to be another way??) by clicking on one of your invoices and grabbing the substring here: `https://my.freshbooks.com/#/invoice/<THIS THING>-1234567`. You can get and set the required arguments to `ApiClient` [here](https://my.freshbooks.com/#/developer). Well, all of them except `FRESHBOOKS_ACCOUNT_ID`, which you can see (there's got to be another way??) by clicking on one of your invoices and grabbing the substring here: `https://my.freshbooks.com/#/invoice/<THIS THING>-1234567`.
@@ -145,8 +140,8 @@ client = Client(
client_id="...", client_id="...",
redirect_uri="https://...", redirect_uri="https://...",
account_id="...", account_id="...",
token_store=avt_fresh.token.TokenStoreOnRedis, token_store=avt_fresh.token.TokenStoreOnRedis,
connection_string="rediss://..." , connection_string="redis://..." ,
) )
``` ```

View File

@@ -1,6 +1,6 @@
import datetime as dt import datetime as dt
from decimal import Decimal import decimal
from functools import partial, lru_cache import functools
import typing import typing
WHAT = "invoice" WHAT = "invoice"
@@ -27,22 +27,22 @@ class FreshbooksLine(typing.NamedTuple):
client_id: int client_id: int
description: str description: str
name: str name: str
rate: Decimal rate: decimal.Decimal
line_id: int line_id: int
quantity: Decimal quantity: decimal.Decimal
amount: Decimal amount: decimal.Decimal
@classmethod @classmethod
def from_api(cls, **kwargs): def from_api(cls, **kwargs):
return cls( return cls(
invoice_id=kwargs["invoice_id"], invoice_id=kwargs["invoice_id"],
client_id=kwargs["client_id"], client_id=kwargs["client_id"],
rate=Decimal(kwargs["unit_cost"]["amount"]), rate=decimal.Decimal(kwargs["unit_cost"]["amount"]),
description=kwargs["description"], description=kwargs["description"],
name=kwargs["name"], name=kwargs["name"],
quantity=Decimal(kwargs["qty"]), quantity=decimal.Decimal(kwargs["qty"]),
line_id=kwargs["lineid"], line_id=kwargs["lineid"],
amount=Decimal(kwargs["amount"]["amount"]), amount=decimal.Decimal(kwargs["amount"]["amount"]),
) )
@property @property
@@ -63,9 +63,9 @@ class FreshbooksInvoice(typing.NamedTuple):
invoice_id: int invoice_id: int
number: str number: str
organization: str organization: str
amount: Decimal amount: decimal.Decimal
status: str status: str
amount_outstanding: Decimal amount_outstanding: decimal.Decimal
po_number: str po_number: str
line_id_line_dict: dict line_id_line_dict: dict
line_description_line_dict: dict line_description_line_dict: dict
@@ -101,8 +101,8 @@ class FreshbooksInvoice(typing.NamedTuple):
number=kwargs["invoice_number"], number=kwargs["invoice_number"],
organization=kwargs["organization"], organization=kwargs["organization"],
allowed_gateways=kwargs["allowed_gateways"], allowed_gateways=kwargs["allowed_gateways"],
amount=Decimal(kwargs["amount"]["amount"]), amount=decimal.Decimal(kwargs["amount"]["amount"]),
amount_outstanding=Decimal(kwargs["outstanding"]["amount"]), amount_outstanding=decimal.Decimal(kwargs["outstanding"]["amount"]),
contacts={contact["email"]: contact for contact in kwargs["contacts"]}, contacts={contact["email"]: contact for contact in kwargs["contacts"]},
status=kwargs["v3_status"], status=kwargs["v3_status"],
) )
@@ -115,10 +115,11 @@ def get_all_draft_invoices(*, get_func: typing.Callable) -> list[FreshbooksInvoi
def get_all_invoices_for_org_name( def get_all_invoices_for_org_name(
*, get_func: typing.Callable, org_name: str *, get_func: typing.Callable, org_name: str
) -> list[FreshbooksInvoice]: ) -> list[FreshbooksInvoice]:
return _get(get_func=get_func, org_name=org_name) from avt_fresh.client import get_freshbooks_client_from_org_name
client_id = get_freshbooks_client_from_org_name(get_func=get_func, org_name=org_name).client_id
return get_all_invoices_for_client_id(get_func=get_func, client_id=client_id)
@lru_cache
def get_all_invoices_for_client_id( def get_all_invoices_for_client_id(
*, get_func: typing.Callable, client_id: int *, get_func: typing.Callable, client_id: int
) -> list[FreshbooksInvoice]: ) -> list[FreshbooksInvoice]:
@@ -147,7 +148,7 @@ def _get(
org_name=None, org_name=None,
status=None, status=None,
) -> list[FreshbooksInvoice]: ) -> list[FreshbooksInvoice]:
get_func = partial(get_func, what=WHAT) get_func = functools.partial(get_func, what=WHAT)
if client_id is not None and org_name is not None: if client_id is not None and org_name is not None:
raise ArgumentError("Please provide either client_id or org_name") raise ArgumentError("Please provide either client_id or org_name")