import calendar
import math
from datetime import date
from typing import Optional
from q2_sdk.hq.models.account import Account
[docs]
class Transaction:
def __init__(
self,
from_account: Account,
to_account: Account,
amount: float,
transaction_date: date,
payment_type: str,
memo: Optional[str] = None,
):
self.from_account = from_account
self.to_account = to_account
self.amount = amount
self.transaction_date = transaction_date
self.payment_type = payment_type
self.memo = memo if memo else ""
self.end_date = None
self.start_date = None
self.is_recurring_payment = False
self.frequency = None
self.recurring_type = None
self.weeks_or_months = None
self.recurring_bit_flag = None
[docs]
def add_recurring_details(
self, frequency_bit_flag: int, end_date: Optional[date] = None
):
"""
if payment type is recurring call this update method with necessary details
"""
assert frequency_bit_flag in [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
], "Invalid frequency bit flag provided"
self.is_recurring_payment = True
self.frequency = frequency_bit_flag
self.start_date = self.transaction_date
self.end_date = end_date
self.recurring_type, self.weeks_or_months, self.recurring_bit_flag = (
self._process_frequency(self.frequency, self.start_date)
)
@staticmethod
def _process_frequency(frequency: int, start_date: date) -> tuple:
month, day, year, weekday = (
start_date.month,
start_date.day,
start_date.year,
start_date.weekday(),
)
# Handle months with less than 31 days. Hq handles logic for months with less than 31
# days. This will cause the processing to occur on the last day of the month for last day of month
# recurring series.
if frequency in {1, 3}:
days_in_month = 31
else:
days_in_month = calendar.monthrange(year, month)[1]
# python version. in python Monday=0 and Sunday=6
process_day_of_week_check_sum = {
6: 1, # sunday
0: 2, # monday
1: 4, # tuesday
2: 8, # wednesday
3: 16, # thursday
4: 32, # friday
5: 64,
} # saturday
# this is for reference
# processDayOfWeekCheckSum = {0: 1, 1: 2, 2: 4, 3: 8, 4: 16, 5: 32, 6: 64}
# java version. in java Sunday=0 and Saturday=6
# recur_type_ID: (recurringTransactionType, recurringEveryXWeeksOrMonths, recurringFrequency)
uux_recur_options = {
0: ("MonthlyByDayOfMonth", 1, "1"), # 1st of the month
1: ("MonthlyByDayOfMonth", 1, str(int(math.pow(2, (days_in_month - 1))))),
# Last day of the month
2: ("MonthlyByDayOfMonth", 1, str(int(1 + math.pow(2, 14)))),
# 1st & 15th of the month
3: (
"MonthlyByDayOfMonth",
1,
str(int(math.pow(2, (days_in_month - 1)) + math.pow(2, 14))),
),
# 15th & last day of the month
4: (
"Weekly",
1,
str(int(process_day_of_week_check_sum[weekday])),
), # Weekly
5: (
"Weekly",
2,
str(int(process_day_of_week_check_sum[weekday])),
), # Every other week
6: ("MonthlyByDayOfMonth", 1, str(int(math.pow(2, (day - 1))))), # Monthly
7: ("MonthlyByDayOfMonth", 3, str(int(math.pow(2, day - 1)))), # Quarterly
8: (
"MonthlyByDayOfMonth",
6,
str(int(math.pow(2, day - 1))),
), # Semi-annually
9: ("MonthlyByDayOfMonth", 12, str(int(math.pow(2, day - 1)))), # Yearly
}
return uux_recur_options.get(frequency)
def __eq__(self, other):
return vars(self) == vars(other)
def __repr__(self):
return str(vars(self))