📄 OrdersController.cs
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
using Walley.Checkout.Api.Models;
using Walley.Checkout.Api.Services;

namespace Walley.Checkout.Api.Controllers;

[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    private readonly IOrderService _orderService;
    private readonly IRefundService _refundService;

    public OrdersController(IOrderService orderService, IRefundService refundService)
    {
        _orderService = orderService;
        _refundService = refundService;
    }

    /// <summary>
    /// Get all orders.
    /// </summary>
    [HttpGet]
    public async Task<ActionResult<IEnumerable<Order>>> GetAll()
    {
        var orders = await _orderService.GetAllOrdersAsync();
        return Ok(orders);
    }

    /// <summary>
    /// Get a specific order by ID.
    /// </summary>
    [HttpGet("{id}")]
    public async Task<ActionResult<Order>> GetById(string id)
    {
        var order = await _orderService.GetOrderByIdAsync(id);
        return order != null ? Ok(order) : NotFound();
    }

    /// <summary>
    /// Creates a new order.
    /// </summary>
    [HttpPost]
    public async Task<ActionResult<Order>> CreateOrder([FromBody] CreateOrderRequest request)
    {
        var order = await _orderService.CreateOrderAsync(request.ToDomainModel());
        return CreatedAtAction(nameof(GetById), new { id = order.Id }, order);
    }

    /// <summary>
    /// Request a refund for an order.
    /// </summary>
    [HttpPost("{orderId}/refunds")]
    public async Task<ActionResult<Refund>> RequestRefund(
        string orderId,
        [FromBody] RefundRequest request)
    {
        var refund = await _refundService.ProcessRefundAsync(
            orderId,
            request.Amount,
            request.Reason);

        if (refund.Status == RefundStatus.Rejected)
        {
            return UnprocessableEntity(refund);
        }

        return Ok(refund);
    }
}

public class CreateOrderRequest
{
    [MinLength(1)]
    public string CustomerName { get; set; } = string.Empty;
    [EmailAddress]
    public string CustomerEmail { get; set; } = string.Empty;
    [MinLength(1)]
    public List<CreateOrderLineRequest> Lines { get; set; } = new();
    [RegularExpression(@"^[A-Z]{3}$")]
    public string Currency { get; set; } = string.Empty;

    public class CreateOrderLineRequest
    {
        [MinLength(1)]
        public string ProductName { get; set; } = string.Empty;
        [Range(1, int.MaxValue)]
        public int Quantity { get; set; }
        [Range(0d, double.MaxValue)]
        public decimal UnitPrice { get; set; }

        public OrderLine ToDomainModel() => new()
        {
            ProductName = ProductName,
            Quantity = Quantity,
            UnitPrice = UnitPrice,
        };
    }

    public Order ToDomainModel() => new()
    {
        CustomerName = CustomerName,
        CustomerEmail = CustomerEmail,
        Lines = Lines.Select(l => l.ToDomainModel()).ToList(),
        Currency = Currency,
    };
}

public class RefundRequest
{
    public decimal Amount { get; set; }
    public string Reason { get; set; } = string.Empty;
}