Explorar o código

Merge branch 'test' into test_Guardian

田爽 hai 2 semanas
pai
achega
c95962aec5
Modificáronse 23 ficheiros con 560 adicións e 390 borrados
  1. 213 190
      src/Hotline.Api/Controllers/OrderController.cs
  2. 115 115
      src/Hotline.Api/Controllers/OrderRevocationController.cs
  3. 2 3
      src/Hotline.Api/Controllers/TestController.cs
  4. 15 15
      src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs
  5. 2 1
      src/Hotline.Application/OrderApp/OrderApplication.cs
  6. 34 24
      src/Hotline.Application/Snapshot/BiSnapshotApplication.cs
  7. 7 0
      src/Hotline.Application/Snapshot/Contracts/IOrderSnapshotApplication.cs
  8. 16 3
      src/Hotline.Application/Snapshot/RedPackApplication.cs
  9. 8 5
      src/Hotline.Application/Snapshot/SnapshotApplicationBase.cs
  10. 20 2
      src/Hotline.Application/Snapshot/SnapshotOrderApplication.cs
  11. 2 1
      src/Hotline.Application/StatisticalReport/OrderReportApplication.cs
  12. 5 0
      src/Hotline.Share/Dtos/FlowEngine/NextStepsDto.cs
  13. 5 0
      src/Hotline.Share/Dtos/Snapshot/RedPackDto.cs
  14. 1 2
      src/Hotline.Share/Dtos/Snapshot/StatisticsDto.cs
  15. 12 12
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  16. 1 1
      src/Hotline/SeedData/SystemDicDataSeedData.cs
  17. 5 0
      src/Hotline/Settings/SettingConstants.cs
  18. 1 1
      src/Hotline/Settings/TimeLimits/TimeLimitDomainService.cs
  19. 4 4
      src/Hotline/Validators/Order/AddOrderDtoValidator.cs
  20. 27 0
      test/Hotline.Tests/Application/BiSnapshotApplicationTest.cs
  21. 32 0
      test/Hotline.Tests/Application/OrderSnapshotApplicationTest.cs
  22. 5 1
      test/Hotline.Tests/Application/XingTangCallsSyncJobTest.cs
  23. 28 10
      test/Hotline.Tests/Mock/OrderServiceMock.cs

+ 213 - 190
src/Hotline.Api/Controllers/OrderController.cs

@@ -26,6 +26,7 @@ using Hotline.OrderTranspond;
 using Hotline.Push.FWMessage;
 using Hotline.Push.Notifies;
 using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.Repository.SqlSugar.Orders;
 using Hotline.Repository.SqlSugar.Ts;
 using Hotline.SeedData;
 using Hotline.Settings;
@@ -2283,6 +2284,12 @@ public class OrderController : BaseController
 
         if (model.BeforeDelay != null)
         {
+            var expiredTimeBase = DateTime.Now;
+            if (_appOptions.Value.IsZiGong)
+            {
+                expiredTimeBase = order.ExpiredTime.Value;
+            }
+
             //model.AfterDelay = _timeLimitDomainService
             var startTime = DateTime.Now;
             if (order.CenterToOrgTime.HasValue)
@@ -2291,7 +2298,7 @@ public class OrderController : BaseController
             }
 
             model.AfterDelay = (await _expireTime
-                .CalcEndTime(DateTime.Now, startTime, delaydto.DelayUnit, delaydto.DelayNum, order.AcceptTypeCode))?.EndTime; //todo
+                .CalcEndTime(expiredTimeBase, startTime, delaydto.DelayUnit, delaydto.DelayNum, order.AcceptTypeCode))?.EndTime; //todo
         }
 
         model.ApplyDelayTime = DateTime.Now;
@@ -2351,110 +2358,6 @@ public class OrderController : BaseController
     /// <summary>
     /// 批量审批延期
     /// </summary>
-
-    //public async Task<string> BatchAuditDelay([FromBody] BatchDelayNextFlowDto dto)
-    //{
-    //    var result = new StringBuilder();
-    //    var fail = 0;
-    //    var success = 0;
-    //    var workflow = dto.NextWorkflow;
-    //    foreach (var item in dto.DelayId)
-    //    {
-    //        try
-    //        {
-    //            if (workflow.NextHandlers.Any() && workflow.NextHandlers.Count() == 1)
-    //            {
-    //                var handler = workflow.NextHandlers.FirstOrDefault();
-    //                if (string.IsNullOrEmpty(handler.UserId))
-    //                {
-    //                    workflow.NextHandlers = new List<StepAssignInfo>();
-    //                }
-    //            }
-
-    //            var delay = await _orderDelayRepository.Queryable().Includes(x => x.Order).Where(x => x.Id == item)
-    //                .FirstAsync(HttpContext.RequestAborted);
-    //            workflow.WorkflowId = delay.WorkflowId;
-    //            var workflowEntuty = await _workflowDomainService.GetWorkflowAsync(workflow.WorkflowId, withDefine: true, withSteps: true,
-    //                cancellationToken: HttpContext.RequestAborted);
-    //            var currentStep = workflowEntuty.Steps.FirstOrDefault(d =>
-    //                d.Status == EWorkflowStepStatus.WaitForAccept || d.Status == EWorkflowStepStatus.WaitForHandle);
-
-    //            NextStepsWithOpinionDto<NextStepOption> next = null;
-
-    //            try
-    //            {
-    //                next = await _workflowApplication.GetNextStepsAsync(delay.WorkflowId, HttpContext.RequestAborted);
-    //            }
-    //            catch (UserFriendlyException e)
-    //            {
-    //                if (e.Message.Contains("未找到对应节点"))
-    //                {
-    //                    result.Append("无权审核:" + delay.No);
-    //                    fail++;
-    //                }
-    //                else
-    //                {
-    //                    throw;
-    //                }
-    //            }
-
-    //            if (next == null) continue;
-
-    //            if (!delay.Order.IsProvince)
-    //            {
-    //                if (next.Steps.Any(x => x.Value == "省审批"))
-    //                {
-    //                    next.Steps.Remove(next.Steps.First(x => x.Value == "省审批"));
-    //                }
-    //            }
-
-    //            if (!_sessionContext.OrgIsCenter && currentStep.Name != "中心初审")
-    //            {
-    //                if (next.Steps.Any(x => x.Value == "中心终审"))
-    //                {
-    //                    next.Steps.Remove(next.Steps.First(x => x.Value == "中心终审"));
-    //                }
-    //            }
-
-    //            workflow.StepId = next.StepId;
-    //            workflow.ReviewResult = dto.IsPass ? EReviewResult.Approval : EReviewResult.Failed;
-
-    //            if (workflow.ReviewResult == EReviewResult.Approval)
-    //            {
-    //                var isBatch = next.Steps.Where(x => x.Value == workflow.NextStepName).Any();
-    //                if (isBatch)
-    //                {
-    //                    var step = next.Steps.Where(x => x.Value == workflow.NextStepName).FirstOrDefault();
-    //                    workflow.NextStepCode = step.Key;
-    //                    workflow.NextStepName = step.Value;
-    //                }
-    //                else
-    //                {
-    //                    result.Append("无权审核:" + delay.No);
-    //                    fail++;
-    //                    continue;
-    //                }
-
-    //                await _workflowDomainService.NextAsync(workflow, cancellationToken: HttpContext.RequestAborted);
-    //            }
-    //            else
-    //            {
-    //                var reject = workflow.Adapt<RejectDto>();
-    //                await _workflowApplication.RejectAsync(reject, HttpContext.RequestAborted);
-    //            }
-
-    //            success++;
-    //        }
-    //        catch (UserFriendlyException e)
-    //        {
-    //            result.Append(e.Message);
-    //            fail++;
-    //        }
-    //    }
-
-    //    return $"总共: {dto.DelayId.Length}, 成功: {success}, 失败: {fail}, 失败原因: {result.ToString()}";
-    //}
-
     [HttpPost("delay/batch_audit")]
     [LogFilter("批量审批延期")]
     //[LogFilterAlpha("延期审核")]
@@ -2463,33 +2366,33 @@ public class OrderController : BaseController
         var result = new StringBuilder();
         var fail = 0;
         var success = 0;
