Esempio n. 1
0
def test_date():
    prop = DateProperty()
    prop.name = 'foo'
    prop.owner = FooBar
    somedate = date(2012, 12, 15)
    assert prop.deflate(somedate) == '2012-12-15'
    assert prop.inflate('2012-12-15') == somedate
Esempio n. 2
0
def test_date():
    prop = DateProperty()
    prop.name = "foo"
    prop.owner = FooBar
    somedate = date(2012, 12, 15)
    assert prop.deflate(somedate) == "2012-12-15"
    assert prop.inflate("2012-12-15") == somedate
Esempio n. 3
0
def test_date_exceptions():
    prop = DateProperty()
    prop.name = 'date'
    prop.owner = FooBar
    faulty = '2012-14-13'

    try:
        prop.inflate(faulty)
    except InflateError as e:
        assert 'inflate property' in str(e)
    else:
        assert False, "InflateError not raised."

    try:
        prop.deflate(faulty)
    except DeflateError as e:
        assert 'deflate property' in str(e)
    else:
        assert False, "DeflateError not raised."
Esempio n. 4
0
def test_date_exceptions():
    prop = DateProperty()
    prop.name = 'date'
    prop.owner = FooBar
    faulty = '2012-14-13'

    try:
        prop.inflate(faulty)
    except InflateError as e:
        assert True
        assert str(e).index('inflate property')
    else:
        assert False

    try:
        prop.deflate(faulty)
    except DeflateError as e:
        assert True
        assert str(e).index('deflate property')
    else:
        assert False
