def store_payment(payment, filename=None): """ Store the Payment to disk as a new file. If no filename is given, generate a random one. N.B: This is not race condition safe for python < 3.3. """ if filename is not None: path = payment.group.path('payments', filename) if os.path.exists(path): raise ValueError('File already exists: %r' % path) while filename is None: filename = generate_random_filename( format_datetime(payment.date, date_only=True), payment.giver) debug(filename) path = payment.group.path('payments', filename) if os.path.exists(path): filename = None mode = 'w' if sys.version_info < (3,3) else 'x' with open(path, mode, encoding=FILE_CHARSET) as f: write(f, payment.serialize())
def run(self, args): args = args[:] if len(args) == 0: print('Error: No command given\nAvailable commands:', file=sys.stderr) for c in self.funcdict: print(' %s' % c, file=sys.stderr) return if args[0] == 'init': # special case because we don't pass a group here self.do_init(args[1:]) return if args[0] in self.funcdict: args.insert(0, 'DEFAULTREPO') #TODO if len(args) <= 1: print('Error: No command given\nAvailable commands:', file=sys.stderr) for c in self.funcdict: print(' %s' % c, file=sys.stderr) return group = Group.load(args[0]) cmd = args[1] rest = args[2:] try: f = self.funcdict[cmd] except KeyError: print('no such command: %s' % cmd, file=sys.stderr) else: debug('running %s(%s) with %r' % (cmd, rest, group)) f(group, rest)
def _calculate_balances(self): from settle import MAX_LIST_RESOLVER_RECURSION_DEPTH self.balances = [] raw_balances, self.amount = self.receivers.apply( self.amount, self.currency) i = MAX_LIST_RESOLVER_RECURSION_DEPTH while raw_balances: new_raw_balances = [] debug('raw: %r' % raw_balances) for name, val in raw_balances: if is_list(name): bal, _amount = self.group.lists[name[1:]].apply(-val) new_raw_balances.extend(bal) else: self.balances.append((name, val)) raw_balances = new_raw_balances i -= 1 if i <= 0: raise RuntimeError( 'Maximum list resolver recursion depth reached. Maybe there is a loop?' ) self.balances.append((self.giver, Money(+self.amount, self.currency)))
def store_payment(payment, filename=None): """ Store the Payment to disk as a new file. If no filename is given, generate a random one. N.B: This is not race condition safe for python < 3.3. """ if filename is not None: path = payment.group.path('payments', filename) if os.path.exists(path): raise ValueError('File already exists: %r' % path) while filename is None: filename = generate_random_filename( format_datetime(payment.date, date_only=True), payment.giver) debug(filename) path = payment.group.path('payments', filename) if os.path.exists(path): filename = None mode = 'w' if sys.version_info < (3, 3) else 'x' with open(path, mode, encoding=FILE_CHARSET) as f: write(f, payment.serialize())
def find_payment_files(group): dir = group.path('payments') debug('searching for payments in %s' % dir) for f_ in os.listdir(dir): f = os.path.join(dir, f_) if f_[0] != '.' and os.path.isfile(f): yield f else: debug('skip %s' % f)
def do_new(self, group, raw_args): p = argparse.ArgumentParser('create new payment') p.add_argument('amount', nargs='?') p.add_argument('receivers', nargs='*') args = p.parse_args(raw_args) if args.amount is None: amount = ask('Amount? ', require=r'^[0-9]*(\.[0-9]*)?$') else: amount = args.amount print('Amount: %s' % amount) if not args.receivers: receivers = ask('Receivers? ', 'Enter the names of the person(s) ' 'the payment was done for. Separate multiple ' 'persons by spaces. Use %name for a payment to a ' 'list of people. ', require=_identifiers_re) #TODO: verify if the names are valid receivers else: receivers = args.receivers print('Receivers:', ' '.join(receivers)) giver = ask('Who payed? ', default=group.default_giver) def _verify_date(d): try: parse_date(d) except ValueError: return 'Invalid date.' date = ask('Date? (- for none) ', default='now', forbidden=_verify_date) if date == 'now': date = datetime.now() elif date == '-': date = None else: date = parse_date(date) comment = ask('Comment? ', blank=True) p = Payment(group, giver, receivers, amount, date=date, comment=comment) debug('%r\n %r' % (p, p.receivers.to_string())) store_payment(p)
def load(cls, name): from settle import DEFAULT_CURRENCY args = {} if not os.path.isdir(Group._path(name)): raise NoSuchGroupError(name) config = read_file(cls._path(name, 'config'), {}) config.update(read_file(cls._path(name, 'localconfig'), {})) args['default_currency'] = config.get('default_currency', DEFAULT_CURRENCY) args['default_giver'] = config.get('default_giver', None) g = cls(name, **args) lists_ = read_file(cls._path(name, 'lists'), {}) for name, s in lists_.items(): debug('parse receivers: %s' % s) g.lists[name] = Receivers.from_string(g, s, is_list=True) return g
def _calculate_balances(self): from settle import MAX_LIST_RESOLVER_RECURSION_DEPTH self.balances = [] raw_balances, self.amount = self.receivers.apply(self.amount, self.currency) i = MAX_LIST_RESOLVER_RECURSION_DEPTH while raw_balances: new_raw_balances = [] debug('raw: %r' % raw_balances) for name, val in raw_balances: if is_list(name): bal, _amount = self.group.lists[name[1:]].apply(-val) new_raw_balances.extend(bal) else: self.balances.append((name, val)) raw_balances = new_raw_balances i -= 1 if i <= 0: raise RuntimeError('Maximum list resolver recursion depth reached. Maybe there is a loop?') self.balances.append((self.giver, Money(+self.amount, self.currency)))
def read_all_payments(group): for f in find_payment_files(group): debug('payment found: %s' % f) yield read_payment(f, group)