-        var workflowDto = dto.NextWorkflow;
-        var delays = await _orderDelayRepository.Queryable()
-            .Includes(x => x.Order)
-            .Includes(x => x.Workflow, d => d.WorkflowDefinition)
-            .Includes(x => x.Workflow, d => d.Steps)
-            .Includes(x => x.Workflow, d => d.Traces)
-            .Includes(x => x.Workflow, d => d.Countersigns)
-            .Where(x => dto.DelayId.Contains(x.Id))
-            .ToListAsync(HttpContext.RequestAborted);
-
-        if (!delays.Any())
-            return string.Empty;
-
-        var currentStep = delays.First().Workflow.Steps.FirstOrDefault(d =>
-            d.Status == EWorkflowStepStatus.WaitForAccept || d.Status == EWorkflowStepStatus.WaitForHandle);
-
-        var updateDelays = new List<OrderDelay>();
-        var updateOrders = new List<Order>();
-        foreach (var delay in delays)
+        var workflow = dto.NextWorkflow;
+        foreach (var item in dto.DelayId)
         {
             try
             {
+                //if (workflow.NextHandlers.Any() && workflow.NextHandlers.Count() == 1)
+                //{
+                //    var handler = workflow.NextHandlers.FirstOrDefault();
+                //    if (string.IsNullOrEmpty(handler.UserId))
+                //    {
+                //        workflow.NextHandlers = new List<StepAssignInfo>();
+                //    }
+                //}
+
+                var delay = await _orderDelayRepository.Queryable().Includes(x => x.Order).Where(x => x.Id == item)
+                    .FirstAsync(HttpContext.RequestAborted);
+                workflow.WorkflowId = delay.WorkflowId;
+                var workflowEntuty = await _workflowDomainService.GetWorkflowAsync(workflow.WorkflowId, withDefine: true, withSteps: true,
+                    cancellationToken: HttpContext.RequestAborted);
+                var currentStep = workflowEntuty.Steps.FirstOrDefault(d =>
+                    d.Status == EWorkflowStepStatus.WaitForAccept || d.Status == EWorkflowStepStatus.WaitForHandle);
+
                 NextStepsWithOpinionDto<NextStepOption> next = null;
 
                 try
                 {
-                    next = await _workflowApplication.GetNextStepsAsync(delay.Workflow, HttpContext.RequestAborted);
+                    next = await _workflowApplication.GetNextStepsAsync(delay.WorkflowId, HttpContext.RequestAborted);
                 }
                 catch (UserFriendlyException e)
                 {
@@ -2522,70 +2425,33 @@ public class OrderController : BaseController
                     }
                 }
 
-                workflowDto.StepId = next.StepId;
-                workflowDto.ReviewResult = dto.IsPass ? EReviewResult.Approval : EReviewResult.Failed;
+                workflow.StepId = next.StepId;
+                workflow.ReviewResult = dto.IsPass ? EReviewResult.Approval : EReviewResult.Failed;
 
-                if (dto.IsPass)
+                if (workflow.ReviewResult == EReviewResult.Approval)
                 {
-                    var step = next.Steps.FirstOrDefault(x => x.Value == workflowDto.NextStepName);
-                    if (step is null)
+                    var isBatch = next.Steps.Where(x => x.Value == workflow.NextStepName).Any();
+                    if (isBatch)
+                    {
+                        var step = next.Steps.Where(x => x.Value == workflow.NextStepName).FirstOrDefault();
+                        workflow.NextStepCode = step.Key;
+                        workflow.NextStepName = step.Value;
+                    }
+                    else
                     {
                         result.Append("无权审核:" + delay.No);
                         fail++;
                         continue;
                     }
 
-                    workflowDto.NextStepCode = step.Key;
-                    workflowDto.NextStepName = step.Value;
-
-                    //处理工单延期
-                    var order = delay.Order;
-                    var expiredTimeBase = DateTime.Now;
-                    if (_appOptions.Value.IsZiGong)
-                    {
-                        expiredTimeBase = order.ExpiredTime.Value;
-                    }
-
-                    var startTime = DateTime.Now;
-                    if (order.CenterToOrgTime.HasValue)
-                    {
-                        startTime = order.CenterToOrgTime!.Value;
-                    }
-
-                    var expiredTimeConfig =
-                        await _expireTime.CalcEndTime(expiredTimeBase, startTime, new TimeConfig(delay.DelayNum, delay.DelayUnit),
-                            order.AcceptTypeCode);
-                    order.ExpiredTime = expiredTimeConfig.ExpiredTime;
-                    order.NearlyExpiredTime = expiredTimeConfig.NearlyExpiredTime;
-                    order.NearlyExpiredTimeOne = expiredTimeConfig.NearlyExpiredTimeOne;
-                    //TODO发送短信即将超期
-                    if (delay.IsProDelay)
-                    {
-                        order.ExpiredTimeProvince = expiredTimeConfig.ExpiredTime;
-                    }
-
-                    updateOrders.Add(order);
-
-                    await _workflowDomainService.NextAsync(delay.Workflow, workflowDto,
-                        expiredTime: order.ExpiredTime,
-                        cancellationToken: HttpContext.RequestAborted);
-
-                    await _workflowDomainService.UpdateUnhandleExpiredTimeAsync(order.WorkflowId, order.ExpiredTime, HttpContext.RequestAborted);
-
-                    var orderDto = _mapper.Map<OrderDto>(order);
-                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
-                        cancellationToken: HttpContext.RequestAborted);
+                    await _workflowDomainService.NextAsync(workflow, cancellationToken: HttpContext.RequestAborted);
                 }
                 else
                 {
-                    var reject = workflowDto.Adapt<RejectDto>();
+                    var reject = workflow.Adapt<RejectDto>();
                     await _workflowApplication.RejectAsync(reject, HttpContext.RequestAborted);
                 }
 
-
-                delay.DelayState = dto.IsPass ? EDelayState.Pass : EDelayState.NoPass;
-                updateDelays.Add(delay);
-
                 success++;
             }
             catch (UserFriendlyException e)
@@ -2595,23 +2461,165 @@ public class OrderController : BaseController
             }
         }
 
+        return $"总共: {dto.DelayId.Length}, 成功: {success}, 失败: {fail}, 失败原因: {result.ToString()}";
+    }
 
-        await _orderDelayRepository.Updateable(updateDelays)
-            .UpdateColumns(d => d.DelayState)
-            .ExecuteCommandAsync(HttpContext.RequestAborted);
+    //[HttpPost("delay/batch_audit")]
+    //[LogFilter("批量审批延期")]
+    //public async Task<string> BatchAuditDelay([FromBody] BatchDelayNextFlowDto dto)
+    //{
+    //    var result = new StringBuilder();
+    //    var fail = 0;
+    //    var success = 0;
+    //    var workflowDto = dto.NextWorkflow;
+    //    var delays = await _orderDelayRepository.Queryable()
+    //        .Includes(x => x.Order)
+    //        .Includes(x => x.Workflow, d => d.WorkflowDefinition)
+    //        .Includes(x => x.Workflow, d => d.Steps)
+    //        .Includes(x => x.Workflow, d => d.Traces)
+    //        .Includes(x => x.Workflow, d => d.Countersigns)
+    //        .Where(x => dto.DelayId.Contains(x.Id))
+    //        .ToListAsync(HttpContext.RequestAborted);
+
+    //    if (!delays.Any())
+    //        return string.Empty;
+
+    //    var currentStep = delays.First().Workflow.Steps.FirstOrDefault(d =>
+    //        d.Status == EWorkflowStepStatus.WaitForAccept || d.Status == EWorkflowStepStatus.WaitForHandle);
+
+    //    var updateDelays = new List<OrderDelay>();
+    //    var updateOrders = new List<Order>();
+    //    foreach (var delay in delays)
+    //    {
+    //        try
+    //        {
+    //            NextStepsWithOpinionDto<NextStepOption> next = null;
 
-        await _orderRepository.Updateable(updateOrders)
-            .UpdateColumns(d => new
-            {
-                d.ExpiredTime,
-                d.NearlyExpiredTime,
-                d.NearlyExpiredTimeOne,
-                d.ExpiredTimeProvince
-            })
-            .ExecuteCommandAsync(HttpContext.RequestAborted);
+    //            try
+    //            {
+    //                next = await _workflowApplication.GetNextStepsAsync(delay.Workflow, HttpContext.RequestAborted);
+    //            }
+    //            catch (UserFriendlyException e)
+    //            {
+    //                if (e.Message.Contains("未找到对应节点"))
+    //                {
+    //                    result.Append("无权审核:" + delay.No);
+    //                    fail++;
+    //                }
+    //                else
+    //                {
+    //                    throw;
+    //                }
+    //            }
 
-        return $"总共: {dto.DelayId.Length}, 成功: {success}, 失败: {fail}, 失败原因: {result}";
-    }
+    //            if (next == null) continue;
+
+    //            if (!delay.Order.IsProvince)
+    //            {
+    //                if (next.Steps.Any(x => x.Value == "省审批"))
+    //                {
+    //                    next.Steps.Remove(next.Steps.First(x => x.Value == "省审批"));
+    //                }
+    //            }
+
+    //            if (!_sessionContext.OrgIsCenter && currentStep.Name != "中心初审")
+    //            {
+    //                if (next.Steps.Any(x => x.Value == "中心终审"))
+    //                {
+    //                    next.Steps.Remove(next.Steps.First(x => x.Value == "中心终审"));
+    //                }
+    //            }
+
+    //            workflowDto.StepId = next.StepId;
+    //            workflowDto.ReviewResult = dto.IsPass ? EReviewResult.Approval : EReviewResult.Failed;
+
+    //            if (dto.IsPass)
+    //            {
+    //                var step = next.Steps.FirstOrDefault(x => x.Value == workflowDto.NextStepName);
+    //                if (step is null)
+    //                {
+    //                    result.Append("无权审核:" + delay.No);
+    //                    fail++;
+    //                    continue;
+    //                }
+
+    //                workflowDto.NextStepCode = step.Key;
+    //                workflowDto.NextStepName = step.Value;
+
+    //                //处理工单延期
+    //                var order = delay.Order;
+    //                var expiredTimeBase = DateTime.Now;
+    //                if (_appOptions.Value.IsZiGong)
+    //                {
+    //                    expiredTimeBase = order.ExpiredTime.Value;
+    //                }
+
+    //                var startTime = DateTime.Now;
+    //                if (order.CenterToOrgTime.HasValue)
+    //                {
+    //                    startTime = order.CenterToOrgTime!.Value;
+    //                }
+
+    //                var expiredTimeConfig =
+    //                    await _expireTime.CalcEndTime(expiredTimeBase, startTime, new TimeConfig(delay.DelayNum, delay.DelayUnit),
+    //                        order.AcceptTypeCode);
+    //                order.ExpiredTime = expiredTimeConfig.ExpiredTime;
+    //                order.NearlyExpiredTime = expiredTimeConfig.NearlyExpiredTime;
+    //                order.NearlyExpiredTimeOne = expiredTimeConfig.NearlyExpiredTimeOne;
+    //                //TODO发送短信即将超期
+    //                if (delay.IsProDelay)
+    //                {
+    //                    order.ExpiredTimeProvince = expiredTimeConfig.ExpiredTime;
+    //                }
+
+    //                updateOrders.Add(order);
+
+    //                await _workflowDomainService.NextAsync(delay.Workflow, workflowDto,
+    //                    expiredTime: order.ExpiredTime,
+    //                    cancellationToken: HttpContext.RequestAborted);
+
+    //                await _workflowDomainService.UpdateUnhandleExpiredTimeAsync(order.WorkflowId, order.ExpiredTime, HttpContext.RequestAborted);
+
+    //                var orderDto = _mapper.Map<OrderDto>(order);
+    //                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
+    //                    cancellationToken: HttpContext.RequestAborted);
+    //            }
+    //            else
+    //            {
+    //                var reject = workflowDto.Adapt<RejectDto>();
+    //                await _workflowApplication.RejectAsync(reject, HttpContext.RequestAborted);
+    //            }
+
+
+    //            delay.DelayState = dto.IsPass ? EDelayState.Pass : EDelayState.NoPass;
+    //            updateDelays.Add(delay);
+
+    //            success++;
+    //        }
+    //        catch (UserFriendlyException e)
+    //        {
+    //            result.Append(e.Message);
+    //            fail++;
+    //        }
+    //    }
+
+
+    //    await _orderDelayRepository.Updateable(updateDelays)
+    //        .UpdateColumns(d => d.DelayState)
+    //        .ExecuteCommandAsync(HttpContext.RequestAborted);
+
+    //    await _orderRepository.Updateable(updateOrders)
+    //        .UpdateColumns(d => new
+    //        {
+    //            d.ExpiredTime,
+    //            d.NearlyExpiredTime,
+    //            d.NearlyExpiredTimeOne,
+    //            d.ExpiredTimeProvince
+    //        })
+    //        .ExecuteCommandAsync(HttpContext.RequestAborted);
+
+    //    return $"总共: {dto.DelayId.Length}, 成功: {success}, 失败: {fail}, 失败原因: {result}";
+    //}
 
 
 
