first commit
CI/CD / CI · Admin API (dotnet build) (push) Successful in 41s
CI/CD / CI · Admin Web (tsc) (push) Failing after 5s
CI/CD / CI · Website (tsc) (push) Failing after 4s
CI/CD / CI · Koja (tsc) (push) Failing after 5s
CI/CD / CI · API (dotnet build + test) (push) Successful in 1m13s
CI/CD / CI · Dashboard (tsc) (push) Failing after 2m32s
CI/CD / Deploy · all services (push) Has been skipped
CI/CD / CI · Admin API (dotnet build) (push) Successful in 41s
CI/CD / CI · Admin Web (tsc) (push) Failing after 5s
CI/CD / CI · Website (tsc) (push) Failing after 4s
CI/CD / CI · Koja (tsc) (push) Failing after 5s
CI/CD / CI · API (dotnet build + test) (push) Successful in 1m13s
CI/CD / CI · Dashboard (tsc) (push) Failing after 2m32s
CI/CD / Deploy · all services (push) Has been skipped
This commit is contained in:
@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Meezi.API.Models.Orders;
|
||||
using Meezi.API.Services;
|
||||
using Meezi.Core.Authorization;
|
||||
using Meezi.Core.Enums;
|
||||
using Meezi.Core.Interfaces;
|
||||
using Meezi.Shared;
|
||||
@@ -13,6 +14,7 @@ namespace Meezi.API.Controllers;
|
||||
public class OrdersController : CafeApiControllerBase
|
||||
{
|
||||
private readonly IOrderService _orderService;
|
||||
private readonly IAuditLogService _audit;
|
||||
private readonly IValidator<CreateOrderRequest> _createValidator;
|
||||
private readonly IValidator<UpdateOrderStatusRequest> _statusValidator;
|
||||
private readonly IValidator<RecordPaymentsRequest> _paymentsValidator;
|
||||
@@ -21,6 +23,7 @@ public class OrdersController : CafeApiControllerBase
|
||||
|
||||
public OrdersController(
|
||||
IOrderService orderService,
|
||||
IAuditLogService audit,
|
||||
IValidator<CreateOrderRequest> createValidator,
|
||||
IValidator<UpdateOrderStatusRequest> statusValidator,
|
||||
IValidator<RecordPaymentsRequest> paymentsValidator,
|
||||
@@ -28,6 +31,7 @@ public class OrdersController : CafeApiControllerBase
|
||||
IValidator<UpdateOrderSessionRequest> sessionValidator)
|
||||
{
|
||||
_orderService = orderService;
|
||||
_audit = audit;
|
||||
_createValidator = createValidator;
|
||||
_statusValidator = statusValidator;
|
||||
_paymentsValidator = paymentsValidator;
|
||||
@@ -131,6 +135,16 @@ public class OrdersController : CafeApiControllerBase
|
||||
if (!result.Success)
|
||||
return OrderError(result.ErrorCode!, result.Field);
|
||||
|
||||
await _audit.LogAsync(new AuditEntry
|
||||
{
|
||||
Category = "Order",
|
||||
Action = "ItemVoided",
|
||||
EntityType = "Order",
|
||||
EntityId = id,
|
||||
Summary = $"Voided a line item on order #{result.Data!.DisplayNumber}",
|
||||
Details = new { orderId = id, itemId, displayNumber = result.Data.DisplayNumber }
|
||||
}, cancellationToken);
|
||||
|
||||
return Ok(new ApiResponse<OrderDto>(true, result.Data));
|
||||
}
|
||||
|
||||
@@ -188,6 +202,42 @@ public class OrdersController : CafeApiControllerBase
|
||||
return Ok(new ApiResponse<OrderDto>(true, data));
|
||||
}
|
||||
|
||||
[HttpPost("{id}/cancel")]
|
||||
public async Task<IActionResult> CancelOrder(
|
||||
string cafeId,
|
||||
string id,
|
||||
[FromBody] CancelOrderRequest request,
|
||||
ITenantContext tenant,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (EnsureCafeAccess(cafeId, tenant) is { } denied) return denied;
|
||||
if (EnsurePermission(tenant, Permission.ProcessOrders) is { } forbidden) return forbidden;
|
||||
|
||||
var result = await _orderService.CancelOrderAsync(
|
||||
cafeId, id, request.Reason, tenant.UserId, cancellationToken);
|
||||
if (!result.Success)
|
||||
return OrderError(result.ErrorCode!, result.Field);
|
||||
|
||||
await _audit.LogAsync(new AuditEntry
|
||||
{
|
||||
Category = "Order",
|
||||
Action = "OrderCancelled",
|
||||
EntityType = "Order",
|
||||
EntityId = id,
|
||||
Summary = $"Order #{result.Data!.DisplayNumber} cancelled"
|
||||
+ (string.IsNullOrWhiteSpace(request.Reason) ? "" : $": {request.Reason!.Trim()}"),
|
||||
Details = new
|
||||
{
|
||||
orderId = id,
|
||||
displayNumber = result.Data.DisplayNumber,
|
||||
total = result.Data.Total,
|
||||
reason = request.Reason
|
||||
}
|
||||
}, cancellationToken);
|
||||
|
||||
return Ok(new ApiResponse<OrderDto>(true, result.Data));
|
||||
}
|
||||
|
||||
[HttpPost("{id}/payments")]
|
||||
public async Task<IActionResult> RecordPayments(
|
||||
string cafeId,
|
||||
@@ -203,6 +253,23 @@ public class OrdersController : CafeApiControllerBase
|
||||
var result = await _orderService.RecordPaymentsAsync(
|
||||
cafeId, id, request, tenant.UserId, cancellationToken);
|
||||
if (!result.Success) return OrderError(result.ErrorCode!, result.Field);
|
||||
|
||||
var paidTotal = result.Data!.Sum(p => p.Amount);
|
||||
await _audit.LogAsync(new AuditEntry
|
||||
{
|
||||
Category = "Payment",
|
||||
Action = "PaymentRecorded",
|
||||
EntityType = "Order",
|
||||
EntityId = id,
|
||||
Summary = $"Recorded payment(s) totalling {paidTotal:0.##} on order",
|
||||
Details = new
|
||||
{
|
||||
orderId = id,
|
||||
total = paidTotal,
|
||||
methods = result.Data!.Select(p => new { p.Method, p.Amount })
|
||||
}
|
||||
}, cancellationToken);
|
||||
|
||||
return Ok(new ApiResponse<IReadOnlyList<PaymentDto>>(true, result.Data));
|
||||
}
|
||||
|
||||
@@ -219,6 +286,10 @@ public class OrdersController : CafeApiControllerBase
|
||||
false, null, new ApiError(code, "Order not found.", field))),
|
||||
"ORDER_ALREADY_CLOSED" => BadRequest(new ApiResponse<object>(
|
||||
false, null, new ApiError(code, "Order is already closed.", field))),
|
||||
"ORDER_ALREADY_CANCELLED" => BadRequest(new ApiResponse<object>(
|
||||
false, null, new ApiError(code, "Order is already cancelled.", field))),
|
||||
"ORDER_HAS_PAYMENTS" => Conflict(new ApiResponse<object>(
|
||||
false, null, new ApiError(code, "Refund the recorded payments before cancelling this order.", field))),
|
||||
"ITEM_NOT_FOUND" => NotFound(new ApiResponse<object>(
|
||||
false, null, new ApiError(code, "Line item not found.", field))),
|
||||
"ITEM_ALREADY_VOIDED" => BadRequest(new ApiResponse<object>(
|
||||
|
||||
Reference in New Issue
Block a user