Compare commits
2 Commits
1b6e91b09d
...
b17e6639a4
| Author | SHA1 | Date | |
|---|---|---|---|
| b17e6639a4 | |||
| 79099776a5 |
@ -93,6 +93,7 @@ public class AiSkillService : ApplicationService
|
||||
}
|
||||
|
||||
entity ??= await AiSkillRepository.GetBySkillKeyAsync(skillKey);
|
||||
entity ??= await AiSkillRepository.GetBySkillKeyIncludingDeletedAsync(skillKey);
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
@ -106,9 +107,17 @@ public class AiSkillService : ApplicationService
|
||||
throw new BusinessException($"SkillKey 已存在:{skillKey}");
|
||||
}
|
||||
|
||||
var softDeleted = await AiSkillRepository.GetBySkillKeyIncludingDeletedAsync(skillKey);
|
||||
if (softDeleted is { IsDeleted: true } && softDeleted.Id != entity.Id)
|
||||
{
|
||||
softDeleted.SkillKey = $"{skillKey}__deleted_{softDeleted.Id}";
|
||||
await AiSkillRepository.UpdateAsync(softDeleted);
|
||||
}
|
||||
|
||||
entity.SkillKey = skillKey;
|
||||
}
|
||||
|
||||
entity.IsDeleted = false;
|
||||
entity.Scene = scene;
|
||||
entity.Name = input.Name.Trim();
|
||||
entity.Description = NormalizeOptional(input.Description);
|
||||
|
||||
@ -23,6 +23,21 @@ public partial class SalesProductService
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新时若目标编码被软删记录占用,改名释放 uk_sp_code。
|
||||
/// </summary>
|
||||
private async Task FreeSoftDeletedProductCodeIfNeededAsync(string productCode, int currentId)
|
||||
{
|
||||
var conflict = await SalesProductRepository.GetByProductCodeIncludingDeletedAsync(productCode);
|
||||
if (conflict == null || !conflict.IsDeleted || conflict.Id == currentId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
conflict.ProductCode = $"{productCode}__deleted_{conflict.Id}";
|
||||
await SalesProductRepository.UpdateAsync(conflict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取销售产品,不存在时直接抛异常。
|
||||
/// </summary>
|
||||
@ -388,10 +403,11 @@ public partial class SalesProductService
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 保险/偏远费等附加费用项的计费条件校验。
|
||||
/// 保险/偏远费等附加费用项的计费条件校验;同一提交批次内费用项不可重复。
|
||||
/// </summary>
|
||||
private static void ValidateBillingPriceItemRules(IReadOnlyList<SalesProductPriceSaveInput> prices)
|
||||
{
|
||||
EnsureUniqueCostItemsInBatch(prices.Select(x => x.CostItem));
|
||||
foreach (var price in prices)
|
||||
{
|
||||
var costItem = price.CostItem?.Trim() ?? string.Empty;
|
||||
@ -417,6 +433,44 @@ public partial class SalesProductService
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同一销售产品下每种费用项只能有一条卖价配置。
|
||||
/// </summary>
|
||||
private async Task EnsureCostItemUniqueAsync(int salesProductId, string? costItem, int? excludePriceId)
|
||||
{
|
||||
var trimmed = costItem?.Trim() ?? string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(trimmed))
|
||||
{
|
||||
throw new Fake.Application.BusinessException("费用项不能为空");
|
||||
}
|
||||
|
||||
var existing = await SalesProductRepository.GetPricesAsync(salesProductId);
|
||||
var duplicated = existing.Any(p =>
|
||||
(!excludePriceId.HasValue || p.Id != excludePriceId.Value)
|
||||
&& string.Equals(p.CostItem?.Trim(), trimmed, StringComparison.OrdinalIgnoreCase));
|
||||
if (duplicated)
|
||||
{
|
||||
throw new Fake.Application.BusinessException(
|
||||
$"该产品已存在费用项「{trimmed}」,同一产品下每种费用项只能有一条");
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureUniqueCostItemsInBatch(IEnumerable<string?> costItems)
|
||||
{
|
||||
var duplicates = costItems
|
||||
.Select(x => x?.Trim() ?? string.Empty)
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||
.GroupBy(x => x, StringComparer.OrdinalIgnoreCase)
|
||||
.Where(g => g.Count() > 1)
|
||||
.Select(g => g.Key)
|
||||
.ToList();
|
||||
if (duplicates.Count > 0)
|
||||
{
|
||||
throw new Fake.Application.BusinessException(
|
||||
$"同一产品下费用项不能重复:{string.Join("、", duplicates)}");
|
||||
}
|
||||
}
|
||||
|
||||
private static string? NormalizeAdditionalServices(string? raw)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(raw))
|
||||
|
||||
@ -75,6 +75,16 @@ public partial class SalesProductService : ApplicationService
|
||||
public async Task CreateAsync(SalesProductSaveInput input)
|
||||
{
|
||||
await ValidateProductCodeAsync(input.ProductCode, null);
|
||||
var code = input.ProductCode.Trim();
|
||||
var deleted = await SalesProductRepository.GetByProductCodeIncludingDeletedAsync(code);
|
||||
if (deleted != null && deleted.IsDeleted)
|
||||
{
|
||||
deleted.IsDeleted = false;
|
||||
ApplyProductInput(deleted, input);
|
||||
await SalesProductRepository.UpdateAsync(deleted);
|
||||
return;
|
||||
}
|
||||
|
||||
var entity = new SalesProduct();
|
||||
ApplyProductInput(entity, input);
|
||||
await SalesProductRepository.InsertAsync(entity);
|
||||
@ -90,6 +100,7 @@ public partial class SalesProductService : ApplicationService
|
||||
{
|
||||
var entity = await GetProductOrThrowAsync(input.Id);
|
||||
await ValidateProductCodeAsync(input.ProductCode, entity.Id);
|
||||
await FreeSoftDeletedProductCodeIfNeededAsync(input.ProductCode.Trim(), entity.Id);
|
||||
ApplyProductInput(entity, input);
|
||||
await SalesProductRepository.UpdateAsync(entity);
|
||||
}
|
||||
@ -159,6 +170,7 @@ public partial class SalesProductService : ApplicationService
|
||||
{
|
||||
await GetProductOrThrowAsync(input.SalesProductId);
|
||||
ValidateBillingPriceItemRules([input]);
|
||||
await EnsureCostItemUniqueAsync(input.SalesProductId, input.CostItem, excludePriceId: null);
|
||||
await SalesProductRepository.InsertPriceAsync(
|
||||
new SalesProductPrice
|
||||
{
|
||||
@ -190,6 +202,7 @@ public partial class SalesProductService : ApplicationService
|
||||
}
|
||||
|
||||
ValidateBillingPriceItemRules([input]);
|
||||
await EnsureCostItemUniqueAsync(input.SalesProductId, input.CostItem, excludePriceId: price.Id);
|
||||
price.SerialNumber = input.SerialNumber;
|
||||
price.Status = input.Status;
|
||||
price.PriceName = input.PriceName;
|
||||
|
||||
@ -91,6 +91,21 @@ public partial class ServiceChannelService
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新时若目标编码被软删记录占用,改名释放 uk_sc_code。
|
||||
/// </summary>
|
||||
private async Task FreeSoftDeletedChannelCodeIfNeededAsync(string channelCode, int currentId)
|
||||
{
|
||||
var conflict = await ServiceChannelRepository.GetByChannelCodeIncludingDeletedAsync(channelCode);
|
||||
if (conflict == null || !conflict.IsDeleted || conflict.Id == currentId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
conflict.ChannelCode = $"{channelCode}__deleted_{conflict.Id}";
|
||||
await ServiceChannelRepository.UpdateAsync(conflict);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取服务渠道,不存在时直接抛异常。
|
||||
/// </summary>
|
||||
@ -329,10 +344,11 @@ public partial class ServiceChannelService
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 买价偏远费等附加费用项的计费条件校验。
|
||||
/// 买价偏远费等附加费用项的计费条件校验;同一提交批次内费用项不可重复。
|
||||
/// </summary>
|
||||
private static void ValidateBillingPriceItemRules(IReadOnlyList<ServiceChannelPriceSaveInput> prices)
|
||||
{
|
||||
EnsureUniqueCostItemsInBatch(prices.Select(x => x.CostItem));
|
||||
foreach (var price in prices)
|
||||
{
|
||||
var costItem = price.CostItem?.Trim() ?? string.Empty;
|
||||
@ -349,6 +365,44 @@ public partial class ServiceChannelService
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同一服务渠道下每种费用项只能有一条买价配置。
|
||||
/// </summary>
|
||||
private async Task EnsureCostItemUniqueAsync(int serviceChannelId, string? costItem, int? excludePriceId)
|
||||
{
|
||||
var trimmed = costItem?.Trim() ?? string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(trimmed))
|
||||
{
|
||||
throw new Fake.Application.BusinessException("费用项不能为空");
|
||||
}
|
||||
|
||||
var existing = await ServiceChannelRepository.GetPricesAsync(serviceChannelId);
|
||||
var duplicated = existing.Any(p =>
|
||||
(!excludePriceId.HasValue || p.Id != excludePriceId.Value)
|
||||
&& string.Equals(p.CostItem?.Trim(), trimmed, StringComparison.OrdinalIgnoreCase));
|
||||
if (duplicated)
|
||||
{
|
||||
throw new Fake.Application.BusinessException(
|
||||
$"该渠道已存在费用项「{trimmed}」,同一渠道下每种费用项只能有一条");
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureUniqueCostItemsInBatch(IEnumerable<string?> costItems)
|
||||
{
|
||||
var duplicates = costItems
|
||||
.Select(x => x?.Trim() ?? string.Empty)
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||
.GroupBy(x => x, StringComparer.OrdinalIgnoreCase)
|
||||
.Where(g => g.Count() > 1)
|
||||
.Select(g => g.Key)
|
||||
.ToList();
|
||||
if (duplicates.Count > 0)
|
||||
{
|
||||
throw new Fake.Application.BusinessException(
|
||||
$"同一渠道下费用项不能重复:{string.Join("、", duplicates)}");
|
||||
}
|
||||
}
|
||||
|
||||
private static ServiceChannelGroupListOutput MapGroupListOutput(ServiceChannelGroup entity)
|
||||
{
|
||||
return new ServiceChannelGroupListOutput
|
||||
|
||||
@ -73,6 +73,16 @@ public partial class ServiceChannelService : ApplicationService
|
||||
public async Task CreateAsync(ServiceChannelSaveInput input)
|
||||
{
|
||||
await ValidateChannelCodeAsync(input.ChannelCode, null);
|
||||
var code = input.ChannelCode.Trim();
|
||||
var deleted = await ServiceChannelRepository.GetByChannelCodeIncludingDeletedAsync(code);
|
||||
if (deleted != null && deleted.IsDeleted)
|
||||
{
|
||||
deleted.IsDeleted = false;
|
||||
ApplyInput(deleted, input);
|
||||
await ServiceChannelRepository.UpdateAsync(deleted);
|
||||
return;
|
||||
}
|
||||
|
||||
var entity = new ServiceChannel();
|
||||
ApplyInput(entity, input);
|
||||
await ServiceChannelRepository.InsertAsync(entity);
|
||||
@ -88,6 +98,7 @@ public partial class ServiceChannelService : ApplicationService
|
||||
{
|
||||
var entity = await GetEntityOrThrowAsync(input.Id);
|
||||
await ValidateChannelCodeAsync(input.ChannelCode, entity.Id);
|
||||
await FreeSoftDeletedChannelCodeIfNeededAsync(input.ChannelCode.Trim(), entity.Id);
|
||||
ApplyInput(entity, input);
|
||||
await ServiceChannelRepository.UpdateAsync(entity);
|
||||
}
|
||||
@ -223,6 +234,7 @@ public partial class ServiceChannelService : ApplicationService
|
||||
{
|
||||
await GetEntityOrThrowAsync(input.ServiceChannelId);
|
||||
ValidateBillingPriceItemRules([input]);
|
||||
await EnsureCostItemUniqueAsync(input.ServiceChannelId, input.CostItem, excludePriceId: null);
|
||||
await ServiceChannelRepository.InsertPriceAsync(
|
||||
new ServiceChannelPrice
|
||||
{
|
||||
@ -254,6 +266,7 @@ public partial class ServiceChannelService : ApplicationService
|
||||
}
|
||||
|
||||
ValidateBillingPriceItemRules([input]);
|
||||
await EnsureCostItemUniqueAsync(input.ServiceChannelId, input.CostItem, excludePriceId: price.Id);
|
||||
price.SerialNumber = input.SerialNumber;
|
||||
price.Status = input.Status;
|
||||
price.PriceName = input.PriceName;
|
||||
|
||||
@ -178,6 +178,12 @@ public class CustomerService : ApplicationService
|
||||
NormalizeRequiredText(input.Email, "邮箱"),
|
||||
WeChatRegistrationFieldNormalizer.EmailMaxLength);
|
||||
|
||||
await FreeSoftDeletedCustomerIdentityIfNeededAsync(
|
||||
customer.CustomerCode,
|
||||
phone,
|
||||
email,
|
||||
excludeId: customer.Id);
|
||||
|
||||
var duplicatedPhone = await CustomerRepository.GetByPhoneAsync(phone, cancellationToken);
|
||||
if (duplicatedPhone != null && duplicatedPhone.Id != customer.Id)
|
||||
{
|
||||
@ -216,6 +222,10 @@ public class CustomerService : ApplicationService
|
||||
{
|
||||
var normalized = await NormalizeCreateCustomerInputAsync(input, "客户编号", "客户名称");
|
||||
|
||||
await FreeSoftDeletedCustomerIdentityIfNeededAsync(
|
||||
normalized.CustomerCode,
|
||||
normalized.Phone,
|
||||
normalized.Email);
|
||||
await EnsureCustomerIdentityUniqueAsync(normalized.CustomerCode, normalized.Phone, normalized.Email);
|
||||
|
||||
var customerRoleId = await GetCustomerRoleIdOrThrowAsync();
|
||||
@ -268,6 +278,10 @@ public class CustomerService : ApplicationService
|
||||
var normalized = await NormalizeCreateCustomerInputAsync(input, "子客户编号", "子客户名称");
|
||||
var permissions = await NormalizeAndValidateSubCustomerPermissionsAsync(input.Permissions);
|
||||
|
||||
await FreeSoftDeletedCustomerIdentityIfNeededAsync(
|
||||
normalized.CustomerCode,
|
||||
normalized.Phone,
|
||||
normalized.Email);
|
||||
await EnsureCustomerIdentityUniqueAsync(normalized.CustomerCode, normalized.Phone, normalized.Email);
|
||||
|
||||
var user = await CreateRbacUserAsync(input, normalized);
|
||||
@ -550,8 +564,46 @@ public class CustomerService : ApplicationService
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 客户创建会新建 RBAC 用户,不适合直接恢复软删行;释放软删占用的唯一键即可。
|
||||
/// </summary>
|
||||
private async Task FreeSoftDeletedCustomerIdentityIfNeededAsync(
|
||||
string customerCode,
|
||||
string phone,
|
||||
string? email,
|
||||
int? excludeId = null)
|
||||
{
|
||||
var byCode = await CustomerRepository.GetByCustomerCodeIncludingDeletedAsync(customerCode);
|
||||
if (byCode != null && byCode.IsDeleted && byCode.Id != excludeId)
|
||||
{
|
||||
byCode.CustomerCode = $"{customerCode}__deleted_{byCode.Id}";
|
||||
await CustomerRepository.UpdateAsync(byCode);
|
||||
}
|
||||
|
||||
var byPhone = await CustomerRepository.GetByPhoneIncludingDeletedAsync(phone);
|
||||
if (byPhone != null && byPhone.IsDeleted && byPhone.Id != excludeId)
|
||||
{
|
||||
byPhone.Phone = $"{phone}__deleted_{byPhone.Id}";
|
||||
await CustomerRepository.UpdateAsync(byPhone);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(email))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var byEmail = await CustomerRepository.GetByEmailIncludingDeletedAsync(email);
|
||||
if (byEmail != null && byEmail.IsDeleted && byEmail.Id != excludeId)
|
||||
{
|
||||
byEmail.Email = $"{email}__deleted_{byEmail.Id}";
|
||||
await CustomerRepository.UpdateAsync(byEmail);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task EnsureCustomerIdentityUniqueForUpdateAsync(int id, string customerCode, string phone, string? email)
|
||||
{
|
||||
await FreeSoftDeletedCustomerIdentityIfNeededAsync(customerCode, phone, email, excludeId: id);
|
||||
|
||||
var duplicatedCode = await CustomerRepository.GetByCustomerCodeAsync(customerCode);
|
||||
if (duplicatedCode != null && duplicatedCode.Id != id)
|
||||
{
|
||||
|
||||
@ -64,7 +64,22 @@ public class KbCategoryService : ApplicationService
|
||||
throw new BusinessException($"分类编码已存在:{code}");
|
||||
}
|
||||
|
||||
entity ??= new KbCategory();
|
||||
if (entity == null)
|
||||
{
|
||||
var deleted = await CategoryRepository.GetByCodeIncludingDeletedAsync(code);
|
||||
entity = deleted is { IsDeleted: true } ? deleted : new KbCategory();
|
||||
}
|
||||
else
|
||||
{
|
||||
var softDeleted = await CategoryRepository.GetByCodeIncludingDeletedAsync(code);
|
||||
if (softDeleted is { IsDeleted: true } && softDeleted.Id != entity.Id)
|
||||
{
|
||||
softDeleted.Code = $"{code}__deleted_{softDeleted.Id}";
|
||||
await CategoryRepository.UpdateAsync(softDeleted);
|
||||
}
|
||||
}
|
||||
|
||||
entity.IsDeleted = false;
|
||||
entity.Code = code;
|
||||
entity.Name = name;
|
||||
entity.SortOrder = input.SortOrder;
|
||||
|
||||
@ -132,14 +132,10 @@ public class DictService : ApplicationService
|
||||
}
|
||||
|
||||
entity ??= await DictTypeRepository.GetByDictTypeAsync(dictType);
|
||||
// 软删后列表查不到,但 uk_dict_type_code 仍占坑;重建时恢复原行
|
||||
entity ??= await DictTypeRepository.GetByDictTypeIncludingDeletedAsync(dictType);
|
||||
if (entity == null)
|
||||
{
|
||||
var existedType = await DictTypeRepository.GetByDictTypeAsync(dictType);
|
||||
if (existedType != null)
|
||||
{
|
||||
throw new BusinessException("字典类型已存在");
|
||||
}
|
||||
|
||||
await DictTypeRepository.InsertAsync(new DictTypeMeta
|
||||
{
|
||||
DictType = dictType,
|
||||
@ -151,13 +147,19 @@ public class DictService : ApplicationService
|
||||
|
||||
if (!string.Equals(entity.DictType, dictType, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var duplicate = await DictTypeRepository.GetByDictTypeAsync(dictType);
|
||||
if (duplicate != null && duplicate.Id != entity.Id)
|
||||
var duplicate = await DictTypeRepository.GetByDictTypeIncludingDeletedAsync(dictType);
|
||||
if (duplicate != null && duplicate.Id != entity.Id && !duplicate.IsDeleted)
|
||||
{
|
||||
throw new BusinessException("字典类型已存在");
|
||||
}
|
||||
|
||||
if (duplicate != null && duplicate.Id != entity.Id && duplicate.IsDeleted)
|
||||
{
|
||||
throw new BusinessException("字典类型编码与已删除记录冲突,请换编码或联系管理员恢复");
|
||||
}
|
||||
}
|
||||
|
||||
entity.IsDeleted = false;
|
||||
entity.DictType = dictType;
|
||||
entity.Remark = remark;
|
||||
entity.TypeSort = input.TypeSort;
|
||||
@ -317,6 +319,14 @@ public class DictService : ApplicationService
|
||||
return;
|
||||
}
|
||||
|
||||
var deleted = await DictTypeRepository.GetByDictTypeIncludingDeletedAsync(dictType);
|
||||
if (deleted != null)
|
||||
{
|
||||
deleted.IsDeleted = false;
|
||||
await DictTypeRepository.UpdateAsync(deleted);
|
||||
return;
|
||||
}
|
||||
|
||||
await DictTypeRepository.InsertAsync(new DictTypeMeta
|
||||
{
|
||||
DictType = dictType,
|
||||
|
||||
@ -61,9 +61,26 @@ public class SystemOtherConfigService : ApplicationService
|
||||
public async Task CreateAsync(SystemOtherConfigCreateInput input)
|
||||
{
|
||||
await ValidateInputAsync(input, null);
|
||||
var configCode = input.ConfigCode.Trim();
|
||||
var deleted = await SystemOtherConfigRepository.GetByConfigCodeIncludingDeletedAsync(configCode);
|
||||
if (deleted != null && deleted.IsDeleted)
|
||||
{
|
||||
deleted.IsDeleted = false;
|
||||
deleted.ConfigCode = configCode;
|
||||
deleted.ConfigName = input.ConfigName.Trim();
|
||||
deleted.Enabled = input.Enabled;
|
||||
deleted.BaseUrl = NormalizeOptional(input.BaseUrl);
|
||||
deleted.AppKey = NormalizeOptional(input.AppKey);
|
||||
deleted.AppSecret = NormalizeOptional(input.AppSecret);
|
||||
deleted.TimeoutSeconds = NormalizeTimeoutSeconds(input.TimeoutSeconds);
|
||||
deleted.Remark = NormalizeOptional(input.Remark);
|
||||
await SystemOtherConfigRepository.UpdateAsync(deleted);
|
||||
return;
|
||||
}
|
||||
|
||||
await SystemOtherConfigRepository.InsertAsync(new SystemOtherConfig
|
||||
{
|
||||
ConfigCode = input.ConfigCode.Trim(),
|
||||
ConfigCode = configCode,
|
||||
ConfigName = input.ConfigName.Trim(),
|
||||
Enabled = input.Enabled,
|
||||
BaseUrl = NormalizeOptional(input.BaseUrl),
|
||||
@ -82,8 +99,16 @@ public class SystemOtherConfigService : ApplicationService
|
||||
{
|
||||
var entity = await GetConfigOrThrowAsync(input.Id);
|
||||
await ValidateInputAsync(input, entity.Id);
|
||||
var configCode = input.ConfigCode.Trim();
|
||||
var softDeleted = await SystemOtherConfigRepository.GetByConfigCodeIncludingDeletedAsync(configCode);
|
||||
if (softDeleted != null && softDeleted.IsDeleted && softDeleted.Id != entity.Id)
|
||||
{
|
||||
softDeleted.ConfigCode = $"{configCode}__deleted_{softDeleted.Id}";
|
||||
await SystemOtherConfigRepository.UpdateAsync(softDeleted);
|
||||
}
|
||||
|
||||
var clearWeChatAccessToken = ShouldClearWeChatAccessToken(entity, input);
|
||||
entity.ConfigCode = input.ConfigCode.Trim();
|
||||
entity.ConfigCode = configCode;
|
||||
entity.ConfigName = input.ConfigName.Trim();
|
||||
entity.Enabled = input.Enabled;
|
||||
entity.BaseUrl = NormalizeOptional(input.BaseUrl);
|
||||
|
||||
@ -81,15 +81,29 @@ public class WarehouseService : ApplicationService
|
||||
[HttpPost("/system/warehouse/create")]
|
||||
public async Task CreateAsync(CreateWarehouseInput input)
|
||||
{
|
||||
var duplicatedWarehouse = await WarehouseAddressRepository.GetByWarehouseNameAsync(input.WarehouseName);
|
||||
var warehouseName = input.WarehouseName.Trim();
|
||||
var duplicatedWarehouse = await WarehouseAddressRepository.GetByWarehouseNameAsync(warehouseName);
|
||||
if (duplicatedWarehouse != null)
|
||||
{
|
||||
throw new BusinessException("仓库名称已存在");
|
||||
}
|
||||
|
||||
var deleted = await WarehouseAddressRepository.GetByWarehouseNameIncludingDeletedAsync(warehouseName);
|
||||
if (deleted != null && deleted.IsDeleted)
|
||||
{
|
||||
deleted.IsDeleted = false;
|
||||
deleted.WarehouseName = warehouseName;
|
||||
deleted.WarehouseType = input.WarehouseType;
|
||||
deleted.Recipient = input.Recipient;
|
||||
deleted.ContactPhone = input.ContactPhone;
|
||||
deleted.ShippingAddress = input.ShippingAddress;
|
||||
await WarehouseAddressRepository.UpdateAsync(deleted);
|
||||
return;
|
||||
}
|
||||
|
||||
var entity = new WarehouseAddress
|
||||
{
|
||||
WarehouseName = input.WarehouseName,
|
||||
WarehouseName = warehouseName,
|
||||
WarehouseType = input.WarehouseType,
|
||||
Recipient = input.Recipient,
|
||||
ContactPhone = input.ContactPhone,
|
||||
@ -108,13 +122,21 @@ public class WarehouseService : ApplicationService
|
||||
public async Task UpdateAsync(UpdateWarehouseInput input)
|
||||
{
|
||||
var entity = await GetWarehouseOrThrowAsync(input.Id);
|
||||
var duplicatedWarehouse = await WarehouseAddressRepository.GetByWarehouseNameAsync(input.WarehouseName);
|
||||
var warehouseName = input.WarehouseName.Trim();
|
||||
var duplicatedWarehouse = await WarehouseAddressRepository.GetByWarehouseNameAsync(warehouseName);
|
||||
if (duplicatedWarehouse != null && duplicatedWarehouse.Id != entity.Id)
|
||||
{
|
||||
throw new BusinessException("仓库名称已存在");
|
||||
}
|
||||
|
||||
entity.WarehouseName = input.WarehouseName;
|
||||
var softDeleted = await WarehouseAddressRepository.GetByWarehouseNameIncludingDeletedAsync(warehouseName);
|
||||
if (softDeleted != null && softDeleted.IsDeleted && softDeleted.Id != entity.Id)
|
||||
{
|
||||
softDeleted.WarehouseName = $"{warehouseName}__deleted_{softDeleted.Id}";
|
||||
await WarehouseAddressRepository.UpdateAsync(softDeleted);
|
||||
}
|
||||
|
||||
entity.WarehouseName = warehouseName;
|
||||
entity.WarehouseType = input.WarehouseType;
|
||||
entity.Recipient = input.Recipient;
|
||||
entity.ContactPhone = input.ContactPhone;
|
||||
|
||||
@ -63,7 +63,12 @@ public partial class WarehouseService
|
||||
}
|
||||
else
|
||||
{
|
||||
entity = new CBinLocation { WarehouseId = input.WarehouseId };
|
||||
var deleted = await BinLocationRepository.GetByWarehouseAndBinCodeIncludingDeletedAsync(
|
||||
input.WarehouseId,
|
||||
binCode);
|
||||
entity = deleted is { IsDeleted: true }
|
||||
? deleted
|
||||
: new CBinLocation { WarehouseId = input.WarehouseId };
|
||||
}
|
||||
|
||||
var duplicate = await BinLocationRepository.FirstOrDefaultAsync(x =>
|
||||
@ -73,13 +78,26 @@ public partial class WarehouseService
|
||||
throw new BusinessException("库位编码已存在");
|
||||
}
|
||||
|
||||
if (input.Id > 0)
|
||||
{
|
||||
var softDeleted = await BinLocationRepository.GetByWarehouseAndBinCodeIncludingDeletedAsync(
|
||||
input.WarehouseId,
|
||||
binCode);
|
||||
if (softDeleted is { IsDeleted: true } && softDeleted.Id != entity.Id)
|
||||
{
|
||||
softDeleted.BinCode = $"{binCode}__deleted_{softDeleted.Id}";
|
||||
await BinLocationRepository.UpdateAsync(softDeleted);
|
||||
}
|
||||
}
|
||||
|
||||
entity.IsDeleted = false;
|
||||
entity.BinCode = binCode;
|
||||
entity.BinName = string.IsNullOrWhiteSpace(input.BinName) ? null : input.BinName.Trim();
|
||||
entity.ZoneCode = string.IsNullOrWhiteSpace(input.ZoneCode) ? null : input.ZoneCode.Trim();
|
||||
entity.IsEnabled = input.IsEnabled;
|
||||
entity.Remark = string.IsNullOrWhiteSpace(input.Remark) ? null : input.Remark.Trim();
|
||||
|
||||
if (input.Id > 0)
|
||||
if (entity.Id > 0)
|
||||
{
|
||||
await BinLocationRepository.UpdateAsync(entity);
|
||||
}
|
||||
|
||||
@ -105,7 +105,10 @@ public partial class WarehouseService
|
||||
}
|
||||
else
|
||||
{
|
||||
entity = new Domain.WarehouseAggregate.Entities.CSku { CustomerId = customerId };
|
||||
var deleted = await SkuRepository.GetByCustomerAndSkuCodeIncludingDeletedAsync(customerId, skuCode);
|
||||
entity = deleted is { IsDeleted: true }
|
||||
? deleted
|
||||
: new Domain.WarehouseAggregate.Entities.CSku { CustomerId = customerId };
|
||||
}
|
||||
|
||||
var duplicate = await SkuRepository.FirstOrDefaultAsync(x =>
|
||||
@ -115,6 +118,17 @@ public partial class WarehouseService
|
||||
throw new BusinessException("SKU 编码已存在");
|
||||
}
|
||||
|
||||
if (input.Id > 0)
|
||||
{
|
||||
var softDeleted = await SkuRepository.GetByCustomerAndSkuCodeIncludingDeletedAsync(customerId, skuCode);
|
||||
if (softDeleted is { IsDeleted: true } && softDeleted.Id != entity.Id)
|
||||
{
|
||||
softDeleted.SkuCode = $"{skuCode}__deleted_{softDeleted.Id}";
|
||||
await SkuRepository.UpdateAsync(softDeleted);
|
||||
}
|
||||
}
|
||||
|
||||
entity.IsDeleted = false;
|
||||
entity.SkuCode = skuCode;
|
||||
entity.SkuName = skuName;
|
||||
entity.SkuNameEn = string.IsNullOrWhiteSpace(input.SkuNameEn) ? null : input.SkuNameEn.Trim();
|
||||
@ -129,7 +143,7 @@ public partial class WarehouseService
|
||||
entity.HeightCm = input.HeightCm;
|
||||
entity.Remark = string.IsNullOrWhiteSpace(input.Remark) ? null : input.Remark.Trim();
|
||||
|
||||
if (input.Id > 0)
|
||||
if (entity.Id > 0)
|
||||
{
|
||||
await SkuRepository.UpdateAsync(entity);
|
||||
}
|
||||
|
||||
@ -6,4 +6,8 @@ namespace Oms.Domain.AiAggregate.Repositories;
|
||||
public interface IAiSkillRepository : IRepository<AiSkill>
|
||||
{
|
||||
Task<AiSkill?> GetBySkillKeyAsync(string skillKey, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<AiSkill?> GetBySkillKeyIncludingDeletedAsync(
|
||||
string skillKey,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@ -7,6 +7,10 @@ public interface ISalesProductRepository : IRepository<SalesProduct>
|
||||
{
|
||||
Task<SalesProduct?> GetByProductCodeAsync(string productCode, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<SalesProduct?> GetByProductCodeIncludingDeletedAsync(
|
||||
string productCode,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<bool> HasProductCodeAsync(string productCode, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<List<SalesProductPrice>> GetPricesAsync(int salesProductId, CancellationToken cancellationToken = default);
|
||||
|
||||
@ -7,6 +7,10 @@ public interface IServiceChannelRepository : IRepository<ServiceChannel>
|
||||
{
|
||||
Task<ServiceChannel?> GetByChannelCodeAsync(string channelCode, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<ServiceChannel?> GetByChannelCodeIncludingDeletedAsync(
|
||||
string channelCode,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<bool> HasChannelCodeAsync(string channelCode, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<List<ServiceChannelGroup>> GetGroupsAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
@ -7,10 +7,18 @@ public interface ICustomerRepository : IRepository<Customer>
|
||||
{
|
||||
Task<Customer?> GetByCustomerCodeAsync(string customerCode, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<Customer?> GetByCustomerCodeIncludingDeletedAsync(
|
||||
string customerCode,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<Customer?> GetByPhoneAsync(string phone, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<Customer?> GetByPhoneIncludingDeletedAsync(string phone, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<Customer?> GetByEmailAsync(string email, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<Customer?> GetByEmailIncludingDeletedAsync(string email, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<Customer?> GetByWechatOpenidAsync(string wechatOpenid, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<bool> ExistsPhoneAsync(string phone, CancellationToken cancellationToken = default);
|
||||
|
||||
@ -7,5 +7,7 @@ public interface IKbCategoryRepository : IRepository<KbCategory>
|
||||
{
|
||||
Task<KbCategory?> GetByCodeAsync(string code, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<KbCategory?> GetByCodeIncludingDeletedAsync(string code, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<bool> ExistsCodeAsync(string code, int? excludeId = null, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@ -6,4 +6,11 @@ namespace Oms.Domain.SystemAggregate.Repositories;
|
||||
public interface IDictTypeRepository : IRepository<DictTypeMeta>
|
||||
{
|
||||
Task<DictTypeMeta?> GetByDictTypeAsync(string dictType, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 按类型编码查询(含软删除),用于唯一键冲突时恢复。
|
||||
/// </summary>
|
||||
Task<DictTypeMeta?> GetByDictTypeIncludingDeletedAsync(
|
||||
string dictType,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@ -6,4 +6,8 @@ namespace Oms.Domain.SystemAggregate.Repositories;
|
||||
public interface ISystemOtherConfigRepository : IRepository<SystemOtherConfig>
|
||||
{
|
||||
Task<SystemOtherConfig?> GetByConfigCodeAsync(string configCode, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<SystemOtherConfig?> GetByConfigCodeIncludingDeletedAsync(
|
||||
string configCode,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@ -7,5 +7,9 @@ public interface IWarehouseAddressRepository : IRepository<WarehouseAddress>
|
||||
{
|
||||
Task<WarehouseAddress?> GetByWarehouseNameAsync(string warehouseName, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<WarehouseAddress?> GetByWarehouseNameIncludingDeletedAsync(
|
||||
string warehouseName,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<bool> ExistsWarehouseNameAsync(string warehouseName, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
@ -3,9 +3,21 @@ using Oms.Domain.WarehouseAggregate.Entities;
|
||||
|
||||
namespace Oms.Domain.WarehouseAggregate.Repositories;
|
||||
|
||||
public interface ICSkuRepository : IRepository<CSku>;
|
||||
public interface ICSkuRepository : IRepository<CSku>
|
||||
{
|
||||
Task<CSku?> GetByCustomerAndSkuCodeIncludingDeletedAsync(
|
||||
int customerId,
|
||||
string skuCode,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public interface ICBinLocationRepository : IRepository<CBinLocation>;
|
||||
public interface ICBinLocationRepository : IRepository<CBinLocation>
|
||||
{
|
||||
Task<CBinLocation?> GetByWarehouseAndBinCodeIncludingDeletedAsync(
|
||||
int warehouseId,
|
||||
string binCode,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public interface ICInventoryRepository : IRepository<CInventory>;
|
||||
|
||||
|
||||
@ -12,4 +12,15 @@ public class AiSkillRepository
|
||||
string skillKey,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
FirstOrDefaultAsync(x => x.SkillKey == skillKey, cancellationToken);
|
||||
|
||||
public async Task<AiSkill?> GetBySkillKeyIncludingDeletedAsync(
|
||||
string skillKey,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var db = await GetDbContextAsync(cancellationToken);
|
||||
return await SoftDeleteQuery.FirstIncludingDeletedAsync<AiSkill>(
|
||||
db,
|
||||
x => x.SkillKey == skillKey,
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,17 @@ public class SalesProductRepository : OmsSqlSugarRepository<SalesProduct>, ISale
|
||||
return FirstOrDefaultAsync(x => x.ProductCode == productCode, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<SalesProduct?> GetByProductCodeIncludingDeletedAsync(
|
||||
string productCode,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var db = await GetDbContextAsync(cancellationToken);
|
||||
return await SoftDeleteQuery.FirstIncludingDeletedAsync<SalesProduct>(
|
||||
db,
|
||||
x => x.ProductCode == productCode,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
public Task<bool> HasProductCodeAsync(string productCode, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return AnyAsync(x => x.ProductCode == productCode, cancellationToken);
|
||||
|
||||
@ -13,6 +13,17 @@ public class ServiceChannelRepository : OmsSqlSugarRepository<ServiceChannel>, I
|
||||
return FirstOrDefaultAsync(x => x.ChannelCode == channelCode, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<ServiceChannel?> GetByChannelCodeIncludingDeletedAsync(
|
||||
string channelCode,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var db = await GetDbContextAsync(cancellationToken);
|
||||
return await SoftDeleteQuery.FirstIncludingDeletedAsync<ServiceChannel>(
|
||||
db,
|
||||
x => x.ChannelCode == channelCode,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
public Task<bool> HasChannelCodeAsync(string channelCode, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return AnyAsync(x => x.ChannelCode == channelCode, cancellationToken);
|
||||
|
||||
@ -12,16 +12,49 @@ public class CustomerRepository : OmsSqlSugarRepository<Customer>, ICustomerRepo
|
||||
return FirstOrDefaultAsync(x => x.CustomerCode == customerCode, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<Customer?> GetByCustomerCodeIncludingDeletedAsync(
|
||||
string customerCode,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var db = await GetDbContextAsync(cancellationToken);
|
||||
return await SoftDeleteQuery.FirstIncludingDeletedAsync<Customer>(
|
||||
db,
|
||||
x => x.CustomerCode == customerCode,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
public Task<Customer?> GetByPhoneAsync(string phone, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return FirstOrDefaultAsync(x => x.Phone == phone, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<Customer?> GetByPhoneIncludingDeletedAsync(
|
||||
string phone,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var db = await GetDbContextAsync(cancellationToken);
|
||||
return await SoftDeleteQuery.FirstIncludingDeletedAsync<Customer>(
|
||||
db,
|
||||
x => x.Phone == phone,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
public Task<Customer?> GetByEmailAsync(string email, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return FirstOrDefaultAsync(x => x.Email == email, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<Customer?> GetByEmailIncludingDeletedAsync(
|
||||
string email,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var db = await GetDbContextAsync(cancellationToken);
|
||||
return await SoftDeleteQuery.FirstIncludingDeletedAsync<Customer>(
|
||||
db,
|
||||
x => x.Email == email,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
public Task<Customer?> GetByWechatOpenidAsync(string wechatOpenid, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return FirstOrDefaultAsync(x => x.WechatOpenid == wechatOpenid, cancellationToken);
|
||||
|
||||
@ -11,6 +11,17 @@ public class KbCategoryRepository
|
||||
public Task<KbCategory?> GetByCodeAsync(string code, CancellationToken cancellationToken = default) =>
|
||||
FirstOrDefaultAsync(x => x.Code == code, cancellationToken);
|
||||
|
||||
public async Task<KbCategory?> GetByCodeIncludingDeletedAsync(
|
||||
string code,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var db = await GetDbContextAsync(cancellationToken);
|
||||
return await SoftDeleteQuery.FirstIncludingDeletedAsync<KbCategory>(
|
||||
db,
|
||||
x => x.Code == code,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<bool> ExistsCodeAsync(
|
||||
string code,
|
||||
int? excludeId = null,
|
||||
|
||||
24
src/Oms.SqlSugarCore/Repositories/SoftDeleteQuery.cs
Normal file
24
src/Oms.SqlSugarCore/Repositories/SoftDeleteQuery.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System.Linq.Expressions;
|
||||
using SqlSugar;
|
||||
|
||||
namespace Oms.SqlSugarCore.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// 软删场景下按业务唯一键查询(ClearFilter),供新增恢复 / 释放唯一键使用。
|
||||
/// </summary>
|
||||
public static class SoftDeleteQuery
|
||||
{
|
||||
public static async Task<TEntity?> FirstIncludingDeletedAsync<TEntity>(
|
||||
ISqlSugarClient db,
|
||||
Expression<Func<TEntity, bool>> predicate,
|
||||
CancellationToken cancellationToken = default)
|
||||
where TEntity : class, new()
|
||||
{
|
||||
var rows = await db.Queryable<TEntity>()
|
||||
.ClearFilter()
|
||||
.Where(predicate)
|
||||
.Take(1)
|
||||
.ToListAsync(cancellationToken);
|
||||
return rows.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
@ -11,4 +11,17 @@ public class DictTypeRepository : OmsSqlSugarRepository<DictTypeMeta>, IDictType
|
||||
{
|
||||
return FirstOrDefaultAsync(x => x.DictType == dictType, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<DictTypeMeta?> GetByDictTypeIncludingDeletedAsync(
|
||||
string dictType,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var db = await GetDbContextAsync(cancellationToken);
|
||||
var rows = await db.Queryable<DictTypeMeta>()
|
||||
.ClearFilter()
|
||||
.Where(x => x.DictType == dictType)
|
||||
.Take(1)
|
||||
.ToListAsync(cancellationToken);
|
||||
return rows.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,4 +11,15 @@ public class SystemOtherConfigRepository : OmsSqlSugarRepository<SystemOtherConf
|
||||
{
|
||||
return FirstOrDefaultAsync(x => x.ConfigCode == configCode, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<SystemOtherConfig?> GetByConfigCodeIncludingDeletedAsync(
|
||||
string configCode,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var db = await GetDbContextAsync(cancellationToken);
|
||||
return await SoftDeleteQuery.FirstIncludingDeletedAsync<SystemOtherConfig>(
|
||||
db,
|
||||
x => x.ConfigCode == configCode,
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,17 @@ public class WarehouseAddressRepository : OmsSqlSugarRepository<WarehouseAddress
|
||||
return FirstOrDefaultAsync(x => x.WarehouseName == warehouseName, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<WarehouseAddress?> GetByWarehouseNameIncludingDeletedAsync(
|
||||
string warehouseName,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var db = await GetDbContextAsync(cancellationToken);
|
||||
return await SoftDeleteQuery.FirstIncludingDeletedAsync<WarehouseAddress>(
|
||||
db,
|
||||
x => x.WarehouseName == warehouseName,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
public Task<bool> ExistsWarehouseNameAsync(string warehouseName, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return AnyAsync(x => x.WarehouseName == warehouseName, cancellationToken);
|
||||
|
||||
@ -5,9 +5,35 @@ using Oms.SqlSugarCore.Repositories;
|
||||
|
||||
namespace Oms.SqlSugarCore.Warehouse;
|
||||
|
||||
public class CSkuRepository : OmsSqlSugarRepository<CSku>, ICSkuRepository, IScopedDependency;
|
||||
public class CSkuRepository : OmsSqlSugarRepository<CSku>, ICSkuRepository, IScopedDependency
|
||||
{
|
||||
public async Task<CSku?> GetByCustomerAndSkuCodeIncludingDeletedAsync(
|
||||
int customerId,
|
||||
string skuCode,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var db = await GetDbContextAsync(cancellationToken);
|
||||
return await SoftDeleteQuery.FirstIncludingDeletedAsync<CSku>(
|
||||
db,
|
||||
x => x.CustomerId == customerId && x.SkuCode == skuCode,
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public class CBinLocationRepository : OmsSqlSugarRepository<CBinLocation>, ICBinLocationRepository, IScopedDependency;
|
||||
public class CBinLocationRepository : OmsSqlSugarRepository<CBinLocation>, ICBinLocationRepository, IScopedDependency
|
||||
{
|
||||
public async Task<CBinLocation?> GetByWarehouseAndBinCodeIncludingDeletedAsync(
|
||||
int warehouseId,
|
||||
string binCode,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var db = await GetDbContextAsync(cancellationToken);
|
||||
return await SoftDeleteQuery.FirstIncludingDeletedAsync<CBinLocation>(
|
||||
db,
|
||||
x => x.WarehouseId == warehouseId && x.BinCode == binCode,
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
public class CInventoryRepository : OmsSqlSugarRepository<CInventory>, ICInventoryRepository, IScopedDependency;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user