20261008-ide1.0发布 #1
@ -93,6 +93,7 @@ public class AiSkillService : ApplicationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
entity ??= await AiSkillRepository.GetBySkillKeyAsync(skillKey);
|
entity ??= await AiSkillRepository.GetBySkillKeyAsync(skillKey);
|
||||||
|
entity ??= await AiSkillRepository.GetBySkillKeyIncludingDeletedAsync(skillKey);
|
||||||
|
|
||||||
if (entity == null)
|
if (entity == null)
|
||||||
{
|
{
|
||||||
@ -106,9 +107,17 @@ public class AiSkillService : ApplicationService
|
|||||||
throw new BusinessException($"SkillKey 已存在:{skillKey}");
|
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.SkillKey = skillKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entity.IsDeleted = false;
|
||||||
entity.Scene = scene;
|
entity.Scene = scene;
|
||||||
entity.Name = input.Name.Trim();
|
entity.Name = input.Name.Trim();
|
||||||
entity.Description = NormalizeOptional(input.Description);
|
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>
|
||||||
/// 获取销售产品,不存在时直接抛异常。
|
/// 获取销售产品,不存在时直接抛异常。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -75,6 +75,16 @@ public partial class SalesProductService : ApplicationService
|
|||||||
public async Task CreateAsync(SalesProductSaveInput input)
|
public async Task CreateAsync(SalesProductSaveInput input)
|
||||||
{
|
{
|
||||||
await ValidateProductCodeAsync(input.ProductCode, null);
|
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();
|
var entity = new SalesProduct();
|
||||||
ApplyProductInput(entity, input);
|
ApplyProductInput(entity, input);
|
||||||
await SalesProductRepository.InsertAsync(entity);
|
await SalesProductRepository.InsertAsync(entity);
|
||||||
@ -90,6 +100,7 @@ public partial class SalesProductService : ApplicationService
|
|||||||
{
|
{
|
||||||
var entity = await GetProductOrThrowAsync(input.Id);
|
var entity = await GetProductOrThrowAsync(input.Id);
|
||||||
await ValidateProductCodeAsync(input.ProductCode, entity.Id);
|
await ValidateProductCodeAsync(input.ProductCode, entity.Id);
|
||||||
|
await FreeSoftDeletedProductCodeIfNeededAsync(input.ProductCode.Trim(), entity.Id);
|
||||||
ApplyProductInput(entity, input);
|
ApplyProductInput(entity, input);
|
||||||
await SalesProductRepository.UpdateAsync(entity);
|
await SalesProductRepository.UpdateAsync(entity);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>
|
||||||
/// 获取服务渠道,不存在时直接抛异常。
|
/// 获取服务渠道,不存在时直接抛异常。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -73,6 +73,16 @@ public partial class ServiceChannelService : ApplicationService
|
|||||||
public async Task CreateAsync(ServiceChannelSaveInput input)
|
public async Task CreateAsync(ServiceChannelSaveInput input)
|
||||||
{
|
{
|
||||||
await ValidateChannelCodeAsync(input.ChannelCode, null);
|
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();
|
var entity = new ServiceChannel();
|
||||||
ApplyInput(entity, input);
|
ApplyInput(entity, input);
|
||||||
await ServiceChannelRepository.InsertAsync(entity);
|
await ServiceChannelRepository.InsertAsync(entity);
|
||||||
@ -88,6 +98,7 @@ public partial class ServiceChannelService : ApplicationService
|
|||||||
{
|
{
|
||||||
var entity = await GetEntityOrThrowAsync(input.Id);
|
var entity = await GetEntityOrThrowAsync(input.Id);
|
||||||
await ValidateChannelCodeAsync(input.ChannelCode, entity.Id);
|
await ValidateChannelCodeAsync(input.ChannelCode, entity.Id);
|
||||||
|
await FreeSoftDeletedChannelCodeIfNeededAsync(input.ChannelCode.Trim(), entity.Id);
|
||||||
ApplyInput(entity, input);
|
ApplyInput(entity, input);
|
||||||
await ServiceChannelRepository.UpdateAsync(entity);
|
await ServiceChannelRepository.UpdateAsync(entity);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -178,6 +178,12 @@ public class CustomerService : ApplicationService
|
|||||||
NormalizeRequiredText(input.Email, "邮箱"),
|
NormalizeRequiredText(input.Email, "邮箱"),
|
||||||
WeChatRegistrationFieldNormalizer.EmailMaxLength);
|
WeChatRegistrationFieldNormalizer.EmailMaxLength);
|
||||||
|
|
||||||
|
await FreeSoftDeletedCustomerIdentityIfNeededAsync(
|
||||||
|
customer.CustomerCode,
|
||||||
|
phone,
|
||||||
|
email,
|
||||||
|
excludeId: customer.Id);
|
||||||
|
|
||||||
var duplicatedPhone = await CustomerRepository.GetByPhoneAsync(phone, cancellationToken);
|
var duplicatedPhone = await CustomerRepository.GetByPhoneAsync(phone, cancellationToken);
|
||||||
if (duplicatedPhone != null && duplicatedPhone.Id != customer.Id)
|
if (duplicatedPhone != null && duplicatedPhone.Id != customer.Id)
|
||||||
{
|
{
|
||||||
@ -216,6 +222,10 @@ public class CustomerService : ApplicationService
|
|||||||
{
|
{
|
||||||
var normalized = await NormalizeCreateCustomerInputAsync(input, "客户编号", "客户名称");
|
var normalized = await NormalizeCreateCustomerInputAsync(input, "客户编号", "客户名称");
|
||||||
|
|
||||||
|
await FreeSoftDeletedCustomerIdentityIfNeededAsync(
|
||||||
|
normalized.CustomerCode,
|
||||||
|
normalized.Phone,
|
||||||
|
normalized.Email);
|
||||||
await EnsureCustomerIdentityUniqueAsync(normalized.CustomerCode, normalized.Phone, normalized.Email);
|
await EnsureCustomerIdentityUniqueAsync(normalized.CustomerCode, normalized.Phone, normalized.Email);
|
||||||
|
|
||||||
var customerRoleId = await GetCustomerRoleIdOrThrowAsync();
|
var customerRoleId = await GetCustomerRoleIdOrThrowAsync();
|
||||||
@ -268,6 +278,10 @@ public class CustomerService : ApplicationService
|
|||||||
var normalized = await NormalizeCreateCustomerInputAsync(input, "子客户编号", "子客户名称");
|
var normalized = await NormalizeCreateCustomerInputAsync(input, "子客户编号", "子客户名称");
|
||||||
var permissions = await NormalizeAndValidateSubCustomerPermissionsAsync(input.Permissions);
|
var permissions = await NormalizeAndValidateSubCustomerPermissionsAsync(input.Permissions);
|
||||||
|
|
||||||
|
await FreeSoftDeletedCustomerIdentityIfNeededAsync(
|
||||||
|
normalized.CustomerCode,
|
||||||
|
normalized.Phone,
|
||||||
|
normalized.Email);
|
||||||
await EnsureCustomerIdentityUniqueAsync(normalized.CustomerCode, normalized.Phone, normalized.Email);
|
await EnsureCustomerIdentityUniqueAsync(normalized.CustomerCode, normalized.Phone, normalized.Email);
|
||||||
|
|
||||||
var user = await CreateRbacUserAsync(input, normalized);
|
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)
|
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);
|
var duplicatedCode = await CustomerRepository.GetByCustomerCodeAsync(customerCode);
|
||||||
if (duplicatedCode != null && duplicatedCode.Id != id)
|
if (duplicatedCode != null && duplicatedCode.Id != id)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -64,7 +64,22 @@ public class KbCategoryService : ApplicationService
|
|||||||
throw new BusinessException($"分类编码已存在:{code}");
|
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.Code = code;
|
||||||
entity.Name = name;
|
entity.Name = name;
|
||||||
entity.SortOrder = input.SortOrder;
|
entity.SortOrder = input.SortOrder;
|
||||||
|
|||||||
@ -132,14 +132,10 @@ public class DictService : ApplicationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
entity ??= await DictTypeRepository.GetByDictTypeAsync(dictType);
|
entity ??= await DictTypeRepository.GetByDictTypeAsync(dictType);
|
||||||
|
// 软删后列表查不到,但 uk_dict_type_code 仍占坑;重建时恢复原行
|
||||||
|
entity ??= await DictTypeRepository.GetByDictTypeIncludingDeletedAsync(dictType);
|
||||||
if (entity == null)
|
if (entity == null)
|
||||||
{
|
{
|
||||||
var existedType = await DictTypeRepository.GetByDictTypeAsync(dictType);
|
|
||||||
if (existedType != null)
|
|
||||||
{
|
|
||||||
throw new BusinessException("字典类型已存在");
|
|
||||||
}
|
|
||||||
|
|
||||||
await DictTypeRepository.InsertAsync(new DictTypeMeta
|
await DictTypeRepository.InsertAsync(new DictTypeMeta
|
||||||
{
|
{
|
||||||
DictType = dictType,
|
DictType = dictType,
|
||||||
@ -151,13 +147,19 @@ public class DictService : ApplicationService
|
|||||||
|
|
||||||
if (!string.Equals(entity.DictType, dictType, StringComparison.OrdinalIgnoreCase))
|
if (!string.Equals(entity.DictType, dictType, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var duplicate = await DictTypeRepository.GetByDictTypeAsync(dictType);
|
var duplicate = await DictTypeRepository.GetByDictTypeIncludingDeletedAsync(dictType);
|
||||||
if (duplicate != null && duplicate.Id != entity.Id)
|
if (duplicate != null && duplicate.Id != entity.Id && !duplicate.IsDeleted)
|
||||||
{
|
{
|
||||||
throw new BusinessException("字典类型已存在");
|
throw new BusinessException("字典类型已存在");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (duplicate != null && duplicate.Id != entity.Id && duplicate.IsDeleted)
|
||||||
|
{
|
||||||
|
throw new BusinessException("字典类型编码与已删除记录冲突,请换编码或联系管理员恢复");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entity.IsDeleted = false;
|
||||||
entity.DictType = dictType;
|
entity.DictType = dictType;
|
||||||
entity.Remark = remark;
|
entity.Remark = remark;
|
||||||
entity.TypeSort = input.TypeSort;
|
entity.TypeSort = input.TypeSort;
|
||||||
@ -317,6 +319,14 @@ public class DictService : ApplicationService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var deleted = await DictTypeRepository.GetByDictTypeIncludingDeletedAsync(dictType);
|
||||||
|
if (deleted != null)
|
||||||
|
{
|
||||||
|
deleted.IsDeleted = false;
|
||||||
|
await DictTypeRepository.UpdateAsync(deleted);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await DictTypeRepository.InsertAsync(new DictTypeMeta
|
await DictTypeRepository.InsertAsync(new DictTypeMeta
|
||||||
{
|
{
|
||||||
DictType = dictType,
|
DictType = dictType,
|
||||||
|
|||||||
@ -61,9 +61,26 @@ public class SystemOtherConfigService : ApplicationService
|
|||||||
public async Task CreateAsync(SystemOtherConfigCreateInput input)
|
public async Task CreateAsync(SystemOtherConfigCreateInput input)
|
||||||
{
|
{
|
||||||
await ValidateInputAsync(input, null);
|
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
|
await SystemOtherConfigRepository.InsertAsync(new SystemOtherConfig
|
||||||
{
|
{
|
||||||
ConfigCode = input.ConfigCode.Trim(),
|
ConfigCode = configCode,
|
||||||
ConfigName = input.ConfigName.Trim(),
|
ConfigName = input.ConfigName.Trim(),
|
||||||
Enabled = input.Enabled,
|
Enabled = input.Enabled,
|
||||||
BaseUrl = NormalizeOptional(input.BaseUrl),
|
BaseUrl = NormalizeOptional(input.BaseUrl),
|
||||||
@ -82,8 +99,16 @@ public class SystemOtherConfigService : ApplicationService
|
|||||||
{
|
{
|
||||||
var entity = await GetConfigOrThrowAsync(input.Id);
|
var entity = await GetConfigOrThrowAsync(input.Id);
|
||||||
await ValidateInputAsync(input, entity.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);
|
var clearWeChatAccessToken = ShouldClearWeChatAccessToken(entity, input);
|
||||||
entity.ConfigCode = input.ConfigCode.Trim();
|
entity.ConfigCode = configCode;
|
||||||
entity.ConfigName = input.ConfigName.Trim();
|
entity.ConfigName = input.ConfigName.Trim();
|
||||||
entity.Enabled = input.Enabled;
|
entity.Enabled = input.Enabled;
|
||||||
entity.BaseUrl = NormalizeOptional(input.BaseUrl);
|
entity.BaseUrl = NormalizeOptional(input.BaseUrl);
|
||||||
|
|||||||
@ -81,15 +81,29 @@ public class WarehouseService : ApplicationService
|
|||||||
[HttpPost("/system/warehouse/create")]
|
[HttpPost("/system/warehouse/create")]
|
||||||
public async Task CreateAsync(CreateWarehouseInput input)
|
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)
|
if (duplicatedWarehouse != null)
|
||||||
{
|
{
|
||||||
throw new BusinessException("仓库名称已存在");
|
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
|
var entity = new WarehouseAddress
|
||||||
{
|
{
|
||||||
WarehouseName = input.WarehouseName,
|
WarehouseName = warehouseName,
|
||||||
WarehouseType = input.WarehouseType,
|
WarehouseType = input.WarehouseType,
|
||||||
Recipient = input.Recipient,
|
Recipient = input.Recipient,
|
||||||
ContactPhone = input.ContactPhone,
|
ContactPhone = input.ContactPhone,
|
||||||
@ -108,13 +122,21 @@ public class WarehouseService : ApplicationService
|
|||||||
public async Task UpdateAsync(UpdateWarehouseInput input)
|
public async Task UpdateAsync(UpdateWarehouseInput input)
|
||||||
{
|
{
|
||||||
var entity = await GetWarehouseOrThrowAsync(input.Id);
|
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)
|
if (duplicatedWarehouse != null && duplicatedWarehouse.Id != entity.Id)
|
||||||
{
|
{
|
||||||
throw new BusinessException("仓库名称已存在");
|
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.WarehouseType = input.WarehouseType;
|
||||||
entity.Recipient = input.Recipient;
|
entity.Recipient = input.Recipient;
|
||||||
entity.ContactPhone = input.ContactPhone;
|
entity.ContactPhone = input.ContactPhone;
|
||||||
|
|||||||
@ -63,7 +63,12 @@ public partial class WarehouseService
|
|||||||
}
|
}
|
||||||
else
|
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 =>
|
var duplicate = await BinLocationRepository.FirstOrDefaultAsync(x =>
|
||||||
@ -73,13 +78,26 @@ public partial class WarehouseService
|
|||||||
throw new BusinessException("库位编码已存在");
|
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.BinCode = binCode;
|
||||||
entity.BinName = string.IsNullOrWhiteSpace(input.BinName) ? null : input.BinName.Trim();
|
entity.BinName = string.IsNullOrWhiteSpace(input.BinName) ? null : input.BinName.Trim();
|
||||||
entity.ZoneCode = string.IsNullOrWhiteSpace(input.ZoneCode) ? null : input.ZoneCode.Trim();
|
entity.ZoneCode = string.IsNullOrWhiteSpace(input.ZoneCode) ? null : input.ZoneCode.Trim();
|
||||||
entity.IsEnabled = input.IsEnabled;
|
entity.IsEnabled = input.IsEnabled;
|
||||||
entity.Remark = string.IsNullOrWhiteSpace(input.Remark) ? null : input.Remark.Trim();
|
entity.Remark = string.IsNullOrWhiteSpace(input.Remark) ? null : input.Remark.Trim();
|
||||||
|
|
||||||
if (input.Id > 0)
|
if (entity.Id > 0)
|
||||||
{
|
{
|
||||||
await BinLocationRepository.UpdateAsync(entity);
|
await BinLocationRepository.UpdateAsync(entity);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -105,7 +105,10 @@ public partial class WarehouseService
|
|||||||
}
|
}
|
||||||
else
|
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 =>
|
var duplicate = await SkuRepository.FirstOrDefaultAsync(x =>
|
||||||
@ -115,6 +118,17 @@ public partial class WarehouseService
|
|||||||
throw new BusinessException("SKU 编码已存在");
|
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.SkuCode = skuCode;
|
||||||
entity.SkuName = skuName;
|
entity.SkuName = skuName;
|
||||||
entity.SkuNameEn = string.IsNullOrWhiteSpace(input.SkuNameEn) ? null : input.SkuNameEn.Trim();
|
entity.SkuNameEn = string.IsNullOrWhiteSpace(input.SkuNameEn) ? null : input.SkuNameEn.Trim();
|
||||||
@ -129,7 +143,7 @@ public partial class WarehouseService
|
|||||||
entity.HeightCm = input.HeightCm;
|
entity.HeightCm = input.HeightCm;
|
||||||
entity.Remark = string.IsNullOrWhiteSpace(input.Remark) ? null : input.Remark.Trim();
|
entity.Remark = string.IsNullOrWhiteSpace(input.Remark) ? null : input.Remark.Trim();
|
||||||
|
|
||||||
if (input.Id > 0)
|
if (entity.Id > 0)
|
||||||
{
|
{
|
||||||
await SkuRepository.UpdateAsync(entity);
|
await SkuRepository.UpdateAsync(entity);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,4 +6,8 @@ namespace Oms.Domain.AiAggregate.Repositories;
|
|||||||
public interface IAiSkillRepository : IRepository<AiSkill>
|
public interface IAiSkillRepository : IRepository<AiSkill>
|
||||||
{
|
{
|
||||||
Task<AiSkill?> GetBySkillKeyAsync(string skillKey, CancellationToken cancellationToken = default);
|
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?> GetByProductCodeAsync(string productCode, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
Task<SalesProduct?> GetByProductCodeIncludingDeletedAsync(
|
||||||
|
string productCode,
|
||||||
|
CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task<bool> HasProductCodeAsync(string productCode, CancellationToken cancellationToken = default);
|
Task<bool> HasProductCodeAsync(string productCode, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task<List<SalesProductPrice>> GetPricesAsync(int salesProductId, 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?> GetByChannelCodeAsync(string channelCode, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
Task<ServiceChannel?> GetByChannelCodeIncludingDeletedAsync(
|
||||||
|
string channelCode,
|
||||||
|
CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task<bool> HasChannelCodeAsync(string channelCode, CancellationToken cancellationToken = default);
|
Task<bool> HasChannelCodeAsync(string channelCode, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task<List<ServiceChannelGroup>> GetGroupsAsync(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?> GetByCustomerCodeAsync(string customerCode, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
Task<Customer?> GetByCustomerCodeIncludingDeletedAsync(
|
||||||
|
string customerCode,
|
||||||
|
CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task<Customer?> GetByPhoneAsync(string phone, 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?> GetByEmailAsync(string email, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
Task<Customer?> GetByEmailIncludingDeletedAsync(string email, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task<Customer?> GetByWechatOpenidAsync(string wechatOpenid, CancellationToken cancellationToken = default);
|
Task<Customer?> GetByWechatOpenidAsync(string wechatOpenid, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task<bool> ExistsPhoneAsync(string phone, 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?> 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);
|
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>
|
public interface IDictTypeRepository : IRepository<DictTypeMeta>
|
||||||
{
|
{
|
||||||
Task<DictTypeMeta?> GetByDictTypeAsync(string dictType, CancellationToken cancellationToken = default);
|
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>
|
public interface ISystemOtherConfigRepository : IRepository<SystemOtherConfig>
|
||||||
{
|
{
|
||||||
Task<SystemOtherConfig?> GetByConfigCodeAsync(string configCode, CancellationToken cancellationToken = default);
|
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?> GetByWarehouseNameAsync(string warehouseName, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
Task<WarehouseAddress?> GetByWarehouseNameIncludingDeletedAsync(
|
||||||
|
string warehouseName,
|
||||||
|
CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task<bool> ExistsWarehouseNameAsync(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;
|
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>;
|
public interface ICInventoryRepository : IRepository<CInventory>;
|
||||||
|
|
||||||
|
|||||||
@ -12,4 +12,15 @@ public class AiSkillRepository
|
|||||||
string skillKey,
|
string skillKey,
|
||||||
CancellationToken cancellationToken = default) =>
|
CancellationToken cancellationToken = default) =>
|
||||||
FirstOrDefaultAsync(x => x.SkillKey == skillKey, cancellationToken);
|
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);
|
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)
|
public Task<bool> HasProductCodeAsync(string productCode, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return AnyAsync(x => x.ProductCode == productCode, cancellationToken);
|
return AnyAsync(x => x.ProductCode == productCode, cancellationToken);
|
||||||
|
|||||||
@ -13,6 +13,17 @@ public class ServiceChannelRepository : OmsSqlSugarRepository<ServiceChannel>, I
|
|||||||
return FirstOrDefaultAsync(x => x.ChannelCode == channelCode, cancellationToken);
|
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)
|
public Task<bool> HasChannelCodeAsync(string channelCode, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return AnyAsync(x => x.ChannelCode == channelCode, cancellationToken);
|
return AnyAsync(x => x.ChannelCode == channelCode, cancellationToken);
|
||||||
|
|||||||
@ -12,16 +12,49 @@ public class CustomerRepository : OmsSqlSugarRepository<Customer>, ICustomerRepo
|
|||||||
return FirstOrDefaultAsync(x => x.CustomerCode == customerCode, cancellationToken);
|
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)
|
public Task<Customer?> GetByPhoneAsync(string phone, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return FirstOrDefaultAsync(x => x.Phone == phone, cancellationToken);
|
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)
|
public Task<Customer?> GetByEmailAsync(string email, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return FirstOrDefaultAsync(x => x.Email == email, cancellationToken);
|
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)
|
public Task<Customer?> GetByWechatOpenidAsync(string wechatOpenid, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return FirstOrDefaultAsync(x => x.WechatOpenid == wechatOpenid, cancellationToken);
|
return FirstOrDefaultAsync(x => x.WechatOpenid == wechatOpenid, cancellationToken);
|
||||||
|
|||||||
@ -11,6 +11,17 @@ public class KbCategoryRepository
|
|||||||
public Task<KbCategory?> GetByCodeAsync(string code, CancellationToken cancellationToken = default) =>
|
public Task<KbCategory?> GetByCodeAsync(string code, CancellationToken cancellationToken = default) =>
|
||||||
FirstOrDefaultAsync(x => x.Code == code, cancellationToken);
|
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(
|
public async Task<bool> ExistsCodeAsync(
|
||||||
string code,
|
string code,
|
||||||
int? excludeId = null,
|
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);
|
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);
|
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);
|
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)
|
public Task<bool> ExistsWarehouseNameAsync(string warehouseName, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return AnyAsync(x => x.WarehouseName == warehouseName, cancellationToken);
|
return AnyAsync(x => x.WarehouseName == warehouseName, cancellationToken);
|
||||||
|
|||||||
@ -5,9 +5,35 @@ using Oms.SqlSugarCore.Repositories;
|
|||||||
|
|
||||||
namespace Oms.SqlSugarCore.Warehouse;
|
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;
|
public class CInventoryRepository : OmsSqlSugarRepository<CInventory>, ICInventoryRepository, IScopedDependency;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user