Files
nashel-backend/src/Modules/Order/Presentation/OrderEndpoints.cs
Халимов Рустам 5c9c6ab975 Создание заказов
2026-03-08 00:55:47 +03:00

267 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Security.Claims;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Nashel.Modules.Order.Application.Commands;
using Nashel.Modules.Order.Application.Queries;
using Nashel.Modules.Order.Domain.Enums;
namespace Nashel.Modules.Order.Presentation;
public static class OrderEndpoints
{
public static void MapOrderEndpoints(this IEndpointRouteBuilder app)
{
// ─── Создание заказа (временно без авторизации) ─────────────────────────────
// AllowAnonymous не перекрывает RequireAuthorization на группе в Minimal API,
// поэтому создание вынесено в отдельную группу.
app.MapPost("/api/orders", async ([FromBody] CreateOrderRequest request, ISender sender) =>
{
var command = new CreateOrderCommand(
request.CustomerId,
request.CustomerName,
request.ServiceId,
request.ServiceTitle,
request.PriceAmount,
request.PriceType,
request.Type,
request.Address,
request.Latitude,
request.Longitude,
request.Deadline,
request.PerformerId,
request.PerformerName
);
var orderId = await sender.Send(command);
return Results.Ok(orderId);
})
.WithTags("Заказы")
.WithName("CreateOrder")
.WithOpenApi(op => new(op)
{
Summary = "Создать заказ",
Description = "Создаёт прямой заказ (конкретному мастеру) или публичную заявку."
})
.AllowAnonymous();
var group = app.MapGroup("/api/orders")
.WithTags("Заказы")
.RequireAuthorization();
// ─── Получить мои заказы (как заказчик) ─────────────────────────────────────
group.MapGet("/as-customer/{userId:guid}", async (Guid userId, ISender sender) =>
{
var result = await sender.Send(new GetMyOrdersAsCustomerQuery(userId));
return Results.Ok(result);
})
.WithName("GetMyOrdersAsCustomer")
.WithOpenApi(op => new(op)
{
Summary = "Мои заказы (роль: Заказчик)",
Description = "Возвращает список всех заказов, где текущий пользователь является заказчиком, отсортированных по дате создания."
});
// ─── Получить мои заказы (как исполнитель) ───────────────────────────────────
group.MapGet("/as-performer/{userId:guid}", async (Guid userId, ISender sender) =>
{
var result = await sender.Send(new GetMyOrdersAsPerformerQuery(userId));
return Results.Ok(result);
})
.WithName("GetMyOrdersAsPerformer")
.WithOpenApi(op => new(op)
{
Summary = "Мои заказы (роль: Исполнитель)",
Description = "Возвращает список всех заказов, где текущий пользователь является назначенным исполнителем."
});
// ─── Принять заказ (мастер) ──────────────────────────────────────────────────
group.MapPost("/{id:guid}/accept", async (Guid id, AcceptOrderRequest request, ISender sender) =>
{
var command = new AcceptOrderCommand(id, request.PerformerId);
await sender.Send(command);
return Results.Ok();
})
.WithName("AcceptOrder")
.WithOpenApi(op => new(op)
{
Summary = "Принять заказ",
Description = "Исполнитель принимает заказ. Переводит заказ в статус «В работе»."
});
// ─── Завершить заказ ─────────────────────────────────────────────────────────
group.MapPost("/{id:guid}/complete", async (Guid id, CompleteOrderRequest request, ISender sender) =>
{
var command = new CompleteOrderCommand(id, request.RequesterId);
await sender.Send(command);
return Results.Ok();
})
.WithName("CompleteOrder")
.WithOpenApi(op => new(op)
{
Summary = "Завершить заказ",
Description = "Заказчик или исполнитель завершает заказ. Переводит в статус «Завершён»."
});
// ─── Отменить заказ ──────────────────────────────────────────────────────────
group.MapPost("/{id:guid}/cancel", async (Guid id, CancelOrderRequest request, ISender sender) =>
{
var command = new CancelOrderCommand(id, request.RequesterId, request.Reason);
await sender.Send(command);
return Results.Ok();
})
.WithName("CancelOrder")
.WithOpenApi(op => new(op)
{
Summary = "Отменить заказ",
Description = "Заказчик или исполнитель отменяет заказ с указанием причины."
});
// ─── Добавить отклик (мастер на публичный заказ) ─────────────────────────────
group.MapPost("/{id:guid}/applications", async (Guid id, AddApplicationRequest request, ISender sender) =>
{
var command = new AddApplicationCommand(id, request.PerformerId, request.Amount, request.Currency, request.Comment);
await sender.Send(command);
return Results.Ok();
})
.WithName("AddOrderApplication")
.WithOpenApi(op => new(op)
{
Summary = "Откликнуться на заказ",
Description = "Исполнитель отправляет отклик на публичный заказ с указанием цены и комментария."
});
// ─── Выбрать исполнителя из откликов (заказчик) ─────────────────────────────
group.MapPost("/{id:guid}/select-performer", async (Guid id, SelectPerformerRequest request, ISender sender) =>
{
var command = new SelectPerformerCommand(id, request.PerformerId);
await sender.Send(command);
return Results.Ok();
})
.WithName("SelectPerformer")
.WithOpenApi(op => new(op)
{
Summary = "Выбрать исполнителя",
Description = "Заказчик выбирает конкретного исполнителя из откликнувшихся. Запускает SLA-таймер 60 минут."
});
}
}
// ─── Request DTOs ────────────────────────────────────────────────────────────
/// <summary>
/// Запрос на создание заказа.
/// </summary>
public record CreateOrderRequest
{
/// <summary>Идентификатор заказчика.</summary>
public Guid CustomerId { get; init; }
/// <summary>ФИО заказчика.</summary>
public string CustomerName { get; init; } = default!;
/// <summary>Идентификатор услуги.</summary>
public Guid ServiceId { get; init; }
/// <summary>Название услуги.</summary>
public string ServiceTitle { get; init; } = default!;
/// <summary>Сумма услуги.</summary>
public decimal PriceAmount { get; init; }
/// <summary>Тип цены (0=Фикс, 1=Почасовая, 2=Договорная).</summary>
public PriceType PriceType { get; init; }
/// <summary>Тип заказа: Direct (прямой) или PublicJob (публичный).</summary>
public OrderType Type { get; init; }
/// <summary>Адрес выполнения заказа (текстовый).</summary>
public string Address { get; init; } = default!;
/// <summary>Широта места выполнения.</summary>
public double Latitude { get; init; }
/// <summary>Долгота места выполнения.</summary>
public double Longitude { get; init; }
/// <summary>Крайний срок выполнения (необязательно).</summary>
public DateTime? Deadline { get; init; }
/// <summary>Идентификатор исполнителя (обязателен для прямого заказа).</summary>
public Guid? PerformerId { get; init; }
/// <summary>Имя исполнителя (обязателен для прямого заказа).</summary>
public string? PerformerName { get; init; }
public CreateOrderRequest() { }
}
/// <summary>
/// Запрос принятия заказа исполнителем.
/// </summary>
public record AcceptOrderRequest
{
/// <summary>Идентификатор исполнителя, принимающего заказ.</summary>
public Guid PerformerId { get; init; }
public AcceptOrderRequest() { }
}
/// <summary>
/// Запрос завершения заказа.
/// </summary>
public record CompleteOrderRequest
{
/// <summary>Идентификатор пользователя (заказчик или исполнитель).</summary>
public Guid RequesterId { get; init; }
public CompleteOrderRequest() { }
}
/// <summary>
/// Запрос отмены заказа.
/// </summary>
public record CancelOrderRequest
{
/// <summary>Идентификатор пользователя, инициирующего отмену.</summary>
public Guid RequesterId { get; init; }
/// <summary>Причина отмены (необязательно).</summary>
public string? Reason { get; init; }
public CancelOrderRequest() { }
}
/// <summary>
/// Запрос добавления отклика на заказ.
/// </summary>
public record AddApplicationRequest
{
/// <summary>Идентификатор исполнителя.</summary>
public Guid PerformerId { get; init; }
/// <summary>Предлагаемая сумма.</summary>
public decimal Amount { get; init; }
/// <summary>Валюта (например, RUB).</summary>
public string Currency { get; init; } = "RUB";
/// <summary>Комментарий к отклику.</summary>
public string Comment { get; init; } = default!;
public AddApplicationRequest() { }
}
/// <summary>
/// Запрос выбора исполнителя.
/// </summary>
public record SelectPerformerRequest
{
/// <summary>Идентификатор выбранного исполнителя.</summary>
public Guid PerformerId { get; init; }
public SelectPerformerRequest() { }
}