@@ -3434,6 +3442,15 @@ public class OrderController : BaseController
                     orderScreen.Status = EScreenStatus.SendBack;
                     orderScreen.SendBackApply = true;
                     await _orderScreenRepository.UpdateAsync(orderScreen, cancellationToken: HttpContext.RequestAborted);
+
+                    //自贡任务 220 修改甄别截止申请日期的计算方式
+                    //甄别截止申请日期=回访时间+2个工作日  ,若退回到申请人节点,甄别截止申请日期=退回时间+2个工作日
+                    var orderVisitDetail = await _orderVisitedDetailRepository.GetAsync(p => p.Id == orderScreen.VisitDetailId, cancellationToken: HttpContext.RequestAborted);
+                    if (orderVisitDetail != null)
+                    {
+                        orderVisitDetail.ScreenByEndTime = (await _expireTime.CalcEndTime(DateTime.Now, DateTime.Now, ETimeType.WorkDay, 2, 0, 0)).EndTime;
+                        await _orderVisitedDetailRepository.UpdateAsync(orderVisitDetail, cancellationToken: HttpContext.RequestAborted);
+                    }
                 }
             }
             else
@@ -5356,6 +5373,10 @@ public class OrderController : BaseController
         if (orderId.NotNullOrEmpty())
         {
             dto.Opinion = await _typeCache.GetAsync($"tmp_opinion_{orderId}{_sessionContext.UserId}", HttpContext.RequestAborted);
+            if (!string.IsNullOrEmpty(dto.Opinion))
+            {
+                dto.Opinion = await _typeCache.GetAsync($"tmp_opinion_{orderId}{dto.StepId}{_sessionContext.UserId}", HttpContext.RequestAborted);
+            }
             dto.Content = (await _orderRepository.GetAsync(orderId, HttpContext.RequestAborted))?.Content;
         }
 
@@ -5897,7 +5918,9 @@ public class OrderController : BaseController
     public async Task TempSaveAsync([FromBody] StepTempInDto dto)
     {
         if (dto.OrderId.IsNullOrEmpty() || dto.Opinion.IsNullOrEmpty()) return;
-        await _typeCache.SetAsync($"tmp_opinion_{dto.OrderId}{_sessionContext.UserId}", dto.Opinion, TimeSpan.FromDays(3),
+        //获取配置
+        int days = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.TempOpinionDays)?.SettingValue[0]);
+        await _typeCache.SetAsync($"tmp_opinion_{dto.OrderId}{dto.StepId}{_sessionContext.UserId}", dto.Opinion, TimeSpan.FromDays(days),
             HttpContext.RequestAborted);
     }
 

+ 115 - 115
src/Hotline.Api/Controllers/OrderRevocationController.cs

@@ -37,10 +37,10 @@ namespace Hotline.Api.Controllers
         private readonly IRepository<User> _userRepository;
         private readonly IMediator _mediator;
         private readonly IWorkflowDomainService _workflowDomainService;
-		private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
+        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
 
 
-		public OrderRevocationController(IMapper mapper,
+        public OrderRevocationController(IMapper mapper,
             IRepository<OrderRevocation> orderRevocationRepository,
             IRepository<Order> orderRepository,
             ISessionContext sessionContext,
@@ -50,7 +50,7 @@ namespace Hotline.Api.Controllers
             IRepository<User> userRepository,
             IMediator mediator,
             IWorkflowDomainService workflowDomainService,
-			IOptionsSnapshot<AppConfiguration> appOptions)
+            IOptionsSnapshot<AppConfiguration> appOptions)
         {
             _mapper = mapper;
             _orderRevocationRepository = orderRevocationRepository;
@@ -62,8 +62,8 @@ namespace Hotline.Api.Controllers
             _userRepository = userRepository;
             _mediator = mediator;
             _workflowDomainService = workflowDomainService;
-			_appOptions = appOptions;
-		}
+            _appOptions = appOptions;
+        }
 
         /// <summary>
         /// 撤销件处理
@@ -80,140 +80,140 @@ namespace Hotline.Api.Controllers
                 throw UserFriendlyException.SameMessage("撤销说明不能为空!");
             int successNum = 0;
             int errorNum = 0;
