Skip to content

Commit

Permalink
Merge pull request #2 from dnbasta/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
dnbasta authored Apr 23, 2024
2 parents a9d1c31 + a9a830f commit 3000fac
Show file tree
Hide file tree
Showing 33 changed files with 841 additions and 650 deletions.
56 changes: 30 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# ynab-transaction-adjuster

[![GitHub Release](https://img.shields.io/github/release/dnbasta/ynab-transaction-adjuster?style=flat)]()
[![Github Release](https://img.shields.io/maintenance/yes/2100)]()
[![Maintained](https://img.shields.io/maintenance/yes/2100)]()
[![Monthly downloads](https://img.shields.io/pypi/dm/ynab-transaction-adjuster)]()

[!["Buy Me A Coffee"](https://img.shields.io/badge/Buy_Me_A_Coffee-FFDD00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/dnbasta)

Expand All @@ -27,46 +28,49 @@ A detailed documentation is available at https://ynab-transaction-adjuster.readt
# Basic Usage

### Create an Adjuster
Create a child class of `YnabTransactionAdjuster`.
This class needs to implement a `filter()` and an `adjust()` method which contain the intended logic. The `filter()`
method receives a list of `OriginalTransaction` objects which can be filtered before
adjustement. The `adjust()` method receives a singular `OriginalTransaction` and a
`TransactionModifier`. The latter is prefilled with values from the original transaction.
Its attributes can be modified, and it needs to be returned at the end of the function.
Please check the [detailed usage](https://ynab-transaction-adjuster.readthedocs.io/en/latest/detailed_usage/) section for explanations how to change different attributes.
Create a child class of `Adjuster`. This class needs to implement a `filter()` and an `adjust()` method which contain
the intended logic. The `filter()` method receives a list of `Transaction` objects which can be filtered before
adjustement. The `adjust()` method receives a single `Transaction` and a `Modifier`.The latter is prefilled with values
from the original transaction and can be altered. The modifier needs to be returned at the end of the function.
Please check the [detailed usage](https://ynab-transaction-adjuster.readthedocs.io/en/latest/detailed_usage/) section
for explanations how to change different attributes.

```py
from ynabtransactionadjuster import YnabTransactionAdjuster
from ynabtransactionadjuster.models import OriginalTransaction, TransactionModifier
from ynabtransactionadjuster import Adjuster, Transaction, Modifier


class MyAdjuster(Adjuster):

def filter(self, transactions: List[Transaction]) -> List[Transaction]:
# your implementation

class MyAdjuster(YnabTransactionAdjuster):

def filter(self, transactions: List[OriginalTransaction]) -> List[OriginalTransaction]:
# your implementation

# return the filtered list of transactions
return transactions

def adjust(self, original: OriginalTransaction, modifier: TransactionModifier) -> TransactionModifier:
# your implementation
# return the filtered list of transactions
return transactions

def adjust(self, transaction: Transaction, modifier: Modifier) -> Modifier:
# your implementation

# return the altered modifier
return modifier
```

### Initialize
Initalize the adjuster with `token`, `budget` and `account` from YNAB
Create a [`Credentials`][models.Credentials] object and initialize Adjuster class with it
```py
my_adjuster = MyAdjuster(token='<token>', budget='<budget>', account='<account>')
from ynabtransactionadjuster import Credentials

my_credentials = Credentials(token='<token>', budget='<budget>', account='<account>')
my_adjuster = MyAdjuster.from_credentials(credentials=my_credentials)
```

### Test
Test the adjuster on records fetched via the `test()`method. The method fetches and executes the
adjustments but doesn't write the results back to YNAB. Instead it returns a list of
the changed transactions which can be inspected for the changed properties.
Test the adjuster on records fetched via the `dry_run()` method. It executes the adjustments but doesn't write the
results back to YNAB. Instead it returns a list of the changed transactions which can be inspected for the changed
properties. It takes an optional parameter `pretty_print` which, if set to `True`, prints modifications in an easy
readable string representation to the console.

```py
mod_transactions = my_adjuster.test()
mod_transactions = my_adjuster.dry_run()
```

### Run
Expand Down
50 changes: 27 additions & 23 deletions docs/basic_usage.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,50 @@
# Basic Usage

### Create an Adjuster
Create a child class of [`YnabTransactionAdjuster`][ynabtransactionadjuster.YnabTransactionAdjuster].
Create a child class of [`Adjuster`][ynabtransactionadjuster.Adjuster].
This class needs to implement a `filter()` and an `adjust()` method which contain the intended logic. The `filter()`
method receives a list of [`OriginalTransaction`][models.OriginalTransaction] objects which can be filtered before
adjustement. The `adjust()` method receives a singular [`OriginalTransaction`][models.OriginalTransaction] and a
[`TransactionModifier`][models.TransactionModifier]. The latter is prefilled with values from the original transaction.
Its attributes can be modified, and it needs to be returned at the end of the function.
method receives a list of [`Transaction`][models.Transaction] objects which can be filtered before
adjustement. The `adjust()` method receives a single [`Transaction`][models.Transaction] and a
[`Modifier`][models.Modifier]. The latter is prefilled with values from the original transaction and can be altered.
The modifier needs to be returned at the end of the function.
Please check the [detailed usage](detailed_usage.md) section for explanations how to change different attributes.

```py
from ynabtransactionadjuster import YnabTransactionAdjuster
from ynabtransactionadjuster.models import OriginalTransaction, TransactionModifier
from ynabtransactionadjuster import Adjuster, Transaction, Modifier


class MyAdjuster(Adjuster):

def filter(self, transactions: List[Transaction]) -> List[Transaction]:
# your implementation

class MyAdjuster(YnabTransactionAdjuster):

def filter(self, transactions: List[OriginalTransaction]) -> List[OriginalTransaction]:
# your implementation

# return the filtered list of transactions
return transactions

def adjust(self, original: OriginalTransaction, modifier: TransactionModifier) -> TransactionModifier:
# your implementation
# return the filtered list of transactions
return transactions

def adjust(self, transaction: Transaction, modifier: Modifier) -> Modifier:
# your implementation

# return the altered modifier
return modifier
```

### Initialize
Initalize the adjuster with `token`, `budget` and `account` from YNAB
Create a [`Credentials`][models.Credentials] object and initialize Adjuster class with it
```py
my_adjuster = MyAdjuster(token='<token>', budget='<budget>', account='<account>')
from ynabtransactionadjuster import Credentials

my_credentials = Credentials(token='<token>', budget='<budget>', account='<account>')
my_adjuster = MyAdjuster.from_credentials(credentials=my_credentials)
```

### Test
Test the adjuster on records fetched via the `test()`method. The method fetches and executes the
adjustments but doesn't write the results back to YNAB. Instead it returns a list of
the changed transactions which can be inspected for the changed properties.
Test the adjuster on records fetched via the `dry_run()` method. It executes the adjustments but doesn't write the
results back to YNAB. Instead it returns a list of the changed transactions which can be inspected for the changed
properties. It takes an optional parameter `pretty_print` which, if set to `True`, prints modifications in an easy
readable string representation to the console.

```py
mod_transactions = my_adjuster.test()
mod_transactions = my_adjuster.dry_run()
```

### Run
Expand Down
128 changes: 56 additions & 72 deletions docs/detailed_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,97 +2,81 @@
## Change the category
The `adjust()` method allows changing the category of the transaction. For that purpose the adjuster class comes with a
[`CategoryRepo`][repos.CategoryRepo] instance attached which can be used in the method via `self.categories`. The repo
can be called with either `fetch_by_name()` or `fetch_by_id()` method to fetch a valid category. Using the repo is
recommended to ensure you only assign valid categories to the modifier. The library doesn't allow creating new
categories and specifying a non-existing category will raise an error.
can be called with either `fetch_by_name()` or `fetch_by_id()` method to fetch a valid category. `fetch_all()` will
return a `dict` with group names as key and a list of categories as values. It can be used for custom search patterns
if needed. Using the category lookup is recommended to ensure only assign valid categories are assigned. The library
doesn't allow creating new categories and specifying a non-existing category will raise an error.

```py
from ynabtransactionadjuster import YnabTransactionAdjuster
from ynabtransactionadjuster import Adjuster


class MyAdjusterFactory(YnabTransactionAdjuster):

def filter(self, transactions):
return transactions

def adjust(self, original, modifier):
my_category = self.categories.fetch_by_name('my_category')
# or alternatively
my_category = self.categories.fetch_by_id('category_id')
modifier.category = my_category
class MyAdjusterFactory(Adjuster):

return modifier
```
The [`CategoryRepo`][repos.CategoryRepo] instance gets build when the adjuster gets initialized and can also be accessed
from the main instance (e.g. for finding category ids to be used in the parser later). The `fetch_all()` method fetches
all categories and returns a dict with group name as key and list of categories as values.
```py
my_adjuster = MyAdjuster(token='<token>', budget='<budget>', account='<account>')
categories = my_adjuster.categories.fetch_all()
def filter(self, transactions):
return transactions

def adjust(self, transaction, modifier):
my_category = self.categories.fetch_by_name('my_category')
# or alternatively
my_category = self.categories.fetch_by_id('category_id')
modifier.category = my_category

return modifier
```

## Change the payee
The payee of the transaction can be changed either by creating a new [`Payee`][models.Payee] object or fetching an
existing payee from the [`PayeeRepo`][repos.PayeeRepo] which can be used in the adjust function via `self.payees`. The
repo can be called with either `fetch_by_name()` or `fetch_by_id()` method to fetch an existing payee. It can also be
called with `fetch_by_transfer_account_id()` to fetch a transfer payee. You can find the account id for the transfer
account following the method mentioned in the [preparations](#preparations) section.
called with `fetch_by_transfer_account_id()` to fetch a transfer payee or with `fetch_all()`to get all payees.
You can find the account id for the transfer account following the method mentioned in the [preparations](#preparations) section.

```py
from ynabtransactionadjuster import YnabTransactionAdjuster
from ynabtransactionadjuster.models import Payee


class MyAdjuster(YnabTransactionAdjuster):

def filter(self, transactions):
return transactions

def adjust(self, original, modifier):
my_payee = Payee(name='My Payee')
# or
my_payee = self.payees.fetch_by_name('My Payee')
# or
my_payee = self.payees.fetch_by_id('payee_id')
# or for transfers
my_payee = self.payees.fetch_by_transfer_account_id('transfer_account_id')
modifier.payee = my_payee

return modifier
```
The [`PayeeRepo`][repos.PayeeRepo] instance gets build when the adjuster gets initialized and can also be accessed
from the main instance. The `fetch_all()` method fetches all payees in the budget.
from ynabtransactionadjuster import Adjuster, Payee

```py
my_adjuster = MyAdjuster(token='<token>', budget='<budget>', account='<account>')
payees = my_adjuster.payees.fetch_all()
class MyAdjuster(Adjuster):

def filter(self, transactions):
return transactions

def adjust(self, transaction, modifier):
my_payee = Payee(name='My Payee')
# or
my_payee = self.payees.fetch_by_name('My Payee')
# or
my_payee = self.payees.fetch_by_id('payee_id')
# or for transfers
my_payee = self.payees.fetch_by_transfer_account_id('transfer_account_id')
modifier.payee = my_payee

return modifier
```

## Split the transaction
The transaction can be splitted if the original transaction is not already a split (YNAB doesn't allow updating splits
of an existing split transaction). Splits can be created by using [`SubTransaction`][models.SubTransaction] instances.
There must be at least two subtransactions and the sum of their amounts must be equal to the amount of the original
transaction.
The transaction can be split if the original transaction is not already a split (YNAB doesn't allow updating splits
of an existing split transaction). Splits can be created by using [`ModifierSubTransaction`][models.ModifierSubTransaction]
instances. There must be at least two subtransactions and the sum of their amounts must be equal to the amount of the
original transaction.

```py
from ynabtransactionadjuster import YnabTransactionAdjuster
from ynabtransactionadjuster.models import SubTransaction


class MyAdjuster(YnabTransactionAdjuster):

def filter(self, transactions):
return transactions

def adjust(self, original, modifier):
# example for splitting a transaction in two equal amount subtransactions with different categories
subtransaction_1 = SubTransaction(amount=original.amount / 2,
category=original.category)
subtransaction_2 = SubTransaction(amount=original.amount / 2,
category=self.categories.fetch_by_name('My 2nd Category'))
modifier.subtransactions = [subtransaction_1, subtransaction_2]

return modifier
from ynabtransactionadjuster import Adjuster, ModifierSubTransaction


class MyAdjuster(Adjuster):

def filter(self, transactions):
return transactions

def adjust(self, transaction, modifier):
# example for splitting a transaction in two equal amount subtransactions with different categories
subtransaction_1 = ModifierSubTransaction(amount=transaction.amount / 2,
category=transaction.category)
subtransaction_2 = ModifierSubTransaction(amount=transaction.amount / 2,
category=self.categories.fetch_by_name('My 2nd Category'))
modifier.subtransactions = [subtransaction_1, subtransaction_2]

return modifier
```


12 changes: 6 additions & 6 deletions docs/reference.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Reference


::: ynabtransactionadjuster.YnabTransactionAdjuster
::: ynabtransactionadjuster.Adjuster
options:
merge_init_into_class: true
show_root_full_path: false
Expand All @@ -12,11 +11,12 @@
::: repos.PayeeRepo

## Models

::: models.OriginalTransaction
::: models.OriginalSubTransaction
::: models.TransactionModifier
::: models.Credentials
::: models.Transaction
::: models.SubTransaction
::: models.Modifier
::: models.ModifierSubTransaction
::: models.ModifiedTransaction
::: models.Category
::: models.Payee

Expand Down
Loading

0 comments on commit 3000fac

Please sign in to comment.