zhangxiaofeng 8 months ago
commit 273beb928a

@ -17,6 +17,7 @@ using Myshipping.Core.Service;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Myshipping.Application.Helper; using Myshipping.Application.Helper;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Globalization;
namespace Myshipping.Application.Service.BookingOrder namespace Myshipping.Application.Service.BookingOrder
{ {
@ -280,6 +281,7 @@ namespace Myshipping.Application.Service.BookingOrder
userSecret = App.Configuration["MSKAPIDjyUserSecret"], userSecret = App.Configuration["MSKAPIDjyUserSecret"],
operatingEnvironment = App.Configuration["MSKAPIOPEnvironment"], operatingEnvironment = App.Configuration["MSKAPIOPEnvironment"],
mskAppKey = webAccountConfig.Account, mskAppKey = webAccountConfig.Account,
mskAppSecret = webAccountConfig.Password,
bookingBody = new MSKAPIBookingBodyDto() bookingBody = new MSKAPIBookingBodyDto()
}; };
@ -288,6 +290,7 @@ namespace Myshipping.Application.Service.BookingOrder
priceReference = model.priceReference, priceReference = model.priceReference,
productCode = model.productCode, productCode = model.productCode,
sender = model.sender, sender = model.sender,
bookingOfficeUNLocationCode = "CNTAO"
}; };
bookingDto.bookingBody.mandatoryParties = new MSKAPIBookingMandatoryParties bookingDto.bookingBody.mandatoryParties = new MSKAPIBookingMandatoryParties
@ -311,7 +314,7 @@ namespace Myshipping.Application.Service.BookingOrder
bookingDto.bookingBody.transport = new MSKAPIBookingTransport bookingDto.bookingBody.transport = new MSKAPIBookingTransport
{ {
carrierCode = model.carrierCode, carrierCode = model.carrierCode,
earliestDepartureDate = model.earliestDepartureDate, earliestDepartureDate = model.earliestDepartureDate.Value.ToString("yyyy-MM-ddTHH:mm:ss"),
exportServiceMode = model.exportServiceMode, exportServiceMode = model.exportServiceMode,
importServiceMode = model.importServiceMode, importServiceMode = model.importServiceMode,
routeDetails = new MSKAPIBookingRouteDetails routeDetails = new MSKAPIBookingRouteDetails
@ -328,30 +331,32 @@ namespace Myshipping.Application.Service.BookingOrder
}, },
selectedRoute = new MSKAPIBookingRoute selectedRoute = new MSKAPIBookingRoute
{ {
bookingSchedules = new MSKAPIBookingSchedules bookingSchedules = new List<MSKAPIBookingSchedules> {
{ new MSKAPIBookingSchedules
originDepartureDateTimeLocal = model.originDepartureDateTimeLocal.Value.ToString("yyyy-MM-dd"),
destinationArrivalDateTimeLocal = model.destinationArrivalDateTimeLocal.Value.ToString("yyyy-MM-dd"),
transportMode = new MSKAPIBookingTransportMode
{ {
vessel = new MSKAPIBookingTransportModeVessel originDepartureDateTimeLocal = model.originDepartureDateTimeLocal.Value.ToString("yyyy-MM-ddTHH:mm:ss"),
destinationArrivalDateTimeLocal = model.destinationArrivalDateTimeLocal.Value.ToString("yyyy-MM-ddTHH:mm:ss"),
transportMode = new MSKAPIBookingTransportMode
{ {
name = model.vesselName, vessel = new MSKAPIBookingTransportModeVessel
maerskVesselCode = model.carrierVesselCode, {
name = model.vesselName,
maerskVesselCode = model.carrierVesselCode,
},
exportVoyageNumber = model.exportVoyageNumber,
}, },
exportVoyageNumber = model.exportVoyageNumber, startLocation = new MSKAPIBookingRouteDetailsBase
}, {
startLocation = new MSKAPIBookingRouteDetailsBase cityName = model.placeOfReceiptCityName,
{ UNLocationCode = model.placeOfReceiptUnLocCode
cityName = model.placeOfReceiptCityName, },
UNLocationCode = model.placeOfReceiptUnLocCode endLocation = new MSKAPIBookingRouteDetailsBase
}, {
endLocation = new MSKAPIBookingRouteDetailsBase cityName = model.placeOfDeliveryCityName,
{ UNLocationCode = model.placeOfDeliveryUnLocCode
cityName = model.placeOfDeliveryCityName, },
UNLocationCode = model.placeOfDeliveryUnLocCode transportModeCode = model.transportMode
}, }
transportModeCode = model.transportMode
} }
}, },
} }
@ -412,13 +417,14 @@ namespace Myshipping.Application.Service.BookingOrder
}); });
} }
var id = await Save(model); var id = await InnerSave(model, isSendApi: true);
MSKAPIBookingResultDto resultInfo = null; MSKAPIBookingResultDto resultInfo = null;
_logger.LogInformation($"开始请求MSK API订舱JSON={JSON.Serialize(bookingDto)}"); _logger.LogInformation($"开始请求MSK API订舱JSON={JSON.Serialize(bookingDto)}");
var rlt = await sendUrl.SetBody(bookingDto) var jsonBody = Newtonsoft.Json.JsonConvert.SerializeObject(bookingDto);
var rlt = await sendUrl.SetBody(jsonBody)
.PostAsStringAsync(); .PostAsStringAsync();
_logger.LogInformation($"开始请求MSK API订舱返回结果 JSON={JSON.Serialize(rlt)}"); _logger.LogInformation($"开始请求MSK API订舱返回结果 JSON={JSON.Serialize(rlt)}");
@ -437,14 +443,21 @@ namespace Myshipping.Application.Service.BookingOrder
} }
} }
MSKAPIBookingResultDataDto resultData = null;
if(resultInfo.code == 200)
{
resultData = JSON.Deserialize<MSKAPIBookingResultDataDto>(JSON.Serialize(resultInfo.data));
}
var entity = _bookingDeliveryRecordRep var entity = _bookingDeliveryRecordRep
.FirstOrDefault(a => a.Id == recordInfo.Id); .FirstOrDefault(a => a.Id == recordInfo.Id);
if (resultInfo != null && resultInfo.code == 200 if (resultInfo != null && resultInfo.code == 200
&& resultInfo.data != null) && resultData != null)
{ {
entity.REQUEST_ACKNOWLEDGEMENT_ID = resultInfo.data.requestAcknowledgementId; entity.REQUEST_ACKNOWLEDGEMENT_ID = resultData.requestAcknowledgementId;
entity.BOOKING_REFERENCE = resultInfo.data.bookingReference; entity.BOOKING_REFERENCE = resultData.bookingReference;
entity.STATUS = "SUCC"; entity.STATUS = "SUCC";
await _bookingDeliveryRecordRep.AsUpdateable(entity).UpdateColumns(x => new await _bookingDeliveryRecordRep.AsUpdateable(entity).UpdateColumns(x => new
@ -464,6 +477,9 @@ namespace Myshipping.Application.Service.BookingOrder
x.STATUS, x.STATUS,
x.NOTES x.NOTES
}).ExecuteCommandAsync(); }).ExecuteCommandAsync();
throw Oops.Bah(resultInfo.msg);
} }
} }
catch (Exception ex) catch (Exception ex)
@ -500,6 +516,7 @@ namespace Myshipping.Application.Service.BookingOrder
12 12
13 13
14=* 14=*
15
*/ */
if (string.IsNullOrWhiteSpace(model.priceReference)) if (string.IsNullOrWhiteSpace(model.priceReference))
throw Oops.Bah($"订舱合同惟一ID必填"); throw Oops.Bah($"订舱合同惟一ID必填");
@ -585,6 +602,9 @@ namespace Myshipping.Application.Service.BookingOrder
if (string.IsNullOrWhiteSpace(model.cargoType)) if (string.IsNullOrWhiteSpace(model.cargoType))
throw Oops.Bah($"货物标志必填"); throw Oops.Bah($"货物标志必填");
if(!model.earliestDepartureDate.HasValue)
throw Oops.Bah($"预计离港日期必填");
if (model.isReefer) if (model.isReefer)
{ {
if (!model.temperature.HasValue) if (!model.temperature.HasValue)
@ -960,9 +980,9 @@ namespace Myshipping.Application.Service.BookingOrder
/// <param name="id">马士基API订舱ID</param> /// <param name="id">马士基API订舱ID</param>
/// <returns>返回详情</returns> /// <returns>返回详情</returns>
[HttpGet("/BookingMSKAPI/GetInfo")] [HttpGet("/BookingMSKAPI/GetInfo")]
public async Task<BookingDeliveryRecordDto> GetInfo(long id) public async Task<MSKBookingDto> GetInfo(long id)
{ {
BookingDeliveryRecordDto model = null; MSKBookingDto model = null;
var entity = await _bookingDeliveryRecordRep.AsQueryable() var entity = await _bookingDeliveryRecordRep.AsQueryable()
.FirstAsync(a => a.Id == id); .FirstAsync(a => a.Id == id);
@ -970,14 +990,15 @@ namespace Myshipping.Application.Service.BookingOrder
if(entity == null) if(entity == null)
throw Oops.Oh($"获取马士基API订舱详情失败不存在或已作废"); throw Oops.Oh($"获取马士基API订舱详情失败不存在或已作废");
model = entity.Adapt<BookingDeliveryRecordDto>(); model = entity.Adapt<MSKBookingDto>();
var ctnList = _bookingDeliveryRecordCtnRep.AsQueryable() var ctnList = _bookingDeliveryRecordCtnRep.AsQueryable()
.Where(a => a.RECORD_ID == id && a.IsDeleted == false).ToList(); .Where(a => a.RECORD_ID == id && a.IsDeleted == false).ToList();
if (ctnList.Count > 0) if (ctnList.Count > 0)
{ {
model.ctns = ctnList.Select(a => new BookingDeliveryRecordCtnDto { model.ctns = ctnList.Select(a => new MSKBookingCtnInfo
{
id = a.Id, id = a.Id,
ctnCode = a.CTN_CODE, ctnCode = a.CTN_CODE,
carrierCtnCode = a.CARRIER_CTN_CODE, carrierCtnCode = a.CARRIER_CTN_CODE,
@ -1000,6 +1021,18 @@ namespace Myshipping.Application.Service.BookingOrder
/// <returns>返回ID</returns> /// <returns>返回ID</returns>
[HttpPost("/BookingMSKAPI/Save")] [HttpPost("/BookingMSKAPI/Save")]
public async Task<long> Save([FromBody] MSKBookingDto model) public async Task<long> Save([FromBody] MSKBookingDto model)
{
return await InnerSave(model);
}
#endregion
/// <summary>
/// 保存内部方法
/// </summary>
/// <param name="model">API订舱详情</param>
/// <param name="isSendApi">是否发送APItrue-发送需要校验状态false-不校验状态</param>
/// <returns></returns>
private async Task<long> InnerSave(MSKBookingDto model,bool isSendApi = false)
{ {
DateTime nowDate = DateTime.Now; DateTime nowDate = DateTime.Now;
@ -1013,10 +1046,20 @@ namespace Myshipping.Application.Service.BookingOrder
.Select(a => $"{a.Key}*{a.ToList().Sum(b => b.ctnNum.HasValue ? b.ctnNum.Value : 0)}").ToArray()); .Select(a => $"{a.Key}*{a.ToList().Sum(b => b.ctnNum.HasValue ? b.ctnNum.Value : 0)}").ToArray());
} }
if (model.id.HasValue && model.id.Value > 0) if (model.id.HasValue && model.id.Value > 0)
{ {
var oldInfo = _bookingDeliveryRecordRep.AsQueryable()
.First(a=>a.Id == model.id);
if (oldInfo == null)
throw Oops.Oh("订舱数据不存在或已作废");
if (isSendApi)
{
if(oldInfo.STATUS == "SUCC")
throw Oops.Oh("订舱数据已发送成功,不能重复发送");
}
BookingDeliveryRecord entity = model.Adapt<BookingDeliveryRecord>(); BookingDeliveryRecord entity = model.Adapt<BookingDeliveryRecord>();
entity.Id = model.id.Value; entity.Id = model.id.Value;
@ -1086,7 +1129,7 @@ namespace Myshipping.Application.Service.BookingOrder
}); });
if(ctnEntityList.Count > 0) if (ctnEntityList.Count > 0)
{ {
ctnEntityList.ForEach(async ctn => { ctnEntityList.ForEach(async ctn => {
ctn.IsDeleted = true; ctn.IsDeleted = true;
@ -1140,7 +1183,6 @@ namespace Myshipping.Application.Service.BookingOrder
return entity.Id; return entity.Id;
} }
} }
#endregion
#region 删除 #region 删除
/// <summary> /// <summary>

@ -136,8 +136,56 @@ namespace Myshipping.Application
.Map(dest => dest.PRICE_REFERENCE_NAME, src => src.priceReferenceName) .Map(dest => dest.PRICE_REFERENCE_NAME, src => src.priceReferenceName)
.Map(dest => dest.PRICE_OWNER_REFERENCE_ID, src => src.priceOwnerReferenceId) .Map(dest => dest.PRICE_OWNER_REFERENCE_ID, src => src.priceOwnerReferenceId)
.Map(dest => dest.PRICE_OWNER_REFERENCE, src => src.priceOwnerReference) .Map(dest => dest.PRICE_OWNER_REFERENCE, src => src.priceOwnerReference)
.Map(dest => dest.PRICE_OWNER_REFERENCE_NAME, src => src.priceOwnerReferenceName); .Map(dest => dest.PRICE_OWNER_REFERENCE_NAME, src => src.priceOwnerReferenceName)
.Map(dest => dest.IS_REEFER, src => src.isReefer);
config.ForType<BookingDeliveryRecord, MSKBookingDto>()
.Map(dest => dest.id, src => src.Id)
.Map(dest => dest.carrierId, src => src.CARRIERID)
.Map(dest => dest.priceReference, src => src.PRICE_REFERENCE)
.Map(dest => dest.productCode, src => src.PRODUCT_CODE)
.Map(dest => dest.sender, src => src.SENDER)
.Map(dest => dest.bookedByCompanyName, src => src.BOOKEDBY_COMPANY_NAME)
.Map(dest => dest.bookedByMaerskPartyCode, src => src.BOOKEDBY_COMPANY_PARTYCODE)
.Map(dest => dest.bookedByCompanyContactName, src => src.BOOKEDBY_COMPANY_CONTACT)
.Map(dest => dest.bookedByCompanyContactEmail, src => src.BOOKEDBY_COMPANY_CONTACT_EMAIL)
.Map(dest => dest.isBookingPartOwnPrice, src => src.IS_BOOKING_PART_OWN_PRICE)
.Map(dest => dest.priceOwnerCompanyName, src => src.PRICE_OWNER_COMPANY_NAME)
.Map(dest => dest.priceOwnerMaerskPartyCode, src => src.PRICE_OWNER_COMPANY_PARTYCODE)
.Map(dest => dest.priceOwnerContactName, src => src.PRICE_OWNER_COMPANY_CONTACT)
.Map(dest => dest.priceOwnerContactEmail, src => src.PRICE_OWNER_COMPANY_CONTACT_EMAIL)
.Map(dest => dest.carrierCode, src => src.CARRIER_CODE)
.Map(dest => dest.earliestDepartureDate, src => src.EARLIEST_DEPARTURE_DATE)
.Map(dest => dest.exportServiceMode, src => src.EXPORT_SERVICE_MODE)
.Map(dest => dest.importServiceMode, src => src.IMPORT_SERVICE_MODE)
.Map(dest => dest.placeOfReceiptCityName, src => src.PLACERECEIPT_CITY)
.Map(dest => dest.placeOfReceiptUnLocCode, src => src.PLACERECEIPT_UNLOC_CODE)
.Map(dest => dest.placeOfDeliveryCityName, src => src.PLACEDELIVERY_CITY)
.Map(dest => dest.placeOfDeliveryUnLocCode, src => src.PLACEDELIVERY_UNLOC_CODE)
.Map(dest => dest.originDepartureDateTimeLocal, src => src.ETD)
.Map(dest => dest.destinationArrivalDateTimeLocal, src => src.ETA)
.Map(dest => dest.vesselName, src => src.VESSEL)
.Map(dest => dest.carrierVesselCode, src => src.VESSEL_CODE)
.Map(dest => dest.exportVoyageNumber, src => src.VOYNO)
.Map(dest => dest.transportMode, src => src.TRANSPORT_MODE)
.Map(dest => dest.totalCargoWeight, src => src.TOTAL_CARGO_WEIGHT)
.Map(dest => dest.noOfProbes, src => src.NO_OF_PROBES)
.Map(dest => dest.temperature, src => src.TEMPSET)
.Map(dest => dest.ventilation, src => src.VENT)
.Map(dest => dest.humidity, src => src.HUMIDITY)
.Map(dest => dest.commodityCodeType, src => src.COMMODITY_CODE_TYPE)
.Map(dest => dest.commodityCode, src => src.GOODSCODE)
.Map(dest => dest.commodityName, src => src.GOODSNAME)
.Map(dest => dest.isReefer, src => src.IS_REEFER)
.Map(dest => dest.cargoType, src => src.CARGO_TYPE)
.Map(dest => dest.placeOfReceiptCountryCode, src => src.PLACERECEIPT_COUNTRY_CODE)
.Map(dest => dest.placeOfDeliveryCountryCode, src => src.PLACEDELIVERY_COUNTRY_CODE)
.Map(dest => dest.EstSailingDays, src => src.EST_SAILING_DAYS)
.Map(dest => dest.priceReferenceId, src => src.PRICE_REFERENCE_ID)
.Map(dest => dest.priceReferenceName, src => src.PRICE_REFERENCE_NAME)
.Map(dest => dest.priceOwnerReferenceId, src => src.PRICE_OWNER_REFERENCE_ID)
.Map(dest => dest.priceOwnerReference, src => src.PRICE_OWNER_REFERENCE)
.Map(dest => dest.priceOwnerReferenceName, src => src.PRICE_OWNER_REFERENCE_NAME);
config.ForType<MSKBookingCtnInfo, BookingDeliveryRecordCtn>() config.ForType<MSKBookingCtnInfo, BookingDeliveryRecordCtn>()
.Map(dest => dest.CTN_CODE, src => src.ctnCode) .Map(dest => dest.CTN_CODE, src => src.ctnCode)

@ -382,7 +382,7 @@ namespace Myshipping.Application
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public MSKAPIBookingSchedules bookingSchedules { get; set; } public List<MSKAPIBookingSchedules> bookingSchedules { get; set; }
/// <summary> /// <summary>
/// 航行时间,分钟为单位 /// 航行时间,分钟为单位

@ -21,7 +21,7 @@ namespace Myshipping.Application
/// <summary> /// <summary>
/// 订舱回执详情 /// 订舱回执详情
/// </summary> /// </summary>
public MSKAPIBookingResultDataDto data { get; set; } public object data { get; set; }
} }
/// <summary> /// <summary>

@ -121,7 +121,7 @@ namespace Myshipping.Application
/// <summary> /// <summary>
/// 最早起运日期, 不可小于当前日期 /// 最早起运日期, 不可小于当前日期
/// </summary> /// </summary>
public string earliestDepartureDate { get; set; } public Nullable<DateTime> earliestDepartureDate { get; set; }
/// <summary> /// <summary>
/// 出口服务类型(CY, SD, CFS) /// 出口服务类型(CY, SD, CFS)
@ -293,5 +293,20 @@ namespace Myshipping.Application
/// 集装箱主键 /// 集装箱主键
/// </summary> /// </summary>
public Nullable<long> id { get; set; } public Nullable<long> id { get; set; }
/// <summary>
/// 对应船公司箱型
/// </summary>
public string carrierCtnCode { get; set; }
/// <summary>
/// 箱计量单位
/// </summary>
public string stuffingMeasurementType { get; set; }
/// <summary>
/// 重量或者体积的计量单位
/// </summary>
public string stuffingMeasurementUnit { get; set; }
} }
} }

@ -50,7 +50,7 @@ namespace Myshipping.Application
/// </summary> /// </summary>
/// <param name="id">马士基API订舱ID</param> /// <param name="id">马士基API订舱ID</param>
/// <returns>返回详情</returns> /// <returns>返回详情</returns>
Task<BookingDeliveryRecordDto> GetInfo(long id); Task<MSKBookingDto> GetInfo(long id);
/// <summary> /// <summary>
/// 保存 /// 保存

@ -89,5 +89,12 @@ namespace Myshipping.Application
/// <param name="taskPKId">BC任务主键</param> /// <param name="taskPKId">BC任务主键</param>
/// <returns>返回回执</returns> /// <returns>返回回执</returns>
Task<List<CompareResultDetailInfo>> GetCompareResult(string taskPKId); Task<List<CompareResultDetailInfo>> GetCompareResult(string taskPKId);
/// <summary>
/// 同步舱位变更
/// </summary>
/// <param name="taskPKId">BC任务主键</param>
/// <returns>返回回执</returns>
Task<TaskManageOrderResultDto> SyncBookingSlotChange(string taskPKId);
} }
} }

