This project implements an Order Management System with an integrated Discount Module using the Chain of Responsibility pattern. It ensures scalability, efficiency, and data consistency through technologies like Symfony, RabbitMQ, Docker, PostgreSQL, Nginx, and Supervisor.
- Asynchronous Order Processing: Orders are processed using Symfony Messenger and RabbitMQ for reliable and efficient handling.
- FIFO Queue Handling: Orders are processed in a first-in, first-out manner to prevent race conditions.
- Discount Rules Engine: Uses Chain of Responsibility to apply multiple discount rules dynamically.
- DTO-based Validation: Ensures data integrity by validating requests with Symfony DTOs and constraints.
- Dockerized Infrastructure: Consistent Local & Production Environment Using Docker & Docker Compose
- Supervised Background Processing: Supervisor manages long-running Symfony Messenger consumers.
- A new order request is received via the REST API.
- The order is placed in the
order_create
queue (RabbitMQ) for asynchronous processing. - Symfony Messenger Consumer retrieves the message and starts processing.
- The system validates stock availability and creates the order.
- If stock is sufficient, the system reduces stock levels and sets the order status to
CREATED
. - If stock is insufficient, the order is still created but marked as
FAILED
. - After successful processing, an
OrderCreatedMessage
is dispatched.
- RabbitMQ is configured for FIFO processing using:
x-single-active-consumer: true
(Ensures only one worker processes a queue at a time).
The discount module follows the Chain of Responsibility Pattern:
- The DiscountProcessor iterates through registered discount rules.
- Applicable rules update the discount context, modifying the subtotal.
- Each rule operates on the updated values from previous discounts.
Rule Name | Condition | Applied Discount |
---|---|---|
BUY_6_GET_1 | Buy 6 items from category 2 | 1 item free |
10_PERCENT_OVER_1000 | Order total is over 1000 | 10% off total |
CHEAPEST_20_PERCENT | Buy 2+ items from category 1 | 20% off the cheapest |
Example Discount Calculation:
{
"orderId": 5,
"originalTotal": "2000.00",
"discounts": [
{
"discountReason": "BUY_6_GET_1",
"discountAmount": "100.00",
"subtotal": "1900.00"
},
{
"discountReason": "10_PERCENT_OVER_1000",
"discountAmount": "190.00",
"subtotal": "1710.00"
}
],
"totalDiscount": "290.00",
"discountedTotal": "1710.00"
}
├── src/
│ ├── Controller/API
│ │ ├── ApiController.php # API Base Controller
│ │ ├── OrderController.php # API Endpoints for orders
│ │ ├── OrderDiscountController.php # API Endpoints for order discounts
│ ├── Services/
│ │ ├── Order/
│ │ │ ├── OrderFactory.php
│ │ │ ├── OrderItemFactory.php
│ │ │ ├── OrderCreateService.php
│ │ │ ├── OrderDeleteService.php
│ │ │ ├── OrderDiscountService.php
│ │ │ ├── OrderProcessingService.php
│ │ │ ├── OrderValidationService.php
│ │ ├── Discount/
│ │ │ ├── DiscountContext.php
│ │ │ ├── DiscountProcessor.php
│ │ │ ├── DiscountRuleInterface.php
│ │ │ ├── Rules/
│ │ │ │ ├── Over1000TotalDiscountRule.php # Discount rule 1
│ │ │ │ ├── CategoryTwoBuySixGetOneFreeRule.php # Discount rule 2
│ │ │ │ ├── CategoryOneCheapestItemDiscountRule.php # Discount rule 3
│ ├── Message/Order
│ │ ├── OrderCreatingMessage.php # Message for order creation
│ │ ├── OrderCreatedMessage.php # Message when order is created
│ │ ├── OrderDeletedMessage.php # Message when order is deleted
│ ├── MessageHandler/Order
│ │ ├── OrderCreatingMessageHandler.php # Handles order processing in queue
│ │ ├── OrderCreatedMessageHandler.php
│ │ ├── OrderDeletedMessageHandler.php
POST /api/orders
{
"customerId": 1,
"orderItems": [
{ "productId": 1, "quantity": 1 },
{ "productId": 2, "quantity": 1 }
]
}
Response:
{
"success": true,
"message": "Order creation initialized",
"data": {
"uuid": "01JJY9N55AFDHPWNWWNMMVSMDK",
"status": "creating"
}
}
GET /api/orders
GET /api/orders/{orderUUID}
DELETE /api/orders/{orderId}
Response:
{
"success": true,
"message": "Order deleted successfully!",
"data": null
}
This project uses DTOs (Data Transfer Objects) for request validation, ensuring all data is structured correctly before processing.
final class OrderCreateDTO
{
#[Assert\Positive]
#[Assert\NotBlank]
public readonly int $customerId;
#[Assert\Valid]
#[Assert\Count(min: 1)]
public array $orderItems;
}
This project is built to be scalable, maintainable, and efficient, leveraging Symfony Messenger, RabbitMQ, and a modular services structure to handle order management and discount processing effectively.
For installation instructions, refer to the Installation Guide: INSTALLATION.md