diff --git a/src/SJZY.Track.Api/appsettings.json b/src/SJZY.Track.Api/appsettings.json
index ac8a5882..0c0044ed 100644
--- a/src/SJZY.Track.Api/appsettings.json
+++ b/src/SJZY.Track.Api/appsettings.json
@@ -1,6 +1,6 @@
{
"Configuration": {
- "UseLocalConfiguration": false,
+ "UseLocalConfiguration": true,
//是否使用本地配置文件
"ConfiguraFileName": "appsettings.Development.json",
//指定配置文件名称,开启UseLocalConfiguration时生效
diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchUpsertTrackInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchUpsertTrackInput.cs
index b5a73ed3..a8ced808 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchUpsertTrackInput.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/BatchUpsertTrackInput.cs
@@ -119,4 +119,9 @@ public class BatchUpsertTrackInput : OrderNosInfo
///
[Range(-12, 12)]
public float? DestinationTimeZone { get; set; }
+
+ ///
+ /// 扩展信息字段,用与轨迹推送的附加字段
+ ///
+ public Dictionary? Extra { get; set; }
}
diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackTemplateListInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackTemplateListInput.cs
new file mode 100644
index 00000000..a591adf7
--- /dev/null
+++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetPageTrackTemplateListInput.cs
@@ -0,0 +1,29 @@
+namespace SJZY.Track.Application.Contract.Dtos.ProvideServices;
+
+public class GetPageTrackTemplateListInput : PageInfoInput
+{
+ ///
+ /// 子系统id
+ ///
+ public int SubSystemId { get; set; }
+
+ ///
+ /// 客户id
+ ///
+ public int? CustomerId { get; set; }
+
+ ///
+ /// 模版分类
+ ///
+ public int? TemplateType { get; set; }
+
+ ///
+ /// 模板code
+ ///
+ public string? TemplateCode { get; set; }
+
+ ///
+ /// 关键字
+ ///
+ public string? KeyWord { get; set; }
+}
diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackOutput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackOutput.cs
index 84c1ed15..7af8aabd 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackOutput.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackOutput.cs
@@ -101,4 +101,9 @@ public class TrackDetail
/// 目的地时区
///
public float? DestinationTimeZone { get; set; }
+
+ ///
+ /// 扩展信息字段,用与轨迹推送的附加字段
+ ///
+ public Dictionary? Extra { get; set; }
}
diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackTemplateListInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackTemplateListInput.cs
index 269a1a0e..e1c04282 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackTemplateListInput.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/GetTrackTemplateListInput.cs
@@ -16,4 +16,9 @@ public class GetTrackTemplateListInput
/// 模版分类
///
public int? TemplateType { get; set; }
+
+ ///
+ /// 模板code
+ ///
+ public string? TemplateCode { get; set; }
}
diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderInput.cs
index b46ff5be..d9d6d235 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderInput.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpdateOrderInput.cs
@@ -1,4 +1,4 @@
-using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
namespace SJZY.Track.Application.Contract.Dtos.ProvideServices;
@@ -76,6 +76,12 @@ public class UpdateOrderInput : OrderNoInfo
/// 订单航班信息
///
public List FlightInfos { get; set; } = new();
+
+
+ ///
+ /// 模板code
+ ///
+ public List TemplateCodes { get; set; }
}
public class PullConfigInfo
diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertOrderInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertOrderInput.cs
index 1214f51d..628a6155 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertOrderInput.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertOrderInput.cs
@@ -1,4 +1,4 @@
-using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
namespace SJZY.Track.Application.Contract.Dtos.ProvideServices;
@@ -9,11 +9,6 @@ public class UpsertOrderInput : UpdateOrderInput
///
public int CustomId { get; set; }
- ///
- /// 模板code
- ///
- public List TemplateCodes { get; set; }
-
///
/// 当前操作人
///
diff --git a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertTrackInput.cs b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertTrackInput.cs
index 2b34f832..22762d6c 100644
--- a/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertTrackInput.cs
+++ b/src/SJZY.Track.Application.Contract/Dtos/ProvideServices/UpsertTrackInput.cs
@@ -123,4 +123,9 @@ public class UpsertTrackInput : OrderNoInfo
/// 当前操作人
///
public int OptionUserId { get; set; }
+
+ ///
+ /// 扩展信息字段,用与轨迹推送的附加字段
+ ///
+ public Dictionary? Extra { get; set; }
}
diff --git a/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs b/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs
index 4102df32..d08a1171 100644
--- a/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs
+++ b/src/SJZY.Track.Application.Contract/Events/TrackUpsertEvent.cs
@@ -141,6 +141,11 @@ public class TrackUpsertEvent
///
public float? DestinationTimeZone { get; set; }
+ ///
+ /// 扩展信息字段,用与轨迹推送的附加字段
+ ///
+ public Dictionary? Extra { get; set; }
+
public override string ToString()
{
return
diff --git a/src/SJZY.Track.Application/AutoMapper/OrderAutoMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/OrderAutoMapperProfile.cs
index f1a32d4d..0ec4b79a 100644
--- a/src/SJZY.Track.Application/AutoMapper/OrderAutoMapperProfile.cs
+++ b/src/SJZY.Track.Application/AutoMapper/OrderAutoMapperProfile.cs
@@ -21,11 +21,7 @@ public class OrderAutoMapperProfile : Profile
CreateMap(MemberList.None);
CreateMap(MemberList.None);
- CreateMap(MemberList.None)
- .ForMember(dest => dest.OrderTypeName,
- opt => opt.MapFrom(source => GetEnumDescription(2, source.OrderType)))
- .ForMember(dest => dest.QuestionTypeName,
- opt => opt.MapFrom(source => GetEnumDescription(1, source.QuestionType)));
+ CreateMap(MemberList.None);
CreateMap, UnifyPageResultDto>(MemberList.None);
CreateMap(MemberList.None).Ignore(dest => dest.TrackTimeZone)
diff --git a/src/SJZY.Track.Application/AutoMapper/TrackTemplateAutoMapperProfile.cs b/src/SJZY.Track.Application/AutoMapper/TrackTemplateAutoMapperProfile.cs
index 850ff421..f6e6b53b 100644
--- a/src/SJZY.Track.Application/AutoMapper/TrackTemplateAutoMapperProfile.cs
+++ b/src/SJZY.Track.Application/AutoMapper/TrackTemplateAutoMapperProfile.cs
@@ -20,6 +20,8 @@ public class TrackTemplateAutoMapperProfile : Profile
CreateMap(MemberList.None);
CreateMap, UnifyPageResultDto>(MemberList
.None);
+ CreateMap(MemberList.None);
+ CreateMap, UnifyPageResultDto>(MemberList.None);
CreateMap(MemberList.None);
CreateMap(MemberList.None);
diff --git a/src/SJZY.Track.Application/CAP/CAPFilter.cs b/src/SJZY.Track.Application/CAP/CAPFilter.cs
index 35fa9f23..0decb640 100644
--- a/src/SJZY.Track.Application/CAP/CAPFilter.cs
+++ b/src/SJZY.Track.Application/CAP/CAPFilter.cs
@@ -29,7 +29,7 @@ public class CapFilter : SubscribeFilter
context.DeliverMessage.Headers["sjzy-arguments-hash"] = hash;
}
- if (await RedisHelper.Client.ExistsAsync($"CapExecuteFilter:{hash}"))
+ if (await RedisHelper.Client.ExistsAsync($"CapExecuteFilter:{hash}{DateTime.Now:G}"))
{
throw new BusinessException(GlobalConst.CapNoRetryErrorCode, $"检测到重复消费,消费参数:{argumentJsonStr}");
}
@@ -41,7 +41,7 @@ public class CapFilter : SubscribeFilter
context.DeliverMessage.Headers.TryGetValue("sjzy-arguments-hash", out var hash);
if (!hash.IsNullOrEmpty())
{
- await RedisHelper.Client.SetAsync($"CapExecuteFilter:{hash}", 1, TimeSpan.FromMinutes(3));
+ await RedisHelper.Client.SetAsync($"CapExecuteFilter:{hash}{DateTime.Now:G}", 1, TimeSpan.FromMinutes(3));
}
}
diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs
index 08e079d6..e9db1cfa 100644
--- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs
+++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackDeleteEventHandler.cs
@@ -175,23 +175,27 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
{
List orderIds;
List tracks;
+ List deleteTracks;
if (@event.EsIds != null && @event.EsIds.Any()) //根据明确的esid进行删除
{
- tracks = await _trackDetailsEsRepository.GetDataByIds(@event.EsIds);
- orderIds = tracks.Select(m => m.OrderId).Distinct().ToList();
+ deleteTracks = await _trackDetailsEsRepository.GetDataByIds(@event.EsIds);
+ orderIds = deleteTracks.Select(m => m.OrderId).Distinct().ToList();
@event.OrderIds = orderIds.ToArray();
- @event.TrackIdentifiers = tracks.Select(x => new TrackIdentifierDto
+ @event.TrackIdentifiers = deleteTracks.Select(x => new TrackIdentifierDto
{
TrackCode = x.TrackCode,
TrackTime = x.TrackTime
}).ToList();
// 外部api获取的轨迹不允许删除
- if (tracks.Any(m => m.Source == TrackSourceEnum.ExternalServiceProvide.GetHashCode()))
- return tracks;
+ if (deleteTracks.Any(m => m.Source == TrackSourceEnum.ExternalServiceProvide.GetHashCode()))
+ return deleteTracks;
+
+ //查出订单下的所有轨迹,以供后面回退使用
+ tracks = await _trackDetailsEsRepository.GetListAsync(@event.OrderIds);
// 删除轨迹
- foreach (var item in tracks)
+ foreach (var item in deleteTracks)
{
await _trackDetailsEsRepository.DeleteTrackByIdAsync(item.Id, item.IndexName);
}
@@ -205,9 +209,9 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
tracks = await _trackDetailsEsRepository.GetListAsync(@event.OrderIds);
//构建标识符集合
- var ids = @event.TrackIdentifiers.Select(x => $"{x.TrackCode}{x.TrackTime}").ToList();
+ var ids = @event.TrackIdentifiers.Select(x => $"{x.TrackCode}{x.TrackTime:G}").ToList();
//根据标识符选出要删除的轨迹明细
- var deleteTracks = tracks.Where(x => ids.Contains($"{x.TrackCode}{x.TrackTime}")).ToList();
+ deleteTracks = tracks.Where(x => ids.Contains($"{x.TrackCode}{x.TrackTime:G}")).ToList();
if (deleteTracks.Count == 0) return deleteTracks;
@@ -218,10 +222,10 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
//从被删除轨迹寻找订单id,稍后会更新订单主表
orderIds = deleteTracks.Select(m => m.OrderId).Distinct().ToList();
- //排除掉已经删除的轨迹
- tracks = tracks.Except(deleteTracks).ToList();
}
+ //排除掉已经删除的轨迹
+ tracks = tracks.Except(deleteTracks).ToList();
var orders = await _orderRepository.GetListAsync(x => orderIds.Contains(x.Id),
x => new OrderEntity
@@ -232,13 +236,15 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
LatestTrackPlace = x.LatestTrackPlace,
LatestTrackTime = x.LatestTrackTime,
LatestTrackTimeZone = x.LatestTrackTimeZone,
+ EstimatedDeliveryDate = x.EstimatedDeliveryDate,
+ DestinationTimeZone = x.DestinationTimeZone
});
if (orders.Count == 0) return tracks;
foreach (var order in orders)
{
//找到最新的轨迹数据
- var track = tracks?.OrderByDescending(x=>x.TrackTime)
+ var track = tracks?.OrderByDescending(x => x.TrackTime)
.FirstOrDefault(x => x.OrderId == order.Id);
// 删除全部轨迹导致的重置行为
@@ -258,6 +264,8 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
order.LatestTrackPlace = track.TrackPlace;
order.LatestTrackTime = track.TrackTime;
order.LatestTrackTimeZone = track.TrackTimeZone;
+ order.EstimatedDeliveryDate = track.EstimatedDeliveryDate;
+ order.DestinationTimeZone = track.DestinationTimeZone;
}
@@ -267,7 +275,7 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
OrderId = order.Id,
OrderNo = order.OrderNo,
OptionType = OrderOperationType.删除轨迹.ToString(),
- Content = tracks?.Where(m => m.OrderId == order.Id).ToList().ToJson(),
+ Content = deleteTracks?.Where(m => m.OrderId == order.Id).ToList().ToJson(),
CreateUserId = @event.OperationManId,
CreateUserName = @event.OperationMan ?? "",
CreateTime = DateTime.Now
@@ -281,9 +289,11 @@ public class TrackDeleteEventHandler : ITransientDependency, ICapSubscribe
x.LatestTrackEnContent,
x.LatestTrackPlace,
x.LatestTrackTime,
- x.LatestTrackTimeZone
+ x.LatestTrackTimeZone,
+ x.EstimatedDeliveryDate,
+ x.DestinationTimeZone
});
- return tracks;
+ return deleteTracks;
}
}
diff --git a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs
index c26118a3..1b6ee76f 100644
--- a/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs
+++ b/src/SJZY.Track.Application/CAP/EventHandlers/TrackUpsertEventHandler.cs
@@ -199,7 +199,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
return default;
}
- //#7001:未来潜在需求,当轨迹内容匹配预设,记录一个标记,保证下刷过程都是使用预设内衣
+ //#7001:未来潜在需求,当轨迹内容匹配预设,记录一个标记,保证下刷过程都是使用预设内容
//虽然在引发事件之前做了判断,引发之后并不一定立即处理,在此过程中轨迹内容仍然可能被修改,所以要二次进行判断。
//通过来源指示是否为手动操作
var manualOperation = @event.Source == (int) TrackSourceEnum.Artificial;
@@ -241,7 +241,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
TrackContent = trackContent.TrackContent,
TrackEnContent = trackContent.TrackEnContent,
TrackPlace = @event.TrackPlace,
- TrackTime = @event.TrackTime,
+ TrackTime = @event.NewTrackTime ?? @event.TrackTime,
TrackTimeZone = @event.TrackTimeZone,
DestinationTimeZone = @event.DestinationTimeZone,
EstimatedDeliveryDate = @event.EstimatedDeliveryDate
@@ -261,7 +261,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
TrackStatus = trackContent.TrackStatus,
TrackContent = trackContent.TrackContent,
TrackPlace = @event.TrackPlace,
- TrackTime = @event.TrackTime,
+ TrackTime = @event.NewTrackTime ?? @event.TrackTime,
TrackTimeZone = @event.TrackTimeZone
}
};
@@ -353,9 +353,11 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
CreateUser = @event.OperationMan ?? GlobalConst.SystemUser,
CreateTime = DateTime.Now,
//来源轨迹内容,第一次新增的时候使用轨迹内容表提供的
+ TrackStatusId = trackContent.TrackStatusId,
TrackStatus = trackContent.TrackStatus,
TrackStatusCode = trackContent.TrackStatusCode,
//跨子系统?
+ TrackContentId = trackContent.TrackContentId,
TrackContent = @event.Content ?? trackContent.TrackContent,
TrackEnContent = @event.EnStatus ?? trackContent.TrackEnContent,
//S06新增轨迹明细字段
@@ -376,6 +378,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
TrackPlacePostcode = @event.TrackPlacePostcode ?? GlobalConst.EmptyString,
DestinationTimeZone = @event.DestinationTimeZone,
EstimatedDeliveryDate = @event.EstimatedDeliveryDate,
+ Extra = @event.Extra
};
track.ZeroTrackTime = Math.Abs(track.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1
@@ -432,6 +435,7 @@ public class TrackUpsertEventHandler : ITransientDependency, ICapSubscribe
track.TrackPlacePostcode = @event.TrackPlacePostcode ?? GlobalConst.EmptyString;
track.DestinationTimeZone = @event.DestinationTimeZone;
track.EstimatedDeliveryDate = @event.EstimatedDeliveryDate;
+ track.Extra = @event.Extra;
updateTracks.Add(track);
diff --git a/src/SJZY.Track.Application/Rabbit/TrackRefreshEventHandler.cs b/src/SJZY.Track.Application/Rabbit/TrackRefreshEventHandler.cs
index 36baaec7..14e80f79 100644
--- a/src/SJZY.Track.Application/Rabbit/TrackRefreshEventHandler.cs
+++ b/src/SJZY.Track.Application/Rabbit/TrackRefreshEventHandler.cs
@@ -300,8 +300,10 @@ public class TrackRefreshEventHandler : ITransientDependency, IRabbitHandler
CreateUser = GlobalConst.SystemUser,
CreateTime = DateTime.Now,
//来源轨迹内容,第一次新增的时候使用轨迹内容表提供的
+ TrackStatusId = GlobalConst.NotExistId,
TrackStatus = GlobalConst.EmptyString,
TrackStatusCode = GlobalConst.EmptyString,
+ TrackContentId = GlobalConst.NotExistId,
TrackContent = GlobalConst.EmptyString,
TrackEnContent = GlobalConst.EmptyString,
//S06新增轨迹明细字段
@@ -318,6 +320,7 @@ public class TrackRefreshEventHandler : ITransientDependency, IRabbitHandler
TrackPlacePostcode = null,
DestinationTimeZone = null,
EstimatedDeliveryDate = null,
+ Extra = null
};
track.ZeroTrackTime = Math.Abs(track.TrackTimeZone - GlobalConst.NoneTrackTimeZone) < 1
diff --git a/src/SJZY.Track.Application/SJZY.Track.Application.csproj b/src/SJZY.Track.Application/SJZY.Track.Application.csproj
index 0beb6ea8..8226317a 100644
--- a/src/SJZY.Track.Application/SJZY.Track.Application.csproj
+++ b/src/SJZY.Track.Application/SJZY.Track.Application.csproj
@@ -11,10 +11,10 @@
-
+
-
+
diff --git a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs
index 8bf60542..d529f83d 100644
--- a/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs
+++ b/src/SJZY.Track.Application/Services/ProvideServices/OrderService.cs
@@ -1,4 +1,4 @@
-using DotNetCore.CAP;
+using DotNetCore.CAP;
using SJZY.Expand.ABP.Core.PublicMethords;
using SJZY.Track.Application.Contract.Dtos.ProvideServices;
using SJZY.Track.Application.Contract.Services.ProvideServices;
@@ -131,6 +131,7 @@ public partial class OrderService : ApplicationService, IOrderService
order.OrderFlights = ObjectMapper.Map, List>(input.FlightInfos);
order.OrderPullStatus = BuiltOrderPullStatus(input.PullConfigInfos);
order.OrderPlatformNumbers = BuiltOrderPlatformNumbers(input.PullConfigInfos);
+ order.TemplateCodes = string.Join(',', input.TemplateCodes);
await _orderRepository.UpdateOrderAsync(order);
}
diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs
index 48c89192..3934c950 100644
--- a/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs
+++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackPushService.cs
@@ -8,7 +8,7 @@ using SJZY.Track.Domain.Aggregates.OrderAggregate;
using SJZY.Track.Domain.Aggregates.TrackPushAggregate;
using SJZY.Track.Domain.Dtos.TrackPush;
using SJZY.Track.Domain.Queries;
-using SJZY.UserCenter.HttpApi.Services;
+using SJZY.UserCenter.HttpApi.Services.User;
using Volo.Abp.Http.Client.DynamicProxying;
namespace SJZY.Track.Application.Services.ProvideServices;
@@ -23,14 +23,14 @@ public class TrackPushService : ApplicationService, ITrackPushService
private readonly ICapPublisher _capPublisher;
private readonly IOrderRepository _orderRepository;
private readonly IProvideQueries _provideQueries;
- private readonly IHttpClientProxy _requestCurrentUserService;
+ private readonly IHttpClientProxy _requestCurrentUserService;
private readonly ITrackPushConfigRepository _trackPushConfigRepository;
private readonly ITrackPushRecordEsRepository _trackPushRecordEsRepository;
public TrackPushService(IOrderRepository orderRepository
, ICapPublisher capPublisher
, ITrackPushRecordEsRepository trackPushRecordEsRepository
- , IHttpClientProxy requestCurrentUserService
+ , IHttpClientProxy requestCurrentUserService
, ITrackPushConfigRepository trackPushConfigRepository, IProvideQueries provideQueries)
{
_orderRepository = orderRepository;
diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.Query.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.Query.cs
index ab0bd27d..6e36fae2 100644
--- a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.Query.cs
+++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.Query.cs
@@ -79,7 +79,8 @@ public partial class TrackService
TrackPlaceNationId = x.TrackPlaceNationId,
TrackPlacePostcode = x.TrackPlacePostcode,
DestinationTimeZone = x.DestinationTimeZone,
- EstimatedDeliveryDate = x.EstimatedDeliveryDate
+ EstimatedDeliveryDate = x.EstimatedDeliveryDate,
+ Extra = x.Extra
}).ToList();
res.Add(item);
diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs
index b1afaa30..a73ffe17 100644
--- a/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs
+++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackService.cs
@@ -7,6 +7,7 @@ using SJZY.Track.Domain.Aggregates.TrackContentAggregate;
using SJZY.Track.Domain.Aggregates.TrackDetailsAggregate;
using SJZY.Track.Domain.Enums;
using SJZY.UserCenter.HttpApi.Services;
+using SJZY.UserCenter.HttpApi.Services.User;
using Volo.Abp.Http.Client.DynamicProxying;
namespace SJZY.Track.Application.Services.ProvideServices;
@@ -20,12 +21,12 @@ public partial class TrackService : ApplicationService, ITrackService
{
private readonly ICapPublisher _capPublisher;
private readonly IOrderRepository _orderRepository;
- private readonly IHttpClientProxy _requestCurrentUserService;
+ private readonly IHttpClientProxy _requestCurrentUserService;
private readonly ITrackContentRepository _trackContentRepository;
public TrackService(IOrderRepository orderRepository, ICapPublisher capPublisher,
ITrackDetailsEsRepository trackDetailsEsRepository, ITrackContentRepository trackContentRepository,
- IHttpClientProxy requestCurrentUserService)
+ IHttpClientProxy requestCurrentUserService)
{
_orderRepository = orderRepository;
_capPublisher = capPublisher;
@@ -62,7 +63,7 @@ public partial class TrackService : ApplicationService, ITrackService
//要求时间在当前时间的前后100年之间内
bool ValidateTrackTime(DateTime? d) => (d != null && d < DateTime.Now.AddYears(-100) || d > DateTime.Now.AddYears(100));
- if (ValidateTrackTime(input.TrackTime) || ValidateTrackTime(input.NewTrackTime))
+ if (ValidateTrackTime(input.TrackTime) || ValidateTrackTime(input.NewTrackTime) || ValidateTrackTime(input.EstimatedDeliveryDate))
{
throw new BusinessException(message: "轨迹时间不合法");
}
@@ -104,6 +105,35 @@ public partial class TrackService : ApplicationService, ITrackService
.Where(x => x.TrackTime == input.TrackTime)
.ToList();
+ //当为更新操作时发现更新的数目为0进行重试操作
+ if (!input.IsAdd && tracks.Count == 0)
+ {
+ var curRetryCount = 0;
+ var success = false;
+ while (!success && curRetryCount < GlobalConst.MaxUpdateTrackRetryCount)
+ {
+ try
+ {
+ tracks = (await _trackDetailsEsRepository.GetListAsync(new[] { order.Id }, input.TrackCode, true))
+ .Where(x => x.TrackTime == input.TrackTime)
+ .ToList();
+ if (tracks.Count > 0)
+ success = true;
+ await Task.Delay(300);
+ }
+ finally
+ {
+ curRetryCount++;
+ }
+ }
+
+ if (tracks.Count == 0)
+ {
+ throw new BusinessException(message: $"订单:{input.OrderNo},轨迹代码:{input.TrackCode}没有要更新的记录");
+ }
+ }
+
+
//更新轨迹,同一时间存在多条轨迹记录,理由:不清晰到底要修改哪一条或是全部修改
if (!input.IsAdd && tracks.Count > 1)
{
@@ -330,7 +360,7 @@ public partial class TrackService : ApplicationService, ITrackService
//要求时间在当前时间的前后100年之间内
bool ValidateTrackTime(DateTime? d) => (d != null && d < DateTime.Now.AddYears(-100) || d > DateTime.Now.AddYears(100));
- if (ValidateTrackTime(input.TrackTime) || ValidateTrackTime(input.NewTrackTime))
+ if (ValidateTrackTime(input.TrackTime) || ValidateTrackTime(input.NewTrackTime) || ValidateTrackTime(input.EstimatedDeliveryDate))
{
throw new BusinessException(message: "轨迹时间不合法");
}
@@ -366,6 +396,34 @@ public partial class TrackService : ApplicationService, ITrackService
.Where(x => x.TrackTime == input.TrackTime)
.ToList();
+ //当为更新操作时发现更新的数目为0进行重试操作
+ if (!input.IsAdd && tracks.Count == 0)
+ {
+ var curRetryCount = 0;
+ var success = false;
+ while (!success && curRetryCount < GlobalConst.MaxUpdateTrackRetryCount)
+ {
+ try
+ {
+ tracks = (await _trackDetailsEsRepository.GetListAsync(new[] { order.Id }, input.TrackCode, true))
+ .Where(x => x.TrackTime == input.TrackTime)
+ .ToList();
+ if (tracks.Count > 0)
+ success = true;
+ await Task.Delay(300);
+ }
+ finally
+ {
+ curRetryCount++;
+ }
+ }
+
+ if (tracks.Count == 0)
+ {
+ throw new BusinessException(message: $"订单:[{string.Join(",", input.OrderNos)}],轨迹代码:{input.TrackCode}没有要更新的记录");
+ }
+ }
+
//更新轨迹,同一时间存在多条轨迹记录,理由:不清晰到底要修改哪一条或是全部修改
if (!input.IsAdd && tracks.Count > 1)
{
@@ -386,10 +444,10 @@ public partial class TrackService : ApplicationService, ITrackService
{
SubSystemId = input.SubSystemId,
CustomId = group.Key,
- OrderIdentifiers = group.Select(order => new OrderIdentifier
+ OrderIdentifiers = group.Select(o => new OrderIdentifier
{
- OrderId = order.Id,
- OrderNo = order.OrderNo,
+ OrderId = o.Id,
+ OrderNo = o.OrderNo,
OrderType = input.OrderType,
}).ToArray(),
IsAdd = input.IsAdd,
@@ -415,6 +473,7 @@ public partial class TrackService : ApplicationService, ITrackService
TrackPlacePostcode = input.TrackPlacePostcode,
EstimatedDeliveryDate = input.EstimatedDeliveryDate,
DestinationTimeZone = input.DestinationTimeZone,
+ Extra = input.Extra
};
await _capPublisher.PublishAsync(GlobalConst.TrackUpsertSubscribe, @event);
}
diff --git a/src/SJZY.Track.Application/Services/ProvideServices/TrackTemplateService.cs b/src/SJZY.Track.Application/Services/ProvideServices/TrackTemplateService.cs
index 838f0397..ae02e06e 100644
--- a/src/SJZY.Track.Application/Services/ProvideServices/TrackTemplateService.cs
+++ b/src/SJZY.Track.Application/Services/ProvideServices/TrackTemplateService.cs
@@ -33,4 +33,18 @@ public class TrackTemplateService : ApplicationService, ITrackTemplateService
var res = ObjectMapper.Map, List>(templates);
return res;
}
+
+ ///
+ /// 分页获取轨迹模版列表
+ ///
+ ///
+ ///
+ [HttpPost("Template/GetTrackTemplateListByPage")]
+ public async Task> GetTrackTemplateListByPageAsync(GetPageTrackTemplateListInput input)
+ {
+ var inputVo = ObjectMapper.Map(input);
+ var templates = await _trackTemplateRepository.GetPageTrackTemplateListAsync(inputVo);
+ var res = ObjectMapper.Map, UnifyPageResultDto>(templates);
+ return res;
+ }
}
diff --git a/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs b/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs
index 3f3aa542..53bfc8c3 100644
--- a/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs
+++ b/src/SJZY.Track.Application/Services/TrackOrders/TrackOrderService.cs
@@ -127,13 +127,13 @@ public class TrackOrderService : ApplicationService
if (whereExpression == default)
throw new BusinessException(message: "请求参数异常");
- var subSystemId = await _orderRepository.GetFirstAsync(whereExpression, x => x.SubSystemId);
- if (subSystemId == default)
+ var order = await _orderRepository.GetFirstAsync(whereExpression);
+ if (order == default)
{
throw new BusinessException(message: "订单不存在");
}
- var trackDetails = await _trackDetailsEsRepository.GetListAsync(orderId ?? 0);
+ var trackDetails = await _trackDetailsEsRepository.GetListAsync(order.Id);
if (trackDetails.IsNullOrEmpty())
{
return new List();
@@ -150,7 +150,7 @@ public class TrackOrderService : ApplicationService
if (!trackCodes.IsNullOrEmpty())
{
var trackContents = await _trackContentRepository.GetListAsync(x =>
- x.SubSystemId == subSystemId && trackCodes.Contains(x.Code), x => new
+ x.SubSystemId == order.SubSystemId && trackCodes.Contains(x.Code), x => new
{
x.Code,
x.IsExternal
diff --git a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs
index 762c1324..eaf3ca71 100644
--- a/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs
+++ b/src/SJZY.Track.Domain/Aggregates/OrderAggregate/OrderEntity.cs
@@ -201,5 +201,7 @@ public class OrderEntity : IFullAuditedBasicEntitys, IAggregateRoot
LatestTrackTime = null;
LatestTrackPlace = null;
LatestTrackTimeZone = null;
+ EstimatedDeliveryDate = null;
+ DestinationTimeZone = null;
}
}
diff --git a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/TrackDetailsIndex.cs b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/TrackDetailsIndex.cs
index c842786b..60eed6a3 100644
--- a/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/TrackDetailsIndex.cs
+++ b/src/SJZY.Track.Domain/Aggregates/TrackDetailsAggregate/TrackDetailsIndex.cs
@@ -32,6 +32,11 @@ public class TrackDetailsIndex : IdBaseIndex
///
public int OrderType { get; set; }
+ ///
+ /// 轨迹状态Id
+ ///
+ public int TrackStatusId { get; set; } = GlobalConst.NotExistId;
+
///
/// 轨迹状态
///
@@ -42,6 +47,11 @@ public class TrackDetailsIndex : IdBaseIndex
///
public string TrackStatusCode { get; set; } = GlobalConst.EmptyString;
+ ///
+ /// 轨迹内容Id
+ ///
+ public int TrackContentId { get; set; } = GlobalConst.NotExistId;
+
///
/// 轨迹内容代码
///
@@ -176,4 +186,9 @@ public class TrackDetailsIndex : IdBaseIndex
/// 签收地时区
///
public float? DestinationTimeZone { get; set; }
+
+ ///
+ /// 扩展信息字段,用与轨迹推送的附加字段
+ ///
+ public Dictionary? Extra { get; set; }
}
diff --git a/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/ITrackTemplateRepository.cs b/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/ITrackTemplateRepository.cs
index db202083..efae67b2 100644
--- a/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/ITrackTemplateRepository.cs
+++ b/src/SJZY.Track.Domain/Aggregates/TrackTemplateAggregate/ITrackTemplateRepository.cs
@@ -45,5 +45,6 @@ public interface ITrackTemplateRepository : IBasicRepository> whereExpression);
Task> GetTrackTemplateListAsync(GetTrackTemplateListInputVo input);
+ Task> GetPageTrackTemplateListAsync(GetPageTrackTemplateListInputVo input);
Task> GetContentByTemplateCodes(string[] codes, int systemId);
}
diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.Track.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.Track.cs
index eed1301d..3ffed645 100644
--- a/src/SJZY.Track.Domain/Consts/GlobalConst.Track.cs
+++ b/src/SJZY.Track.Domain/Consts/GlobalConst.Track.cs
@@ -8,4 +8,9 @@ public partial class GlobalConst
/// 轨迹数据来源:1外部服务商创建,2内部系统创建,3人工创建
///
public static readonly ImmutableHashSet SupportTrackSources = ImmutableHashSet.Create(1, 2, 3);
+
+ ///
+ /// 最大更新轨迹重试次数
+ ///
+ public const int MaxUpdateTrackRetryCount = 3;
}
diff --git a/src/SJZY.Track.Domain/Consts/GlobalConst.cs b/src/SJZY.Track.Domain/Consts/GlobalConst.cs
index d8064f12..c6416b1d 100644
--- a/src/SJZY.Track.Domain/Consts/GlobalConst.cs
+++ b/src/SJZY.Track.Domain/Consts/GlobalConst.cs
@@ -2,6 +2,8 @@ namespace SJZY.Track.Domain.Consts;
public partial class GlobalConst
{
+ public const string MainDataKey_OrderType = "TrackOrderType";
+ public const string MainDataKey_TrackQuestionType = "TrackQuestionType";
public const string SystemUser = "系统";
public const string EmptyString = "--";
public const int ChunkSize = 100;
diff --git a/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs b/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs
index 8b7cdf3f..07982ec1 100644
--- a/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs
+++ b/src/SJZY.Track.Domain/Dtos/TrackContents/TrackContentVO.cs
@@ -17,6 +17,11 @@ public class TrackContentVO
///
public string TrackStatus { get; set; } = null!;
+ ///
+ /// 轨迹内容Id
+ ///
+ public int TrackContentId { get; set; }
+
///
/// 轨迹内容
///
diff --git a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetPageTrackTemplateListInputVo.cs b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetPageTrackTemplateListInputVo.cs
new file mode 100644
index 00000000..f801ffdc
--- /dev/null
+++ b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetPageTrackTemplateListInputVo.cs
@@ -0,0 +1,29 @@
+namespace SJZY.Track.Domain.Dtos.TrackTemplate;
+
+public class GetPageTrackTemplateListInputVo : PageInfoInput
+{
+ ///
+ /// 子系统id
+ ///
+ public int SubSystemId { get; set; }
+
+ ///
+ /// 客户id
+ ///
+ public int? CustomerId { get; set; }
+
+ ///
+ /// 模版分类
+ ///
+ public int? TemplateType { get; set; }
+
+ ///
+ /// 模板code
+ ///
+ public string? TemplateCode { get; set; }
+
+ ///
+ /// 关键字
+ ///
+ public string? KeyWord { get; set; }
+}
diff --git a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateListInputVo.cs b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateListInputVo.cs
index 7e0abd82..a2f111a7 100644
--- a/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateListInputVo.cs
+++ b/src/SJZY.Track.Domain/Dtos/TrackTemplate/GetTrackTemplateListInputVo.cs
@@ -16,4 +16,9 @@ public class GetTrackTemplateListInputVo
/// 模版分类
///
public int? TemplateType { get; set; }
+
+ ///
+ /// 模板code
+ ///
+ public string? TemplateCode { get; set; }
}
diff --git a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs
index ec5f18fe..413097c8 100644
--- a/src/SJZY.Track.Repository/Repositories/OrderRepository.cs
+++ b/src/SJZY.Track.Repository/Repositories/OrderRepository.cs
@@ -1,3 +1,4 @@
+using NUglify.Helpers;
using SJZY.Expand.ABP.Core.Logger;
using SJZY.Track.Domain;
using SJZY.Track.Domain.Aggregates.OrderAggregate;
@@ -55,6 +56,45 @@ public class OrderRepository : BasicRepository, IOrderRepository, I
})
.ToPagedListAsync(input.PageIndex, input.PageSize);
+ //查询订单类型描述
+ var orderTypes = pageList.List.Select(x => x.OrderType).Distinct().ToList();
+ var questTypes = pageList.List.Select(x => x.QuestionType).Distinct().ToList();
+ //从主数据中心查询类型描述
+ var typeDispDict = (await Context.Queryable()
+ .Where(x =>
+ (x.Property == GlobalConst.MainDataKey_OrderType && orderTypes.Contains(x.Enumkey))
+ || (x.Property == GlobalConst.MainDataKey_TrackQuestionType && questTypes.Contains(x.Enumkey))
+ )
+ .Select(x => new
+ {
+ x.Property,
+ x.Enumkey,
+ x.Disp
+ })
+ .ToListAsync()
+ )
+ .GroupBy(x => x.Property)
+ .ToDictionary(
+ g => g.Key,
+ y => y.ToDictionary(x => x.Enumkey, x => x.Disp)
+ );
+
+ //填充数描述信息
+ pageList.List.ForEach(x =>
+ {
+ x.OrderTypeName = typeDispDict.TryGetValue(GlobalConst.MainDataKey_OrderType, out var orderTypeDisplayDict)
+ ? orderTypeDisplayDict.TryGetValue(x.OrderType, out var orderTypeDisplay)
+ ? orderTypeDisplay
+ : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}] Enumkey:[{x.OrderType}]"
+ : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}]";
+
+ x.QuestionTypeName = typeDispDict.TryGetValue(GlobalConst.MainDataKey_TrackQuestionType, out var questDisplayDict)
+ ? questDisplayDict.TryGetValue(x.QuestionType, out var questDisplay)
+ ? questDisplay
+ : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_OrderType}] Enumkey:[{x.OrderType}]"
+ : $"未在主数据中心找到Property:[{GlobalConst.MainDataKey_TrackQuestionType}]";
+ });
+
return pageList;
}
diff --git a/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs
index d619613b..7db9435d 100644
--- a/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs
+++ b/src/SJZY.Track.Repository/Repositories/TrackContentRepository.cs
@@ -261,6 +261,7 @@ public class TrackContentRepository : BasicRepository, ITrac
TrackStatusId = x.TrackStatusId,
TrackStatus = y.Status,
TrackStatusCode = y.Code,
+ TrackContentId = x.Id,
TrackContent = x.Content,
TrackContentCode = x.Code,
TrackEnContent = x.EnContent,
diff --git a/src/SJZY.Track.Repository/Repositories/TrackDetailsEsRepository.cs b/src/SJZY.Track.Repository/Repositories/TrackDetailsEsRepository.cs
index 246cfa7e..e25c9b89 100644
--- a/src/SJZY.Track.Repository/Repositories/TrackDetailsEsRepository.cs
+++ b/src/SJZY.Track.Repository/Repositories/TrackDetailsEsRepository.cs
@@ -173,7 +173,8 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract p
.Add("trackPlace", track.TrackPlace)
@@ -241,6 +242,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract p
.Add("trackPlace", track.TrackPlace)
.Add("trackTime", track.TrackTime)
@@ -314,8 +317,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract, ITr
.Where(x => x.SubSystemId == input.SubSystemId)
.WhereIF(input.CustomerId.HasValue, x => x.CustomerId == input.CustomerId)
.WhereIF(input.TemplateType.HasValue, x => x.CategoryId == input.TemplateType)
+ .WhereIF(!input.TemplateCode.IsNullOrWhiteSpace(), x => x.Code == input.TemplateCode)
.Select(x => new TrackTemplateOutputVo
{
Id = x.Id,
@@ -227,9 +228,49 @@ public class TrackTemplateRepository : BasicRepository, ITr
return templates;
}
+ public async Task> GetPageTrackTemplateListAsync(GetPageTrackTemplateListInputVo input)
+ {
+ var templates = await Context.Queryable()
+ .Where(x => x.SubSystemId == input.SubSystemId)
+ .WhereIF(input.CustomerId.HasValue, x => x.CustomerId == input.CustomerId)
+ .WhereIF(input.TemplateType.HasValue, x => x.CategoryId == input.TemplateType)
+ .WhereIF(!input.TemplateCode.IsNullOrWhiteSpace(), x => x.Code == input.TemplateCode)
+ .Select(x => new TrackTemplateOutputVo
+ {
+ Id = x.Id,
+ TemplateName = x.Name,
+ TemplateCode = x.Code,
+ })
+ .ToListAsync();
+
+ if (templates == default) return new UnifyPageResultDto();
+ var templateIds = templates.Select(x => x.Id).ToArray();
+ var contents = await Context.Queryable()
+ .LeftJoin((a, b) => a.TrackContentId == b.Id)
+ .LeftJoin((a, b, c) => b.TrackStatusId == c.Id)
+ .LeftJoin((a, b, c, d) => c.Node == d.Id)
+ .Where(a => templateIds.Contains(a.TrackTemplateId))
+ .WhereIF(!input.KeyWord.IsNullOrWhiteSpace(), (a, b, c, d) =>
+ b.Code.Contains(input.KeyWord!)
+ || b.EnContent.Contains(input.KeyWord!)
+ || b.Content.Contains(input.KeyWord!)
+ )
+ .Select((a, b, c, d) => new TemplateContentDtoVo
+ {
+ TemplateId = a.TrackTemplateId,
+ Code = b.Code,
+ ContentCn = b.Content,
+ ContentEn = b.EnContent,
+ Status = c.Status,
+ Node = d.NodeName
+ })
+ .ToPagedListAsync(input.PageIndex, input.PageSize);
+
+ return contents;
+ }
+
public async Task> GetContentByTemplateCodes(string[] codes, int systemId)
{
-
var sql = @$"
select
distinct
@@ -244,7 +285,10 @@ public class TrackTemplateRepository : BasicRepository, ITr
";
- var list = Context.Ado.SqlQuery(sql, new {codes = codes}).ToList();
+ var list = Context.Ado.SqlQuery(sql, new
+ {
+ codes = codes
+ }).ToList();
return list;
}
diff --git a/src/SJZY.Track.Repository/SJZY.Track.Repository.csproj b/src/SJZY.Track.Repository/SJZY.Track.Repository.csproj
index bc16be84..4718739b 100644
--- a/src/SJZY.Track.Repository/SJZY.Track.Repository.csproj
+++ b/src/SJZY.Track.Repository/SJZY.Track.Repository.csproj
@@ -8,9 +8,9 @@
-
+
-
+