예제 #1
0
 def test_amount(self):
     """
     amount should always be a fixedpoint or None
     """
     e = Event()
     e.amount = None
     assert e.amount is None # make sure no error trying FixedPoint(None)
     e.amount = 1
예제 #2
0
 def test_amount(self):
     """
     amount should always be a decimal or None
     """
     e = Event()
     e.amount = None
     assert e.amount is None
     e.amount = 1
예제 #3
0
 def test_amount(self):
     """
     amount should always be a decimal or None
     """
     e = Event()
     e.amount = None
     assert e.amount is None
     e.amount = 1
예제 #4
0
    def test_aging(self):
        acc = self.oldAccount()
        
        goal = (Event(event="charge", amount=10, posted="1/1/2002"),
                Event(event="charge", amount=5,  posted="2/1/2002"),
                Event(event="charge", amount=10, posted="5/1/2002"))
        actual = acc.aging()

        for a, g in zip(actual, goal):
            assert (a.value == g.value) and (a.posted==g.posted), \
                   "aging isn't working correctly!"
예제 #5
0
    def test_BadPastDue(self):
        """
        This was a bug I noticed in the receivables page.
        """
        acc = Account()

        acc.events << Event(event="charge", amount=20, posted="09/15/2002")
        acc.events << Event(event="charge", amount= 4, posted="09/16/2002")
        acc.events << Event(event="payment", amount=20,posted="09/19/2002")
        
        assert acc.balance() == 4, acc.balance()
        self.assertEquals(acc.amountPastDue("09/20/2002"), 4)
        aging = acc.aging()
        assert len(aging)==1
        assert aging[0].value == 4
예제 #6
0
 def onDue(self):
     """
     Post the recurring charge to the subscription's account.
     """
     self.account.events << Event(event="charge",
                                  posted=self.nextDue,
                                  maturity=self.calcNextDue(),
                                  note=self.calcNote(),
                                  amount=self.calcCharge())
예제 #7
0
    def testVestingPreconditions(self):
        "make sure Event requires valid dates in order"
        e = Event(event="charge", amount="100")
        e.maturity=None; e.posted = "1/1/2002"
        self.assertRaises(AssertionError, e.percentVested, Date("1/1/2002"))

        e.posted = None; e.maturity = "1/1/2002"
        self.assertRaises(AssertionError, e.percentVested, Date("1/1/2002"))

        e.posted = "1/2/2002"; e.maturity = "1/1/2002"
        self.assertRaises(AssertionError, e.percentVested, Date("1/1/2002"))
예제 #8
0
 def chargeAccounts(self, date):
     for a in self.findDueAccounts():
         dirty = 0
         for u in self.findUsersForAccount(a):
             charge = self.calcCharge(u, date)
             if charge:
                 dirty = True
                 a.events << Event(
                     event="charge",
                     amount=charge,
                     posted=date,
                     note=("bandwidth overage [%s]" % u.username))
         if dirty:
             self.clerk.store(a)
예제 #9
0
    def oldAccount(self):
        acc = Account()
        acc.events << Event(event="charge", amount=10, posted="1/1/2002")
        acc.events << Event(event="charge", amount=10, posted="2/1/2002")
        acc.events << Event(event="credit", amount=5,  posted="2/2/2002")

        acc.events << Event(event="charge", amount=10, posted="3/1/2002")
        acc.events << Event(event="charge", amount=10, posted="4/1/2002")
        acc.events << Event(event="credit", amount=20, posted="4/2/2002")
        acc.events << Event(event="charge", amount=10, posted="5/1/2002")

        assert acc.balance() == 25
        return acc
예제 #10
0
    def aging(self):
        credit = 0
        charges = []

        def ischarge(x):
            return x > 0

        def iscredit(x):
            return x < 0

        for e in self.events:

            # whenever a new event is considered, we add
            # in any credit balance that might be there.
            amount = e.value + credit
            credit = 0

            # now apply this new merged value to the account:
            if ischarge(amount):
                charges.append(
                    Event(event="charge", amount=amount, posted=e.posted))
            else:
                cash = abs(amount)
                while cash > 0:
                    if charges:
                        # apply amount to latest charge
                        owed = abs(charges[-1].amount)

                        if cash >= owed:
                            charges.pop()
                            cash -= owed
                        else:
                            charges[-1].amount -= cash
                            cash = 0
                    else:
                        credit -= cash  # because credit is negative
                        cash = 0
        return charges
예제 #11
0
    def toDuckbill(self):
        """
        Returns a duckbill Account with the appropriate
        Subscriptions and Events. 
        """
        a = Account(fname=self.fname,
                    lname=self.lname,
                    email=self.email,
                    company=self.company,
                    phone=self.phone,
                    address1=self.addr1,
                    address2=self.addr2,
                    city=self.city,
                    state=self.state,
                    postal=self.postal,
                    countryCD=self.country,
                    account=self.username,
                    nextDue=Date("today") + 30,
                    brand=self.brand)

        s = Subscription(
            username=self.username,
            service=self.plan,
            rate=self.calcRate(),
            cycLen=self.cycLen,

            # thirty day free trial
            nextDue=Date("today") + 30)

        e = Event(event="note",
                  posted=Date("today"),
                  amount=0,
                  note="30 day free trial")

        a.subscriptions << s
        a.events << e

        return a
예제 #12
0
    def testVesting(self):
        "ensure charges are slowly 'earned' over time"
        e = Event(event="charge",
                  amount="50",
                  posted="1/1/2000",
                  maturity="11/1/2000")
        assert e.percentVested(e.posted) == 0
        assert e.percentVested(e.posted - 1) == 0
        assert e.percentVested(e.maturity) == 100
        assert e.percentVested(e.maturity + 1) == 100

        #@TODO: paramaterize number of decimal places ?

        # In a single month, we're fully vested at the end of the month.
        # With a yearly charge, the vesting happens slowly over time.
        d = Decimal
        self.assertEquals(e.percentVested(Date("2/1/2000")), d('10.16'))
        self.assertEquals(e.percentVested(Date("5/1/2000")), d('39.67'))
        self.assertEquals(e.percentVested(Date("7/1/2000")), d('59.67'))
        self.assertEquals(e.percentVested(Date("10/1/2000")), d('89.84'))
        self.assertEquals(e.percentVested(Date("10/31/2000")), d('99.67'))
        self.assertEquals(e.percentVested(Date("11/1/2000")), d('100.00'))
        self.assertEquals(e.percentVested(Date("12/1/2000")), d('100.00'))

        # valueOn should multiply by amount
        e.amount = 200
        self.assertEquals(e.valueOn(Date("2/1/2000")), d('20.32'))
예제 #13
0
def pay(amt, posted="today"):
    return Event(event="payment", amount=amt, posted=posted)
예제 #14
0
def chg(amt, posted="today", maturity="today"):
    return Event(event="charge", amount=amt, posted=posted, maturity=maturity)
예제 #15
0
 def close(self, why):
     self.status = "closed"
     self.closed = duckbill.TODAY
     for s in self.subscriptions:
         s.close()
     self.events << Event(event="close", note=why)
예제 #16
0
 def test_NoneAmount(self):
     e = Event()
     e.amount = None
     assert e.value == 0