Esempio n. 5
0
class Card(BaseModel):
    """
    Models a card in database
    """
    number = StringProperty(required=True)
    due_day = IntegerProperty(required=True)
    expiration_date = DateProperty(required=True)
    cvv = StringProperty(required=True)
    max_limit = FloatProperty(required=True)
    free_limit_ = FloatProperty(required=True)

    wallet = RelationshipFrom('.wallet.Wallet',
                              'CONTAINED_BY',
                              cardinality=One)
    purchases = RelationshipFrom('.billing.Purchase',
                                 'DID',
                                 model=BillingAction)
    payments = RelationshipFrom('.billing.Payment', 'RECEIVED')

    def __init__(self, date_format='%m/%d/%Y', **kwargs):
        # Test if all arguments are present
        if not all(
                k in kwargs for k in
            ['number', 'due_day', 'expiration_date', 'cvv', 'max_limit']):
            raise NotEnoughCardArguments

        # set initial free_limit equals to max_limit
        kwargs['free_limit_'] = kwargs[
            'free_limit_'] if 'free_limit_' in kwargs else kwargs['max_limit']

        kwargs['cvv'] = str(kwargs['cvv'])

        # as discussed by e-mail, due_day is limited from 1 to 28
        if kwargs['due_day'] < 1 or kwargs['due_day'] > 28:
            raise ValueError(
                'due_date should be limited from 1 to 28 to avoid problems with some months'
            )

        if type(kwargs['expiration_date']) is str:
            kwargs['expiration_date'] = datetime.strptime(
                kwargs['expiration_date'], date_format).date()

        fake_today = kwargs['fake_today'] if 'fake_today' in kwargs else None
        date_format = kwargs[
            'date_format'] if 'date_format' in kwargs else '%m/%d/%Y'

        super(Card, self).__init__(**kwargs)

        self.date_format = '%m/%d/%Y'
        self.fake_today = None

        self.set_fake_today(fake_today, date_format)

    @property
    def due_date(self):
        """
        Calculate next due date based on actual date and due_day
        :return: next due date
        """
        due_date = self.get_fake_today().replace(day=self.due_day)

        # due date is next month
        if self.due_day <= self.fake_today.day:
            year = due_date.year + due_date.month // 12
            month = due_date.month % 12 + 1
            due_date = due_date.replace(month=month, year=year)

        return due_date

    def set_fake_today(self, fake_today=None, date_format='%m/%d/%Y'):
        """
        Assume a fake today date, set for today if None. Useful for tests
        and generate reference cards sortings
        :param fake_today: date or string representing date to be assumed for today
        :param date_format: format for parsing date when fake_today is string
        :return:
        """
        self.fake_today = fake_today if fake_today else datetime.today().date()

        if type(self.fake_today) is str:
            self.fake_today = datetime.strptime(fake_today, date_format).date()

        self.date_format = date_format

    def get_fake_today(self):
        return self.fake_today if self.fake_today else datetime.today().date()

    @property
    def free_limit(self):
        """
        Just get free_limit_
        :return: free_limit
        """
        return self.free_limit_

    @free_limit.setter
    def free_limit(self, value):
        """
        Just to avoid changing free_limit_ directly,
        it should be increased or decreased on
        each payment
        :param value: value to be changed
        """
        raise UnchangeableCardValue()

    @property
    def active(self):
        """
        A card should be inactive if it's set to be inactive, or
        if reached expiration date
        :return:
        """
        if self.expiration_date < self.fake_today:
            return False
        return self.active_

    @active.setter
    def active(self, state):
        """
        Change active state from an user.
        Raise warning if state is not changed
        :param state:
        :return:
        """

        if self.active and state:
            # raise warning if activating an already active card
            warnings.warn(CardAlreadyActive())
        elif (not self.active) and (not state):
            # raise warning if deactivating an already inactive card
            warnings.warn(CardAlreadyInactive())
        else:
            # Otherwise, process limits
            self.active_ = state
            if state:
                # increase wallet limits if activating the card
                self.wallet[0].increase_max_limit(self.max_limit)
                self.wallet[0].increase_free_limit(self.max_limit)
            else:
                # decrease wallet limit if deactivating the card
                self.wallet[0].decrease_max_limit(self.max_limit)
                self.wallet[0].decrease_free_limit(self.max_limit)
            self.save()

    def decrease_free_limit(self, value):
        """
        Decrease free limit, used on purchasing.
        raise NotEnoughCardFreeLimit if free_limit is
        not enough
        :param value: value to reduce free_limit
        :return: new value for free_limit
        """
        # if there is not enough free_limit, raise exception
        if self.free_limit < value:
            raise NotEnoughCardFreeLimit()

        # if there is free limit, reduce value amount from it
        self.free_limit_ -= value
        self.save()

        self.wallet.single().decrease_free_limit(value)
        self.wallet.single().refresh()

        return self.free_limit

    def increase_free_limit(self, value):
        """
        Increase free limit, used on payment.
        raises PaymentExceed when payment value
        and free_limit exceed maximum card limit
        :param value: value to increase free_limit
        :return: new value for free_limit
        """

        # raise exception if exceed maximum limit of card
        if self.free_limit + value > self.max_limit:
            raise PaymentExceed

        # if no problem, increase limit
        self.free_limit_ = self.free_limit_ + value
        self.save()

        self.wallet[0].increase_free_limit(value)
        self.wallet[0].refresh()

        return self.free_limit

    def purchase(self, value):
        """
        Process a purchase,
        raise CardIsInactive if card is inactive
        :param value: purchase value
        """

        if not self.active:
            raise CardIsInactive()

        self.decrease_free_limit(value)
        self.save()

    def pay(self, value):
        """
        Release credit increasing free_limit. Raise PaymentExceed if
        value+free_limit exceeds max_limit
        :param value: payed amount
        :return: new free_limit
        """
        try:
            self.increase_free_limit(value)
            payment = Payment(value=value)
            payment.save()

            # Connect payment to card
            payment.card.connect(self)
            payment.save()

            self.save()
            self.payments.connect(payment)
            self.save()

            # Connect payment to wallet
            self.wallet.single().save()
            payment.wallet.connect(self.wallet.single())
            self.wallet.single().payments.connect(payment)

            payment.save()
            self.wallet.single().save()

            return payment
        except Exception as e:
            raise e

    def to_dict(self):
        return dict(uid=self.uid,
                    due_date=self.due_date,
                    expiration_date=self.expiration_date,
                    max_limit=self.max_limit,
                    free_limit=self.free_limit,
                    active=self.active)

    def __lt__(self, other):
        """
        Order cards, first by largest due date,
        then by smaller maxmimum limit.
        rules defined in https://slack-files.com/T06M9ENDT-F5XK4J0P2-532510c5c0
        :param other: other object which is beeing compared
        :return: True if is lower, False if is bigger than other
        """
        if self.due_date > other.due_date:
            return True
        elif self.due_date == other.due_date:
            return self.max_limit < other.max_limit
        else:
            return False

    def __str__(self):
        s = '<Card[limit: {max_limit}, due_day: {due_date}, expiration: {expiration}, cvv: {cvv}]>'
        return s.format(max_limit=self.max_limit,
                        due_date=self.due_date,
                        expiration=self.due_date,
                        cvv=self.cvv)