Source code for biweeklybudget.models.scheduled_transaction

"""
The latest version of this package is available at:
<http://github.com/jantman/biweeklybudget>

################################################################################
Copyright 2016 Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>

    This file is part of biweeklybudget, also known as biweeklybudget.

    biweeklybudget is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    biweeklybudget is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with biweeklybudget.  If not, see <http://www.gnu.org/licenses/>.

The Copyright and Authors attributions contained herein may not be removed or
otherwise altered, except to add the Author attribution of a contributor to
this work. (Additional Terms pursuant to Section 7b of the AGPL v3)
################################################################################
While not legally required, I sincerely request that anyone who finds
bugs please submit them at <https://github.com/jantman/biweeklybudget> or
to me via email, and that you send any contributions or improvements
either as a pull request on GitHub, or to me via email.
################################################################################

AUTHORS:
Jason Antman <jason@jasonantman.com> <http://www.jasonantman.com>
################################################################################
"""

from sqlalchemy import (
    Column, Integer, String, Boolean, Date, SmallInteger, Numeric,
    ForeignKey, func
)
from sqlalchemy.orm import relationship, validates
from sqlalchemy.sql import case

from biweeklybudget.models.base import Base, ModelAsDict
from biweeklybudget.utils import date_suffix
from sqlalchemy.ext.hybrid import hybrid_property


[docs]class ScheduledTransaction(Base, ModelAsDict): __tablename__ = 'scheduled_transactions' __table_args__ = ( {'mysql_engine': 'InnoDB'} ) #: Primary Key id = Column(Integer, primary_key=True) #: Amount of the transaction amount = Column(Numeric(precision=10, scale=4), nullable=False) #: description description = Column(String(254), nullable=False, index=True) #: notes notes = Column(String(254)) #: ID of the account the transaction is against account_id = Column(Integer, ForeignKey('accounts.id')) #: Relationship - :py:class:`~.Account` the transaction is against account = relationship( "Account", backref="scheduled_transactions" ) #: ID of the budget the transaction is against budget_id = Column(Integer, ForeignKey('budgets.id')) #: Relationship - :py:class:`~.Budget` the transaction is against budget = relationship( "Budget", backref="scheduled_transactions" ) #: whether the scheduled transaction is enabled or disabled is_active = Column(Boolean, default=True) #: Denotes a scheduled transaction that will happen once on the given date date = Column(Date) #: Denotes a scheduled transaction that happens on the same day of each #: month day_of_month = Column(SmallInteger) #: Denotes a scheduled transaction that happens N times per pay period num_per_period = Column(SmallInteger) def __repr__(self): return "<ScheduledTransaction(id=%d)>" % ( self.id )
[docs] @validates('day_of_month') def validate_day_of_month(self, _, value): assert value > 0 assert value <= 28 return value
[docs] @validates('num_per_period') def validate_num_per_period(self, _, value): assert value > 0 return value
@hybrid_property def recurrence_str(self): """ Return a string describing the recurrence interval. This is a string of the format ``YYYY-mm-dd``, ``N per period`` or ``N(st|nd|rd|th)`` where ``N`` is an integer. :return: string describing recurrence interval :rtype: str """ if self.schedule_type == 'date': return self.date.strftime('%Y-%m-%d') if self.schedule_type == 'monthly': return '%d%s' % ( self.day_of_month, date_suffix(self.day_of_month) ) if self.schedule_type == 'per period': return '%d per period' % self.num_per_period return None @recurrence_str.expression def recurrence_str(cls): return case( [ ( cls.date.isnot(None), func.date_format(cls.date, '%Y-%m-%d') ), ( cls.day_of_month.isnot(None), cls.day_of_month ), ( cls.num_per_period.isnot(None), func.concat(cls.num_per_period, ' per period') ) ], else_='' ) @hybrid_property def schedule_type(self): """ Return a string describing the type of schedule; one of ``date`` (a specific Date), ``per period`` (a number per pay period)`` or ``monthly`` (a given day of the month). :return: string describing type of schedule :rtype: str """ if self.date is not None: return 'date' if self.day_of_month is not None: return 'monthly' if self.num_per_period is not None: return 'per period' return None @schedule_type.expression def schedule_type(cls): return case( [ (cls.date.isnot(None), 'date'), (cls.day_of_month.isnot(None), 'monthly'), (cls.num_per_period.isnot(None), 'per period') ], else_='' )