-
-            foreach (var item in dto.Ids)
+            var orders = await _orderRepository.Queryable().Where(p => dto.Ids.Contains(p.Id)).ToListAsync();
+            if (orders != null && orders.Any())
             {
-                var order = await _orderRepository.GetAsync(p => p.Id == item, HttpContext.RequestAborted);
-                if (order != null)
+                foreach (var order in orders)
                 {
-                    //工单状态为会签中、退回审批中、特提审批中、已归档,则不能撤销
-                    if (order.Status == EOrderStatus.Countersigning
-                        || order.Status == EOrderStatus.SendBackAudit
-                        || order.Status == EOrderStatus.SpecialAudit
-                        || order.Status >= EOrderStatus.Filed)
-                    {
-                        errorNum++;
-                    }
-                    else
+                    if (order != null)
                     {
-                        //添加撤销件
-                        OrderRevocation orderRevocation = new()
+                        //工单状态为会签中、退回审批中、特提审批中、已归档,则不能撤销
+                        if (order.Status == EOrderStatus.Countersigning
+                            || order.Status == EOrderStatus.SendBackAudit
+                            || order.Status == EOrderStatus.SpecialAudit
+                            || order.Status >= EOrderStatus.Filed)
                         {
-                            OrderId = order.Id,
-                            No = order.No,
-                            RevocationReason = dto.RevocationReason,
-                            IsSendSms = dto.IsSendSms,
-                        };
-                        var id = await _orderRevocationRepository.AddAsync(orderRevocation, HttpContext.RequestAborted);
-                        if (!string.IsNullOrEmpty(id))
+                            errorNum++;
+                        }
+                        else
                         {
-                            #region 处理短信业务
-
-                            //如果需要发短信、处理短信业务
-                            if (dto.IsSendSms && !string.IsNullOrEmpty(order.WorkflowId))
+                            //添加撤销件
+                            OrderRevocation orderRevocation = new()
                             {
-                                //查询当前工单的实际办理节点,如果在热线中心不处理,如果在部门需要更新期满时间
-                                var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, withTraces: true,
-                                    cancellationToken: HttpContext.RequestAborted);
-                                var nowWorkflow = workflow.Steps.Where(p =>
-                                    p.Id == order.ActualHandleStepId && p.BusinessType >= EBusinessType.Department &&
-                                    p.BusinessType <= EBusinessType.DepartmentLeader).FirstOrDefault();
-                                //在部门才需要发送短信
-                                if (nowWorkflow != null && order.CenterToOrgTime.HasValue)
+                                OrderId = order.Id,
+                                No = order.No,
+                                RevocationReason = dto.RevocationReason,
+                                IsSendSms = dto.IsSendSms,
+                            };
+                            var id = await _orderRevocationRepository.AddAsync(orderRevocation, HttpContext.RequestAborted);
+                            if (!string.IsNullOrEmpty(id))
+                            {
+                                #region 处理短信业务
+
+                                //如果需要发短信、处理短信业务
+                                if (dto.IsSendSms && !string.IsNullOrEmpty(order.WorkflowId))
                                 {
-                                    //处理短信业务
-                                    var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
-                                    //查询部门所有账号
-                                    var userlist = await _userRepository.Queryable().Where(x =>
-                                        x.OrgId == order.CurrentHandleOrgId && !string.IsNullOrEmpty(x.PhoneNo) &&
-                                        x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
-                                    //发送短信
-                                    foreach (var user in userlist)
+                                    //查询当前工单的实际办理节点,如果在热线中心不处理,如果在部门需要更新期满时间
+                                    var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, withTraces: true,
+                                        cancellationToken: HttpContext.RequestAborted);
+                                    var nowWorkflow = workflow.Steps.Where(p =>
+                                        p.Id == order.ActualHandleStepId && p.BusinessType >= EBusinessType.Department &&
+                                        p.BusinessType <= EBusinessType.DepartmentLeader).FirstOrDefault();
+                                    //在部门才需要发送短信
+                                    if (nowWorkflow != null && order.CenterToOrgTime.HasValue)
                                     {
-                                        var messageDto = new Share.Dtos.Push.MessageDto
+                                        //处理短信业务
+                                        var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
+                                        //查询部门所有账号
+                                        var userlist = await _userRepository.Queryable().Where(x =>
+                                            x.OrgId == order.CurrentHandleOrgId && !string.IsNullOrEmpty(x.PhoneNo) &&
+                                            x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
+                                        //发送短信
+                                        foreach (var user in userlist)
                                         {
-                                            PushBusiness = EPushBusiness.OrderRevocationSms,
-                                            PushPlatform = EPushPlatform.Sms,
-                                            Name = user.Name,
-                                            TemplateCode = "1016",
-                                            Params = new List<string>() { order.No },
-                                            TelNumber = user.PhoneNo,
-                                        };
-                                        await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
+                                            var messageDto = new Share.Dtos.Push.MessageDto
+                                            {
+                                                PushBusiness = EPushBusiness.OrderRevocationSms,
+                                                PushPlatform = EPushPlatform.Sms,
+                                                Name = user.Name,
+                                                TemplateCode = "1016",
+                                                Params = new List<string>() { order.No },
+                                                TelNumber = user.PhoneNo,
+                                            };
+                                            await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
+                                        }
                                     }
                                 }
-                            }
 
-                            #endregion
+                                #endregion
 
-                            #region 处理流程业务
+                                #region 处理流程业务
 
-                            //处理流程业务
-                            //如果开启了流程直接归档,如果没开启流程,开启流程到归档
-                            if (string.IsNullOrEmpty(order.WorkflowId))
-                            {
-                                var startDto = new StartWorkflowDto
+                                //处理流程业务
+                                //如果开启了流程直接归档,如果没开启流程,开启流程到归档
+                                if (string.IsNullOrEmpty(order.WorkflowId))
                                 {
-                                    DefinitionModuleCode = WorkflowModuleConsts.OrderHandle,
-                                    Title = order.Title,
-                                    Opinion = dto.RevocationReason,
-                                };
-                                // await _workflowApplication.StartToEndAsync(startDto, order.Id, order.ExpiredTime, HttpContext.RequestAborted);
-                                await _workflowDomainService.StartToEndAsync(startDto, order.Id, order.ExpiredTime, HttpContext.RequestAborted);
-                            }
-                            else
-                            {
-                                if (_appOptions.Value.IsLuZhou)
+                                    var startDto = new StartWorkflowDto
+                                    {
+                                        DefinitionModuleCode = WorkflowModuleConsts.OrderHandle,
+                                        Title = order.Title,
+                                        Opinion = dto.RevocationReason,
+                                    };
+                                    // await _workflowApplication.StartToEndAsync(startDto, order.Id, order.ExpiredTime, HttpContext.RequestAborted);
+                                    await _workflowDomainService.StartToEndAsync(startDto, order.Id, order.ExpiredTime, HttpContext.RequestAborted);
+                                }
+                                else
                                 {
-									await _workflowDomainService.RecallToStartStepAsync(order.WorkflowId, dto.RevocationReason, order.ExpiredTime, order.Status >= EOrderStatus.Filed, EHandleMode.Revocation, cancellationToken: HttpContext.RequestAborted);
-								}
-								await _workflowDomainService.JumpToEndAsync(_sessionContext, order.WorkflowId, dto.RevocationReason,null, order.ExpiredTime, cancellationToken: HttpContext.RequestAborted);
-                            }
-
-                            #endregion
-
-                            #region 处理工单的一级部门和实际办理部门
-
-                            //处理工单的一级部门和实际办理部门
-                            var org = await _systemOrganizeRepository.GetAsync(p => p.Id == OrgSeedData.CenterId, HttpContext.RequestAborted);
-                            order.ActualHandleOrgAreaCode = org?.AreaCode;
-                            order.ActualHandleOrgAreaName = org?.AreaName;
-                            order.ActualHandleOrgCode = OrgSeedData.CenterId;
-                            order.ActualHandleOrgName = OrgSeedData.CenterName;
-                            order.OrgLevelOneCode = OrgSeedData.CenterId;
-                            order.OrgLevelOneName = OrgSeedData.CenterName;
-                            order.ActualHandlerName = _sessionContext.UserName;
-                            order.ActualHandleTime = DateTime.Now;
-                            order.ActualHandlerId = _sessionContext.UserId;
+                                    if (_appOptions.Value.IsLuZhou)
+                                    {
+                                        await _workflowDomainService.RecallToStartStepAsync(order.WorkflowId, dto.RevocationReason, order.ExpiredTime, order.Status >= EOrderStatus.Filed, EHandleMode.Revocation, cancellationToken: HttpContext.RequestAborted);
+                                    }
+                                    await _workflowDomainService.JumpToEndAsync(_sessionContext, order.WorkflowId, dto.RevocationReason, null, order.ExpiredTime, cancellationToken: HttpContext.RequestAborted);
+                                }
 
-                            await _orderRepository.Updateable(order).UpdateColumns(it => new
-                            {
-                                it.ActualHandleOrgName,
-                                it.ActualHandleOrgCode,
-                                it.OrgLevelOneCode,
-                                it.OrgLevelOneName,
-                                it.ActualHandleOrgAreaCode,
-                                it.ActualHandleOrgAreaName,
-                                it.ActualHandlerName,
-                                it.ActualHandleTime,
-                                it.ActualHandlerId
-                            }).ExecuteCommandAsync();
+                                #endregion
 
-                            #endregion
+                                #region 处理工单的一级部门和实际办理部门
 
+                                //处理工单的一级部门和实际办理部门
+                                var org = await _systemOrganizeRepository.GetAsync(p => p.Id == OrgSeedData.CenterId, HttpContext.RequestAborted);
+                                order.ActualHandleOrgAreaCode = org?.AreaCode;
+                                order.ActualHandleOrgAreaName = org?.AreaName;
+                                order.ActualHandleOrgCode = OrgSeedData.CenterId;
+                                order.ActualHandleOrgName = OrgSeedData.CenterName;
+                                order.OrgLevelOneCode = OrgSeedData.CenterId;
+                                order.OrgLevelOneName = OrgSeedData.CenterName;
+                                order.ActualHandlerName = _sessionContext.UserName;
+                                order.ActualHandleTime = DateTime.Now;
+                                order.ActualHandlerId = _sessionContext.UserId;
 
-                            successNum++;
+                                await _orderRepository.Updateable(order).UpdateColumns(it => new
+                                {
+                                    it.ActualHandleOrgName,
+                                    it.ActualHandleOrgCode,
+                                    it.OrgLevelOneCode,
+                                    it.OrgLevelOneName,
+                                    it.ActualHandleOrgAreaCode,
+                                    it.ActualHandleOrgAreaName,
+                                    it.ActualHandlerName,
+                                    it.ActualHandleTime,
+                                    it.ActualHandlerId
+                                }).ExecuteCommandAsync();
+
+                                #endregion
+
+                                successNum++;
+                            }
+                            else
+                                errorNum++;
                         }
-                        else
-                            errorNum++;
                     }
-                }
-                else
-                {
-                    errorNum++;
+                    else
+                    {
+                        errorNum++;
+                    }
                 }
             }
-
             OrderRevocationResponseDto responseDto = new OrderRevocationResponseDto()
             {
                 ErrorNum = errorNum,

+ 2 - 3
src/Hotline.Api/Controllers/TestController.cs

@@ -532,15 +532,14 @@ public class TestController : BaseController
         //var r = await _aiVisitService.QueryAiVisitTaskResult(batchId, DateTime.Parse("2024-07-28"), DateTime.Parse("2024-08-01"), HttpContext.RequestAborted);
 
         //var r = _timeLimitDomainService.CalcExpiredTime(DateTime.Now, EFlowDirection.CenterToCenter, batchId);
-        //var r = _timeLimitDomainService.CalcEndTime(DateTime.Parse("2024-09-12 14:45:47"), Share.Enums.Settings.ETimeType.WorkDay, 2, 80, 50);
+        var times = _timeLimitDomainService.CalcEndTime(DateTime.Parse("2025-04-13 23:55:57.050283"), Share.Enums.Settings.ETimeType.Day,60, 80, 50);
         //_capPublisher.PublishDelay((DateTime.Now.AddMinutes(2) - DateTime.Now), EventNames.OrderRelateCall, "123");
         //var times = await _expireTime.CalcExpiredTime(DateTime.Parse("2025-01-14 09:45:00"), DateTime.Parse("2025-01-07 09:16:53.691249"), EFlowDirection.CenterToOrg, new OrderTimeClacInfo() { AcceptTypeCode = "20" });
         //await _expireTime.CalcWorkTimeToDecimal(visit.VisitTime.Value, DateTime.Now, false);
         //var times = await _expireTime.CalcWorkTimeToDecimal(DateTime.Parse("2024-12-16 21:36:27"), DateTime.Parse("2024-12-17 12:47:05"), false);
         //var query = _userRepository.Queryable().Where(x => false);
         //await _capPublisher.PublishDelay(EventNames.OrderRelateCall, "123", cancellationToken: HttpContext.RequestAborted);
-        var times = await _expireTime.CalcWorkTimeEx(
-                       DateTime.Parse("2025-02-21 16:00:11.154098"), DateTime.Parse("2025-02-28 11:27:11.441577"), false);
+        //var times = await _expireTime.CalcExpiredTime(DateTime.Parse("2025-04-13 23:55:57.050283"), DateTime.Parse("2025-04-13 23:55:57.050283"), EFlowDirection.CenterToOrg,);
         return OpenResponse.Ok(times);
     }
 

