Skip to content

Pairing exercise: Let merchant to notify shipment of an order #31

Open
nikhilJasani wants to merge 4 commits intoozean12:mainfrom
nikhilJasani:pairing-exercise
Open

Pairing exercise: Let merchant to notify shipment of an order #31
nikhilJasani wants to merge 4 commits intoozean12:mainfrom
nikhilJasani:pairing-exercise

Conversation

@nikhilJasani
Copy link

This PR is developed as pairing exercise with the aim to implement following business requirement.

Merchant can let the customers pay with Billie payment method, when it happens merchant is not paid straight away. But merchant needs to inform Billie about shipment the product. One order can have multiple products and hence it is possible order is fulfilled by merchant in different shipments. Merchant is only paid when Billie is notified about the shipment amount.

To ensure merchant is not paid more than order amount, shipment amount is summed up and notification attempt is rejected if it violets this rule.

Technically this PR adds few APIs to let merchant application/admin portal sends order request with total order amount, query all the orders belong to it and finally notifies shipment with shipment amount.

Comment on lines +25 to +26
if (shipmentTotal.compareTo(orderAmount.amount) > 0)
throw ShipmentAmountExceedOrderTotalException(ShipmentAmount(shipmentTotal), orderId!!)
Copy link
Author

Choose a reason for hiding this comment

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

Order domain keeps track of the business rule where total amount of all shipments don't exceed order amount.

*/
data class OrderAmount(val amount: BigDecimal) {
init {
require(amount.compareTo(BigDecimal.ZERO) > 0) { "Order amount must be positive" }
Copy link
Author

Choose a reason for hiding this comment

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

Order amount and also shipment amount domain objects ensure that it always receives positive value

Comment on lines +130 to +146
private fun mapToDtos(orders: List<Order>): List<OrderDto> {
return orders.stream()
.map(this::mapToDto)
.collect(Collectors.toList())
}

private fun mapToDto(order: Order): OrderDto {
return OrderDto(order.orderId!!.id, order.organisationId.id, order.orderAmount.amount)
}

private fun mapToDomain(organisationId: UUID, orderRequest: OrderRequest): Order {
return Order(null, Entity(organisationId), OrderAmount(orderRequest.amount), mutableSetOf())
}

private fun mapToDomain(orderId: UUID, shipmentRequest: ShipmentRequest): Shipment {
return Shipment(null, OrderId(orderId), ShipmentAmount(shipmentRequest.amount))
}
Copy link
Author

Choose a reason for hiding this comment

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

I prefer to use separate domain and dto objects which allow control over what internal domain information is exposed outside domain and it also helps to transform or convert some information at times.

@Service
class OrderService(val repository: OrderRepository) {

@Transactional(readOnly = true)
Copy link
Author

Choose a reason for hiding this comment

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

Order service which offers method to create, fetch orders and notifying shipment for an order

@@ -0,0 +1,6 @@
CREATE TABLE IF NOT EXISTS organisations_schema.shipments
(
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
Copy link
Author

Choose a reason for hiding this comment

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

Intentionally kept the schema simple - just to demonstrate for exercise requirement. Same is applicable to Order table.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants