feat: 完成营销中心优惠券后端模块
All checks were successful
Build and Deploy TenantApi + SkuWorker / build-and-deploy (push) Successful in 1m54s
All checks were successful
Build and Deploy TenantApi + SkuWorker / build-and-deploy (push) Successful in 1m54s
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using TakeoutSaaS.Application.App.Stores.Services;
|
||||
using TakeoutSaaS.Domain.Coupons.Repositories;
|
||||
using TakeoutSaaS.Domain.Deliveries.Repositories;
|
||||
using TakeoutSaaS.Domain.Inventory.Repositories;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
@@ -44,6 +45,7 @@ public static class AppServiceCollectionExtensions
|
||||
services.AddScoped<IMerchantCategoryRepository, EfMerchantCategoryRepository>();
|
||||
services.AddScoped<IStoreRepository, EfStoreRepository>();
|
||||
services.AddScoped<IProductRepository, EfProductRepository>();
|
||||
services.AddScoped<ICouponRepository, EfCouponRepository>();
|
||||
services.AddScoped<IOrderRepository, EfOrderRepository>();
|
||||
services.AddScoped<IPaymentRepository, EfPaymentRepository>();
|
||||
services.AddScoped<IDeliveryRepository, EfDeliveryRepository>();
|
||||
|
||||
@@ -1590,6 +1590,7 @@ public sealed class TakeoutAppDbContext(
|
||||
builder.Property(x => x.CouponType).HasConversion<int>();
|
||||
builder.Property(x => x.Description).HasMaxLength(512);
|
||||
builder.Property(x => x.TotalQuantity);
|
||||
builder.Property(x => x.PerUserLimit);
|
||||
builder.Property(x => x.StoreScopeJson).HasColumnType("text");
|
||||
builder.Property(x => x.ProductScopeJson).HasColumnType("text");
|
||||
builder.Property(x => x.ChannelsJson).HasColumnType("text");
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TakeoutSaaS.Domain.Coupons.Entities;
|
||||
using TakeoutSaaS.Domain.Coupons.Enums;
|
||||
using TakeoutSaaS.Domain.Coupons.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.App.Persistence;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// 优惠券聚合的 EF Core 仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfCouponRepository(TakeoutAppDbContext context) : ICouponRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<CouponTemplate>> GetTemplatesAsync(long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.CouponTemplates
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId)
|
||||
.OrderByDescending(x => x.UpdatedAt ?? x.CreatedAt)
|
||||
.ThenByDescending(x => x.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<CouponTemplate?> FindTemplateByIdAsync(long templateId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.CouponTemplates
|
||||
.Where(x => x.TenantId == tenantId && x.Id == templateId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddTemplateAsync(CouponTemplate template, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.CouponTemplates.AddAsync(template, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task UpdateTemplateAsync(CouponTemplate template, CancellationToken cancellationToken = default)
|
||||
{
|
||||
context.CouponTemplates.Update(template);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task DeleteTemplateAsync(CouponTemplate template, CancellationToken cancellationToken = default)
|
||||
{
|
||||
context.CouponTemplates.Remove(template);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<int> CountIssuedCouponsByTemplateIdAsync(long tenantId, long templateId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.Coupons
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.CouponTemplateId == templateId)
|
||||
.CountAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Dictionary<long, int>> CountRedeemedCouponsByTemplateIdsAsync(
|
||||
long tenantId,
|
||||
IReadOnlyCollection<long> templateIds,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (templateIds.Count == 0)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
return await context.Coupons
|
||||
.AsNoTracking()
|
||||
.Where(x =>
|
||||
x.TenantId == tenantId &&
|
||||
templateIds.Contains(x.CouponTemplateId) &&
|
||||
x.Status == CouponStatus.Redeemed)
|
||||
.GroupBy(x => x.CouponTemplateId)
|
||||
.Select(group => new { CouponTemplateId = group.Key, Count = group.Count() })
|
||||
.ToDictionaryAsync(item => item.CouponTemplateId, item => item.Count, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddCouponTemplatePerUserLimit : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "PerUserLimit",
|
||||
table: "coupon_templates",
|
||||
type: "integer",
|
||||
nullable: true,
|
||||
comment: "每位用户可领取上限。");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "PerUserLimit",
|
||||
table: "coupon_templates");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -548,6 +548,10 @@ namespace TakeoutSaaS.Infrastructure.Migrations
|
||||
.HasColumnType("character varying(128)")
|
||||
.HasComment("模板名称。");
|
||||
|
||||
b.Property<int?>("PerUserLimit")
|
||||
.HasColumnType("integer")
|
||||
.HasComment("每位用户可领取上限。");
|
||||
|
||||
b.Property<string>("ProductScopeJson")
|
||||
.HasColumnType("text")
|
||||
.HasComment("适用品类或商品范围(JSON)。");
|
||||
|
||||
Reference in New Issue
Block a user