+ 15 - 15
src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs

@@ -316,21 +316,21 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
                     // await _enforcementApplication.AddPassTheBuckOrderAsync(order, _sessionContext.OrgId, _sessionContext.OrgName, cancellationToken);
                     break;
                 case WorkflowModuleConsts.OrderDelay:
-                    // var delay = await _orderDelayRepository.GetAsync(workflow.ExternalId, cancellationToken);
-                    // if (delay != null)
-                    // {
-                    //     //delay.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
-                    //     delay.DelayState = isReviewPass ? EDelayState.Pass : EDelayState.NoPass;
-                    //     await _orderDelayRepository.Updateable(delay)
-                    //         .UpdateColumns(d => d.DelayState)
-                    //         .ExecuteCommandAsync(cancellationToken);
-                    //     if (isReviewPass)
-                    //     {
-                    //         //处理工单延期
-                    //         await _orderApplication.DelayOrderExpiredTimeAsync(delay.OrderId, delay.DelayNum,
-                    //             delay.DelayUnit, delay.IsProDelay, cancellationToken);
-                    //     }
-                    // }
+                    var delay = await _orderDelayRepository.GetAsync(workflow.ExternalId, cancellationToken);
+                    if (delay != null)
+                    {
+                        //delay.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
+                        delay.DelayState = isReviewPass ? EDelayState.Pass : EDelayState.NoPass;
+                        await _orderDelayRepository.Updateable(delay)
+                            .UpdateColumns(d => d.DelayState)
+                            .ExecuteCommandAsync(cancellationToken);
+                        if (isReviewPass)
+                        {
+                            //处理工单延期
+                            await _orderApplication.DelayOrderExpiredTimeAsync(delay.OrderId, delay.DelayNum,
+                                delay.DelayUnit, delay.IsProDelay, cancellationToken);
+                        }
+                    }
                     break;
                 case WorkflowModuleConsts.OrderTerminate:
                     var orderTerminate = await _orderTerminateRepository.Queryable()

+ 2 - 1
src/Hotline.Application/OrderApp/OrderApplication.cs

@@ -3687,7 +3687,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 AuditName = x.HandlerName,
                 AuditNum = SqlFunc.AggregateSum(SqlFunc.IIF(x.TraceType == EWorkflowTraceType.Normal && x.TraceState == EWorkflowTraceState.Normal, 1,
                     0)),
-                AuditBackNum = SqlFunc.AggregateSum(SqlFunc.IIF(x.TraceState == EWorkflowTraceState.StepRemoveByPrevious, 1, 0)),
+                AuditBackNum = SqlFunc.AggregateSum(SqlFunc.IIF(x.TraceState == EWorkflowTraceState.StepRemoveByPrevious ||
+                x.TraceState == EWorkflowTraceState.StepRemoveByRecall, 1, 0)),
             });
         return query;
     }

+ 34 - 24
src/Hotline.Application/Snapshot/BiSnapshotApplication.cs

@@ -128,29 +128,33 @@ public class BiSnapshotApplication : IBiSnapshotApplication, IScopeDependency
                 ShouldAmount = industryCase.CitizenReadPackAmount == null ? industry.CitizenReadPackAmount : industryCase.CitizenReadPackAmount,
             }).ToList();
 
-        var redPackOutDto = _redPackAuditRepository.Queryable(includeDeleted: true)
-            .LeftJoin<OrderSnapshot>((audit, snapshot) => audit.OrderId == snapshot.Id)
-            .LeftJoin<RedPackRecord>((audit, snapshot, record) => record.RedPackAuditId == audit.Id)
-            .LeftJoin<SupplementRecord>((audit, snapshot, record, supplement) => supplement.RedPackAuditId == audit.Id)
-            .Where((audit, snapshot) => audit.CreationTime >= dto.StartTime && audit.CreationTime <= dto.EndTime)
-            .GroupBy((audit, snapshot) => new { snapshot.IndustryCase, snapshot.IndustryId, snapshot.IndustryName })
-            .Select((audit, snapshot, record, supplement) => new RedPackStatisticsOutDto
-            {
-                Id = snapshot.IndustryId,
-                Name = snapshot.IndustryName,
-                CaseId = snapshot.IndustryCase,
-                ApprovalAmount = SqlFunc.AggregateSum(SqlFunc.IIF(audit.Status == ERedPackAuditStatus.Agree, audit.ApprovedAmount, 0)), //审批同意总金额
-                ApprovalCount = SqlFunc.AggregateSum(SqlFunc.IIF(audit.Status == ERedPackAuditStatus.Agree, 1, 0)), // 审批同意总个数
-                SentAmount = SqlFunc.AggregateSum(SqlFunc.IIF(audit.IsSend == true, audit.AcutalAmount, 0)), // 发送成功金额
-                SentCount = SqlFunc.AggregateSum(SqlFunc.IIF(audit.IsSend == true, 1, 0)), // 发送成功个数
-                SendFailAmount = SqlFunc.AggregateSum(SqlFunc.IIF(record.DistributionState == EReadPackSendStatus.Fail, record.Amount, 0)), //发送失败金额
-                SendFailCount = SqlFunc.AggregateSum(SqlFunc.IIF(record.DistributionState == EReadPackSendStatus.Fail, 1, 0)), // 发送失败个数
-                PendingAmount = SqlFunc.AggregateSum(SqlFunc.IIF(record.DistributionState == EReadPackSendStatus.Unsend, audit.ApprovedAmount, 0)), // 待发金额
-                PendingCount = SqlFunc.AggregateSum(SqlFunc.IIF(record.DistributionState == EReadPackSendStatus.Unsend, 1, 0)), // 待发个数
-                SupplementAmount = SqlFunc.AggregateSum(supplement.ReplenishAmount), // 补充红包金额
-                SupplementCount = SqlFunc.AggregateCount(supplement.Id), // 补充红包数
-            }).ToList();
+        var query = _redPackAuditRepository.Queryable(includeDeleted: true)
+        .LeftJoin<OrderSnapshot>((audit, snapshot) => audit.OrderId == snapshot.Id)
+        .LeftJoin<RedPackRecord>((audit, snapshot, record) => record.RedPackAuditId == audit.Id)
+        .LeftJoin<SupplementRecord>((audit, snapshot, record, supplement) => supplement.OrderId == snapshot.Id)
+        .Where((audit, snapshot) => audit.CreationTime >= dto.StartTime && audit.CreationTime <= dto.EndTime)
+        .GroupBy((audit, snapshot) => new { snapshot.IndustryCase, snapshot.IndustryId, snapshot.IndustryName })
+        .Select((audit, snapshot, record, supplement) => new RedPackStatisticsOutDto
+        {
+            Id = snapshot.IndustryId,
+            Name = snapshot.IndustryName,
+            CaseId = snapshot.IndustryCase,
+            ApprovalAmount = SqlFunc.AggregateSum(SqlFunc.IIF(audit.Status == ERedPackAuditStatus.Agree, audit.ApprovedAmount, 0)), //审批同意总金额
+            ApprovalCount = SqlFunc.AggregateSum(SqlFunc.IIF(audit.Status == ERedPackAuditStatus.Agree, 1, 0)), // 审批同意总个数
+            SentAmount = SqlFunc.AggregateSum(SqlFunc.IIF(audit.IsSend == true, audit.AcutalAmount, 0)), // 发送成功金额
+            SentCount = SqlFunc.AggregateSum(SqlFunc.IIF(audit.IsSend == true, 1, 0)), // 发送成功个数
+            SendFailAmount = SqlFunc.AggregateSum(SqlFunc.IIF(record.DistributionState == EReadPackSendStatus.Fail, record.Amount, 0)), //发送失败金额
+            SendFailCount = SqlFunc.AggregateSum(SqlFunc.IIF(record.DistributionState == EReadPackSendStatus.Fail, 1, 0)), // 发送失败个数
+            PendingAmount = SqlFunc.AggregateSum(SqlFunc.IIF(record.DistributionState == EReadPackSendStatus.Unsend, audit.ApprovedAmount, 0)), // 待发金额
+            PendingCount = SqlFunc.AggregateSum(SqlFunc.IIF(record.DistributionState == EReadPackSendStatus.Unsend, 1, 0)), // 待发个数
+            SupplementAmount = SqlFunc.AggregateSum(supplement.ReplenishAmount), // 补充红包金额
+            SupplementCount = SqlFunc.AggregateCount(supplement.Id), // 补充红包数
+        });
+#if DEBUG
+        var sql = query.ToSqlString();
+#endif
 
