refactor(commerce): split administration services
This commit is contained in:
195
Tiku.Infrastructure/Points/PointAdministrationService.cs
Normal file
195
Tiku.Infrastructure/Points/PointAdministrationService.cs
Normal file
@@ -0,0 +1,195 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Tiku.Application.Commerce;
|
||||
using Tiku.Application.Points;
|
||||
using Tiku.Domain.Commerce;
|
||||
using Tiku.Infrastructure.Commerce;
|
||||
|
||||
namespace Tiku.Infrastructure.Points;
|
||||
|
||||
internal sealed class PointAdministrationService(CommerceAdministrationDependencies dependencies)
|
||||
: CommerceAdministrationServiceBase(dependencies), IPointAdministrationService
|
||||
{
|
||||
public async Task<TenantPointTaskList> GetPointTasksAsync(
|
||||
CommerceAdminActor actor,
|
||||
TenantPointQuery query,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await AssertAdminAsync(actor, cancellationToken);
|
||||
var tasks = dbContext.PointActivityTasks.AsNoTracking()
|
||||
.Where(item => item.TenantId == actor.TenantId);
|
||||
if (!string.IsNullOrWhiteSpace(query.Status))
|
||||
tasks = tasks.Where(item => item.Status == ParsePointTaskStatus(query.Status));
|
||||
|
||||
var items = await tasks
|
||||
.OrderBy(item => item.SortOrder)
|
||||
.ThenByDescending(item => item.CreatedAt)
|
||||
.Take(Math.Clamp(query.Limit ?? 50, 1, 200))
|
||||
.ToArrayAsync(cancellationToken);
|
||||
return new TenantPointTaskList(items);
|
||||
}
|
||||
|
||||
public async Task<PointActivityTask> UpsertPointTaskAsync(
|
||||
CommerceAdminActor actor,
|
||||
UpsertPointTaskCommand command,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await AssertAdminAsync(actor, cancellationToken);
|
||||
if (command.Points <= 0 || command.MaxClaimsPerUser <= 0)
|
||||
throw new CommerceException("Point task points and claim limit must be positive.", "invalid_point_task");
|
||||
|
||||
var task = command.Id.HasValue
|
||||
? await dbContext.PointActivityTasks.SingleOrDefaultAsync(
|
||||
item => item.TenantId == actor.TenantId && item.Id == command.Id.Value,
|
||||
cancellationToken)
|
||||
: await dbContext.PointActivityTasks.SingleOrDefaultAsync(
|
||||
item => item.TenantId == actor.TenantId && item.TaskKey == command.TaskKey.Trim(),
|
||||
cancellationToken);
|
||||
if (task is null)
|
||||
{
|
||||
task = new PointActivityTask { TenantId = actor.TenantId };
|
||||
dbContext.PointActivityTasks.Add(task);
|
||||
}
|
||||
|
||||
task.TaskKey = command.TaskKey.Trim();
|
||||
task.Title = command.Title.Trim();
|
||||
task.Description = command.Description?.Trim();
|
||||
task.TaskType = command.TaskType;
|
||||
task.Status = command.Status;
|
||||
task.Points = command.Points;
|
||||
task.MaxClaimsPerUser = command.MaxClaimsPerUser;
|
||||
task.StartsAt = command.StartsAt;
|
||||
task.EndsAt = command.EndsAt;
|
||||
task.SortOrder = command.SortOrder;
|
||||
task.Rules = JsonObjectOrDefault(command.Rules);
|
||||
task.Metadata = JsonObjectOrDefault(command.Metadata);
|
||||
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
return task;
|
||||
}
|
||||
|
||||
public async Task<TenantPointClaimList> GetPointClaimsAsync(
|
||||
CommerceAdminActor actor,
|
||||
TenantPointQuery query,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await AssertAdminAsync(actor, cancellationToken);
|
||||
var claims = dbContext.PointActivityClaims.AsNoTracking()
|
||||
.Where(item => item.TenantId == actor.TenantId);
|
||||
if (query.UserId.HasValue) claims = claims.Where(item => item.UserId == query.UserId.Value);
|
||||
|
||||
var items = await claims
|
||||
.OrderByDescending(item => item.CreatedAt)
|
||||
.Take(Math.Clamp(query.Limit ?? 50, 1, 200))
|
||||
.ToArrayAsync(cancellationToken);
|
||||
return new TenantPointClaimList(items);
|
||||
}
|
||||
|
||||
public async Task<TenantPointExchangeItemList> GetPointExchangeItemsAsync(
|
||||
CommerceAdminActor actor,
|
||||
TenantPointQuery query,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await AssertAdminAsync(actor, cancellationToken);
|
||||
var items = dbContext.PointExchangeItems.AsNoTracking()
|
||||
.Where(item => item.TenantId == actor.TenantId);
|
||||
if (!string.IsNullOrWhiteSpace(query.Status))
|
||||
items = items.Where(item => item.Status == ParsePointExchangeItemStatus(query.Status));
|
||||
|
||||
if (query.RegionId.HasValue)
|
||||
items = items.Where(item => item.RegionId == null || item.RegionId == query.RegionId.Value);
|
||||
|
||||
var result = await items
|
||||
.OrderBy(item => item.SortOrder)
|
||||
.ThenByDescending(item => item.CreatedAt)
|
||||
.Take(Math.Clamp(query.Limit ?? 50, 1, 200))
|
||||
.ToArrayAsync(cancellationToken);
|
||||
return new TenantPointExchangeItemList(result);
|
||||
}
|
||||
|
||||
public async Task<PointExchangeItem> UpsertPointExchangeItemAsync(
|
||||
CommerceAdminActor actor,
|
||||
UpsertPointExchangeItemCommand command,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await AssertAdminAsync(actor, cancellationToken);
|
||||
if (command.PointsCost <= 0)
|
||||
throw new CommerceException("Point exchange item cost must be positive.", "invalid_point_exchange_item");
|
||||
|
||||
var item = command.Id.HasValue
|
||||
? await dbContext.PointExchangeItems.SingleOrDefaultAsync(
|
||||
entry => entry.TenantId == actor.TenantId && entry.Id == command.Id.Value,
|
||||
cancellationToken)
|
||||
: await dbContext.PointExchangeItems.SingleOrDefaultAsync(
|
||||
entry => entry.TenantId == actor.TenantId && entry.ItemKey == command.ItemKey.Trim(),
|
||||
cancellationToken);
|
||||
if (item is null)
|
||||
{
|
||||
item = new PointExchangeItem { TenantId = actor.TenantId };
|
||||
dbContext.PointExchangeItems.Add(item);
|
||||
}
|
||||
|
||||
item.RegionId = command.RegionId;
|
||||
item.ItemKey = command.ItemKey.Trim();
|
||||
item.Name = command.Name.Trim();
|
||||
item.Description = command.Description?.Trim();
|
||||
item.ItemType = command.ItemType;
|
||||
item.Status = command.Status;
|
||||
item.PointsCost = command.PointsCost;
|
||||
item.Stock = command.Stock;
|
||||
item.Days = command.Days;
|
||||
item.SortOrder = command.SortOrder;
|
||||
item.StartsAt = command.StartsAt;
|
||||
item.EndsAt = command.EndsAt;
|
||||
item.FulfillmentPayload = JsonObjectOrDefault(command.FulfillmentPayload);
|
||||
item.Metadata = JsonObjectOrDefault(command.Metadata);
|
||||
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
return item;
|
||||
}
|
||||
|
||||
public async Task<TenantPointExchangeOrderList> GetPointExchangeOrdersAsync(
|
||||
CommerceAdminActor actor,
|
||||
TenantPointQuery query,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await AssertAdminAsync(actor, cancellationToken);
|
||||
var orders = dbContext.PointExchangeOrders.AsNoTracking()
|
||||
.Where(item => item.TenantId == actor.TenantId);
|
||||
if (query.UserId.HasValue) orders = orders.Where(item => item.UserId == query.UserId.Value);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(query.Status))
|
||||
orders = orders.Where(item => item.Status == ParsePointExchangeOrderStatus(query.Status));
|
||||
|
||||
var result = await orders
|
||||
.OrderByDescending(item => item.CreatedAt)
|
||||
.Take(Math.Clamp(query.Limit ?? 50, 1, 200))
|
||||
.ToArrayAsync(cancellationToken);
|
||||
return new TenantPointExchangeOrderList(result);
|
||||
}
|
||||
|
||||
public async Task<PointExchangeOrder> UpdatePointExchangeOrderStatusAsync(
|
||||
CommerceAdminActor actor,
|
||||
UpdatePointExchangeOrderStatusCommand command,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await AssertAdminAsync(actor, cancellationToken);
|
||||
var order = await dbContext.PointExchangeOrders
|
||||
.SingleOrDefaultAsync(item => item.TenantId == actor.TenantId && item.Id == command.OrderId,
|
||||
cancellationToken)
|
||||
?? throw new CommerceException("Point exchange order was not found.",
|
||||
"point_exchange_order_not_found");
|
||||
order.Status = command.Status;
|
||||
if (command.Status == PointExchangeOrderStatus.Completed)
|
||||
{
|
||||
order.CompletedAt ??= DateTimeOffset.UtcNow;
|
||||
order.CancelledAt = null;
|
||||
}
|
||||
else if (command.Status == PointExchangeOrderStatus.Cancelled)
|
||||
{
|
||||
order.CancelledAt ??= DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
return order;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user