2
2
from datetime import datetime , timedelta
3
3
from typing import Optional
4
4
5
+ from modules .bidding .domain .events import (
6
+ BidWasPlaced ,
7
+ BidWasRetracted ,
8
+ HighestBidderWasOutbid ,
9
+ ListingWasCancelled ,
10
+ )
5
11
from modules .bidding .domain .rules import (
6
12
BidCanBeRetracted ,
7
13
ListingCanBeCancelled ,
8
- PlacedBidMustBeGreaterOrEqualThanNextMinimumBid ,
14
+ PriceOfPlacedBidMustBeGreaterOrEqualThanNextMinimumPrice ,
9
15
)
10
16
from modules .bidding .domain .value_objects import Bid , Bidder , Seller
11
17
from seedwork .domain .entities import AggregateRoot
@@ -26,18 +32,6 @@ class ListingCannotBeCancelled(DomainException):
26
32
...
27
33
28
34
29
- class BidPlacedEvent (DomainEvent ):
30
- ...
31
-
32
-
33
- class BidRetractedEvent (DomainEvent ):
34
- ...
35
-
36
-
37
- class ListingCancelledEvent (DomainEvent ):
38
- ...
39
-
40
-
41
35
@dataclass (kw_only = True )
42
36
class Listing (AggregateRoot [GenericUUID ]):
43
37
seller : Seller
@@ -61,34 +55,57 @@ def next_minimum_price(self) -> Money:
61
55
return self .current_price + Money (amount = 1 , currency = self .ask_price .currency )
62
56
63
57
# public commands
64
- def place_bid (self , bid : Bid ) -> DomainEvent :
58
+ def place_bid (self , bid : Bid ):
65
59
"""Public method"""
66
60
self .check_rule (
67
- PlacedBidMustBeGreaterOrEqualThanNextMinimumBid (
61
+ PriceOfPlacedBidMustBeGreaterOrEqualThanNextMinimumPrice (
68
62
current_price = bid .max_price , next_minimum_price = self .next_minimum_price
69
63
)
70
64
)
71
65
66
+ previous_winner_id = self .highest_bid .bidder .id if self .highest_bid else None
67
+ current_winner_id = bid .bidder .id
68
+
72
69
if self .has_bid_placed_by (bidder = bid .bidder ):
73
70
self ._update_bid (bid )
74
71
else :
75
72
self ._add_bid (bid )
76
73
77
- return BidPlacedEvent (
78
- listing_id = self .id , bidder = bid .bidder , max_price = bid .max_price
74
+ self .register_event (
75
+ BidWasPlaced (
76
+ listing_id = self .id ,
77
+ bidder_id = bid .bidder .id ,
78
+ )
79
79
)
80
80
81
- def retract_bid_of (self , bidder : Bidder ) -> DomainEvent :
81
+ # if there was previous winner...
82
+ if previous_winner_id is not None and previous_winner_id != current_winner_id :
83
+ self .register_event (
84
+ HighestBidderWasOutbid (
85
+ listing_id = self .id ,
86
+ outbid_bidder_id = previous_winner_id ,
87
+ )
88
+ )
89
+
90
+ def retract_bid_of (self , bidder : Bidder ):
82
91
"""Public method"""
83
92
bid = self .get_bid_of (bidder )
84
93
self .check_rule (
85
94
BidCanBeRetracted (listing_ends_at = self .ends_at , bid_placed_at = bid .placed_at )
86
95
)
87
96
88
97
self ._remove_bid_of (bidder = bidder )
89
- return BidRetractedEvent (listing_id = self .id , bidder_id = bidder .id )
98
+ self .register_event (
99
+ BidWasRetracted (
100
+ listing_id = self .id ,
101
+ retracting_bidder_id = bidder .id ,
102
+ winning_bidder_id = self .highest_bid .bidder .id
103
+ if self .highest_bid
104
+ else None ,
105
+ )
106
+ )
90
107
91
- def cancel (self ) -> DomainEvent :
108
+ def cancel (self ):
92
109
"""
93
110
Seller can cancel a listing (end a listing early). Listing must be eligible to cancelled,
94
111
depending on time left and if bids have been placed.
@@ -100,14 +117,13 @@ def cancel(self) -> DomainEvent:
100
117
)
101
118
)
102
119
self .ends_at = datetime .utcnow ()
103
- return ListingCancelledEvent ( listing_id = self .id )
120
+ self . register_event ( ListingWasCancelled ( listing_id = self .id ) )
104
121
105
122
def end (self ) -> DomainEvent :
106
123
"""
107
124
Ends listing.
108
125
"""
109
126
raise NotImplementedError ()
110
- return []
111
127
112
128
# public queries
113
129
def get_bid_of (self , bidder : Bidder ) -> Bid :
@@ -126,7 +142,7 @@ def has_bid_placed_by(self, bidder: Bidder) -> bool:
126
142
return True
127
143
128
144
@property
129
- def winning_bid (self ) -> Optional [Bid ]:
145
+ def highest_bid (self ) -> Optional [Bid ]:
130
146
try :
131
147
highest_bid = max (self .bids , key = lambda bid : bid .max_price )
132
148
except ValueError :
0 commit comments