#!/usr/bin/env python3
"""Viewer for ledger .dat files."""
-from decimal import Decimal
+from datetime import date as dt_date
+from decimal import Decimal, InvalidOperation as DecimalInvalidOperation
from os import environ
from pathlib import Path
from sys import exit as sys_exit
@property
def is_intro(self) -> bool:
"""Return if intro line of a Booking."""
- return self.booking_line.is_intro if self.booking_line else False
+ return isinstance(self.booking_line, IntroLine)
@property
def booking_id(self) -> int:
class BookingLine:
"""Parsed code part of a DatLine belonging to a Booking."""
- def __init__(self, booking_id: int, code: str, as_intro: bool = False
- ) -> None:
+ def __init__(self, booking_id: int) -> None:
self.error = ''
self.booking_id = booking_id
- self.is_intro = as_intro
- if self.is_intro:
- if code[0].isspace():
- self.error = 'intro line indented'
+
+
+class IntroLine(BookingLine):
+ """First line of a Booking, expected to carry date etc."""
+
+ def __init__(self, booking_id: int, code: str) -> None:
+ super().__init__(booking_id)
+ if code[0].isspace():
+ self.error = 'intro line indented'
+ toks = code.lstrip().split(maxsplit=1)
+ if len(toks) != 2:
+ self.error = 'illegal number of tokens'
return
+ try:
+ dt_date.fromisoformat(toks[0])
+ except ValueError:
+ self.error = 'not starting with properly formatted legal date'
+
+
+class TransactionLine(BookingLine):
+ """Non-first Booking line, expected to carry value movement."""
+
+ def __init__(self, booking_id: int, code: str) -> None:
+ super().__init__(booking_id)
self.acc, self.amt, self.curr = '', '', ''
if not code[0].isspace():
self.error = 'non-intro line not indented'
self.error = 'illegal number of tokens'
return
if 3 == len(toks):
- amt_dec = Decimal(toks[1])
+ try:
+ amt_dec = Decimal(toks[1])
+ except DecimalInvalidOperation:
+ self.error = 'improper amount value'
+ return
exp = amt_dec.as_tuple().exponent
assert isinstance(exp, int)
self.amt = (f'{amt_dec:.1f}…' if exp < -2
def __init__(self, id_: int, dat_lines: list[DatLine]) -> None:
self.id_ = id_
self.dat_lines = dat_lines
- self.dat_lines[0].booking_line = BookingLine(
- self.id_, self.dat_lines[0].code, as_intro=True)
+ self.dat_lines[0].booking_line = IntroLine(self.id_,
+ self.dat_lines[0].code)
for dat_line in self.dat_lines[1:]:
- dat_line.booking_line = BookingLine(self.id_, dat_line.code)
+ dat_line.booking_line = TransactionLine(self.id_, dat_line.code)
class Handler(PlomHttpHandler):