Main расходился с БД стейджа (Phase2c3_MsStrict в history, но код ещё ссылался на VatRate etc.) — деплой ломался. Реплицирую удаление сущностей вручную, чтобы код совпадал с таблицами. Убрано (нет в OtherSystem — не выдумываем): - Domain: VatRate сущность целиком; Counterparty.Kind + enum CounterpartyKind; Store.Kind + enum StoreKind; Product.IsAlcohol; UnitOfMeasure.Symbol/DecimalPlaces/IsBase. - EF: DbSet<VatRate>, ConfigureVatRate, Product.VatRate navigation, индекс Counterparty.Kind. - DTO/Input: соответствующие поля и VatRateDto/Input. - API: VatRatesController удалён; references в Products/Counterparties/Stores/UoM/Supplies/Retail/Stock. Добавлено как в OtherSystem: - Product.Vat (int) + Product.VatEnabled — OtherSystem держит НДС числом на товаре. - KZ default VAT 16% — applied в сидерах и в OtherSystemImportService когда товар не принёс свой vat. OtherSystemImportService: - ResolveKind убран; CompanyType=entrepreneur→Individual (как и было). - VatRates lookup → прямой p.Vat ?? 16 + p.Vat > 0 для VatEnabled. - baseUnit ищется по code="796" вместо IsBase. Web: - types.ts: убраны CounterpartyKind/StoreKind/VatRate/Product.vatRateId/vatPercent/isAlcohol/UoM.symbol/decimalPlaces/isBase; добавлено Product.vat/vatEnabled; унифицировано unitSymbol→unitName. - VatRatesPage удалён, роут из App.tsx тоже. - CounterpartiesPage/StoresPage/UnitsOfMeasurePage: убраны соответствующие поля в формах. - ProductEditPage: select "Ставка НДС" теперь с фиксированными 0/10/12/16/20 + чекбокс VatEnabled. - Stock/RetailSale/Supply pages: unitSymbol → unitName. deploy-stage unguarded — теперь код соответствует DB, авто-deploy безопасен.
85 lines
3.1 KiB
C#
85 lines
3.1 KiB
C#
using foodmarket.Application.Catalog;
|
|
using foodmarket.Application.Common;
|
|
using foodmarket.Domain.Catalog;
|
|
using foodmarket.Infrastructure.Persistence;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace foodmarket.Api.Controllers.Catalog;
|
|
|
|
[ApiController]
|
|
[Authorize]
|
|
[Route("api/catalog/units-of-measure")]
|
|
public class UnitsOfMeasureController : ControllerBase
|
|
{
|
|
private readonly AppDbContext _db;
|
|
|
|
public UnitsOfMeasureController(AppDbContext db) => _db = db;
|
|
|
|
[HttpGet]
|
|
public async Task<ActionResult<PagedResult<UnitOfMeasureDto>>> List([FromQuery] PagedRequest req, CancellationToken ct)
|
|
{
|
|
var q = _db.UnitsOfMeasure.AsNoTracking().AsQueryable();
|
|
if (!string.IsNullOrWhiteSpace(req.Search))
|
|
{
|
|
var s = req.Search.Trim().ToLower();
|
|
q = q.Where(u => u.Name.ToLower().Contains(s) || u.Code.ToLower().Contains(s));
|
|
}
|
|
var total = await q.CountAsync(ct);
|
|
var items = await q
|
|
.OrderBy(u => u.Name)
|
|
.Skip(req.Skip).Take(req.Take)
|
|
.Select(u => new UnitOfMeasureDto(u.Id, u.Code, u.Name, u.Description, u.IsActive))
|
|
.ToListAsync(ct);
|
|
return new PagedResult<UnitOfMeasureDto> { Items = items, Total = total, Page = req.Page, PageSize = req.Take };
|
|
}
|
|
|
|
[HttpGet("{id:guid}")]
|
|
public async Task<ActionResult<UnitOfMeasureDto>> Get(Guid id, CancellationToken ct)
|
|
{
|
|
var u = await _db.UnitsOfMeasure.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id, ct);
|
|
return u is null ? NotFound() : new UnitOfMeasureDto(u.Id, u.Code, u.Name, u.Description, u.IsActive);
|
|
}
|
|
|
|
[HttpPost, Authorize(Roles = "Admin,Manager")]
|
|
public async Task<ActionResult<UnitOfMeasureDto>> Create([FromBody] UnitOfMeasureInput input, CancellationToken ct)
|
|
{
|
|
var e = new UnitOfMeasure
|
|
{
|
|
Code = input.Code,
|
|
Name = input.Name,
|
|
Description = input.Description,
|
|
IsActive = input.IsActive,
|
|
};
|
|
_db.UnitsOfMeasure.Add(e);
|
|
await _db.SaveChangesAsync(ct);
|
|
return CreatedAtAction(nameof(Get), new { id = e.Id },
|
|
new UnitOfMeasureDto(e.Id, e.Code, e.Name, e.Description, e.IsActive));
|
|
}
|
|
|
|
[HttpPut("{id:guid}"), Authorize(Roles = "Admin,Manager")]
|
|
public async Task<IActionResult> Update(Guid id, [FromBody] UnitOfMeasureInput input, CancellationToken ct)
|
|
{
|
|
var e = await _db.UnitsOfMeasure.FirstOrDefaultAsync(x => x.Id == id, ct);
|
|
if (e is null) return NotFound();
|
|
|
|
e.Code = input.Code;
|
|
e.Name = input.Name;
|
|
e.Description = input.Description;
|
|
e.IsActive = input.IsActive;
|
|
await _db.SaveChangesAsync(ct);
|
|
return NoContent();
|
|
}
|
|
|
|
[HttpDelete("{id:guid}"), Authorize(Roles = "Admin")]
|
|
public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
|
|
{
|
|
var e = await _db.UnitsOfMeasure.FirstOrDefaultAsync(x => x.Id == id, ct);
|
|
if (e is null) return NotFound();
|
|
_db.UnitsOfMeasure.Remove(e);
|
|
await _db.SaveChangesAsync(ct);
|
|
return NoContent();
|
|
}
|
|
}
|