feat(member): implement member center management module
Some checks failed
Build and Deploy TenantApi + SkuWorker / build-and-deploy (push) Failing after 1m54s
Some checks failed
Build and Deploy TenantApi + SkuWorker / build-and-deploy (push) Failing after 1m54s
This commit is contained in:
@@ -4,6 +4,7 @@ using TakeoutSaaS.Application.App.Stores.Services;
|
||||
using TakeoutSaaS.Domain.Coupons.Repositories;
|
||||
using TakeoutSaaS.Domain.Deliveries.Repositories;
|
||||
using TakeoutSaaS.Domain.Inventory.Repositories;
|
||||
using TakeoutSaaS.Domain.Membership.Repositories;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Domain.Merchants.Services;
|
||||
using TakeoutSaaS.Domain.Orders.Repositories;
|
||||
@@ -49,6 +50,7 @@ public static class AppServiceCollectionExtensions
|
||||
services.AddScoped<INewCustomerGiftRepository, EfNewCustomerGiftRepository>();
|
||||
services.AddScoped<IPromotionCampaignRepository, EfPromotionCampaignRepository>();
|
||||
services.AddScoped<IPunchCardRepository, EfPunchCardRepository>();
|
||||
services.AddScoped<IMemberRepository, EfMemberRepository>();
|
||||
services.AddScoped<IOrderRepository, EfOrderRepository>();
|
||||
services.AddScoped<IPaymentRepository, EfPaymentRepository>();
|
||||
services.AddScoped<IDeliveryRepository, EfDeliveryRepository>();
|
||||
|
||||
@@ -390,6 +390,14 @@ public sealed class TakeoutAppDbContext(
|
||||
/// </summary>
|
||||
public DbSet<MemberTier> MemberTiers => Set<MemberTier>();
|
||||
/// <summary>
|
||||
/// 会员标签。
|
||||
/// </summary>
|
||||
public DbSet<MemberProfileTag> MemberProfileTags => Set<MemberProfileTag>();
|
||||
/// <summary>
|
||||
/// 会员日设置。
|
||||
/// </summary>
|
||||
public DbSet<MemberDaySetting> MemberDaySettings => Set<MemberDaySetting>();
|
||||
/// <summary>
|
||||
/// 积分流水。
|
||||
/// </summary>
|
||||
public DbSet<MemberPointLedger> MemberPointLedgers => Set<MemberPointLedger>();
|
||||
@@ -557,6 +565,8 @@ public sealed class TakeoutAppDbContext(
|
||||
ConfigurePunchCardUsageRecord(modelBuilder.Entity<PunchCardUsageRecord>());
|
||||
ConfigureMemberProfile(modelBuilder.Entity<MemberProfile>());
|
||||
ConfigureMemberTier(modelBuilder.Entity<MemberTier>());
|
||||
ConfigureMemberProfileTag(modelBuilder.Entity<MemberProfileTag>());
|
||||
ConfigureMemberDaySetting(modelBuilder.Entity<MemberDaySetting>());
|
||||
ConfigureMemberPointLedger(modelBuilder.Entity<MemberPointLedger>());
|
||||
ConfigureChatSession(modelBuilder.Entity<ChatSession>());
|
||||
ConfigureChatMessage(modelBuilder.Entity<ChatMessage>());
|
||||
@@ -1785,8 +1795,12 @@ public sealed class TakeoutAppDbContext(
|
||||
builder.Property(x => x.Mobile).HasMaxLength(32).IsRequired();
|
||||
builder.Property(x => x.Nickname).HasMaxLength(64);
|
||||
builder.Property(x => x.AvatarUrl).HasMaxLength(256);
|
||||
builder.Property(x => x.StoredBalance).HasPrecision(18, 2);
|
||||
builder.Property(x => x.StoredRechargeBalance).HasPrecision(18, 2);
|
||||
builder.Property(x => x.StoredGiftBalance).HasPrecision(18, 2);
|
||||
builder.Property(x => x.Status).HasConversion<int>();
|
||||
builder.HasIndex(x => new { x.TenantId, x.Mobile }).IsUnique();
|
||||
builder.HasIndex(x => new { x.TenantId, x.MemberTierId });
|
||||
}
|
||||
|
||||
private static void ConfigureMemberTier(EntityTypeBuilder<MemberTier> builder)
|
||||
@@ -1794,8 +1808,33 @@ public sealed class TakeoutAppDbContext(
|
||||
builder.ToTable("member_tiers");
|
||||
builder.HasKey(x => x.Id);
|
||||
builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
|
||||
builder.Property(x => x.IconKey).HasMaxLength(32).IsRequired();
|
||||
builder.Property(x => x.ColorHex).HasMaxLength(16).IsRequired();
|
||||
builder.Property(x => x.UpgradeRuleType).HasMaxLength(16).IsRequired();
|
||||
builder.Property(x => x.UpgradeAmountThreshold).HasPrecision(18, 2);
|
||||
builder.Property(x => x.BenefitsJson).HasColumnType("text");
|
||||
builder.HasIndex(x => new { x.TenantId, x.Name }).IsUnique();
|
||||
builder.HasIndex(x => new { x.TenantId, x.SortOrder });
|
||||
}
|
||||
|
||||
private static void ConfigureMemberProfileTag(EntityTypeBuilder<MemberProfileTag> builder)
|
||||
{
|
||||
builder.ToTable("member_profile_tags");
|
||||
builder.HasKey(x => x.Id);
|
||||
builder.Property(x => x.MemberProfileId).IsRequired();
|
||||
builder.Property(x => x.TagName).HasMaxLength(32).IsRequired();
|
||||
builder.HasIndex(x => new { x.TenantId, x.MemberProfileId, x.TagName }).IsUnique();
|
||||
builder.HasIndex(x => new { x.TenantId, x.MemberProfileId });
|
||||
}
|
||||
|
||||
private static void ConfigureMemberDaySetting(EntityTypeBuilder<MemberDaySetting> builder)
|
||||
{
|
||||
builder.ToTable("member_day_settings");
|
||||
builder.HasKey(x => x.Id);
|
||||
builder.Property(x => x.IsEnabled).IsRequired();
|
||||
builder.Property(x => x.Weekday).IsRequired();
|
||||
builder.Property(x => x.ExtraDiscountRate).HasPrecision(5, 2);
|
||||
builder.HasIndex(x => x.TenantId).IsUnique();
|
||||
}
|
||||
|
||||
private static void ConfigureMemberPointLedger(EntityTypeBuilder<MemberPointLedger> builder)
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TakeoutSaaS.Domain.Membership.Entities;
|
||||
using TakeoutSaaS.Domain.Membership.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.App.Persistence;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// 会员聚合 EF Core 仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfMemberRepository(TakeoutAppDbContext context) : IMemberRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<MemberProfile>> GetProfilesAsync(long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.MemberProfiles
|
||||
.Where(x => x.TenantId == tenantId)
|
||||
.OrderByDescending(x => x.UpdatedAt ?? x.CreatedAt)
|
||||
.ThenByDescending(x => x.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<MemberProfile>> GetProfilesByMobilesAsync(
|
||||
long tenantId,
|
||||
IReadOnlyCollection<string> mobiles,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (mobiles.Count == 0)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
return await context.MemberProfiles
|
||||
.Where(x => x.TenantId == tenantId && mobiles.Contains(x.Mobile))
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<MemberProfile?> FindProfileByIdAsync(long tenantId, long memberId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.MemberProfiles
|
||||
.Where(x => x.TenantId == tenantId && x.Id == memberId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task AddProfilesAsync(IEnumerable<MemberProfile> profiles, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var profileList = profiles?.ToList() ?? [];
|
||||
if (profileList.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await context.MemberProfiles.AddRangeAsync(profileList, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task UpdateProfileAsync(MemberProfile profile, CancellationToken cancellationToken = default)
|
||||
{
|
||||
context.MemberProfiles.Update(profile);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<MemberTier>> GetTiersAsync(long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.MemberTiers
|
||||
.Where(x => x.TenantId == tenantId)
|
||||
.OrderBy(x => x.SortOrder)
|
||||
.ThenBy(x => x.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<MemberTier?> FindTierByIdAsync(long tenantId, long tierId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.MemberTiers
|
||||
.Where(x => x.TenantId == tenantId && x.Id == tierId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddTierAsync(MemberTier tier, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.MemberTiers.AddAsync(tier, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task UpdateTierAsync(MemberTier tier, CancellationToken cancellationToken = default)
|
||||
{
|
||||
context.MemberTiers.Update(tier);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task DeleteTierAsync(MemberTier tier, CancellationToken cancellationToken = default)
|
||||
{
|
||||
context.MemberTiers.Remove(tier);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<MemberDaySetting?> GetMemberDaySettingAsync(long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.MemberDaySettings
|
||||
.Where(x => x.TenantId == tenantId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddMemberDaySettingAsync(MemberDaySetting setting, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.MemberDaySettings.AddAsync(setting, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task UpdateMemberDaySettingAsync(MemberDaySetting setting, CancellationToken cancellationToken = default)
|
||||
{
|
||||
context.MemberDaySettings.Update(setting);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<MemberProfileTag>> GetProfileTagsAsync(
|
||||
long tenantId,
|
||||
long memberProfileId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await context.MemberProfileTags
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.MemberProfileId == memberProfileId)
|
||||
.OrderBy(x => x.TagName)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task ReplaceProfileTagsAsync(
|
||||
long tenantId,
|
||||
long memberProfileId,
|
||||
IReadOnlyCollection<string> tags,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var normalizedTags = (tags ?? Array.Empty<string>())
|
||||
.Select(x => (x ?? string.Empty).Trim())
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.OrderBy(x => x, StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
var existing = await context.MemberProfileTags
|
||||
.Where(x => x.TenantId == tenantId && x.MemberProfileId == memberProfileId)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
context.MemberProfileTags.RemoveRange(existing);
|
||||
|
||||
if (normalizedTags.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var entities = normalizedTags.Select(tag => new MemberProfileTag
|
||||
{
|
||||
MemberProfileId = memberProfileId,
|
||||
TagName = tag
|
||||
});
|
||||
|
||||
await context.MemberProfileTags.AddRangeAsync(entities, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddMemberCenterModule : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "ColorHex",
|
||||
table: "member_tiers",
|
||||
type: "character varying(16)",
|
||||
maxLength: 16,
|
||||
nullable: false,
|
||||
defaultValue: "#999999");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "DowngradeWindowDays",
|
||||
table: "member_tiers",
|
||||
type: "integer",
|
||||
nullable: false,
|
||||
defaultValue: 90);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "IconKey",
|
||||
table: "member_tiers",
|
||||
type: "character varying(32)",
|
||||
maxLength: 32,
|
||||
nullable: false,
|
||||
defaultValue: "user");
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "IsDefault",
|
||||
table: "member_tiers",
|
||||
type: "boolean",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "UpgradeAmountThreshold",
|
||||
table: "member_tiers",
|
||||
type: "numeric(18,2)",
|
||||
precision: 18,
|
||||
scale: 2,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "UpgradeOrderCountThreshold",
|
||||
table: "member_tiers",
|
||||
type: "integer",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "UpgradeRuleType",
|
||||
table: "member_tiers",
|
||||
type: "character varying(16)",
|
||||
maxLength: 16,
|
||||
nullable: false,
|
||||
defaultValue: "none");
|
||||
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "StoredBalance",
|
||||
table: "member_profiles",
|
||||
type: "numeric(18,2)",
|
||||
precision: 18,
|
||||
scale: 2,
|
||||
nullable: false,
|
||||
defaultValue: 0m);
|
||||
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "StoredGiftBalance",
|
||||
table: "member_profiles",
|
||||
type: "numeric(18,2)",
|
||||
precision: 18,
|
||||
scale: 2,
|
||||
nullable: false,
|
||||
defaultValue: 0m);
|
||||
|
||||
migrationBuilder.AddColumn<decimal>(
|
||||
name: "StoredRechargeBalance",
|
||||
table: "member_profiles",
|
||||
type: "numeric(18,2)",
|
||||
precision: 18,
|
||||
scale: 2,
|
||||
nullable: false,
|
||||
defaultValue: 0m);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "member_day_settings",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
IsEnabled = table.Column<bool>(type: "boolean", nullable: false, comment: "是否启用会员日。"),
|
||||
Weekday = table.Column<int>(type: "integer", nullable: false, comment: "周几(1-7)。"),
|
||||
ExtraDiscountRate = table.Column<decimal>(type: "numeric(5,2)", precision: 5, scale: 2, nullable: false, comment: "会员日额外折扣。"),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。"),
|
||||
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "所属租户 ID。")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_member_day_settings", x => x.Id);
|
||||
},
|
||||
comment: "会员日设置。");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "member_profile_tags",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
MemberProfileId = table.Column<long>(type: "bigint", nullable: false, comment: "会员标识。"),
|
||||
TagName = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false, comment: "标签名。"),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。"),
|
||||
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "所属租户 ID。")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_member_profile_tags", x => x.Id);
|
||||
},
|
||||
comment: "会员标签。");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_member_day_settings_TenantId",
|
||||
table: "member_day_settings",
|
||||
column: "TenantId",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_member_profiles_TenantId_MemberTierId",
|
||||
table: "member_profiles",
|
||||
columns: new[] { "TenantId", "MemberTierId" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_member_profile_tags_TenantId_MemberProfileId",
|
||||
table: "member_profile_tags",
|
||||
columns: new[] { "TenantId", "MemberProfileId" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_member_profile_tags_TenantId_MemberProfileId_TagName",
|
||||
table: "member_profile_tags",
|
||||
columns: new[] { "TenantId", "MemberProfileId", "TagName" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_member_tiers_TenantId_SortOrder",
|
||||
table: "member_tiers",
|
||||
columns: new[] { "TenantId", "SortOrder" });
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "member_day_settings");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "member_profile_tags");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_member_profiles_TenantId_MemberTierId",
|
||||
table: "member_profiles");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_member_tiers_TenantId_SortOrder",
|
||||
table: "member_tiers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ColorHex",
|
||||
table: "member_tiers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "DowngradeWindowDays",
|
||||
table: "member_tiers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "IconKey",
|
||||
table: "member_tiers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "IsDefault",
|
||||
table: "member_tiers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "UpgradeAmountThreshold",
|
||||
table: "member_tiers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "UpgradeOrderCountThreshold",
|
||||
table: "member_tiers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "UpgradeRuleType",
|
||||
table: "member_tiers");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "StoredBalance",
|
||||
table: "member_profiles");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "StoredGiftBalance",
|
||||
table: "member_profiles");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "StoredRechargeBalance",
|
||||
table: "member_profiles");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user