From 035cfdf4fcb1bbcb4ad31df6c3414b9036c408f2 Mon Sep 17 00:00:00 2001 From: Paul de Raaij Date: Wed, 29 Jul 2026 02:14:24 -0400 Subject: [PATCH] feat: add UpdateText and UpdatePrice to ClassifiedAd with domain events --- domain/marketplace/classified_ad.py | 16 +++++ tests/test_classified_ad.py | 102 ++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/domain/marketplace/classified_ad.py b/domain/marketplace/classified_ad.py index e84ff8f..babb5f8 100644 --- a/domain/marketplace/classified_ad.py +++ b/domain/marketplace/classified_ad.py @@ -9,6 +9,8 @@ from domain.marketplace.classified_ad_state import ClassifiedAdState from domain.marketplace.classified_ad_text import ClassifiedAdText from domain.marketplace.classified_ad_title import ClassifiedAdTitle from domain.marketplace.domain_event import ( + ClassifiedAdPriceUpdated, + ClassifiedAdTextUpdated, ClassifiedAdTitleChanged, DomainEvent, ) @@ -54,3 +56,17 @@ class ClassifiedAd(Entity): return updated.raise_event( ClassifiedAdTitleChanged(id=self.id.value, title=title.title) ) + + def update_text(self, text: ClassifiedAdText) -> ClassifiedAd: + updated = replace(self, text=text) + updated._ensure_valid_state() + return updated.raise_event( + ClassifiedAdTextUpdated(id=self.id.value, ad_text=text.text) + ) + + def update_price(self, price: Price) -> ClassifiedAd: + updated = replace(self, price=price) + updated._ensure_valid_state() + return updated.raise_event( + ClassifiedAdPriceUpdated(id=self.id.value, price=price.amount) + ) diff --git a/tests/test_classified_ad.py b/tests/test_classified_ad.py index 9220121..293e16e 100644 --- a/tests/test_classified_ad.py +++ b/tests/test_classified_ad.py @@ -10,7 +10,9 @@ from domain.marketplace.classified_ad_state import ClassifiedAdState from domain.marketplace.classified_ad_text import ClassifiedAdText from domain.marketplace.classified_ad_title import ClassifiedAdTitle from domain.marketplace.domain_event import ( + ClassifiedAdPriceUpdated, ClassifiedAdSentForReview, + ClassifiedAdTextUpdated, ClassifiedAdTitleChanged, ) from domain.marketplace.invalid_entity_state_exception import ( @@ -323,3 +325,103 @@ def test_set_title_raises_classified_ad_title_changed_event(): assert isinstance(event, ClassifiedAdTitleChanged) assert event.id == ad.id.value assert event.title == "New Title" + + +def test_update_text_updates_text(): + ad = ClassifiedAd( + id=ClassifiedAdId(value=uuid4()), + _ownerId=UserId(value=uuid4()), + title=ClassifiedAdTitle(title="Title"), + text=ClassifiedAdText(text="Old text"), + price=Price(amount=Decimal("10.00")), + ) + new_text = ClassifiedAdText(text="New text") + + updated = ad.update_text(new_text) + + assert updated.text == new_text + assert ad.text == ClassifiedAdText(text="Old text") + + +def test_update_text_fails_when_new_text_empty(): + ad = ClassifiedAd( + id=ClassifiedAdId(value=uuid4()), + _ownerId=UserId(value=uuid4()), + title=ClassifiedAdTitle(title="Title"), + text=ClassifiedAdText(text="Text"), + price=Price(amount=Decimal("10.00")), + ) + + with pytest.raises(InvalidEntityStateException) as exc_info: + ad.update_text(ClassifiedAdText(text="")) + + assert "text" in str(exc_info.value) + + +def test_update_text_raises_classified_ad_text_updated_event(): + ad = ClassifiedAd( + id=ClassifiedAdId(value=uuid4()), + _ownerId=UserId(value=uuid4()), + title=ClassifiedAdTitle(title="Title"), + text=ClassifiedAdText(text="Old text"), + price=Price(amount=Decimal("10.00")), + ) + + updated = ad.update_text(ClassifiedAdText(text="New text")) + + changes = updated.get_changes() + assert len(changes) == 1 + event = changes[0] + assert isinstance(event, ClassifiedAdTextUpdated) + assert event.id == ad.id.value + assert event.ad_text == "New text" + + +def test_update_price_updates_price(): + ad = ClassifiedAd( + id=ClassifiedAdId(value=uuid4()), + _ownerId=UserId(value=uuid4()), + title=ClassifiedAdTitle(title="Title"), + text=ClassifiedAdText(text="Text"), + price=Price(amount=Decimal("10.00")), + ) + new_price = Price(amount=Decimal("25.00")) + + updated = ad.update_price(new_price) + + assert updated.price == new_price + assert ad.price == Price(amount=Decimal("10.00")) + + +def test_update_price_fails_when_price_zero(): + ad = ClassifiedAd( + id=ClassifiedAdId(value=uuid4()), + _ownerId=UserId(value=uuid4()), + title=ClassifiedAdTitle(title="Title"), + text=ClassifiedAdText(text="Text"), + price=Price(amount=Decimal("10.00")), + ) + + with pytest.raises(InvalidEntityStateException) as exc_info: + ad.update_price(Price(amount=Decimal("0.00"))) + + assert "price" in str(exc_info.value) + + +def test_update_price_raises_classified_ad_price_updated_event(): + ad = ClassifiedAd( + id=ClassifiedAdId(value=uuid4()), + _ownerId=UserId(value=uuid4()), + title=ClassifiedAdTitle(title="Title"), + text=ClassifiedAdText(text="Text"), + price=Price(amount=Decimal("10.00")), + ) + + updated = ad.update_price(Price(amount=Decimal("25.00"))) + + changes = updated.get_changes() + assert len(changes) == 1 + event = changes[0] + assert isinstance(event, ClassifiedAdPriceUpdated) + assert event.id == ad.id.value + assert event.price == Decimal("25.00")