You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
45 lines
2.4 KiB
45 lines
2.4 KiB
from finance.models import Account, Transaction, Transfer |
|
from .base import DomainError, identity, lock, money, save, write |
|
from .posting import record |
|
|
|
|
|
def match(outgoing_id, incoming_id): |
|
ids = [identity(outgoing_id), identity(incoming_id)] |
|
if ids[0] == ids[1]: |
|
raise DomainError("invalid_transfer_legs") |
|
rows = {obj.pk: obj for obj in Transaction.objects.select_for_update().filter(pk__in=ids).order_by("pk")} |
|
if len(rows) != 2: |
|
raise DomainError("not_found") |
|
outgoing, incoming = rows[ids[0]], rows[ids[1]] |
|
if outgoing.kind != "TRANSFER" or incoming.kind != "TRANSFER" or outgoing.amount >= 0 or incoming.amount <= 0 or outgoing.amount != incoming.amount.copy_negate(): |
|
raise DomainError("invalid_transfer_legs") |
|
if outgoing.account_id == incoming.account_id or outgoing.account.currency != incoming.account.currency: |
|
raise DomainError("transfer_account_or_currency_mismatch") |
|
if Transfer.objects.filter(outgoing=outgoing).exists() or Transfer.objects.filter(incoming=incoming).exists(): |
|
raise DomainError("already_paired") |
|
return save(Transfer(outgoing=outgoing, incoming=incoming)) |
|
|
|
|
|
@write("match_transfer") |
|
def match_transfer(*, outgoing_id, incoming_id): |
|
return match(outgoing_id, incoming_id), ["outgoing", "incoming"] |
|
|
|
|
|
@write("create_transfer") |
|
def create_transfer(*, outgoing_account_id, incoming_account_id, amount, outgoing_date, incoming_date): |
|
amount = money(amount) |
|
if amount <= 0: |
|
raise DomainError("transfer_amount_must_be_positive") |
|
ids = [identity(outgoing_account_id), identity(incoming_account_id)] |
|
if ids[0] == ids[1]: |
|
raise DomainError("transfer_account_or_currency_mismatch") |
|
accounts = {obj.pk: obj for obj in Account.objects.select_for_update().filter(pk__in=ids).order_by("pk")} |
|
if len(accounts) != 2: |
|
raise DomainError("not_found") |
|
if any(obj.archived for obj in accounts.values()): |
|
raise DomainError("archived_reference") |
|
if accounts[ids[0]].currency != accounts[ids[1]].currency: |
|
raise DomainError("transfer_account_or_currency_mismatch") |
|
outgoing = record(account_id=ids[0], amount=amount.copy_negate(), posting_date=outgoing_date, kind="TRANSFER") |
|
incoming = record(account_id=ids[1], amount=amount, posting_date=incoming_date, kind="TRANSFER") |
|
return match(outgoing.pk, incoming.pk), ["outgoing", "incoming"]
|
|
|