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
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
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!"
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
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())
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"))
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)
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
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
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
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'))
def pay(amt, posted="today"): return Event(event="payment", amount=amt, posted=posted)
def chg(amt, posted="today", maturity="today"): return Event(event="charge", amount=amt, posted=posted, maturity=maturity)
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)
def test_NoneAmount(self): e = Event() e.amount = None assert e.value == 0