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

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"]