@ -925,7 +925,7 @@ namespace Myshipping.Application
/// <param name="taskBCCtnList">BC任务集装箱列表</param> /// <param name="taskBCCtnList">BC任务集装箱列表</param>
/// <param name="taskFileList">BC任务附件列表</param> /// <param name="taskFileList">BC任务附件列表</param>
/// <returns>返回舱位ID</returns> /// <returns>返回舱位ID</returns>
private async Task<long> GenerateBookingSlot(TaskBCInfo taskBCInfo, List<TaskBCCTNInfo> taskBCCtnList, List<TaskFileInfo> taskFileList) private async Task<long> GenerateBookingSlot(TaskBCInfo taskBCInfo, List<TaskBCCTNInfo> taskBCCtnList, List<TaskFileInfo> taskFileList,string opType = "add")
{ {
long id = 0; long id = 0;
@ -972,7 +972,7 @@ namespace Myshipping.Application
TRANSFER_PORT_2 = taskBCInfo.TRANSFER_PORT_2, TRANSFER_PORT_2 = taskBCInfo.TRANSFER_PORT_2,
CtnList = new List<BookingSlotCtnSaveInput>() CtnList = new List<BookingSlotCtnSaveInput>()
}, },
OpType = "add" OpType = opType
}; };
var ctnCodeList = _cache.GetAllCodeCtn().GetAwaiter().GetResult().ToList(); var ctnCodeList = _cache.GetAllCodeCtn().GetAwaiter().GetResult().ToList();
@ -1809,6 +1809,54 @@ namespace Myshipping.Application
return await _bookingSlotService.GetSlotCompareResult(bcOrder.BOOKING_SLOT_ID.Value, bcOrder.BATCH_NO); return await _bookingSlotService.GetSlotCompareResult(bcOrder.BOOKING_SLOT_ID.Value, bcOrder.BATCH_NO);
} }
/// <summary>
/// 同步舱位变更
/// </summary>
/// <param name="taskPKId">BC任务主键</param>
/// <returns>返回回执</returns>
[HttpGet("/TaskManageBC/SyncBookingSlotChange")]
public async Task<TaskManageOrderResultDto> SyncBookingSlotChange(string taskPKId)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
/*
1
2
3
*/
try
{
var bcOrder = _taskBCInfoRepository.AsQueryable().First(a => a.TASK_ID == taskPKId);
if (bcOrder == null)
throw Oops.Oh($"任务主键{taskPKId}无法获取BC业务信息");
if(bcOrder.BOOKING_SLOT_ID.HasValue && bcOrder.BOOKING_SLOT_ID.Value > 0)
{
var bcCtnList = _taskBCCTNInfoRepository.AsQueryable().Where(a => a.P_ID == bcOrder.PK_ID).ToList();
var fileList = _taskFileRepository.AsQueryable().Where(a => a.TASK_PKID == taskPKId).ToList();
//推送舱位
var bookingSlotId = GenerateBookingSlot(bcOrder, bcCtnList, fileList,"update").GetAwaiter().GetResult();
}
else
{
throw Oops.Oh($"未检索到对应的舱位信息");
}
}
catch (Exception ex)
{
result.succ = false;
result.msg = $"处理异常,原因:{ex.Message}";
}
return result;
}
} }
/// <summary> /// <summary>

@ -741,6 +741,21 @@ namespace Myshipping.Application
await _taskBCCTNInfoRepository.InsertAsync(bcCtnInfo); await _taskBCCTNInfoRepository.InsertAsync(bcCtnInfo);
}); });
/*
BC_MODIFY
1
2
3
CANCELLATION
1
2
*/
if (info.Main.TaskType == TaskBaseTypeEnum.BC_MODIFY)
{
}
} }
#endregion #endregion

Loading…
Cancel
Save