|  |  | 
 |  |  | using ZeroD.Util; | 
 |  |  | using LifePayment.Domain; | 
 |  |  | using static LifePayment.Domain.Shared.LifePaymentConstant; | 
 |  |  | using Newtonsoft.Json; | 
 |  |  | using LifePayment.Domain.Common; | 
 |  |  | using Spire.Pdf.Exporting.XPS.Schema; | 
 |  |  |  | 
 |  |  | namespace LifePayment.Application.LifePay | 
 |  |  | { | 
 |  |  | 
 |  |  |     { | 
 |  |  |         private readonly IRepository<LifePayRechargeReceipts, Guid> _lifePayRechargeReceiptsRepository; | 
 |  |  |         private readonly IRepository<LifePayExpensesReceipts, Guid> _lifePayExpensesReceiptsRepository; | 
 |  |  |         private readonly IRepository<LifePayChannlesRake, Guid> _lifePayChannlesRakeRepository; | 
 |  |  |         private readonly IRepository<LifePayOrder, Guid> _lifePayOrderRepository; | 
 |  |  |         private readonly IAliPayApi _aliPayApi; | 
 |  |  |         private readonly IWxPayApi _wxPayApi; | 
 |  |  |  | 
 |  |  |         public LifePayOrderService( | 
 |  |  |                               IRepository<LifePayRechargeReceipts, Guid> lifePayRechargeReceiptsRepository, | 
 |  |  |                               IRepository<LifePayExpensesReceipts, Guid> lifePayExpensesReceiptsRepository, | 
 |  |  |                               IRepository<LifePayChannlesRake, Guid> lifePayChannlesRakeRepository, | 
 |  |  |                               IRepository<LifePayOrder, Guid> lifePayOrderRepository, | 
 |  |  |                               IAliPayApi aliPayApi, | 
 |  |  |                               IWxPayApi wxPayApi) | 
 |  |  |         { | 
 |  |  |             _lifePayRechargeReceiptsRepository = lifePayRechargeReceiptsRepository; | 
 |  |  |             _lifePayExpensesReceiptsRepository = lifePayExpensesReceiptsRepository; | 
 |  |  |             _lifePayChannlesRakeRepository = lifePayChannlesRakeRepository; | 
 |  |  |             _lifePayOrderRepository = lifePayOrderRepository; | 
 |  |  |             _aliPayApi = aliPayApi; | 
 |  |  |             _wxPayApi = wxPayApi; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         #region 查询 | 
 |  |  |         /// <summary> | 
 |  |  |         /// 获取充值流水 | 
 |  |  |         /// </summary> | 
 |  |  |         /// <param name="input"></param> | 
 |  |  |         /// <returns></returns> | 
 |  |  |         public async Task<LifePayRechargeReceiptsPageOutput<LifePayRechargeReceiptsListOutput>> GetLifePayRechargeReceiptsPage(LifePayRechargeReceiptsPageInput input) | 
 |  |  |         public async Task<PageOutput<LifePayRechargeReceiptsListOutput>> GetLifePayRechargeReceiptsPage(LifePayRechargeReceiptsPageInput input) | 
 |  |  |         { | 
 |  |  |             var list = await _lifePayRechargeReceiptsRepository.Where(x => x.IsDeleted == false) | 
 |  |  |                 .WhereIf(input.KeyWord.IsNotNullOrEmpty(), x => x.OrderNo.Contains(input.KeyWord)) | 
 |  |  | 
 |  |  |                 .GetPageResult(input.PageModel); | 
 |  |  |  | 
 |  |  |             var total = await _lifePayRechargeReceiptsRepository.Where(x => x.IsDeleted == false).SumAsync(x => x.RechargeAmount); | 
 |  |  |             LifePayRechargeReceiptsPageOutput<LifePayRechargeReceiptsListOutput> result = new LifePayRechargeReceiptsPageOutput<LifePayRechargeReceiptsListOutput>(); | 
 |  |  |             result.Data = list.Data; | 
 |  |  |             result.TotalRechargeAmount = total; | 
 |  |  |             LifePayRechargeReceiptsStatistics objectData = new LifePayRechargeReceiptsStatistics(); | 
 |  |  |             objectData.TotalRechargeAmount = total; | 
 |  |  |             list.ObjectData = objectData; | 
 |  |  |             return list; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         /// <summary> | 
 |  |  |         /// 获取收支流水 | 
 |  |  |         /// </summary> | 
 |  |  |         /// <param name="input"></param> | 
 |  |  |         /// <returns></returns> | 
 |  |  |         public async Task<PageOutput<LifePayExpensesReceiptsListOutput>> GetLifePayExpensesReceiptsPage(LifePayExpensesReceiptsPageInput input) | 
 |  |  |         { | 
 |  |  |             var list = await _lifePayExpensesReceiptsRepository.Where(x => x.IsDeleted == false) | 
 |  |  |                 .WhereIf(input.KeyWord.IsNotNullOrEmpty(), x => x.OrderNo.Contains(input.KeyWord) || x.OutOrderNo.Contains(input.KeyWord)) | 
 |  |  |                 .WhereIf(input.LifePayType.HasValue, x => x.LifePayType == input.LifePayType) | 
 |  |  |                 .WhereIf(input.ExpensesReceiptsType.HasValue, x => x.ExpensesReceiptsType == input.ExpensesReceiptsType) | 
 |  |  |                 .WhereIf(input.TimeBegin.HasValue, x => x.FinishTime >= input.TimeBegin) | 
 |  |  |                 .WhereIf(input.TimeEnd.HasValue, x => x.FinishTime <= input.TimeEnd) | 
 |  |  |  | 
 |  |  |                 .Select(x => new LifePayExpensesReceiptsListOutput() | 
 |  |  |                 { | 
 |  |  |                     Id = x.Id, | 
 |  |  |                     OrderNo = x.OrderNo, | 
 |  |  |                     OutOrderNo = x.OutOrderNo, | 
 |  |  |                     LifePayType = x.LifePayType, | 
 |  |  |                     ExpensesReceiptsType = x.ExpensesReceiptsType.Value, | 
 |  |  |                     Amount = x.Amount, | 
 |  |  |                     FinishTime = x.FinishTime | 
 |  |  |                 }) | 
 |  |  |                 .GetPageResult(input.PageModel); | 
 |  |  |  | 
 |  |  |             var totalIncome = await _lifePayExpensesReceiptsRepository.Where(x => x.IsDeleted == false && x.ExpensesReceiptsType == ExpensesReceiptsTypeEnum.Expenses).SumAsync(x => x.Amount); | 
 |  |  |             var totalRefund = await _lifePayExpensesReceiptsRepository.Where(x => x.IsDeleted == false && x.ExpensesReceiptsType == ExpensesReceiptsTypeEnum.Receipts).SumAsync(x => x.Amount); | 
 |  |  |  | 
 |  |  |             LifePayExpensesReceiptsStatistics objectData = new LifePayExpensesReceiptsStatistics(); | 
 |  |  |             objectData.TotalIncome = totalIncome; | 
 |  |  |             objectData.TotalRefund = totalRefund; | 
 |  |  |             objectData.RealIncome = totalIncome - totalRefund; | 
 |  |  |             list.ObjectData = objectData; | 
 |  |  |             return list; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         /// <summary> | 
 |  |  |         /// 获取渠道分佣 | 
 |  |  |         /// </summary> | 
 |  |  |         /// <param name="input"></param> | 
 |  |  |         /// <returns></returns> | 
 |  |  |         public async Task<PageOutput<LifePayChannlesRakeListOutput>> GetLifePayChannlesRakePage(LifePayChannlesRakePageInput input) | 
 |  |  |         { | 
 |  |  |             var list = await _lifePayChannlesRakeRepository.Where(x => x.IsDeleted == false) | 
 |  |  |                 .WhereIf(input.ChannelId.IsNotNullOrEmpty(), x => x.ChannelId == input.ChannelId) | 
 |  |  |                 .WhereIf(input.CreationTimeBegin.HasValue, x => x.CreationTime >= input.CreationTimeBegin) | 
 |  |  |                 .WhereIf(input.CreationTimeEnd.HasValue, x => x.CreationTime <= input.CreationTimeEnd) | 
 |  |  |                 .WhereIf(input.FinishTimeBegin.HasValue, x => x.FinishTime >= input.FinishTimeBegin) | 
 |  |  |                 .WhereIf(input.FinishTimeEnd.HasValue, x => x.FinishTime <= input.FinishTimeEnd) | 
 |  |  |  | 
 |  |  |                 .Select(x => new LifePayChannlesRakeListOutput() | 
 |  |  |                 { | 
 |  |  |                     Id = x.Id, | 
 |  |  |                     OrderNo = x.OrderNo, | 
 |  |  |                     PayAmount = x.PayAmount, | 
 |  |  |                     ChannlesRakeRate = x.ChannlesRakeRate, | 
 |  |  |                     ChannlesRakePrice = x.ChannlesRakePrice, | 
 |  |  |                     ChannelId = x.ChannelId, | 
 |  |  |                     FinishTime = x.FinishTime, | 
 |  |  |                     CreationTime = x.CreationTime, | 
 |  |  |                 }) | 
 |  |  |                 .GetPageResult(input.PageModel); | 
 |  |  |  | 
 |  |  |             var totalRakePrice = await _lifePayChannlesRakeRepository.Where(x => x.IsDeleted == false).SumAsync(x => x.ChannlesRakePrice); | 
 |  |  |  | 
 |  |  |             LifePayLifePayChannlesRakeStatistics objectData = new LifePayLifePayChannlesRakeStatistics(); | 
 |  |  |             objectData.TotalRakePrice = totalRakePrice; | 
 |  |  |             list.ObjectData = objectData; | 
 |  |  |             return list; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         public async Task<List<LifePayChannlesRakeListTemplate>> GetLifePayChannlesRakePageExport(LifePayChannlesRakePageInput input) | 
 |  |  |         { | 
 |  |  |             var result = await (await GetLifePayChannlesRakeListFilter(input)).Select(x => new LifePayChannlesRakeListTemplate | 
 |  |  |             { | 
 |  |  |                 CreationTime = x.CreationTime, | 
 |  |  |                 FinishTime = x.FinishTime, | 
 |  |  |                 OrderNo = x.OrderNo, | 
 |  |  |                 PayAmount = x.PayAmount, | 
 |  |  |                 ChannlesRakeRate = x.ChannlesRakeRate, | 
 |  |  |                 ChannlesRakePrice = x.ChannlesRakePrice | 
 |  |  |             }).OrderByDescending(r => r.CreationTime).ToListAsync(); | 
 |  |  |             var i = 0; | 
 |  |  |             result.ForEach(s => | 
 |  |  |             { | 
 |  |  |                 s.SerialNumber = ++i; | 
 |  |  |                 s.CreationTimeStr = s.CreationTime.ToString(LifePaymentConstant.DateTimeFormatStr.yyyyMMddHHmmss); | 
 |  |  |                 s.PayAmountStr = s.PayAmount.ToString("F2"); | 
 |  |  |                 s.ChannlesRakeRateStr = s.ChannlesRakeRate.ToString("F2"); | 
 |  |  |                 s.ChannlesRakePriceStr = s.ChannlesRakePrice.ToString("F2"); | 
 |  |  |                 s.FinishTimeStr = s.FinishTime.ToString(LifePaymentConstant.DateTimeFormatStr.yyyyMMddHHmmss); | 
 |  |  |             }); | 
 |  |  |             return result; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         #endregion | 
 |  |  |  | 
 |  |  |         #region 操作 | 
 |  |  |  | 
 |  |  |         /// <summary> | 
 |  |  |         /// 编辑充值流水 | 
 |  |  | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |         //public async Task<LifePayExpensesReceiptsPageOutput<LifePayExpensesReceiptsListOutput>> GetLifePayExpensesReceiptsPage(LifePayExpensesReceiptsPageInput input) | 
 |  |  |         //{ | 
 |  |  |         //    var list = await _lifePayExpensesReceiptsRepository.Where(x => x.IsDeleted == false) | 
 |  |  |         //        .WhereIf(input.KeyWord.IsNotNullOrEmpty(), x => x.OrderNo.Contains(input.KeyWord)) | 
 |  |  |         //        .WhereIf(input.CreationTimeBegin.HasValue, x => x.CreationTime >= input.CreationTimeBegin) | 
 |  |  |         //        .WhereIf(input.CreationTimeEnd.HasValue, x => x.CreationTime <= input.CreationTimeEnd) | 
 |  |  |         //        .Select(x => new LifePayRechargeReceiptsListOutput() | 
 |  |  |         //        { | 
 |  |  |         //            Id = x.Id, | 
 |  |  |         //            OrderNo = x.OrderNo, | 
 |  |  |         //            RechargeAmount = x.RechargeAmount, | 
 |  |  |         //            Remark = x.Remark, | 
 |  |  |         //            Voucher = x.Voucher.GetOssPath(), | 
 |  |  |         //            CreationTime = x.CreationTime, | 
 |  |  |         //        }) | 
 |  |  |         //        .GetPageResult(input.PageModel); | 
 |  |  |  | 
 |  |  |         //    var total = await _lifePayRechargeReceiptsRepository.Where(x => x.IsDeleted == false).SumAsync(x => x.RechargeAmount); | 
 |  |  |         //    LifePayRechargeReceiptsPageOutput<LifePayRechargeReceiptsListOutput> result = new LifePayRechargeReceiptsPageOutput<LifePayRechargeReceiptsListOutput>(); | 
 |  |  |         //    result.Data = list.Data; | 
 |  |  |         //    result.TotalRechargeAmount = total; | 
 |  |  |         //    return result; | 
 |  |  |         //} | 
 |  |  |  | 
 |  |  |  | 
 |  |  |         /// <summary> | 
 |  |  |         /// 插入收支流水 | 
 |  |  |         /// </summary> | 
 |  |  | 
 |  |  |                     OutOrderNo = input.OutOrderNo, | 
 |  |  |                     LifePayType = input.LifePayType, | 
 |  |  |                     ExpensesReceiptsType = input.ExpensesReceiptsType, | 
 |  |  |                     Amount = input.Amount | 
 |  |  |                     Amount = input.Amount, | 
 |  |  |                 }; | 
 |  |  |  | 
 |  |  |                 switch (input.LifePayType) | 
 |  |  | 
 |  |  |                         if (input.ExpensesReceiptsType == ExpensesReceiptsTypeEnum.Expenses) | 
 |  |  |                         { | 
 |  |  |                             var query = await _aliPayApi.OrderInQuiry(new OrderInQuiryInput() { OutTradeNo = input.OrderNo }); | 
 |  |  |                             if (query.Code == AlipayResultCode.Success && query.TradeStatus == AlipayStatus.TRADESUCCESS) | 
 |  |  |                             if (query.Code == AlipayResultCode.Success && (query.TradeStatus == AlipayStatus.TRADESUCCESS | 
 |  |  |                                 || query.TradeStatus == AlipayStatus.TRADECLOSED)) | 
 |  |  |                             { | 
 |  |  |                                 data.ExtraProperties = JsonConvert.SerializeObject(query); | 
 |  |  |                                 data.FinishTime = Convert.ToDateTime(query.SendPayDate); | 
 |  |  |                                 await _lifePayExpensesReceiptsRepository.InsertAsync(data); | 
 |  |  |                             } | 
 |  |  |                         } | 
 |  |  | 
 |  |  |                             var query = await _aliPayApi.QueryAlipayTradeRefund(new OrderInQuiryInput() { OutTradeNo = input.OrderNo }); | 
 |  |  |                             if (query.Code == AlipayResultCode.Success && query.RefundStatus == AlipayRefundStatus.Success) | 
 |  |  |                             { | 
 |  |  |                                 data.ExtraProperties = JsonConvert.SerializeObject(query); | 
 |  |  |                                 data.FinishTime = Convert.ToDateTime(query.GmtRefundPay); | 
 |  |  |                                 await _lifePayExpensesReceiptsRepository.InsertAsync(data); | 
 |  |  |                             } | 
 |  |  |                         } | 
 |  |  | 
 |  |  |                         if (input.ExpensesReceiptsType == ExpensesReceiptsTypeEnum.Expenses) | 
 |  |  |                         { | 
 |  |  |                             var query = await _wxPayApi.WxPayTradeQuery(input.OrderNo); | 
 |  |  |                             if (query.Code == AlipayResultCode.Success && query.Status == WxPayStatus.支付成功) | 
 |  |  |                             if (query.TradeState == WxPayStatus.支付成功 || query.TradeState == WxPayStatus.转入退款) | 
 |  |  |                             { | 
 |  |  |                                 data.ExtraProperties = JsonConvert.SerializeObject(query); | 
 |  |  |                                 data.FinishTime = Convert.ToDateTime(query.SuccessTime); | 
 |  |  |                                 await _lifePayExpensesReceiptsRepository.InsertAsync(data); | 
 |  |  |                             } | 
 |  |  |                         } | 
 |  |  |                         else | 
 |  |  |                         { | 
 |  |  |                             var query = await _wxPayApi.WxPayDomesticRefundsQuery(input.OrderNo); | 
 |  |  |                             if (query.Code == AlipayResultCode.Success && query.RefundStatus == WxPayRefundStatus.退款成功) | 
 |  |  |                             if (query.Status == WxPayRefundStatus.退款成功) | 
 |  |  |                             { | 
 |  |  |                                 data.ExtraProperties = JsonConvert.SerializeObject(query); | 
 |  |  |                                 data.FinishTime = Convert.ToDateTime(query.SuccessTime); | 
 |  |  |                                 await _lifePayExpensesReceiptsRepository.InsertAsync(data); | 
 |  |  |                             } | 
 |  |  |                         } | 
 |  |  |                         break; | 
 |  |  |                     default: break; | 
 |  |  |                 } | 
 |  |  |                  | 
 |  |  |                  | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         public async Task GetAllLifePayExpensesReceipts() | 
 |  |  |         { | 
 |  |  |             var orderlist = await (from a in _lifePayOrderRepository.Where(x => x.PayStatus >= LifePayStatusEnum.已支付) | 
 |  |  |                                    join b in _lifePayExpensesReceiptsRepository on a.OrderNo equals b.OrderNo into temp | 
 |  |  |                                    from b in temp.DefaultIfEmpty() | 
 |  |  |                                    select new LifePayExpensesReceiptsTemp() | 
 |  |  |                                    { | 
 |  |  |                                        OrderNo = a.OrderNo, | 
 |  |  |                                        OutOrderNo = a.OutOrderNo, | 
 |  |  |                                        RefundOrderNo = a.RefundOrderNo, | 
 |  |  |                                        LifePayType = a.LifePayType.Value, | 
 |  |  |                                        Amount = a.PayAmount.Value, | 
 |  |  |                                        ExpensesReceiptsType = b.ExpensesReceiptsType | 
 |  |  |                                    }).ToListAsync(); | 
 |  |  |             foreach (var item in orderlist) | 
 |  |  |             { | 
 |  |  |                 if (!item.ExpensesReceiptsType.HasValue) | 
 |  |  |                 { | 
 |  |  |                     /// 入账 | 
 |  |  |                     AddLifePayExpensesReceiptsInput input = new AddLifePayExpensesReceiptsInput() | 
 |  |  |                     { | 
 |  |  |                         OrderNo = item.OrderNo, | 
 |  |  |                         OutOrderNo = item.OutOrderNo, | 
 |  |  |                         LifePayType = item.LifePayType, | 
 |  |  |                         Amount = item.Amount, | 
 |  |  |                         ExpensesReceiptsType = ExpensesReceiptsTypeEnum.Expenses | 
 |  |  |                     }; | 
 |  |  |  | 
 |  |  |                     await AddLifePayExpensesReceipts(input); | 
 |  |  |  | 
 |  |  |                     /// 出账 | 
 |  |  |                     if (item.RefundOrderNo.IsNotNullOrEmpty()) | 
 |  |  |                     { | 
 |  |  |                         if (input.LifePayType == LifePayTypeEnum.WxPay) | 
 |  |  |                         { | 
 |  |  |                             input.OrderNo = item.RefundOrderNo; | 
 |  |  |                         } | 
 |  |  |  | 
 |  |  |                         input.ExpensesReceiptsType = ExpensesReceiptsTypeEnum.Receipts; | 
 |  |  |                         await AddLifePayExpensesReceipts(input); | 
 |  |  |                     } | 
 |  |  |  | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         public async Task GetAllChannlesRake() | 
 |  |  |         { | 
 |  |  |             var orderlist = await _lifePayOrderRepository.Where(x => x.IsDeleted == false && x.PayStatus == LifePayStatusEnum.已支付 && x.LifePayOrderStatus == LifePayOrderStatusEnum.已完成).ToListAsync(); | 
 |  |  |             foreach (var item in orderlist) | 
 |  |  |             { | 
 |  |  |                 /// 毛利 | 
 |  |  |                 var grossProfit = item.RechargeAmount * (item.ChannleRate - item.PlatformRate) / 100; | 
 |  |  |                 /// 渠道佣金  ((充值面额 * 渠道折扣比例)-(充值面额 * 平台折扣比例))* 佣金比例 | 
 |  |  |                 var channlesRakePrice = grossProfit * (item.ChannlesRakeRate) / 100; | 
 |  |  |                 if (channlesRakePrice.HasValue) | 
 |  |  |                 { | 
 |  |  |                     LifePayChannlesRake lifePayChannlesRake = new LifePayChannlesRake() | 
 |  |  |                     { | 
 |  |  |                         OrderNo = item.OrderNo, | 
 |  |  |                         PayAmount = item.PayAmount.Value, | 
 |  |  |                         ChannlesRakeRate = item.ChannlesRakeRate.Value, | 
 |  |  |                         ChannlesRakePrice = channlesRakePrice.Value, | 
 |  |  |                         FinishTime = item.FinishTime.Value, | 
 |  |  |                         ChannelId = item.ChannelId, | 
 |  |  |                     }; | 
 |  |  |                     var repeat = _lifePayChannlesRakeRepository.Where(x => x.OrderNo == item.OrderNo).FirstOrDefaultAsync(); | 
 |  |  |                     if (repeat != null) | 
 |  |  |                     { | 
 |  |  |                         await _lifePayChannlesRakeRepository.InsertAsync(lifePayChannlesRake); | 
 |  |  |                     } | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |         #endregion | 
 |  |  |  | 
 |  |  |         #region 私有 | 
 |  |  |         private async Task<IQueryable<LifePayChannlesRakeListOutput>> GetLifePayChannlesRakeListFilter(LifePayChannlesRakePageInput input) | 
 |  |  |         { | 
 |  |  |             var list = _lifePayChannlesRakeRepository.Where(x => x.IsDeleted == false) | 
 |  |  |                 .WhereIf(input.ChannelId.IsNotNullOrEmpty(), x => x.ChannelId == input.ChannelId) | 
 |  |  |                 .WhereIf(input.CreationTimeBegin.HasValue, x => x.CreationTime >= input.CreationTimeBegin) | 
 |  |  |                 .WhereIf(input.CreationTimeEnd.HasValue, x => x.CreationTime <= input.CreationTimeEnd) | 
 |  |  |                 .WhereIf(input.FinishTimeBegin.HasValue, x => x.FinishTime >= input.FinishTimeBegin) | 
 |  |  |                 .WhereIf(input.FinishTimeEnd.HasValue, x => x.FinishTime <= input.FinishTimeEnd) | 
 |  |  |  | 
 |  |  |                 .Select(x => new LifePayChannlesRakeListOutput() | 
 |  |  |                 { | 
 |  |  |                     Id = x.Id, | 
 |  |  |                     OrderNo = x.OrderNo, | 
 |  |  |                     PayAmount = x.PayAmount, | 
 |  |  |                     ChannlesRakeRate = x.ChannlesRakeRate, | 
 |  |  |                     ChannlesRakePrice = x.ChannlesRakePrice, | 
 |  |  |                     ChannelId = x.ChannelId, | 
 |  |  |                     FinishTime = x.FinishTime, | 
 |  |  |                     CreationTime = x.CreationTime, | 
 |  |  |                 }); | 
 |  |  |  | 
 |  |  |  | 
 |  |  |             return list; | 
 |  |  |         } | 
 |  |  |         #endregion | 
 |  |  |  | 
 |  |  |     } | 
 |  |  | } |