Fixes #21
@@ -1,3 +1,5 @@
|
||||
using Distribution.Models;
|
||||
|
||||
namespace Distribution.Features.Store;
|
||||
|
||||
public interface IStoreRepository
|
||||
@@ -5,6 +7,8 @@ public interface IStoreRepository
|
||||
Task<Models.Store?> GetByIdAsync(Guid id);
|
||||
Task<Models.Store?> GetByIdWithRegionAsync(Guid id);
|
||||
Task<List<Models.Store>> GetAllAsync();
|
||||
Task<List<Models.Store>> GetAllAsync(Guid? routeId, KycStatus? kycStatus, string? search, int page, int pageSize);
|
||||
Task<int> GetCountAsync(Guid? routeId, KycStatus? kycStatus, string? search);
|
||||
Task AddAsync(Models.Store entity);
|
||||
void Update(Models.Store entity);
|
||||
void Remove(Models.Store entity);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Distribution.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Distribution.Features.Store;
|
||||
|
||||
@@ -7,8 +8,13 @@ namespace Distribution.Features.Store;
|
||||
public class StoreController(StoreService service) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll() =>
|
||||
Ok(await service.GetAllAsync());
|
||||
public async Task<IActionResult> GetAll(
|
||||
[FromQuery] Guid? routeId,
|
||||
[FromQuery] KycStatus? kycStatus,
|
||||
[FromQuery] string? search,
|
||||
[FromQuery] int page = 1,
|
||||
[FromQuery] int pageSize = 20) =>
|
||||
Ok(await service.GetAllAsync(routeId, kycStatus, search, page, pageSize));
|
||||
|
||||
[HttpGet("{id:guid}")]
|
||||
public async Task<IActionResult> GetById(Guid id)
|
||||
@@ -100,4 +106,11 @@ public class StoreController(StoreService service) : ControllerBase
|
||||
var result = await service.VerifyKycAsync(id, new VerifyKycRequest(request.KycStatus, null), ct);
|
||||
return result is null ? NotFound() : Ok(result);
|
||||
}
|
||||
|
||||
[HttpPatch("{id:guid}/status")]
|
||||
public async Task<IActionResult> PatchStatus(Guid id, PatchStoreStatusRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await service.SetActiveStatusAsync(id, request.IsActive, ct);
|
||||
return result is null ? NotFound() : Ok(result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@ public record UpdateStoreRequest(
|
||||
decimal Latitude,
|
||||
decimal Longitude,
|
||||
decimal OneTimeAmount,
|
||||
decimal CreditAmount);
|
||||
decimal CreditAmount,
|
||||
bool IsActive = true);
|
||||
|
||||
public record StoreResponse(
|
||||
Guid Id,
|
||||
@@ -55,4 +56,6 @@ public record SchemeEligibilityResponse(bool Eligible, string? Reason);
|
||||
|
||||
public record PatchKycStatusRequest(KycStatus KycStatus);
|
||||
|
||||
public record PatchStoreStatusRequest(bool IsActive);
|
||||
|
||||
public record StoreDashboardResponse(Guid StoreId, string Period, int OrderCount, decimal TotalOrderValue, DateTime? LastOrderDate);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Distribution.Data;
|
||||
using Distribution.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Distribution.Features.Store;
|
||||
@@ -16,6 +17,25 @@ public class StoreRepository(AppDBContext context) : IStoreRepository
|
||||
public async Task<List<Models.Store>> GetAllAsync() =>
|
||||
await context.Stores.ToListAsync();
|
||||
|
||||
private static IQueryable<Models.Store> ApplyFilters(
|
||||
IQueryable<Models.Store> query, Guid? routeId, KycStatus? kycStatus, string? search) =>
|
||||
query
|
||||
.Where(s => routeId == null || s.FK_RouteId == routeId)
|
||||
.Where(s => kycStatus == null || s.KycStatus == kycStatus)
|
||||
.Where(s => string.IsNullOrWhiteSpace(search)
|
||||
|| s.StoreName.Contains(search)
|
||||
|| s.OwnerName.Contains(search));
|
||||
|
||||
public async Task<List<Models.Store>> GetAllAsync(Guid? routeId, KycStatus? kycStatus, string? search, int page, int pageSize) =>
|
||||
await ApplyFilters(context.Stores, routeId, kycStatus, search)
|
||||
.OrderBy(s => s.StoreName)
|
||||
.Skip((page - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToListAsync();
|
||||
|
||||
public async Task<int> GetCountAsync(Guid? routeId, KycStatus? kycStatus, string? search) =>
|
||||
await ApplyFilters(context.Stores, routeId, kycStatus, search).CountAsync();
|
||||
|
||||
public async Task AddAsync(Models.Store entity) =>
|
||||
await context.Stores.AddAsync(entity);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Distribution.Features.Scheme;
|
||||
using Distribution.Features.Stock;
|
||||
using Distribution.Infra.Authorization;
|
||||
using Distribution.Infra.UoW;
|
||||
using Distribution.Models;
|
||||
@@ -23,21 +24,20 @@ public class StoreService(IStoreRepository repo, IUnitOfWork uow, ICurrentUserSe
|
||||
new(s.Id, s.FK_RouteId, s.OwnerName, s.StoreName, s.StoreAddress, s.Latitude, s.Longitude, s.OneTimeAmount, s.CreditAmount,
|
||||
s.CreditLimit, s.OutstandingBalance, s.Segment, s.KycStatus, s.IsActive, s.CreatedAt);
|
||||
|
||||
public async Task<List<StoreResponse>> GetAllAsync()
|
||||
public async Task<PagedResponse<StoreResponse>> GetAllAsync(
|
||||
Guid? routeId, KycStatus? kycStatus, string? search, int page, int pageSize)
|
||||
{
|
||||
var stores = (await repo.GetAllAsync()).Where(s => s.IsActive).ToList();
|
||||
if (!HasGlobalScope && currentUser.UserId is not null)
|
||||
{
|
||||
var accessibleStoreIds = (await scopeAccess.GetAccessibleStoreIdsAsync(currentUser.UserId.Value)).ToHashSet();
|
||||
stores = stores.Where(s => accessibleStoreIds.Contains(s.Id)).ToList();
|
||||
}
|
||||
return stores.Select(ToResponse).ToList();
|
||||
// Deactivated stores stay visible in the list showing Inactive — deactivate never
|
||||
// removes the row, only marks it (same rule as Orders, see testbug.md #42).
|
||||
var total = await repo.GetCountAsync(routeId, kycStatus, search);
|
||||
var stores = await repo.GetAllAsync(routeId, kycStatus, search, page, pageSize);
|
||||
return new PagedResponse<StoreResponse>(page, pageSize, total, stores.Select(ToResponse).ToList());
|
||||
}
|
||||
|
||||
public async Task<StoreResponse?> GetByIdAsync(Guid id)
|
||||
{
|
||||
var store = await repo.GetByIdAsync(id);
|
||||
if (store is null || !store.IsActive) return null;
|
||||
if (store is null) return null;
|
||||
//if (!await HasStoreScopeAsync(id)) return null;
|
||||
return ToResponse(store);
|
||||
}
|
||||
@@ -72,7 +72,7 @@ public class StoreService(IStoreRepository repo, IUnitOfWork uow, ICurrentUserSe
|
||||
public async Task<StoreResponse?> UpdateAsync(Guid id, UpdateStoreRequest request, CancellationToken ct = default)
|
||||
{
|
||||
var store = await repo.GetByIdAsync(id);
|
||||
if (store is null || !store.IsActive) return null;
|
||||
if (store is null) return null;
|
||||
if (!await HasStoreScopeAsync(id)) return null;
|
||||
store.FK_RouteId = request.RouteId;
|
||||
store.OwnerName = request.OwnerName;
|
||||
@@ -82,6 +82,7 @@ public class StoreService(IStoreRepository repo, IUnitOfWork uow, ICurrentUserSe
|
||||
store.Longitude = request.Longitude;
|
||||
store.OneTimeAmount = request.OneTimeAmount;
|
||||
store.CreditAmount = request.CreditAmount;
|
||||
store.IsActive = request.IsActive;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
@@ -205,10 +206,32 @@ public class StoreService(IStoreRepository repo, IUnitOfWork uow, ICurrentUserSe
|
||||
return ToResponse(store);
|
||||
}
|
||||
|
||||
public async Task<StoreResponse?> SetActiveStatusAsync(Guid id, bool isActive, CancellationToken ct = default)
|
||||
{
|
||||
var store = await repo.GetByIdAsync(id);
|
||||
if (store is null) return null;
|
||||
if (!await HasStoreScopeAsync(id)) return null;
|
||||
|
||||
store.IsActive = isActive;
|
||||
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
repo.Update(store);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return ToResponse(store);
|
||||
}
|
||||
|
||||
public async Task<List<StoreVisitHistoryItem>?> GetVisitHistoryAsync(Guid id)
|
||||
{
|
||||
var store = await repo.GetByIdAsync(id);
|
||||
if (store is null || !store.IsActive) return null;
|
||||
if (store is null) return null;
|
||||
if (!await HasStoreScopeAsync(id)) return null;
|
||||
|
||||
var visits = await routeRepo.GetVisitsByStoreIdAsync(id);
|
||||
|
||||
Reference in New Issue
Block a user