Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

## New Features

<!-- Here goes the main new features and examples or instructions on how to use them -->
* Add check to validate order details.

## Bug Fixes

Expand Down
17 changes: 17 additions & 0 deletions src/frequenz/client/electricity_trading/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,23 @@ def from_pb(cls, order_detail: electricity_trading_pb2.OrderDetail) -> Self:

return od

@property
def is_valid(self) -> bool:
"""Check if the order detail is valid.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs should tell what is considered as a valid order.


Returns:
True if the order detail is valid, False otherwise.
"""
# Only cancelled orders are allowed to have missing price or quantity
if self.state_detail.state == OrderState.CANCELED:
return True

return not (
self.order.price.amount.is_nan()
or self.order.price.currency == Currency.UNSPECIFIED
or self.order.quantity.mw.is_nan()
)

def to_pb(self) -> electricity_trading_pb2.OrderDetail:
"""Convert an OrderDetail object to protobuf OrderDetail.

Expand Down
8 changes: 8 additions & 0 deletions tests/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -580,18 +580,26 @@ def test_order_detail_from_pb_missing_fields() -> None:
# Missing price
od_pb1 = electricity_trading_pb2.OrderDetail()
od_pb1.CopyFrom(ORDER_DETAIL_PB)
assert OrderDetail.from_pb(od_pb1).is_valid
od_pb1.order.ClearField("price")
OrderDetail.from_pb(od_pb1)
# Not allowed for active orders
assert not OrderDetail.from_pb(od_pb1).is_valid
od_pb1.state_detail.state = electricity_trading_pb2.OrderState.ORDER_STATE_CANCELED
OrderDetail.from_pb(od_pb1)
# But allowed for canceled orders
assert OrderDetail.from_pb(od_pb1).is_valid

# Missing quantity (same logic as above)
od_pb2 = electricity_trading_pb2.OrderDetail()
od_pb2.CopyFrom(ORDER_DETAIL_PB)
assert OrderDetail.from_pb(od_pb2).is_valid
od_pb2.order.ClearField("quantity")
OrderDetail.from_pb(od_pb2)
assert not OrderDetail.from_pb(od_pb2).is_valid
od_pb2.state_detail.state = electricity_trading_pb2.OrderState.ORDER_STATE_CANCELED
OrderDetail.from_pb(od_pb2)
assert OrderDetail.from_pb(od_pb2).is_valid


def test_order_detail_no_timezone_error() -> None:
Expand Down