84 lines
3.0 KiB
Python
84 lines
3.0 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import date
|
|
from decimal import Decimal
|
|
|
|
from mousehold_api.schemas import ManualObservationCreate, SplitLineCreate
|
|
from mousehold_api.services.ingestion import create_observation_with_candidate
|
|
from mousehold_domain import FinancialEventStatus, FinancialEventType, ObservationStatus, SourceType
|
|
from sqlalchemy.orm import Session
|
|
|
|
|
|
def test_duplicate_observation_is_flagged_without_second_event(
|
|
session: Session,
|
|
household_setup: dict[str, str],
|
|
) -> None:
|
|
payload = ManualObservationCreate(
|
|
household_id=household_setup["household_id"],
|
|
owner_user_id=household_setup["user_a_id"],
|
|
source_account_id=household_setup["account_a_id"],
|
|
source_reference="same-manual-input",
|
|
amount=Decimal("120.00"),
|
|
currency="EUR",
|
|
event_date=date(2026, 1, 1),
|
|
merchant="Groceries",
|
|
description="Weekly groceries",
|
|
split_lines=[
|
|
SplitLineCreate(user_id=household_setup["user_a_id"], share_amount=Decimal("60.00")),
|
|
SplitLineCreate(user_id=household_setup["user_b_id"], share_amount=Decimal("60.00")),
|
|
],
|
|
)
|
|
|
|
first_observation, first_event = create_observation_with_candidate(session, payload)
|
|
second_observation, second_event = create_observation_with_candidate(session, payload)
|
|
|
|
assert first_observation.status == ObservationStatus.CANDIDATE_CREATED
|
|
assert first_event is not None
|
|
assert second_observation.status == ObservationStatus.DUPLICATE_SOURCE
|
|
assert second_event is None
|
|
|
|
|
|
def test_email_with_due_date_becomes_outstanding_event(
|
|
session: Session,
|
|
household_setup: dict[str, str],
|
|
) -> None:
|
|
payload = ManualObservationCreate(
|
|
household_id=household_setup["household_id"],
|
|
owner_user_id=household_setup["user_a_id"],
|
|
source_type=SourceType.KLARNA_EMAIL,
|
|
amount=Decimal("84.00"),
|
|
currency="EUR",
|
|
event_date=date(2026, 1, 3),
|
|
due_date=date(2026, 2, 2),
|
|
merchant="Klarna Shop",
|
|
description="Pay later purchase",
|
|
)
|
|
|
|
_observation, event = create_observation_with_candidate(session, payload)
|
|
|
|
assert event is not None
|
|
assert event.status == FinancialEventStatus.OUTSTANDING
|
|
|
|
|
|
def test_bank_provider_debit_becomes_liability_payment(
|
|
session: Session,
|
|
household_setup: dict[str, str],
|
|
) -> None:
|
|
payload = ManualObservationCreate(
|
|
household_id=household_setup["household_id"],
|
|
owner_user_id=household_setup["user_a_id"],
|
|
source_account_id=household_setup["account_a_id"],
|
|
source_type=SourceType.BANK_CSV,
|
|
amount=Decimal("250.00"),
|
|
currency="EUR",
|
|
event_date=date(2026, 1, 15),
|
|
merchant="Visa Kartenabrechnung",
|
|
description="Monthly credit card payment",
|
|
)
|
|
|
|
_observation, event = create_observation_with_candidate(session, payload)
|
|
|
|
assert event is not None
|
|
assert event.event_type == FinancialEventType.LIABILITY_PAYMENT
|
|
assert event.status == FinancialEventStatus.CONFIRMED
|