using MediatR; using Microsoft.IdentityModel.Tokens; using Netina.Common.Models.Exception; using Netina.Core.Abstracts; using Netina.Core.CoreServices.Abstracts; using Netina.Domain.CommandQueries.Commands; using Netina.Domain.CommandQueries.Queries; using Netina.Domain.Enums; using Netina.Domain.MartenEntities.Settings; using Netina.Domain.Models.Settings; using Netina.Infrastructure.Models.RestApi.Zarinpal; using Netina.Infrastructure.RestServices; using Newtonsoft.Json; namespace Netina.Infrastructure.Services; public class ZarinpalService : IPaymentService { private readonly IRestApiWrapper _restApiWrapper; private readonly IMediator _mediator; private readonly ISettingService _settingService; private readonly SiteSettings _siteSettings; public ZarinpalService(IRestApiWrapper restApiWrapper, IOptionsSnapshot snapshot, IMediator mediator , ISettingService settingService) { _restApiWrapper = restApiWrapper; _mediator = mediator; _settingService = settingService; _siteSettings = snapshot.Value; } public async Task GetPaymentLinkAsync(double amount, string factorNumber, Guid orderId, Guid userId, string phoneNumber, string fullName, CancellationToken cancellationToken = default) { var paymentSetting = (await _settingService.GetSettingAsync("PaymentSetting", cancellationToken)) as PaymentSetting; if (paymentSetting == null) throw new AppException("تنظیمات پرداخت انجام نشده است"); if (paymentSetting.ZarinPalApiKey.IsNullOrEmpty()) throw new AppException("کد مرچنت زرین پال وارد نشده است"); var request = new ZarinaplPaymentLinkRequest { description = $"پرداخت {amount.ToString("N0")} ریال توسط {fullName} با شماره تماس {phoneNumber} برای سفارش با شماره {factorNumber}", amount = (int)amount, callback_url = Path.Combine(_siteSettings.BaseUrl, "api", "accounting", "pay", "verify"), merchant_id = paymentSetting.ZarinPalApiKey, metadata = new ZarinaplPaymentLinkRequestMetadata { mobile = phoneNumber } }; var responseJson = await _restApiWrapper.ZarinpalRestApi.GetPaymentLinkAsync(request); var response = JsonConvert.DeserializeObject(responseJson); if (response.data.code != 100) throw new AppException($"Exception in get link from zarinpal | {response.data.message}"); var createPaymentResult = await _mediator.Send(new CreateOrUpdatePaymentCommand(null, factorNumber, amount, request.description, string.Empty, string.Empty, response.data.authority, PaymentType.Online, PaymentStatus.InPaymentGateway, orderId, userId), cancellationToken); string link = $"https://www.zarinpal.com/pg/StartPay/{response.data.authority}"; return link; } public async Task> VerifyPaymentAsync(string authority, CancellationToken cancellationToken = default) { var paymentSetting = (await _settingService.GetSettingAsync("PaymentSetting", cancellationToken)) as PaymentSetting; if (paymentSetting == null) throw new AppException("تنظیمات پرداخت انجام نشده است"); if (paymentSetting.ZarinPalApiKey.IsNullOrEmpty()) throw new AppException("کد مرچنت زرین پال وارد نشده است"); var payment = await _mediator.Send(new GetPaymentQuery(Authority: authority), cancellationToken); var request = new ZarinaplVerifyPaymentRequest { amount = (int)payment.Amount, authority = payment.Authority, merchant_id = paymentSetting.ZarinPalApiKey }; var response = await _restApiWrapper.ZarinpalRestApi.VerifyPaymentAsync(request); if (response.data.code != 100) throw new AppException($"Exception in get link from zarinpal | {response.data.message}"); payment.Status = PaymentStatus.Paid; payment.CardPan = response.data.card_pan; payment.TransactionCode = response.data.ref_id.ToString(); await _mediator.Send(new CreateOrUpdatePaymentCommand(payment.Id, payment.FactorNumber, payment.Amount, payment.Description, payment.TransactionCode, payment.CardPan, payment.Authority, payment.Type, payment.Status, payment.OrderId, payment.CustomerId), cancellationToken); await _mediator.Send(new SubmitOrderPaymentCommand(payment.OrderId, OrderPaymentMethod.OnlinePayment, true), cancellationToken); return new Tuple(payment.TransactionCode, payment.FactorNumber); } }