+        var redPackOutDto = query.ToList();
         foreach (var industry in industries)
         {
             var item = redPackOutDto
@@ -765,7 +769,9 @@ public class BiSnapshotApplication : IBiSnapshotApplication, IScopeDependency
         dto.FieldName = dto.FieldName.ToLower();
         var query = _orderSnapshotRepository.Queryable(includeDeleted: true)
             .LeftJoin<Order>((snapshot, order) => order.Id == snapshot.Id)
-            .Where((snapshot, order) => snapshot.CreationTime >= dto.StartTime && snapshot.CreationTime <= dto.EndTime && order.ActualHandleOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")) == dto.OrgCode);
+            .Where((snapshot, order) => snapshot.CreationTime >= dto.StartTime && snapshot.CreationTime <= dto.EndTime)
+            .WhereIF(dto.OrgCode.NotNullOrEmpty(), (snapshot, order) =>
+             order.ActualHandleOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")) == dto.OrgCode);
 
         query = dto.FieldName switch
         {
@@ -776,9 +782,13 @@ public class BiSnapshotApplication : IBiSnapshotApplication, IScopeDependency
             "not" => query.Where(snapshot => snapshot.CompliantType == ECompliantType.Not),
             _ => throw new UserFriendlyException($"入参: {dto.FieldName} 异常")
         };
-        return query.Select((snapshot, order) => new CompliantStatisticsDetailsOutDto
+        var b = query.Select((snapshot, order) => new CompliantStatisticsDetailsOutDto
         {
         }, true);
+#if DEBUG
+        var sql = b.ToSqlString();
+#endif
+        return b;
     }
 
     [ExportExcel("随手拍重办统计")]

+ 7 - 0
src/Hotline.Application/Snapshot/Contracts/IOrderSnapshotApplication.cs

@@ -147,4 +147,11 @@ public interface IOrderSnapshotApplication
 
     Task GetOrderDetailAsync(string id, Share.Dtos.Order.OrderDto dto, CancellationToken token);
     Task<string> GetStartflowAsync(string? orderId, CancellationToken requestAborted);
+
+    /// <summary>
+    /// 更新工单
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    Task UpdateOrderAsync(UpdateOrderDto dto, CancellationToken token);
 }

+ 16 - 3
src/Hotline.Application/Snapshot/RedPackApplication.cs

@@ -247,7 +247,7 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
         var industry = await _industryRepository.Queryable(includeDeleted: true)
             .LeftJoin<OrderSnapshot>((i, o) => i.Id == o.IndustryId)
             .Where((i, o) => o.Id == id)
-            .Select((i, o) => new { i.Id, i.CitizenReadPackAmount, i.ArgeePoints, i.ExtraDeductedPoints, i.RefusePoints , i.IsPoints})
+            .Select((i, o) => new { i.Id, i.CitizenReadPackAmount, i.ArgeePoints, i.ExtraDeductedPoints, i.RefusePoints, i.IsPoints })
             .FirstAsync();
         outDto.Amount = industry.CitizenReadPackAmount;
         outDto.ArgeePoints = industry.ArgeePoints;
@@ -555,6 +555,10 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
     public async Task UpdateRedPackAuditRemarkAsync(UpdateRedPackAuditRemarkInDto dto)
     {
         var audit = await _redPackAuditRepository.GetAsync(dto.RedPackAuditId) ?? throw UserFriendlyException.SameMessage("审核记录不存在");
+        if (audit.AcutalAmount == 0)
+            audit.IsSend = false;
+        else
+            audit.IsSend = dto.IsSend;
         audit.AcutalAmount = dto.AcutalAmount;
         audit.IsSend = dto.IsSend;
         audit.SendRemarks = dto.SendRemarks;
@@ -571,7 +575,16 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
                         record.PickupStatus = ERedPackPickupStatus.Excuse;
                 }
                 if (dto.IsSend)
+                {
                     record.DistributionState = EReadPackSendStatus.Successful;
+                    record.PickupStatus = ERedPackPickupStatus.Received;
+                }
+                if (dto.AcutalAmount == 0)
+                {
+                    record.PickupStatus = ERedPackPickupStatus.Unreceived;
+                    record.DistributionState = EReadPackSendStatus.Unsend;
+                }
+                record.Amount = dto.AcutalAmount;
                 await _redPackRecordRepository.UpdateAsync(record);
             });
 
@@ -586,7 +599,7 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
     public async Task UpdateRedPackRecordAsync(UpdateRedPackRecordInDto dto)
     {
         await _redPackAuditRepository.Queryable().Where(m => m.Id == dto.RedPackAuditId)
-            .Select(m => new { m.Id, m.OrderId})
+            .Select(m => new { m.Id, m.OrderId })
             .FirstAsync()
             .Then(async audit =>
             {
@@ -763,7 +776,7 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
             .WhereIF(dto.IndustryId.NotNullOrEmpty(), (supp, order) => supp.IndustryId == dto.IndustryId)
             .WhereIF(dto.BeginCreationTime.HasValue && dto.EndCreationTime.HasValue, (supp, order) => supp.CreationTime >= dto.BeginCreationTime && supp.CreationTime <= dto.EndCreationTime)
             .Select((supp, order) => new SnapshotRedPackRecordSupplementItemsOutDto
-            { 
+            {
                 Remark = supp.ReplenishRemark
             }, true);
         return query;

+ 8 - 5
src/Hotline.Application/Snapshot/SnapshotApplicationBase.cs

@@ -480,7 +480,7 @@ public abstract class SnapshotApplicationBase
     {
         var items = await _redPackRecordRepository.Queryable(includeDeleted: true)
             .Where(m => m.IsDeleted == false)
-            .Where(m => m.WXOpenId == _sessionContext.OpenId || m.PhoneNumber == _sessionContext.Phone)
+            .Where(m => m.WXOpenId == _sessionContext.OpenId)
             .Where(m => m.PickupStatus == dto.Status)
             .Where(m => m.CreationTime.ToString("yyyy-MM") == dto.Time)
             .LeftJoin<Order>((red, order) => red.OrderId == order.Id)
@@ -489,7 +489,8 @@ public abstract class SnapshotApplicationBase
                 OrderId = order.Id,
                 Amount = red.Amount,
                 Title = order.Title,
-                CreationTime = red.CreationTime
+                CreationTime = red.CreationTime,
+                RedPackAuditId = red.RedPackAuditId
             })
             .ToFixedListAsync(dto, cancellationToken);
 
@@ -502,9 +503,11 @@ public abstract class SnapshotApplicationBase
     /// <returns></returns>
     public async Task<string> GetRedPackReceivedTotalAsync(CancellationToken cancellationToken)
     {
-        var member = await _citizenRepository.GetAsync(m => m.Id == _sessionContext.UserId, cancellationToken)
-            ?? throw UserFriendlyException.SameMessage("用户不存在");
-        return (member.TotalAmount ?? 0).ToYuanFinance();
+        var totalAmount = await _redPackRecordRepository.Queryable()
+            .Where(m => m.WXOpenId == _sessionContext.OpenId && m.PickupStatus == ERedPackPickupStatus.Received)
+            .Select(m => SqlFunc.AggregateSum(m.Amount))
+            .FirstAsync(cancellationToken);
+        return totalAmount.ToYuanFinance();
     }
 
     /// <summary>

+ 20 - 2
src/Hotline.Application/Snapshot/SnapshotOrderApplication.cs

@@ -227,7 +227,7 @@ public class SnapshotOrderApplication : IOrderSnapshotApplication, IScopeDepende
             .LeftJoin<Order>((snapshot, order) => snapshot.Id == order.Id)
             .LeftJoin<WorkflowStep>((snapshot, order, step) => step.ExternalId == order.Id && step.Tag == TagDefaults.OrderMark && step.Status != EWorkflowStepStatus.Handled)
             .Where((snapshot, order, step) => snapshot.IndustryName == "安全隐患")
-            .WhereIF(dto.Status == 1, (snapshot, order, step) => step.Id != null && (step.HandlerId == _sessionContext.UserId ||_sessionContext.Roles.Contains(step.RoleId)) && snapshot.IsSafetyDepartment == null) // 待标记
+            .WhereIF(dto.Status == 1, (snapshot, order, step) => step.Id != null && (step.HandlerId == _sessionContext.UserId || _sessionContext.Roles.Contains(step.RoleId)) && snapshot.IsSafetyDepartment == null) // 待标记
             .WhereIF(dto.Status == 2, (snapshot, order, step) => snapshot.IsSafetyDepartment != null && snapshot.SignUserId == _sessionContext.UserId) // 已标记
             .WhereIF(dto.No.NotNullOrEmpty(), (snapshot, order, step) => order.No.Contains(dto.No))
             .WhereIF(dto.Title.NotNullOrEmpty(), (snapshot, order, step) => order.Title.Contains(dto.Title))
@@ -324,7 +324,7 @@ public class SnapshotOrderApplication : IOrderSnapshotApplication, IScopeDepende
     public async Task SaveOrderWorkflowInfo(NextWorkflowDto<OrderHandleFlowDto> dto)
     {
         if (_systemSettingCacheManager.Snapshot == false) return;
-        
+
         var snapshot = await _orderSnapshotRepository.GetAsync(dto.Data.OrderId);
         if (snapshot is null) return;
 
@@ -689,4 +689,22 @@ public class SnapshotOrderApplication : IOrderSnapshotApplication, IScopeDepende
         }
     }
 
+    public async Task UpdateOrderAsync(UpdateOrderDto dto, CancellationToken token)
+    {
+        if (_systemSettingCacheManager.Snapshot == false) return;
+
+        var sspSourceChannel = new List<string>() { "ZGSSP", "SJP12345"};
+        if (sspSourceChannel.Any(m => m == dto.SourceChannelCode) == false)
+        {
+            await _orderSnapshotRepository.Removeable()
+                .Where(m => m.Id == dto.Id)
+                .ExecuteCommandAsync(token);
+            return;
+        }
+        await _orderSnapshotRepository.Updateable()
+            .SetColumns(m => m.IndustryId, dto.IndustryId)
+            .SetColumns(m => m.IndustryName, dto.IndustryName)
+            .Where(m => m.Id == dto.Id)
+            .ExecuteCommandAsync(token);
+    }
 }

+ 2 - 1
src/Hotline.Application/StatisticalReport/OrderReportApplication.cs

@@ -2302,7 +2302,8 @@ namespace Hotline.Application.StatisticalReport
         public ISugarQueryable<Order> DepartmentAcceptanceTypeOrderList(DepartmentKeyWordRequest dto)
         {
             return _orderRepository.Queryable()
-                 .Where(p => p.FiledTime >= dto.StartTime && p.FiledTime <= dto.EndTime && p.Status >= EOrderStatus.Filed)
+                 .WhereIF(dto.TimeType == 2, p => p.FiledTime >= dto.StartTime && p.FiledTime <= dto.EndTime && p.Status >= EOrderStatus.Filed)
+                 .WhereIF(dto.TimeType == 1,p=> p.CreationTime>= dto.StartTime && p.CreationTime<=dto.EndTime)
                  .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.OrgCode == "001", p => p.ActualHandleOrgCode == dto.OrgCode)
                  .WhereIF(dto.TypeId != null && dto.TypeId == 1, p => p.IdentityType == EIdentityType.Citizen)
                  .WhereIF(dto.TypeId != null && dto.TypeId == 2, p => p.IdentityType == EIdentityType.Enterprise)

+ 5 - 0
src/Hotline.Share/Dtos/FlowEngine/NextStepsDto.cs

@@ -156,6 +156,11 @@ public class StepTempInDto
     /// </summary>
     public string OrderId { get; set; }
 
+    /// <summary>
+    /// 节点ID
+    /// </summary>
+    public string StepId { get; set; }
+
     /// <summary>
     /// 意见
     /// </summary>

+ 5 - 0
src/Hotline.Share/Dtos/Snapshot/RedPackDto.cs

@@ -26,6 +26,11 @@ public class RedPackOutDto
     /// 金额(单位:元)
     /// </summary>
     public double Amount { get; set; }
+
+    /// <summary>
+    /// 红包审核Id
+    /// </summary>
+    public string RedPackAuditId { get; set; }
 }
 
 public class RedPacksInDto : QueryFixedDto

