diff --git a/tools/deprecated/finbot/money.py b/tools/deprecated/finbot/money.py deleted file mode 100755 index 2b7b61f580..0000000000 --- a/tools/deprecated/finbot/money.py +++ /dev/null @@ -1,214 +0,0 @@ -#!/usr/bin/env python -from __future__ import division -from __future__ import print_function -import datetime -import monthdelta - -def parse_date(date_str): - return datetime.datetime.strptime(date_str, "%Y-%m-%d") - -def unparse_date(date_obj): - return date_obj.strftime("%Y-%m-%d") - -class Company(object): - def __init__(self, name): - self.name = name - self.flows = [] - self.verbose = False - - def __str__(self): - return self.name - - def add_flow(self, flow): - self.flows.append(flow) - - def cash_at_date_internal(self, start_date, end_date): - cash = 0 - for flow in self.flows: - delta = flow.cashflow(start_date, end_date, (end_date - start_date).days) - cash += delta - if self.verbose: - print(flow.name, round(delta, 2)) - return round(cash, 2) - - def cash_at_date(self, start, end): - start_date = parse_date(start) - end_date = parse_date(end) - return self.cash_at_date_internal(start_date, end_date) - - def cash_monthly_summary(self, start, end): - start_date = parse_date(start) - cur_date = parse_date(start) - end_date = parse_date(end) - while cur_date <= end_date: - print(cur_date, self.cash_at_date_internal(start_date, cur_date)) - cur_date += monthdelta.MonthDelta(1) - if self.verbose: - print() - -# CashFlow objects fundamentally just provide a function that says how -# much cash has been spent by that source at each time -# -# The API is that one needs to define a function .cashflow(date) -class CashFlow(object): - def __init__(self, name): - self.name = name - -class FixedCost(CashFlow): - def __init__(self, name, amount): - super(FixedCost, self).__init__(name) - self.cost = -amount - - def cashflow(self, start, end, days): - return self.cost - -class ConstantCost(CashFlow): - def __init__(self, name, amount): - super(ConstantCost, self).__init__(name) - self.rate = -amount - - def cashflow(self, start, end, days): - return self.rate * days / 365. - -class PeriodicCost(CashFlow): - def __init__(self, name, amount, start, interval): - super(PeriodicCost, self).__init__(name) - self.amount = -amount - self.start = parse_date(start) - self.interval = interval - - def cashflow(self, start, end, days): - cur = self.start - delta = 0 - while (cur <= end): - if cur >= start: - delta += self.amount - cur += datetime.timedelta(days=self.interval) - return delta - -class MonthlyCost(CashFlow): - def __init__(self, name, amount, start): - super(MonthlyCost, self).__init__(name) - self.amount = -amount - self.start = parse_date(start) - - def cashflow(self, start, end, days): - cur = self.start - delta = 0 - while (cur <= end): - if cur >= start: - delta += self.amount - cur += monthdelta.MonthDelta(1) - return delta - -class TotalCost(CashFlow): - def __init__(self, name, *args): - self.name = name - self.flows = args - - def cashflow(self, start, end, days): - return sum(cost.cashflow(start, end, days) for cost in self.flows) - -class SemiMonthlyCost(TotalCost): - def __init__(self, name, amount, start1, start2 = None): - if start2 is None: - start2 = unparse_date(parse_date(start1) + datetime.timedelta(days=14)) - super(SemiMonthlyCost, self).__init__(name, - MonthlyCost(name, amount, start1), - MonthlyCost(name, amount, start2) - ) - -class SemiMonthlyWagesNoTax(SemiMonthlyCost): - def __init__(self, name, wage, start): - super(SemiMonthlyWagesNoTax, self).__init__(name, self.compute_wage(wage), start) - - def compute_wage(self, wage): - return wage / 24. - -class SemiMonthlyWages(SemiMonthlyWagesNoTax): - def compute_wage(self, wage): - fica_tax = min(wage, 110100) * 0.062 + wage * 0.0145 - unemp_tax = 450 - return (wage + fica_tax + unemp_tax) / 24. - - def __init__(self, name, wage, start): - super(SemiMonthlyWages, self).__init__(name, wage, start) - -class DelayedCost(CashFlow): - def __init__(self, start, base_model): - super(DelayedCost, self).__init__("Delayed") - self.base_model = base_model - self.start = parse_date(start) - - def cashflow(self, start, end, days): - start = max(start, self.start) - if start > end: - return 0 - time_delta = (end-start).days - return self.base_model.cashflow(start, end, time_delta) - -class BiweeklyWagesNoTax(PeriodicCost): - def __init__(self, name, wage, start): - super(BiweeklyWagesNoTax, self).__init__(name, self.compute_wage(wage), start, 14) - - def compute_wage(self, wage): - # You would think this calculation would be (wage * 14 / - # 365.24), but you'd be wrong -- companies paying biweekly - # wages overpay by about 0.34% by doing the math this way - return wage / 26. - -class BiweeklyWages(BiweeklyWagesNoTax): - def compute_wage(self, wage): - fica_tax = min(wage, 110100) * 0.062 + wage * 0.0145 - unemp_tax = 450 - # You would think this calculation would be (wage * 14 / - # 365.24), but you'd be wrong -- companies paying biweekly - # wages overpay by about 0.34% by doing the math this way - return (wage + fica_tax + unemp_tax) / 26. - - def __init__(self, name, wage, start): - super(BiweeklyWages, self).__init__(name, wage, start) - - - -if __name__ == "__main__": - # Tests - c = Company("Example Inc") - c.add_flow(FixedCost("Initial Cash", -500000)) - c.add_flow(FixedCost("Incorporation", 500)) - assert(c.cash_at_date("2012-01-01", "2012-03-01") == 500000 - 500) - c.add_flow(FixedCost("Incorporation", -500)) - - c.add_flow(ConstantCost("Office", 50000)) - assert(c.cash_at_date("2012-01-01", "2012-01-02") == 500000 - round(50000*1/365., 2)) - c.add_flow(ConstantCost("Office", -50000)) - - c.add_flow(PeriodicCost("Payroll", 4000, "2012-01-05", 14)) - assert(c.cash_at_date("2012-01-01", "2012-01-02") == 500000) - assert(c.cash_at_date("2012-01-01", "2012-01-06") == 500000 - 4000) - c.add_flow(PeriodicCost("Payroll", -4000, "2012-01-05", 14)) - - c.add_flow(DelayedCost("2012-02-01", ConstantCost("Office", 50000))) - assert(c.cash_at_date("2012-01-01", "2012-01-05") == 500000) - assert(c.cash_at_date("2012-01-01", "2012-02-05") == 500000 - round(50000*4/365., 2)) - c.add_flow(DelayedCost("2012-02-01", ConstantCost("Office", -50000))) - - c.add_flow(DelayedCost("2012-02-01", FixedCost("Financing", 50000))) - assert(c.cash_at_date("2012-01-01", "2012-01-15") == 500000) - c.add_flow(DelayedCost("2012-02-01", FixedCost("Financing", -50000))) - - c.add_flow(SemiMonthlyCost("Payroll", 4000, "2012-01-01")) - assert(c.cash_at_date("2012-01-01", "2012-01-01") == 500000 - 4000) - assert(c.cash_at_date("2012-01-01", "2012-01-14") == 500000 - 4000) - assert(c.cash_at_date("2012-01-01", "2012-01-15") == 500000 - 4000 * 2) - assert(c.cash_at_date("2012-01-01", "2012-01-31") == 500000 - 4000 * 2) - assert(c.cash_at_date("2012-01-01", "2012-02-01") == 500000 - 4000 * 3) - assert(c.cash_at_date("2012-01-01", "2012-02-15") == 500000 - 4000 * 4) - c.add_flow(SemiMonthlyCost("Payroll", -4000, "2012-01-01")) - - c.add_flow(SemiMonthlyWages("Payroll", 4000, "2012-01-01")) - assert(c.cash_at_date("2012-01-01", "2012-02-15") == 499207.33) - c.add_flow(SemiMonthlyWages("Payroll", -4000, "2012-01-01")) - - print(c) - c.cash_monthly_summary("2012-01-01", "2012-07-01") diff --git a/tools/deprecated/finbot/monthdelta.py b/tools/deprecated/finbot/monthdelta.py deleted file mode 100644 index 28e8f46dae..0000000000 --- a/tools/deprecated/finbot/monthdelta.py +++ /dev/null @@ -1,151 +0,0 @@ -"""monthdelta - -Date calculation with months: MonthDelta class and monthmod() function. -""" - -__all__ = ['MonthDelta', 'monthmod'] - -from datetime import date, timedelta - -class MonthDelta(object): - """Number of months offset from a date or datetime. - - MonthDeltas allow date calculation without regard to the different lengths - of different months. A MonthDelta value added to a date produces another - date that has the same day-of-the-month, regardless of the lengths of the - intervening months. If the resulting date is in too short a month, the - last day in that month will result: - - date(2008,1,30) + MonthDelta(1) -> date(2008,2,29) - - MonthDeltas may be added, subtracted, multiplied, and floor-divided - similarly to timedeltas. They may not be added to timedeltas directly, as - both classes are intended to be used directly with dates and datetimes. - Only ints may be passed to the constructor. MonthDeltas are immutable. - - NOTE: in calculations involving the 29th, 30th, and 31st days of the - month, MonthDeltas are not necessarily invertible [i.e., the result above - would not imply that date(2008,2,29) - MonthDelta(1) -> date(2008,1,30)]. - """ - __slots__ = ('__months',) - - def __init__(self, months=1): - if not isinstance(months, int): - raise TypeError('months must be an integer') - self.__months = months - def months(self): - return self.__months - months = property(months) - def __repr__(self): - try: - return 'MonthDelta({0})'.format(self.__months) - except AttributeError: - return 'MonthDelta(' + str(self.__months) + ')' - def __str__(self): - return str(self.__months) + ' month' + ((abs(self.__months) != 1 - and 's') or '') - def __hash__(self): - return hash(self.__months) - def __eq__(self, other): - if isinstance(other, MonthDelta): - return (self.__months == other.months) - return False - def __ne__(self, other): - if isinstance(other, MonthDelta): - return (self.__months != other.months) - return True - def __lt__(self, other): - if isinstance(other, MonthDelta): - return (self.__months < other.months) - return NotImplemented - def __le__(self, other): - if isinstance(other, MonthDelta): - return (self.__months <= other.months) - return NotImplemented - def __gt__(self, other): - if isinstance(other, MonthDelta): - return (self.__months > other.months) - return NotImplemented - def __ge__(self, other): - if isinstance(other, MonthDelta): - return (self.__months >= other.months) - return NotImplemented - def __add__(self, other): - if isinstance(other, MonthDelta): - return MonthDelta(self.__months + other.months) - if isinstance(other, date): - day = other.day - # subract one because months are not zero-based - month = other.month + self.__months - 1 - year = other.year + month // 12 - # now add it back - month = month % 12 + 1 - if month == 2: - if day >= 29 and not year%4 and (year%100 or not year%400): - day = 29 - elif day > 28: - day = 28 - elif month in (4, 6, 9, 11) and day > 30: - day = 30 - try: - return other.replace(year, month, day) - except ValueError: - raise OverflowError('date value out of range') - return NotImplemented - def __sub__(self, other): - if isinstance(other, MonthDelta): - return MonthDelta(self.__months - other.months) - return NotImplemented - def __mul__(self, other): - if isinstance(other, int): - return MonthDelta(self.__months * other) - return NotImplemented - def __floordiv__(self, other): - # MonthDelta // MonthDelta -> int - if isinstance(other, MonthDelta): - return self.__months // other.months - if isinstance(other, int): - return MonthDelta(self.__months // other) - return NotImplemented - def __radd__(self, other): - return self + other - def __rsub__(self, other): - return -self + other - def __rmul__(self, other): - return self * other - def __ifloordiv__(self, other): - # in-place division by a MonthDelta (which will change the variable's - # type) is almost certainly a bug -- raising this error is the reason - # we don't just fall back on __floordiv__ - if isinstance(other, MonthDelta): - raise TypeError('in-place division of a MonthDelta requires an ' - 'integer divisor') - if isinstance(other, int): - return MonthDelta(self.__months // other) - return NotImplemented - def __neg__(self): - return MonthDelta(-self.__months) - def __pos__(self): - return MonthDelta(+self.__months) - def __abs__(self): - return MonthDelta(abs(self.__months)) - def __bool__(self): - return bool(self.__months) - __nonzero__ = __bool__ - -def monthmod(start, end): - """Months between dates, plus leftover time. - - Distribute the interim between start and end dates into MonthDelta and - timedelta portions. If and only if start is after end, returned MonthDelta - will be negative. Returned timedelta is always non-negative, and is always - smaller than the month in which the end date occurs. - - Invariant: dt + monthmod(dt, dt+td)[0] + monthmod(dt, dt+td)[1] = dt + td - """ - if not (isinstance(start, date) and isinstance(end, date)): - raise TypeError('start and end must be dates') - md = MonthDelta(12*(end.year - start.year) + end.month - start.month - - int(start.day > end.day)) - # will overflow (underflow?) for end near date.min - return md, end - (start + md) diff --git a/tools/run-mypy b/tools/run-mypy index 85e18dbded..7733f9dc1f 100755 --- a/tools/run-mypy +++ b/tools/run-mypy @@ -24,8 +24,6 @@ api/integrations/trac/zulip_trac_config.py api/integrations/trac/zulip_trac.py bots/jabber_mirror_backend.py bots/zephyr_mirror_backend.py -tools/deprecated/finbot/monthdelta.py -tools/deprecated/finbot/money.py tools/deprecated/generate-activity-metrics.py zproject/settings.py zproject/test_settings.py