| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- namespace Admin.NET.Plugin.AiDOP.Rule;
- /// <summary>
- /// 规则配置只读查询接口。研发阶段首版只开放 S3 / DELIVERY_GENERATE。
- /// </summary>
- [ApiDescriptionSettings(Order = 330, Description = "规则配置查询")]
- [Route("api/RuleConfig")]
- [AllowAnonymous]
- [NonUnify]
- public class RuleConfigQueryService : IDynamicApiController, ITransient
- {
- private readonly RuleConfigService _ruleConfigService;
- private readonly UserManager _userManager;
- private readonly ISqlSugarClient _db;
- public RuleConfigQueryService(RuleConfigService ruleConfigService, UserManager userManager, ISqlSugarClient db)
- {
- _ruleConfigService = ruleConfigService;
- _userManager = userManager;
- _db = db;
- }
- [DisplayName("查询当前生效规则")]
- [HttpGet("effective-options")]
- public async Task<object> GetEffectiveOptions([FromQuery] RuleConfigQueryInput input)
- {
- var moduleCode = string.IsNullOrWhiteSpace(input.ModuleCode) ? "S3" : input.ModuleCode.Trim();
- var scenarioCode = string.IsNullOrWhiteSpace(input.ScenarioCode) ? "DELIVERY_GENERATE" : input.ScenarioCode.Trim();
- if (!string.Equals(moduleCode, "S3", StringComparison.OrdinalIgnoreCase)
- || !string.Equals(scenarioCode, "DELIVERY_GENERATE", StringComparison.OrdinalIgnoreCase))
- {
- throw Oops.Oh("当前只支持查询 S3 / DELIVERY_GENERATE 规则配置");
- }
- var tenantId = input.TenantId > 0 ? input.TenantId : _userManager.TenantId;
- var factoryId = input.FactoryId > 0 ? input.FactoryId : null;
- return await _ruleConfigService.ResolveS3DeliveryGenerateSnapshotAsync(tenantId, factoryId);
- }
- [DisplayName("保存S3交货单生成规则")]
- [HttpPost("s3-delivery-generate/save")]
- public async Task<object> SaveS3DeliveryGenerate([FromBody] S3DeliveryGenerateRuleSaveInput input)
- {
- var tenantId = input.TenantId > 0 ? input.TenantId : 0;
- var factoryId = input.FactoryId > 0 ? input.FactoryId.Value : 0;
- var profile = (await _db.Ado.SqlQueryAsync<RuleProfileIdRow>(
- """
- SELECT id AS Id
- FROM ado_rule_profile
- WHERE module_code='S3'
- AND scenario_code='DELIVERY_GENERATE'
- AND tenant_id=@TenantId
- AND factory_id=@FactoryId
- AND is_enabled=1
- ORDER BY version DESC, id DESC
- LIMIT 1
- """,
- new SugarParameter("@TenantId", tenantId),
- new SugarParameter("@FactoryId", factoryId))).FirstOrDefault();
- if (profile == null || profile.Id <= 0)
- {
- throw Oops.Oh($"未找到 S3 / DELIVERY_GENERATE 规则方案:tenantId={tenantId},factoryId={factoryId}");
- }
- var values = BuildS3RuleValues(input.Options);
- if (values.Count == 0) throw Oops.Oh("没有可保存的规则项");
- var now = DateTime.Now;
- var account = _userManager.Account ?? "system";
- try
- {
- _db.Ado.BeginTran();
- foreach (var item in values)
- {
- var affected = await _db.Ado.ExecuteCommandAsync(
- """
- UPDATE ado_rule_item
- SET rule_value=@RuleValue,
- updated_at=@UpdatedAt,
- updated_by=@UpdatedBy
- WHERE profile_id=@ProfileId
- AND rule_code=@RuleCode
- AND is_enabled=1
- """,
- new SugarParameter("@RuleValue", item.Value),
- new SugarParameter("@UpdatedAt", now),
- new SugarParameter("@UpdatedBy", account),
- new SugarParameter("@ProfileId", profile.Id),
- new SugarParameter("@RuleCode", item.Key));
- if (affected <= 0) throw Oops.Oh($"规则项不存在或未启用:{item.Key}");
- }
- _db.Ado.CommitTran();
- }
- catch
- {
- _db.Ado.RollbackTran();
- throw;
- }
- return await _ruleConfigService.ResolveS3DeliveryGenerateSnapshotAsync(tenantId, factoryId == 0 ? null : factoryId);
- }
- private static Dictionary<string, string> BuildS3RuleValues(S3DeliveryGenerateRuleOptionsInput options)
- {
- if (options == null) throw Oops.Oh("规则参数不能为空");
- var values = new Dictionary<string, string>();
- if (options.QuotaRequiredTotal.HasValue)
- {
- if (options.QuotaRequiredTotal.Value < 0 || options.QuotaRequiredTotal.Value > 100) throw Oops.Oh("配额合计要求必须在 0-100 之间");
- values["quotaRequiredTotal"] = options.QuotaRequiredTotal.Value.ToString("0.####", System.Globalization.CultureInfo.InvariantCulture);
- }
- if (options.QuotaTolerance.HasValue)
- {
- if (options.QuotaTolerance.Value < 0) throw Oops.Oh("配额误差容忍不能小于 0");
- values["quotaTolerance"] = options.QuotaTolerance.Value.ToString("0.########", System.Globalization.CultureInfo.InvariantCulture);
- }
- if (options.PoBuyerCodes != null) values["poBuyerCodes"] = SerializeStringArray(NormalizeStringArray(options.PoBuyerCodes, "普通 PO 采购组"));
- if (options.DoUsages != null) values["doUsages"] = SerializeStringArray(NormalizeStringArray(options.DoUsages, "DO 可用供应类别"));
- if (options.DefaultLeadDays.HasValue)
- {
- if (options.DefaultLeadDays.Value < 0 || options.DefaultLeadDays.Value > 365) throw Oops.Oh("默认提前期必须在 0-365 天之间");
- values["defaultLeadDays"] = options.DefaultLeadDays.Value.ToString();
- }
- if (options.EnablePackagingRoundUp.HasValue) values["enablePackagingRoundUp"] = ToRuleBool(options.EnablePackagingRoundUp.Value);
- if (options.ShortageCreatePr.HasValue) values["shortageCreatePr"] = ToRuleBool(options.ShortageCreatePr.Value);
- if (options.EnablePrMerge.HasValue) values["enablePrMerge"] = ToRuleBool(options.EnablePrMerge.Value);
- if (options.EnableRequireGoodsToPo.HasValue) values["enableRequireGoodsToPo"] = ToRuleBool(options.EnableRequireGoodsToPo.Value);
- if (options.EnableExternalPushTracking.HasValue) values["enableExternalPushTracking"] = ToRuleBool(options.EnableExternalPushTracking.Value);
- return values;
- }
- private static List<string> NormalizeStringArray(IEnumerable<string> value, string label)
- {
- var list = value.Select(x => (x ?? string.Empty).Trim()).Where(x => !string.IsNullOrWhiteSpace(x)).Distinct().ToList();
- if (list.Count == 0) throw Oops.Oh($"{label}不能为空");
- return list;
- }
- private static string SerializeStringArray(List<string> value)
- {
- return System.Text.Json.JsonSerializer.Serialize(value);
- }
- private static string ToRuleBool(bool value)
- {
- return value ? "true" : "false";
- }
- private sealed class RuleProfileIdRow
- {
- public long Id { get; set; }
- }
- }
- public sealed class RuleConfigQueryInput
- {
- public string? ModuleCode { get; set; }
- public string? ScenarioCode { get; set; }
- public long TenantId { get; set; }
- public long? FactoryId { get; set; }
- }
- public sealed class S3DeliveryGenerateRuleSaveInput
- {
- public long TenantId { get; set; }
- public long? FactoryId { get; set; }
- public S3DeliveryGenerateRuleOptionsInput Options { get; set; } = new();
- }
- public sealed class S3DeliveryGenerateRuleOptionsInput
- {
- public decimal? QuotaRequiredTotal { get; set; }
- public decimal? QuotaTolerance { get; set; }
- public List<string>? PoBuyerCodes { get; set; }
- public List<string>? DoUsages { get; set; }
- public int? DefaultLeadDays { get; set; }
- public bool? EnablePackagingRoundUp { get; set; }
- public bool? ShortageCreatePr { get; set; }
- public bool? EnablePrMerge { get; set; }
- public bool? EnableRequireGoodsToPo { get; set; }
- public bool? EnableExternalPushTracking { get; set; }
- }
|