Source code for payments.services
"""The services defined by the payments package"""
import datetime
from typing import Union
from django.db.models import QuerySet, Q
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from members.models import Member
from .exceptions import PaymentError
from .models import Payment, BankAccount, Payable
[docs]def create_payment(
payable: Payable,
processed_by: Member,
pay_type: Union[Payment.CASH, Payment.CARD, Payment.WIRE, Payment.TPAY],
) -> Payment:
"""
Create a new payment from a payable object
:param payable: Payable object
:param processed_by: Member that processed this payment
:param pay_type: Payment type
:return: Payment object
"""
if pay_type == Payment.TPAY and not payable.payment_payer.tpay_enabled:
raise PaymentError(_("This user does not have Thalia Pay enabled"))
if payable.payment is not None:
payable.payment.amount = payable.payment_amount
payable.payment.notes = payable.payment_notes
payable.payment.topic = payable.payment_topic
payable.payment.paid_by = payable.payment_payer
payable.payment.type = pay_type
payable.payment.save()
else:
payable.payment = Payment.objects.create(
processed_by=processed_by,
amount=payable.payment_amount,
notes=payable.payment_notes,
topic=payable.payment_topic,
paid_by=payable.payment_payer,
processing_date=timezone.now(),
type=pay_type,
)
return payable.payment
[docs]def delete_payment(payable: Payable):
"""
Removes a payment from a payable object
:param payable: Payable object
:return:
"""
payment = payable.payment
payable.payment = None
payable.save()
payment.delete()
[docs]def process_payment(
queryset: QuerySet, processed_by: Member, pay_type: str = Payment.CARD
) -> list:
"""
Process the payment
:param queryset: Queryset of payments that should be processed
:type queryset: QuerySet[Payment]
:param processed_by: Member that processed this payment
:type processed_by: Member
:param pay_type: Type of the payment
:type pay_type: String
"""
queryset = queryset.filter(type=Payment.NONE)
data = []
# This should trigger post_save signals, thus a queryset update
# is not appropriate, moreover save() automatically sets
# the processing date
for payment in queryset:
if pay_type != Payment.TPAY or (
pay_type == Payment.TPAY
and payment.paid_by
and payment.paid_by.tpay_enabled
):
payment.type = pay_type
payment.processed_by = processed_by
payment.save()
data.append(payment)
return data
[docs]def update_last_used(queryset: QuerySet, date: datetime.date = None) -> int:
"""
Update the last used field of a BankAccount queryset
:param queryset: Queryset of BankAccounts
:param date: date to set last_used to
:return: number of affected rows
"""
if not date:
date = timezone.now().date()
result = queryset.filter(
(Q(valid_from__gte=timezone.now()) & Q(valid_until__lt=timezone.now()))
| Q(valid_until=None)
).update(last_used=date)
return result
[docs]def revoke_old_mandates() -> int:
"""
Revokes all mandates that have not been used for 36 months or more
:return: number of affected rows
"""
return BankAccount.objects.filter(
last_used__lte=(timezone.now() - timezone.timedelta(days=36 * 30))
).update(valid_until=timezone.now().date())