Add start date rule
Rename date to end.
This commit is contained in:
parent
23eb2c80bd
commit
f7df033d58
32
alembic/versions/952de57a3c43_start_end_date_rule.py
Normal file
32
alembic/versions/952de57a3c43_start_end_date_rule.py
Normal file
@ -0,0 +1,32 @@
|
||||
"""Start/End date rule
|
||||
|
||||
Revision ID: 952de57a3c43
|
||||
Revises: 18572111d9ff
|
||||
Create Date: 2023-02-06 21:57:57.545327+00:00
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = "952de57a3c43"
|
||||
down_revision = "18572111d9ff"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column(
|
||||
"rules", sa.Column("start", sa.Date(), nullable=True), schema="transactions"
|
||||
)
|
||||
op.alter_column("rules", column_name="date", new_column_name="end", schema="transactions")
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column("rules", column_name="end", new_column_name="date", schema="transactions")
|
||||
op.drop_column("rules", "start", schema="transactions")
|
||||
# ### end Alembic commands ###
|
||||
@ -1,6 +1,3 @@
|
||||
from decimal import Decimal
|
||||
from typing import Sequence
|
||||
|
||||
from pfbudget.cli.argparser import argparser
|
||||
from pfbudget.cli.interactive import Interactive
|
||||
from pfbudget.common.types import Operation
|
||||
@ -146,12 +143,13 @@ if __name__ == "__main__":
|
||||
]
|
||||
|
||||
case Operation.RuleAdd:
|
||||
keys = {"category", "date", "description", "bank", "min", "max"}
|
||||
keys = {"category", "start", "end", "description", "regex", "bank", "min", "max"}
|
||||
assert args.keys() >= keys, f"missing {args.keys() - keys}"
|
||||
|
||||
params = [
|
||||
type.CategoryRule(
|
||||
args["date"][0] if args["date"] else None,
|
||||
args["start"][0] if args["start"] else None,
|
||||
args["end"][0] if args["end"] else None,
|
||||
args["description"][0] if args["description"] else None,
|
||||
args["regex"][0] if args["regex"] else None,
|
||||
args["bank"][0] if args["bank"] else None,
|
||||
@ -197,12 +195,13 @@ if __name__ == "__main__":
|
||||
params = [type.Tag(tag) for tag in args["tag"]]
|
||||
|
||||
case Operation.TagRuleAdd:
|
||||
keys = {"tag", "date", "description", "bank", "min", "max"}
|
||||
keys = {"tag", "start", "end", "description", "regex", "bank", "min", "max"}
|
||||
assert args.keys() >= keys, f"missing {args.keys() - keys}"
|
||||
|
||||
params = [
|
||||
type.TagRule(
|
||||
args["date"][0] if args["date"] else None,
|
||||
args["start"][0] if args["start"] else None,
|
||||
args["end"][0] if args["end"] else None,
|
||||
args["description"][0] if args["description"] else None,
|
||||
args["regex"][0] if args["regex"] else None,
|
||||
args["bank"][0] if args["bank"] else None,
|
||||
|
||||
@ -374,7 +374,8 @@ def tag_rule(parser: argparse.ArgumentParser):
|
||||
|
||||
|
||||
def rules(parser: argparse.ArgumentParser):
|
||||
parser.add_argument("--date", nargs=1, type=dt.date.fromisoformat)
|
||||
parser.add_argument("--start", nargs=1, type=dt.date.fromisoformat)
|
||||
parser.add_argument("--end", nargs=1, type=dt.date.fromisoformat)
|
||||
parser.add_argument("--description", nargs=1, type=str)
|
||||
parser.add_argument("--regex", nargs=1, type=str)
|
||||
parser.add_argument("--bank", nargs=1, type=str)
|
||||
|
||||
@ -335,7 +335,8 @@ class Rule(Base, Export):
|
||||
__tablename__ = "rules"
|
||||
|
||||
id: Mapped[idpk] = mapped_column(init=False)
|
||||
date: Mapped[Optional[dt.date]]
|
||||
start: Mapped[Optional[dt.date]]
|
||||
end: Mapped[Optional[dt.date]]
|
||||
description: Mapped[Optional[str]]
|
||||
regex: Mapped[Optional[str]]
|
||||
bank: Mapped[Optional[str]]
|
||||
@ -349,32 +350,34 @@ class Rule(Base, Export):
|
||||
"polymorphic_on": "type",
|
||||
}
|
||||
|
||||
def matches(self, transaction: BankTransaction) -> bool:
|
||||
if (
|
||||
(self.date and self.date < transaction.date)
|
||||
or (
|
||||
self.description
|
||||
and transaction.description
|
||||
and self.description not in transaction.description
|
||||
def matches(self, t: BankTransaction) -> bool:
|
||||
valid = None
|
||||
if self.regex:
|
||||
valid = re.compile(self.regex, re.IGNORECASE)
|
||||
|
||||
ops = (
|
||||
Rule.exists(self.start, lambda r: r < t.date),
|
||||
Rule.exists(self.end, lambda r: r > t.date),
|
||||
Rule.exists(self.description, lambda r: r == t.description),
|
||||
Rule.exists(
|
||||
valid,
|
||||
lambda r: r.search(t.description) if t.description else False,
|
||||
),
|
||||
Rule.exists(self.bank, lambda r: r == t.bank),
|
||||
Rule.exists(self.min, lambda r: r < t.amount),
|
||||
Rule.exists(self.max, lambda r: r > t.amount),
|
||||
)
|
||||
or (
|
||||
self.regex
|
||||
and transaction.description
|
||||
and not re.compile(self.regex, re.IGNORECASE).search(
|
||||
transaction.description
|
||||
)
|
||||
)
|
||||
or (self.bank and self.bank != transaction.bank)
|
||||
or (self.min and self.min > transaction.amount)
|
||||
or (self.max and self.max < transaction.amount)
|
||||
):
|
||||
return False
|
||||
|
||||
if all(ops):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@property
|
||||
def format(self) -> dict[str, Any]:
|
||||
return dict(
|
||||
date=self.date,
|
||||
start=self.start,
|
||||
end=self.end,
|
||||
description=self.description,
|
||||
regex=self.regex,
|
||||
bank=self.bank,
|
||||
@ -383,6 +386,10 @@ class Rule(Base, Export):
|
||||
type=self.type,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def exists(r, op) -> bool:
|
||||
return op(r) if r is not None else True
|
||||
|
||||
|
||||
class CategoryRule(Rule):
|
||||
__table_args__ = {"schema": "category"}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user