+ 1 - 2
src/Hotline.Share/Dtos/Snapshot/StatisticsDto.cs

@@ -2577,8 +2577,7 @@ public record CompliantStatisticsDetailsInDto : PagedRequest
     /// <summary>
     /// 部门编号
     /// </summary>
-    [Required]
-    public string OrgCode { get; set; }
+    public string? OrgCode { get; set; }
 }
 
 public class CompliantStatisticsDetailsOutDto

+ 12 - 12
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -648,17 +648,17 @@ namespace Hotline.FlowEngine.Workflows
         public async Task StartToEndAsync(StartWorkflowDto dto, string externalId, DateTime? expiredTime = null,
             CancellationToken cancellationToken = default)
         {
-            //var wfModule = await GetWorkflowModuleAsync(dto.DefinitionModuleCode, cancellationToken);
-            //var definition = wfModule.Definition;
-            //if (definition == null)
-            //    throw new UserFriendlyException("无效模板编码");
-            //if (definition.Status is not EDefinitionStatus.Enable)
-            //    throw new UserFriendlyException("该模板不可用");
-
-            //var endStepDefine = definition.FindEndStepDefine();
-            //dto.NextStepCode = endStepDefine.Code;
-            //dto.NextStepName = endStepDefine.Name;
-            //dto.FlowDirection = EFlowDirection.CenterToFile;
+            var wfModule = await GetWorkflowModuleAsync(dto.DefinitionModuleCode, cancellationToken);
+            var definition = wfModule.Definition;
+            if (definition == null)
+                throw new UserFriendlyException("无效模板编码");
+            if (definition.Status is not EDefinitionStatus.Enable)
+                throw new UserFriendlyException("该模板不可用");
+
+            var endStepDefine = definition.FindEndStepDefine();
+            dto.NextStepCode = endStepDefine.Code;
+            dto.NextStepName = endStepDefine.Name;
+            dto.FlowDirection = EFlowDirection.CenterToFile;
 
             //await StartAsync(dto, externalId, expiredTime, cancellationToken: cancellationToken);
 
@@ -667,7 +667,7 @@ namespace Hotline.FlowEngine.Workflows
             nextDto.WorkflowId = workflow.Id;
             nextDto.StepId = startStep.Id;
 
-            var endStepDefine = workflow.WorkflowDefinition.FindEndStepDefine();
+            //var endStepDefine = workflow.WorkflowDefinition.FindEndStepDefine();
             nextDto.NextStepCode = endStepDefine.Code;
             nextDto.NextStepName = endStepDefine.Name;
 

+ 1 - 1
src/Hotline/SeedData/SystemDicDataSeedData.cs

@@ -45,7 +45,7 @@ public class SystemDicDataSeedData : ISeedData<SystemDicData>
                 new() {  Id = "08dd289b-a742-4622-8831-0fba6c8233de", DicDataValue = "waqyh", DicDataName = "无安全隐患", Sort = 2},
                 new() {  Id = "08dd287f-a17b-4404-809c-4b9e8cfaee52", DicDataValue = "hg", DicDataName = "合规", Sort = 3},
                 new() {  Id = "08dd287e-9cb5-4587-814f-1dbb0ab7c776", DicDataValue = "bhg", DicDataName = "不合规", Sort = 4},
-                new() {  Id = "08dd287d-fa29-4a2d-82cd-fae7c4ab1612", DicDataValue = "jdhfj", DicDataName = "阶段回复件", Sort = 5},
+                new() {  Id = "08dd287d-fa29-4a2d-82cd-fae7c4ab1612", DicDataValue = "jdhfj", DicDataName = "阶段回复件", Sort = 5},
                 new() {  Id = "08dd287d-f8a5-490f-8894-3a8f25d27258", DicDataValue = "lszg", DicDataName = "临时整改件", Sort = 6},
                 new() {  Id = "08dd287d-1e60-4adf-818a-ead50eb5a8c9", DicDataValue = "ss", DicDataName = "属实", Sort = 7},
                 new() {  Id = "08dd287c-69a4-4c92-899b-3fe7aa8503af", DicDataValue = "yzg", DicDataName = "已整改", Sort = 8},

+ 5 - 0
src/Hotline/Settings/SettingConstants.cs

@@ -795,5 +795,10 @@ namespace Hotline.Settings
         /// ip白名单
         /// </summary>
         public const string WhiteIp = "WhiteIp";
+
+        /// <summary>
+        /// 临时保存天数
+        /// </summary>
+        public const string TempOpinionDays = "TempOpinionDays";
     }
 }

+ 1 - 1
src/Hotline/Settings/TimeLimits/TimeLimitDomainService.cs

@@ -963,7 +963,7 @@ namespace Hotline.Settings.TimeLimits
                     return new TimeResult { EndTime = beginTime, RuleStr = timeValue + "个工作日", NearlyExpiredTime = startTime , NearlyExpiredTimeOne = startTimeOne };
                 //新增自然日
                 case ETimeType.Day:
-                    return new TimeResult { EndTime = beginTime.AddDays(timeValue), RuleStr = timeValue + "个自然日", NearlyExpiredTime = beginTime };
+                    return new TimeResult { EndTime = beginTime.AddDays(timeValue), RuleStr = timeValue + "个自然日", NearlyExpiredTime = beginTime.AddDays(timeValue*(Percentage/(double)100)), NearlyExpiredTimeOne = beginTime.AddDays(timeValue*(PercentageOne/(double)100)) };
                 default:
                     return null;
             }

+ 4 - 4
src/Hotline/Validators/Order/AddOrderDtoValidator.cs

@@ -102,9 +102,9 @@ public class AddOrderDtoValidator : AbstractValidator<AddOrderDto>
         #endregion
 
         #region 投诉对象信息
-        RuleFor(d => d.OrderExtension.EnterpriseName).MaxLengthWithChineseChar(50).When(d => d.OrderExtension != null).WithMessage("企业名称最多50字符");
+        RuleFor(d => d.OrderExtension.EnterpriseName).MaximumLength(30).When(d => d.OrderExtension != null).WithMessage("企业名称最多30字符");
         RuleFor(d => d.OrderExtension.UnifiedSocialCreditCode).MaxLengthWithChineseChar(30).When(d => d.OrderExtension != null).WithMessage("统一社会信用代码最多30字符");
-        RuleFor(d => d.OrderExtension.RegisterAddress).MaxLengthWithChineseChar(50).When(d => d.OrderExtension != null).WithMessage("企业注册地址最多50字符");
+        RuleFor(d => d.OrderExtension.RegisterAddress).MaximumLength(30).When(d => d.OrderExtension != null).WithMessage("企业注册地址最多30字符");
         RuleFor(d => d.OrderExtension.RegisterNumber).MaxLengthWithChineseChar(50).When(d => d.OrderExtension != null).WithMessage("注册号最多50字符");
         RuleFor(d => d.OrderExtension.EnterpriseContact).MaxLengthWithChineseChar(70).When(d => d.OrderExtension != null).WithMessage("联系人最多70字符");
         RuleFor(d => d.OrderExtension.MarketTypeCode).MaxLengthWithChineseChar(64).When(d => d.OrderExtension != null).WithMessage("市场主体类型代码最多64字符");
@@ -114,7 +114,7 @@ public class AddOrderDtoValidator : AbstractValidator<AddOrderDto>
         #endregion
 
         #region 投诉详情
-        RuleFor(d => d.OrderExtension.ExternalOrderNo).MaxLengthWithChineseChar(50).When(d => d.OrderExtension != null).WithMessage("订单号最多50字符");
+        RuleFor(d => d.OrderExtension.ExternalOrderNo).MaximumLength(15).When(d => d.OrderExtension != null).WithMessage("订单号最多15字符");
         RuleFor(d => d.OrderExtension.Patentee).MaxLengthWithChineseChar(50).When(d => d.OrderExtension != null).WithMessage("专利权人最多50字符");
         RuleFor(d => d.OrderExtension.PatentName).MaxLengthWithChineseChar(200).When(d => d.OrderExtension != null).WithMessage("专利名称最多200字符");
         RuleFor(d => d.OrderExtension.PatentNo).MaxLengthWithChineseChar(50).When(d => d.OrderExtension != null).WithMessage("专利号最多50字符");
