перешли на int

This commit is contained in:
gorbenko.pavel
2026-07-24 13:57:30 +05:00
parent 5e45c18817
commit 5e3ef814f3
20 changed files with 101 additions and 91 deletions
@@ -16,10 +16,10 @@ public sealed class RequestTypesController(RequestTypeService service) : Control
public async Task<IActionResult> List(CancellationToken ct) => public async Task<IActionResult> List(CancellationToken ct) =>
(await service.ListAsync(ct)).ToActionResult(); (await service.ListAsync(ct)).ToActionResult();
[HttpGet("{id:guid}")] [HttpGet("{id:int}")]
[ProducesResponseType(typeof(ApiResponse<RequestTypeDto>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse<RequestTypeDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)]
public async Task<IActionResult> Get(Guid id, CancellationToken ct) => public async Task<IActionResult> Get(int id, CancellationToken ct) =>
(await service.GetAsync(id, ct)).ToActionResult(); (await service.GetAsync(id, ct)).ToActionResult();
[HttpPost] [HttpPost]
@@ -28,16 +28,16 @@ public sealed class RequestTypesController(RequestTypeService service) : Control
public async Task<IActionResult> Create(CreateRequestTypeRequest body, CancellationToken ct) => public async Task<IActionResult> Create(CreateRequestTypeRequest body, CancellationToken ct) =>
(await service.CreateAsync(body, ct)).ToActionResult(); (await service.CreateAsync(body, ct)).ToActionResult();
[HttpPut("{id:guid}")] [HttpPut("{id:int}")]
[ProducesResponseType(typeof(ApiResponse<RequestTypeDto>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse<RequestTypeDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiError), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(ApiError), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)]
public async Task<IActionResult> Update(Guid id, UpdateRequestTypeRequest body, CancellationToken ct) => public async Task<IActionResult> Update(int id, UpdateRequestTypeRequest body, CancellationToken ct) =>
(await service.UpdateAsync(id, body, ct)).ToActionResult(); (await service.UpdateAsync(id, body, ct)).ToActionResult();
[HttpDelete("{id:guid}")] [HttpDelete("{id:int}")]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)]
public async Task<IActionResult> Delete(Guid id, CancellationToken ct) => public async Task<IActionResult> Delete(int id, CancellationToken ct) =>
(await service.DeleteAsync(id, ct)).ToActionResult(); (await service.DeleteAsync(id, ct)).ToActionResult();
} }
@@ -7,38 +7,38 @@ namespace Tnsu.ApprovalRoute.Api.Controllers;
[ApiController] [ApiController]
[Authorize] [Authorize]
[Route("api/template-routes/{routeId:guid}/steps")] [Route("api/template-routes/{routeId:int}/steps")]
[Produces("application/json")] [Produces("application/json")]
public sealed class TemplateRouteStepsController(TemplateRouteStepService service) : ControllerBase public sealed class TemplateRouteStepsController(TemplateRouteStepService service) : ControllerBase
{ {
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(ApiResponse<IReadOnlyList<TemplateRouteStepDto>>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse<IReadOnlyList<TemplateRouteStepDto>>), StatusCodes.Status200OK)]
public async Task<IActionResult> List(Guid routeId, CancellationToken ct) => public async Task<IActionResult> List(int routeId, CancellationToken ct) =>
(await service.ListAsync(routeId, ct)).ToActionResult(); (await service.ListAsync(routeId, ct)).ToActionResult();
[HttpGet("{id:guid}")] [HttpGet("{id:int}")]
[ProducesResponseType(typeof(ApiResponse<TemplateRouteStepDto>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse<TemplateRouteStepDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)]
public async Task<IActionResult> Get(Guid routeId, Guid id, CancellationToken ct) => public async Task<IActionResult> Get(int routeId, int id, CancellationToken ct) =>
(await service.GetAsync(routeId, id, ct)).ToActionResult(); (await service.GetAsync(routeId, id, ct)).ToActionResult();
[HttpPost] [HttpPost]
[ProducesResponseType(typeof(ApiResponse<TemplateRouteStepDto>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse<TemplateRouteStepDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiError), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(ApiError), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)]
public async Task<IActionResult> Create(Guid routeId, CreateTemplateRouteStepRequest body, CancellationToken ct) => public async Task<IActionResult> Create(int routeId, CreateTemplateRouteStepRequest body, CancellationToken ct) =>
(await service.CreateAsync(routeId, body, ct)).ToActionResult(); (await service.CreateAsync(routeId, body, ct)).ToActionResult();
[HttpPut("{id:guid}")] [HttpPut("{id:int}")]
[ProducesResponseType(typeof(ApiResponse<TemplateRouteStepDto>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse<TemplateRouteStepDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiError), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(ApiError), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)]
public async Task<IActionResult> Update(Guid routeId, Guid id, UpdateTemplateRouteStepRequest body, CancellationToken ct) => public async Task<IActionResult> Update(int routeId, int id, UpdateTemplateRouteStepRequest body, CancellationToken ct) =>
(await service.UpdateAsync(routeId, id, body, ct)).ToActionResult(); (await service.UpdateAsync(routeId, id, body, ct)).ToActionResult();
[HttpDelete("{id:guid}")] [HttpDelete("{id:int}")]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)]
public async Task<IActionResult> Delete(Guid routeId, Guid id, CancellationToken ct) => public async Task<IActionResult> Delete(int routeId, int id, CancellationToken ct) =>
(await service.DeleteAsync(routeId, id, ct)).ToActionResult(); (await service.DeleteAsync(routeId, id, ct)).ToActionResult();
} }
@@ -20,13 +20,13 @@ public sealed class TemplateRoutesController(TemplateRouteService service) : Con
[HttpGet] [HttpGet]
[ProducesResponseType(typeof(ApiResponse<IReadOnlyList<TemplateRouteDto>>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse<IReadOnlyList<TemplateRouteDto>>), StatusCodes.Status200OK)]
public async Task<IActionResult> List([FromQuery] Guid? requestTypeId, CancellationToken ct) => public async Task<IActionResult> List([FromQuery] int? requestTypeId, CancellationToken ct) =>
(await service.ListAsync(requestTypeId, ct)).ToActionResult(); (await service.ListAsync(requestTypeId, ct)).ToActionResult();
[HttpGet("{id:guid}")] [HttpGet("{id:int}")]
[ProducesResponseType(typeof(ApiResponse<TemplateRouteDto>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse<TemplateRouteDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)]
public async Task<IActionResult> Get(Guid id, CancellationToken ct) => public async Task<IActionResult> Get(int id, CancellationToken ct) =>
(await service.GetAsync(id, ct)).ToActionResult(); (await service.GetAsync(id, ct)).ToActionResult();
[HttpPost] [HttpPost]
@@ -37,17 +37,17 @@ public sealed class TemplateRoutesController(TemplateRouteService service) : Con
public async Task<IActionResult> Create(CreateTemplateRouteRequest body, CancellationToken ct) => public async Task<IActionResult> Create(CreateTemplateRouteRequest body, CancellationToken ct) =>
(await service.CreateAsync(body, ct)).ToActionResult(); (await service.CreateAsync(body, ct)).ToActionResult();
[HttpPut("{id:guid}")] [HttpPut("{id:int}")]
[ProducesResponseType(typeof(ApiResponse<TemplateRouteDto>), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse<TemplateRouteDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiError), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(ApiError), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(ApiError), StatusCodes.Status409Conflict)] [ProducesResponseType(typeof(ApiError), StatusCodes.Status409Conflict)]
public async Task<IActionResult> Update(Guid id, UpdateTemplateRouteRequest body, CancellationToken ct) => public async Task<IActionResult> Update(int id, UpdateTemplateRouteRequest body, CancellationToken ct) =>
(await service.UpdateAsync(id, body, ct)).ToActionResult(); (await service.UpdateAsync(id, body, ct)).ToActionResult();
[HttpDelete("{id:guid}")] [HttpDelete("{id:int}")]
[ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)]
public async Task<IActionResult> Delete(Guid id, CancellationToken ct) => public async Task<IActionResult> Delete(int id, CancellationToken ct) =>
(await service.DeleteAsync(id, ct)).ToActionResult(); (await service.DeleteAsync(id, ct)).ToActionResult();
} }
@@ -2,7 +2,7 @@ using FluentResults;
namespace Tnsu.ApprovalRoute.Application.Common.Errors; namespace Tnsu.ApprovalRoute.Application.Common.Errors;
public sealed class NotFoundError(string entity, Guid id) public sealed class NotFoundError(string entity, object id)
: Error($"{entity} с id {id} не найден."); : Error($"{entity} с id {id} не найден.");
public sealed class ValidationError(string message) : Error(message); public sealed class ValidationError(string message) : Error(message);
@@ -1,6 +1,6 @@
namespace Tnsu.ApprovalRoute.Application.RequestTypes; namespace Tnsu.ApprovalRoute.Application.RequestTypes;
public sealed record RequestTypeDto(Guid Id, string Name, string PageUrl); public sealed record RequestTypeDto(int Id, string Name, string PageUrl);
public sealed record CreateRequestTypeRequest(string Name, string PageUrl); public sealed record CreateRequestTypeRequest(string Name, string PageUrl);
@@ -18,7 +18,7 @@ public sealed class RequestTypeService(ApprovalRouteDbContext db)
return Result.Ok<IReadOnlyList<RequestTypeDto>>(items); return Result.Ok<IReadOnlyList<RequestTypeDto>>(items);
} }
public async Task<Result<RequestTypeDto>> GetAsync(Guid id, CancellationToken cancellationToken) public async Task<Result<RequestTypeDto>> GetAsync(int id, CancellationToken cancellationToken)
{ {
var entity = await db.RequestTypes.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id, cancellationToken); var entity = await db.RequestTypes.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
@@ -36,7 +36,7 @@ public sealed class RequestTypeService(ApprovalRouteDbContext db)
return Result.Ok(ToDto(entity)); return Result.Ok(ToDto(entity));
} }
public async Task<Result<RequestTypeDto>> UpdateAsync(Guid id, UpdateRequestTypeRequest request, CancellationToken cancellationToken) public async Task<Result<RequestTypeDto>> UpdateAsync(int id, UpdateRequestTypeRequest request, CancellationToken cancellationToken)
{ {
var entity = await db.RequestTypes.FirstOrDefaultAsync(x => x.Id == id, cancellationToken); var entity = await db.RequestTypes.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
if (entity is null) if (entity is null)
@@ -49,7 +49,7 @@ public sealed class RequestTypeService(ApprovalRouteDbContext db)
return Result.Ok(ToDto(entity)); return Result.Ok(ToDto(entity));
} }
public async Task<Result> DeleteAsync(Guid id, CancellationToken cancellationToken) public async Task<Result> DeleteAsync(int id, CancellationToken cancellationToken)
{ {
var entity = await db.RequestTypes.FirstOrDefaultAsync(x => x.Id == id, cancellationToken); var entity = await db.RequestTypes.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
if (entity is null) if (entity is null)
@@ -3,14 +3,14 @@ using Tnsu.ApprovalRoute.Domain.Enums;
namespace Tnsu.ApprovalRoute.Application.TemplateRouteSteps; namespace Tnsu.ApprovalRoute.Application.TemplateRouteSteps;
public sealed record TemplateRouteStepDto( public sealed record TemplateRouteStepDto(
Guid Id, int Id,
int OrderNo, int OrderNo,
string ExecutorEmail, string ExecutorEmail,
string Position, string Position,
ProjectRole ProjectRole, ProjectRole ProjectRole,
HeadType HeadType, HeadType HeadType,
RouteStepStatus Status, RouteStepStatus Status,
Guid RouteId, int RouteId,
bool AllowReassignToOtherApprovers); bool AllowReassignToOtherApprovers);
public sealed record CreateTemplateRouteStepRequest( public sealed record CreateTemplateRouteStepRequest(
@@ -9,7 +9,7 @@ namespace Tnsu.ApprovalRoute.Application.TemplateRouteSteps;
public sealed class TemplateRouteStepService(ApprovalRouteDbContext db) public sealed class TemplateRouteStepService(ApprovalRouteDbContext db)
{ {
public async Task<Result<IReadOnlyList<TemplateRouteStepDto>>> ListAsync(Guid routeId, CancellationToken cancellationToken) public async Task<Result<IReadOnlyList<TemplateRouteStepDto>>> ListAsync(int routeId, CancellationToken cancellationToken)
{ {
var items = await db.TemplateRouteSteps.AsNoTracking() var items = await db.TemplateRouteSteps.AsNoTracking()
.Where(x => x.RouteId == routeId) .Where(x => x.RouteId == routeId)
@@ -21,7 +21,7 @@ public sealed class TemplateRouteStepService(ApprovalRouteDbContext db)
return Result.Ok<IReadOnlyList<TemplateRouteStepDto>>(items); return Result.Ok<IReadOnlyList<TemplateRouteStepDto>>(items);
} }
public async Task<Result<TemplateRouteStepDto>> GetAsync(Guid routeId, Guid id, CancellationToken cancellationToken) public async Task<Result<TemplateRouteStepDto>> GetAsync(int routeId, int id, CancellationToken cancellationToken)
{ {
var entity = await db.TemplateRouteSteps.AsNoTracking() var entity = await db.TemplateRouteSteps.AsNoTracking()
.FirstOrDefaultAsync(x => x.Id == id && x.RouteId == routeId, cancellationToken); .FirstOrDefaultAsync(x => x.Id == id && x.RouteId == routeId, cancellationToken);
@@ -31,7 +31,7 @@ public sealed class TemplateRouteStepService(ApprovalRouteDbContext db)
: Result.Ok(ToDto(entity)); : Result.Ok(ToDto(entity));
} }
public async Task<Result<TemplateRouteStepDto>> CreateAsync(Guid routeId, CreateTemplateRouteStepRequest r, CancellationToken cancellationToken) public async Task<Result<TemplateRouteStepDto>> CreateAsync(int routeId, CreateTemplateRouteStepRequest r, CancellationToken cancellationToken)
{ {
var route = await db.TemplateRoutes.FirstOrDefaultAsync(x => x.Id == routeId, cancellationToken); var route = await db.TemplateRoutes.FirstOrDefaultAsync(x => x.Id == routeId, cancellationToken);
if (route is null) if (route is null)
@@ -60,7 +60,7 @@ public sealed class TemplateRouteStepService(ApprovalRouteDbContext db)
} }
public async Task<Result<TemplateRouteStepDto>> UpdateAsync( public async Task<Result<TemplateRouteStepDto>> UpdateAsync(
Guid routeId, Guid id, UpdateTemplateRouteStepRequest r, CancellationToken cancellationToken) int routeId, int id, UpdateTemplateRouteStepRequest r, CancellationToken cancellationToken)
{ {
var route = await db.TemplateRoutes.FirstOrDefaultAsync(x => x.Id == routeId, cancellationToken); var route = await db.TemplateRoutes.FirstOrDefaultAsync(x => x.Id == routeId, cancellationToken);
if (route is null) if (route is null)
@@ -87,7 +87,7 @@ public sealed class TemplateRouteStepService(ApprovalRouteDbContext db)
return await AppendMissingProjectRoleWarningAsync(route, result, cancellationToken); return await AppendMissingProjectRoleWarningAsync(route, result, cancellationToken);
} }
public async Task<Result> DeleteAsync(Guid routeId, Guid id, CancellationToken cancellationToken) public async Task<Result> DeleteAsync(int routeId, int id, CancellationToken cancellationToken)
{ {
var entity = await db.TemplateRouteSteps.FirstOrDefaultAsync(x => x.Id == id && x.RouteId == routeId, cancellationToken); var entity = await db.TemplateRouteSteps.FirstOrDefaultAsync(x => x.Id == id && x.RouteId == routeId, cancellationToken);
if (entity is null) if (entity is null)
@@ -3,7 +3,7 @@ using Tnsu.ApprovalRoute.Domain.Enums;
namespace Tnsu.ApprovalRoute.Application.TemplateRoutes; namespace Tnsu.ApprovalRoute.Application.TemplateRoutes;
public sealed record ResolvedRouteStepDto( public sealed record ResolvedRouteStepDto(
Guid Id, int Id,
int OrderNo, int OrderNo,
string ExecutorEmail, string ExecutorEmail,
string Position, string Position,
@@ -13,13 +13,13 @@ public sealed record ResolvedRouteStepDto(
bool AllowReassignToOtherApprovers); bool AllowReassignToOtherApprovers);
public sealed record ResolveTemplateRouteResultDto( public sealed record ResolveTemplateRouteResultDto(
Guid RouteId, int RouteId,
RouteType RouteType, RouteType RouteType,
bool RequiresControl, bool RequiresControl,
IReadOnlyList<ResolvedRouteStepDto> Steps); IReadOnlyList<ResolvedRouteStepDto> Steps);
public sealed record ResolveTemplateRouteRequest( public sealed record ResolveTemplateRouteRequest(
Guid RequestTypeId, int RequestTypeId,
string? UserEmail, string? UserEmail,
Guid? ProjectId, Guid? ProjectId,
RouteStepStatus Status); RouteStepStatus Status);
@@ -3,9 +3,9 @@ using Tnsu.ApprovalRoute.Domain.Enums;
namespace Tnsu.ApprovalRoute.Application.TemplateRoutes; namespace Tnsu.ApprovalRoute.Application.TemplateRoutes;
public sealed record TemplateRouteDto( public sealed record TemplateRouteDto(
Guid Id, int Id,
RouteType RouteType, RouteType RouteType,
Guid RequestTypeId, int RequestTypeId,
string? Department, string? Department,
string Company, string Company,
bool ByProject, bool ByProject,
@@ -13,7 +13,7 @@ public sealed record TemplateRouteDto(
public sealed record CreateTemplateRouteRequest( public sealed record CreateTemplateRouteRequest(
RouteType RouteType, RouteType RouteType,
Guid RequestTypeId, int RequestTypeId,
string? Department, string? Department,
string Company, string Company,
bool ByProject, bool ByProject,
@@ -14,7 +14,7 @@ public sealed class TemplateRouteService(
ITnsuPortalClient portalClient, ITnsuPortalClient portalClient,
ICurrentUser currentUser) ICurrentUser currentUser)
{ {
public async Task<Result<IReadOnlyList<TemplateRouteDto>>> ListAsync(Guid? requestTypeId, CancellationToken cancellationToken) public async Task<Result<IReadOnlyList<TemplateRouteDto>>> ListAsync(int? requestTypeId, CancellationToken cancellationToken)
{ {
var query = db.TemplateRoutes.AsNoTracking().AsQueryable(); var query = db.TemplateRoutes.AsNoTracking().AsQueryable();
if (requestTypeId is { } id) if (requestTypeId is { } id)
@@ -28,7 +28,7 @@ public sealed class TemplateRouteService(
return Result.Ok<IReadOnlyList<TemplateRouteDto>>(items); return Result.Ok<IReadOnlyList<TemplateRouteDto>>(items);
} }
public async Task<Result<TemplateRouteDto>> GetAsync(Guid id, CancellationToken cancellationToken) public async Task<Result<TemplateRouteDto>> GetAsync(int id, CancellationToken cancellationToken)
{ {
var entity = await db.TemplateRoutes.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id, cancellationToken); var entity = await db.TemplateRoutes.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
@@ -64,7 +64,7 @@ public sealed class TemplateRouteService(
return Result.Ok(ToDto(entity)); return Result.Ok(ToDto(entity));
} }
public async Task<Result<TemplateRouteDto>> UpdateAsync(Guid id, UpdateTemplateRouteRequest r, CancellationToken cancellationToken) public async Task<Result<TemplateRouteDto>> UpdateAsync(int id, UpdateTemplateRouteRequest r, CancellationToken cancellationToken)
{ {
var entity = await db.TemplateRoutes.FirstOrDefaultAsync(x => x.Id == id, cancellationToken); var entity = await db.TemplateRoutes.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
if (entity is null) if (entity is null)
@@ -86,7 +86,7 @@ public sealed class TemplateRouteService(
return Result.Ok(ToDto(entity)); return Result.Ok(ToDto(entity));
} }
public async Task<Result> DeleteAsync(Guid id, CancellationToken cancellationToken) public async Task<Result> DeleteAsync(int id, CancellationToken cancellationToken)
{ {
var entity = await db.TemplateRoutes.FirstOrDefaultAsync(x => x.Id == id, cancellationToken); var entity = await db.TemplateRoutes.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
if (entity is null) if (entity is null)
@@ -113,7 +113,7 @@ public sealed class TemplateRouteService(
var employee = await portalClient.GetEmployeeByEmailAsync(email, cancellationToken); var employee = await portalClient.GetEmployeeByEmailAsync(email, cancellationToken);
if (employee is null) if (employee is null)
return Result.Fail<ResolveTemplateRouteResultDto>( return Result.Fail<ResolveTemplateRouteResultDto>(
new NotFoundError("Сотрудник по email в справочнике api.tnsu.kz не найден", Guid.Empty)); new NotFoundError("Сотрудник в справочнике api.tnsu.kz по email", email));
var byProject = request.ProjectId is not null; var byProject = request.ProjectId is not null;
var department = Normalize(employee.Department); var department = Normalize(employee.Department);
@@ -154,7 +154,7 @@ public sealed class TemplateRouteService(
} }
private Task<bool> HasDuplicateAsync( private Task<bool> HasDuplicateAsync(
Guid requestTypeId, string? department, string company, bool byProject, Guid? excludeId, CancellationToken cancellationToken) => int requestTypeId, string? department, string company, bool byProject, int? excludeId, CancellationToken cancellationToken) =>
db.TemplateRoutes.AnyAsync(x => db.TemplateRoutes.AnyAsync(x =>
x.Id != excludeId && x.Id != excludeId &&
x.RequestTypeId == requestTypeId && x.RequestTypeId == requestTypeId &&
@@ -1,11 +1,8 @@
using System;
using System.Collections.Generic;
namespace Tnsu.ApprovalRoute.Domain.Entities; namespace Tnsu.ApprovalRoute.Domain.Entities;
public class RequestType public class RequestType
{ {
public Guid Id { get; set; } = Guid.NewGuid(); public int Id { get; set; }
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
public string PageUrl { get; set; } = string.Empty; public string PageUrl { get; set; } = string.Empty;
@@ -4,9 +4,9 @@ namespace Tnsu.ApprovalRoute.Domain.Entities;
public class TemplateRoute public class TemplateRoute
{ {
public Guid Id { get; set; } = Guid.NewGuid(); public int Id { get; set; }
public RouteType RouteType { get; set; } = RouteType.Sequential; public RouteType RouteType { get; set; } = RouteType.Sequential;
public Guid RequestTypeId { get; set; } public int RequestTypeId { get; set; }
// Компания и отдел инициатора — названия из справочника AD (api-tnsu-portal /Employee/ByEmail), // Компания и отдел инициатора — названия из справочника AD (api-tnsu-portal /Employee/ByEmail),
// хранятся строками без FK в этой БД. Отдел опционален, компания обязательна. // хранятся строками без FK в этой БД. Отдел опционален, компания обязательна.
@@ -4,7 +4,7 @@ namespace Tnsu.ApprovalRoute.Domain.Entities;
public class TemplateRouteStep public class TemplateRouteStep
{ {
public Guid Id { get; set; } = Guid.NewGuid(); public int Id { get; set; }
public int OrderNo { get; set; } public int OrderNo { get; set; }
// Внешняя ссылка на пользователя (1С/ZUP) — без локальной таблицы Users. // Внешняя ссылка на пользователя (1С/ZUP) — без локальной таблицы Users.
@@ -14,7 +14,7 @@ public class TemplateRouteStep
public HeadType HeadType { get; set; } = HeadType.None; public HeadType HeadType { get; set; } = HeadType.None;
public RouteStepStatus Status { get; set; } = RouteStepStatus.Approval; public RouteStepStatus Status { get; set; } = RouteStepStatus.Approval;
public Guid RouteId { get; set; } public int RouteId { get; set; }
public bool AllowReassignToOtherApprovers { get; set; } public bool AllowReassignToOtherApprovers { get; set; }
public TemplateRoute? Route { get; set; } public TemplateRoute? Route { get; set; }
@@ -1,5 +1,4 @@
// <auto-generated /> // <auto-generated />
using System;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations;
@@ -12,7 +11,7 @@ using Tnsu.ApprovalRoute.Infrastructure.Persistence;
namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
{ {
[DbContext(typeof(ApprovalRouteDbContext))] [DbContext(typeof(ApprovalRouteDbContext))]
[Migration("20260724071302_InitialCreate")] [Migration("20260724085143_InitialCreate")]
partial class InitialCreate partial class InitialCreate
{ {
/// <inheritdoc /> /// <inheritdoc />
@@ -27,11 +26,13 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RequestType", b => modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RequestType", b =>
{ {
b.Property<Guid>("Id") b.Property<int>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("uuid") .HasColumnType("integer")
.HasColumnName("id"); .HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Name") b.Property<string>("Name")
.IsRequired() .IsRequired()
.HasMaxLength(256) .HasMaxLength(256)
@@ -52,11 +53,13 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.TemplateRoute", b => modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.TemplateRoute", b =>
{ {
b.Property<Guid>("Id") b.Property<int>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("uuid") .HasColumnType("integer")
.HasColumnName("id"); .HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<bool>("ByProject") b.Property<bool>("ByProject")
.HasColumnType("boolean") .HasColumnType("boolean")
.HasColumnName("by_project"); .HasColumnName("by_project");
@@ -72,8 +75,8 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
.HasColumnType("character varying(256)") .HasColumnType("character varying(256)")
.HasColumnName("department"); .HasColumnName("department");
b.Property<Guid>("RequestTypeId") b.Property<int>("RequestTypeId")
.HasColumnType("uuid") .HasColumnType("integer")
.HasColumnName("request_type_id"); .HasColumnName("request_type_id");
b.Property<bool>("RequiresControl") b.Property<bool>("RequiresControl")
@@ -98,11 +101,13 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.TemplateRouteStep", b => modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.TemplateRouteStep", b =>
{ {
b.Property<Guid>("Id") b.Property<int>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("uuid") .HasColumnType("integer")
.HasColumnName("id"); .HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<bool>("AllowReassignToOtherApprovers") b.Property<bool>("AllowReassignToOtherApprovers")
.HasColumnType("boolean") .HasColumnType("boolean")
.HasColumnName("allow_reassign_to_other_approvers"); .HasColumnName("allow_reassign_to_other_approvers");
@@ -135,8 +140,8 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
.HasColumnType("character varying(32)") .HasColumnType("character varying(32)")
.HasColumnName("project_role"); .HasColumnName("project_role");
b.Property<Guid>("RouteId") b.Property<int>("RouteId")
.HasColumnType("uuid") .HasColumnType("integer")
.HasColumnName("route_id"); .HasColumnName("route_id");
b.Property<string>("Status") b.Property<string>("Status")
@@ -1,5 +1,5 @@
using System; using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable #nullable disable
@@ -15,7 +15,8 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
name: "request_types", name: "request_types",
columns: table => new columns: table => new
{ {
id = table.Column<Guid>(type: "uuid", nullable: false), id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false), name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
page_url = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false) page_url = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: false)
}, },
@@ -28,9 +29,10 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
name: "template_routes", name: "template_routes",
columns: table => new columns: table => new
{ {
id = table.Column<Guid>(type: "uuid", nullable: false), id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
route_type = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false), route_type = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
request_type_id = table.Column<Guid>(type: "uuid", nullable: false), request_type_id = table.Column<int>(type: "integer", nullable: false),
department = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true), department = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
company = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false), company = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
by_project = table.Column<bool>(type: "boolean", nullable: false), by_project = table.Column<bool>(type: "boolean", nullable: false),
@@ -51,14 +53,15 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
name: "template_route_steps", name: "template_route_steps",
columns: table => new columns: table => new
{ {
id = table.Column<Guid>(type: "uuid", nullable: false), id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
order_no = table.Column<int>(type: "integer", nullable: false), order_no = table.Column<int>(type: "integer", nullable: false),
executor_email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false), executor_email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
position = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false), position = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
project_role = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false), project_role = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
head_type = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false), head_type = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
status = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false), status = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
route_id = table.Column<Guid>(type: "uuid", nullable: false), route_id = table.Column<int>(type: "integer", nullable: false),
allow_reassign_to_other_approvers = table.Column<bool>(type: "boolean", nullable: false) allow_reassign_to_other_approvers = table.Column<bool>(type: "boolean", nullable: false)
}, },
constraints: table => constraints: table =>
@@ -1,5 +1,4 @@
// <auto-generated /> // <auto-generated />
using System;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
@@ -24,11 +23,13 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RequestType", b => modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.RequestType", b =>
{ {
b.Property<Guid>("Id") b.Property<int>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("uuid") .HasColumnType("integer")
.HasColumnName("id"); .HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Name") b.Property<string>("Name")
.IsRequired() .IsRequired()
.HasMaxLength(256) .HasMaxLength(256)
@@ -49,11 +50,13 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.TemplateRoute", b => modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.TemplateRoute", b =>
{ {
b.Property<Guid>("Id") b.Property<int>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("uuid") .HasColumnType("integer")
.HasColumnName("id"); .HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<bool>("ByProject") b.Property<bool>("ByProject")
.HasColumnType("boolean") .HasColumnType("boolean")
.HasColumnName("by_project"); .HasColumnName("by_project");
@@ -69,8 +72,8 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
.HasColumnType("character varying(256)") .HasColumnType("character varying(256)")
.HasColumnName("department"); .HasColumnName("department");
b.Property<Guid>("RequestTypeId") b.Property<int>("RequestTypeId")
.HasColumnType("uuid") .HasColumnType("integer")
.HasColumnName("request_type_id"); .HasColumnName("request_type_id");
b.Property<bool>("RequiresControl") b.Property<bool>("RequiresControl")
@@ -95,11 +98,13 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.TemplateRouteStep", b => modelBuilder.Entity("Tnsu.ApprovalRoute.Domain.Entities.TemplateRouteStep", b =>
{ {
b.Property<Guid>("Id") b.Property<int>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("uuid") .HasColumnType("integer")
.HasColumnName("id"); .HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<bool>("AllowReassignToOtherApprovers") b.Property<bool>("AllowReassignToOtherApprovers")
.HasColumnType("boolean") .HasColumnType("boolean")
.HasColumnName("allow_reassign_to_other_approvers"); .HasColumnName("allow_reassign_to_other_approvers");
@@ -132,8 +137,8 @@ namespace Tnsu.ApprovalRoute.Infrastructure.Persistence.Migrations
.HasColumnType("character varying(32)") .HasColumnType("character varying(32)")
.HasColumnName("project_role"); .HasColumnName("project_role");
b.Property<Guid>("RouteId") b.Property<int>("RouteId")
.HasColumnType("uuid") .HasColumnType("integer")
.HasColumnName("route_id"); .HasColumnName("route_id");
b.Property<string>("Status") b.Property<string>("Status")
@@ -33,7 +33,7 @@ public sealed class RequestTypeServiceTests(PostgresDatabaseFixture fixture) : I
public async Task GetAsync_UnknownId_ReturnsFailedResult() public async Task GetAsync_UnknownId_ReturnsFailedResult()
{ {
// Action // Action
var result = await _service.GetAsync(Guid.NewGuid(), CancellationToken.None); var result = await _service.GetAsync(999999, CancellationToken.None);
// Assert // Assert
result.IsFailed.ShouldBeTrue(); result.IsFailed.ShouldBeTrue();
@@ -60,7 +60,7 @@ public sealed class RequestTypeServiceTests(PostgresDatabaseFixture fixture) : I
{ {
// Action // Action
var result = await _service.UpdateAsync( var result = await _service.UpdateAsync(
Guid.NewGuid(), new UpdateRequestTypeRequest("X", "/x"), CancellationToken.None); 999999, new UpdateRequestTypeRequest("X", "/x"), CancellationToken.None);
// Assert // Assert
result.IsFailed.ShouldBeTrue(); result.IsFailed.ShouldBeTrue();
@@ -34,7 +34,7 @@ public sealed class TemplateRouteServiceTests : IClassFixture<PostgresDatabaseFi
_requestTypeService = _services.GetRequiredService<RequestTypeService>(); _requestTypeService = _services.GetRequiredService<RequestTypeService>();
} }
private async Task<Guid> CreateRequestTypeAsync(string name) => private async Task<int> CreateRequestTypeAsync(string name) =>
(await _requestTypeService.CreateAsync(new CreateRequestTypeRequest(name, $"/{name}"), CancellationToken.None)).Value.Id; (await _requestTypeService.CreateAsync(new CreateRequestTypeRequest(name, $"/{name}"), CancellationToken.None)).Value.Id;
[Fact(DisplayName = "Создание маршрута и получение его по Id возвращает сохранённые данные")] [Fact(DisplayName = "Создание маршрута и получение его по Id возвращает сохранённые данные")]
@@ -62,7 +62,7 @@ public sealed class TemplateRouteServiceTests : IClassFixture<PostgresDatabaseFi
{ {
// Action // Action
var result = await _service.CreateAsync( var result = await _service.CreateAsync(
new CreateTemplateRouteRequest(RouteType.Sequential, Guid.NewGuid(), Department, Company, ByProject: false, RequiresControl: false), new CreateTemplateRouteRequest(RouteType.Sequential, 999999, Department, Company, ByProject: false, RequiresControl: false),
CancellationToken.None); CancellationToken.None);
// Assert // Assert
@@ -202,7 +202,7 @@ public sealed class TemplateRouteServiceTests : IClassFixture<PostgresDatabaseFi
{ {
// Action // Action
var resolved = await _service.ResolveAsync( var resolved = await _service.ResolveAsync(
new ResolveTemplateRouteRequest(Guid.NewGuid(), "someone@tnsu.kz", null, RouteStepStatus.Approval), new ResolveTemplateRouteRequest(999999, "someone@tnsu.kz", null, RouteStepStatus.Approval),
CancellationToken.None); CancellationToken.None);
// Assert // Assert
@@ -24,7 +24,7 @@ public sealed class TemplateRouteStepServiceTests : IClassFixture<PostgresDataba
_requestTypeService = services.GetRequiredService<RequestTypeService>(); _requestTypeService = services.GetRequiredService<RequestTypeService>();
} }
private async Task<Guid> CreateRouteAsync(string requestTypeName, bool byProject) private async Task<int> CreateRouteAsync(string requestTypeName, bool byProject)
{ {
var requestTypeId = (await _requestTypeService.CreateAsync( var requestTypeId = (await _requestTypeService.CreateAsync(
new CreateRequestTypeRequest(requestTypeName, $"/{requestTypeName}"), CancellationToken.None)).Value.Id; new CreateRequestTypeRequest(requestTypeName, $"/{requestTypeName}"), CancellationToken.None)).Value.Id;
@@ -41,7 +41,7 @@ public sealed class TemplateRouteStepServiceTests : IClassFixture<PostgresDataba
{ {
// Action // Action
var result = await _service.CreateAsync( var result = await _service.CreateAsync(
Guid.NewGuid(), 999999,
new CreateTemplateRouteStepRequest(1, "a@b.kz", "Engineer", ProjectRole.None, HeadType.None, RouteStepStatus.Approval, false), new CreateTemplateRouteStepRequest(1, "a@b.kz", "Engineer", ProjectRole.None, HeadType.None, RouteStepStatus.Approval, false),
CancellationToken.None); CancellationToken.None);