@@ -124,7 +124,7 @@ public class AddOrderDtoValidator : AbstractValidator<AddOrderDto>
         RuleFor(d => d.OrderExtension.ProductStandard).MaxLengthWithChineseChar(50).When(d => d.OrderExtension != null).WithMessage("产品规格最多50字符");
         RuleFor(d => d.OrderExtension.Manufacturer).MaxLengthWithChineseChar(50).When(d => d.OrderExtension != null).WithMessage("生产厂家最多50字符");
         RuleFor(d => d.OrderExtension.SalesEnterprise).MaxLengthWithChineseChar(50).When(d => d.OrderExtension != null).WithMessage("销售企业最多50字符");
-        RuleFor(d => d.OrderExtension.ConsumerAddress).MaxLengthWithChineseChar(100).When(d => d.OrderExtension != null).WithMessage("消费者地址最多100字符");
+        RuleFor(d => d.OrderExtension.ConsumerAddress).MaximumLength(30).When(d => d.OrderExtension != null).WithMessage("消费者地址最多30字符");
         RuleFor(d => d.OrderExtension.BusinessPosition.Street).MaxLengthWithChineseChar(100).When(d => d.OrderExtension != null && d.OrderExtension.BusinessPosition != null).WithMessage("经营详细地址最多100字符");
         #endregion
     }

+ 27 - 0
test/Hotline.Tests/Application/BiSnapshotApplicationTest.cs

@@ -2,6 +2,7 @@
 using Hotline.Application.Snapshot.Contracts;
 using Hotline.Identity.Accounts;
 using Hotline.Identity.Roles;
+using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.Settings;
 using Hotline.Share.Dtos.Snapshot;
 using Hotline.Share.Tools;
@@ -110,4 +111,30 @@ public class BiSnapshotApplicationTest : TestBase
         var e = _biSnapshotApplication.GetIndustryStatistics(inDto.Adapt<IndustryStatisticsInDto>());
         e.ShouldNotBeNull();
     }
+
+    [Fact]
+    public async Task GetCompliantStatisticsDetails_Test()
+    {
+        var inDto = new CompliantStatisticsDetailsInDto()
+        {
+            PageIndex = 1,
+            PageSize = 20,
+            StartTime = DateTime.Now.AddDays(-30),
+            EndTime = DateTime.Now,
+            FieldName = "orderCountNum",
+        };
+        var items = await _biSnapshotApplication.GetCompliantStatisticsDetails(inDto).ToPagedListAsync(inDto);
+        items.Total.ShouldNotBe(0);
+    }
+
+    [Fact]
+    public async Task GetRedPackAuditStatistics_Test()
+    {
+        var items = _biSnapshotApplication.GetRedPackAuditStatistics(new RedPackStatisticsInDto()
+        {
+            StartTime = DateTime.Now.AddDays(-7),
+            EndTime = DateTime.Now
+        });
+        items.ShouldNotBeNull();
+    }
 }

+ 32 - 0
test/Hotline.Tests/Application/OrderSnapshotApplicationTest.cs

@@ -1,4 +1,5 @@
 using Hotline.Api.Controllers;
+using Hotline.Application.Snapshot;
 using Hotline.Application.Snapshot.Contracts;
 using Hotline.Caching.Interfaces;
 using Hotline.FlowEngine.WorkflowModules;
@@ -286,6 +287,37 @@ public class OrderSnapshotApplicationTest : TestBase
                 {
                     e.Message.ShouldBe("该工单已发放红包,不能撤销审批");
                 }
+
+                var redPack = await _redPackApplication.GetRedPackAuditItems(new SnapshotOrderAuditItemsInDto() { No = order.No }).FirstAsync();
+
+                await _redPackApplication.UpdateRedPackAuditRemarkAsync(new UpdateRedPackAuditRemarkInDto()
+                {
+                    RedPackAuditId = redPack.Id,
+                    AcutalAmount = 0,
+                    SendRemarks = "单元测试备注",
+                    IsSend = true
+                }); // 添加备注
+
+                SetWeiXin();
+                var redPackItems = await _snapshotApplication.GetRedPacksAsync(new RedPacksInDto() { Status = ERedPackPickupStatus.Unreceived }, CancellationToken.None);
+                var redPackRecord = redPackItems.Where(m => m.OrderId == order.Id).FirstOrDefault();
+                redPackRecord.ShouldNotBeNull();
+                redPackRecord.Amount.ShouldBe(0);
+
+                Set应急管理局();
+                await _redPackApplication.UpdateRedPackAuditRemarkAsync(new UpdateRedPackAuditRemarkInDto()
+                {
+                    RedPackAuditId = redPackRecord.RedPackAuditId,
+                    AcutalAmount = 11,
+                    SendRemarks = "单元测试备注",
+                    IsSend = true
+                }); // 添加备注
+
+                SetWeiXin();
+                redPackItems =  await _snapshotApplication.GetRedPacksAsync(new RedPacksInDto() { Status = ERedPackPickupStatus.Received }, CancellationToken.None);
+                redPackRecord = redPackItems.Where(m => m.OrderId == order.Id).FirstOrDefault();
+                redPackRecord.ShouldNotBeNull();
+                redPackRecord.Amount.ShouldBe(11);
             })
             .GetCreateResult();
         order.Id.ShouldNotBeNull();

+ 5 - 1
test/Hotline.Tests/Application/XingTangCallsSyncJobTest.cs

@@ -1,5 +1,6 @@
 using AutoFixture;
 using Hotline.Application.Jobs;
+using Hotline.Caching.Interfaces;
 using Hotline.Repository.SqlSugar;
 using Quartz;
 using SqlSugar;
@@ -12,18 +13,21 @@ public class XingTangCallsSyncJobTest
     private readonly ISqlSugarClient _db;
     private readonly IFixture _fixture;
     private readonly XingTangCallSatisfactionSyncJob _xingTangCallSatisfactionSyncJob;
+    private readonly ISystemSettingCacheManager _systemSettingCacheManager;
 
-    public XingTangCallsSyncJobTest(XingTangCallsSyncJob xingTangCallsSyncJob, ISugarUnitOfWork<XingTangDbContext> uow, XingTangCallSatisfactionSyncJob xingTangCallSatisfactionSyncJob)
+    public XingTangCallsSyncJobTest(XingTangCallsSyncJob xingTangCallsSyncJob, ISugarUnitOfWork<XingTangDbContext> uow, XingTangCallSatisfactionSyncJob xingTangCallSatisfactionSyncJob, ISystemSettingCacheManager systemSettingCacheManager)
     {
         this.xingTangCallsSyncJob = xingTangCallsSyncJob;
         _db = uow.Db;
         _fixture = new Fixture();
         _xingTangCallSatisfactionSyncJob = xingTangCallSatisfactionSyncJob;
+        _systemSettingCacheManager = systemSettingCacheManager;
     }
 
     [Fact]
     public async Task Handler_Test()
     {
+        var unPushTime = _systemSettingCacheManager.CallSyncUnPushDateTime;
         var second = new Random().Next(0, 60);
         var inDto = _fixture.Create<XingtangCall>();
         inDto.CallStartTime = DateTime.Parse("2024/11/19 18:07:" + second);

+ 28 - 10
test/Hotline.Tests/Mock/OrderServiceMock.cs

@@ -94,13 +94,21 @@ public class OrderServiceMock
         inDto.Latitude = 29.3661181959828;
         inDto.Longitude = 104.41928;
         //inDto.JobType = 
+        var file = 0;
         foreach (var item in inDto.Files)
         {
-            var result = UploadImage().Result;
+            var i = UploadImage();
+            if (i.Code == -1)
+            {
+                file = i.Code;
+                break;
+            }
+            var result = i.Result;
             item.FileName = result.FileName;
             item.Path = result.Path;
             item.AdditionId = result.Id;
         }
+        if (file == -1) inDto.Files = new List<SnapshotFileInDto>();
         CreateOrderOutDto = _snapshotController.AddOrderAsync(inDto).GetAwaiter().GetResult().ToJson().FromJson<CreateOrderOutDto>();
         _orderServiceStartWorkflow.orderServiceMock = this;
         return _orderServiceStartWorkflow;
@@ -430,6 +438,7 @@ public class OrderServiceMock
         var uploadUrl = _systemSettingCacheManager.FileServerUrl + "/file/upload?source=hotline";
         var file = "测试图片" + DateTime.Now.ToString("ss") + ".png";
         var resultJson = UploadFileFromMemory(imageBytes, file, uploadUrl);
+        if (resultJson.IsNullOrEmpty()) return new ApiResponse<FileJson>() { Code = -1 };
         var result = resultJson.FromJson<ApiResponse<FileJson>>();
         return result;
     }
@@ -558,18 +567,27 @@ public class OrderServiceMock
 
     private string UploadFileFromMemory(byte[] fileBytes, string fileName, string uploadUrl)
     {
-        using HttpClient client = new HttpClient();
-        using var multipartContent = new MultipartFormDataContent();
-        var fileContent = new ByteArrayContent(fileBytes);
-        fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
+        try
+        {
+            using HttpClient client = new HttpClient();
+            using var multipartContent = new MultipartFormDataContent();
+            var fileContent = new ByteArrayContent(fileBytes);
+            fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
 
-        multipartContent.Add(fileContent, "fileData", fileName);
+            multipartContent.Add(fileContent, "fileData", fileName);
 
-        HttpResponseMessage response = client.PostAsync(uploadUrl, multipartContent).GetAwaiter().GetResult();
-        response.EnsureSuccessStatusCode();
+            HttpResponseMessage response = client.PostAsync(uploadUrl, multipartContent).GetAwaiter().GetResult();
+            response.EnsureSuccessStatusCode();
 
-        var result = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
-        return result;
+            var result = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
+            return result;
+
+        }
+        catch (Exception e)
+        {
+            var msg = e.Message;
+        }
+        return string.Empty;
     }
 
     public OrderServiceMock StepHandle(Func<CreateOrderOutDto, OrderServiceMock, Task> handle)