private async Task <PaymentStatusUpdateErrorCodes> ChangeStatusAsync (string paymentRequestId, PaymentRequestStatus requiredStatus, PaymentRequestStatus updateStatus) { if (string.IsNullOrEmpty(paymentRequestId)) { throw new ArgumentNullException(nameof(paymentRequestId)); } return(await _transactionScopeHandler.WithTransactionAsync(async() => { var payment = await _paymentsRepository.GetByPaymentRequestIdAsync(paymentRequestId); if (payment == null) { return PaymentStatusUpdateErrorCodes.PaymentDoesNotExist; } if (payment.Status != requiredStatus) { return PaymentStatusUpdateErrorCodes.PaymentIsInInvalidStatus; } await _paymentsRepository.SetStatusAsync(paymentRequestId, updateStatus); await _statusUpdatePublisher.PublishAsync(new PartnersPaymentStatusUpdatedEvent { PaymentRequestId = paymentRequestId, Status = updateStatus.ToContractModel() }); return PaymentStatusUpdateErrorCodes.None; })); }
public void MapToString_FromPaymentRequestStatusEnum_ExpectedResult(PaymentRequestStatus input, string expectedResult) { // Arrange + Act var result = input.MapToString(); // Assert Assert.AreEqual(expectedResult, result); }
public static PaymentRequestResult Succeeded(PaymentRequestStatus status, string paymentRequestId) { return(new PaymentRequestResult { Status = status, PaymentRequestId = paymentRequestId }); }
public static PartnerPaymentStatus ToContractModel(this PaymentRequestStatus src) { switch (src) { case PaymentRequestStatus.Created: return(PartnerPaymentStatus.Created); case PaymentRequestStatus.RequestExpired: return(PartnerPaymentStatus.RequestExpired); case PaymentRequestStatus.RejectedByCustomer: return(PartnerPaymentStatus.RejectedByCustomer); case PaymentRequestStatus.TokensBurnFailed: return(PartnerPaymentStatus.TokensBurnFailed); case PaymentRequestStatus.TokensBurnStarted: return(PartnerPaymentStatus.TokensBurnStarted); case PaymentRequestStatus.TokensBurnSucceeded: return(PartnerPaymentStatus.TokensBurnSucceeded); case PaymentRequestStatus.TokensRefundFailed: return(PartnerPaymentStatus.TokensRefundFailed); case PaymentRequestStatus.TokensRefundStarted: return(PartnerPaymentStatus.TokensRefundStarted); case PaymentRequestStatus.TokensRefundSucceeded: return(PartnerPaymentStatus.TokensRefundSucceeded); case PaymentRequestStatus.TokensTransferFailed: return(PartnerPaymentStatus.TokensTransferFailed); case PaymentRequestStatus.TokensTransferStarted: return(PartnerPaymentStatus.TokensTransferStarted); case PaymentRequestStatus.TokensTransferSucceeded: return(PartnerPaymentStatus.TokensTransferSucceeded); case PaymentRequestStatus.ExpirationTokensRefundFailed: return(PartnerPaymentStatus.ExpirationTokensRefundFailed); case PaymentRequestStatus.ExpirationTokensRefundStarted: return(PartnerPaymentStatus.ExpirationTokensRefundStarted); case PaymentRequestStatus.ExpirationTokensRefundSucceeded: return(PartnerPaymentStatus.ExpirationTokensRefundSucceeded); case PaymentRequestStatus.CancelledByPartner: return(PartnerPaymentStatus.CancelledByPartner); default: throw new ArgumentOutOfRangeException(nameof(src), $"Payment request status value was not expected: {src.ToString()}"); } }
private async Task UpdateStatusAsync(IPaymentRequest paymentRequest, PaymentRequestStatusInfo statusInfo = null) { PaymentRequestStatusInfo newStatusInfo = statusInfo ?? await _paymentRequestStatusResolver.GetStatus(paymentRequest.WalletAddress); PaymentRequestStatus previousStatus = paymentRequest.Status; PaymentRequestProcessingError previousProcessingError = paymentRequest.ProcessingError; paymentRequest.Status = newStatusInfo.Status; paymentRequest.PaidDate = newStatusInfo.Date; if (newStatusInfo.Amount.HasValue) { paymentRequest.PaidAmount = newStatusInfo.Amount.Value; } paymentRequest.ProcessingError = (paymentRequest.Status == PaymentRequestStatus.Error || paymentRequest.Status == PaymentRequestStatus.SettlementError) ? newStatusInfo.ProcessingError : PaymentRequestProcessingError.None; await _paymentRequestRepository.UpdateAsync(paymentRequest); // if we are updating status from "InProcess" to any other - we have to release the lock if (previousStatus == PaymentRequestStatus.InProcess) { await _paymentLocksService.ReleaseLockAsync(paymentRequest.Id, paymentRequest.MerchantId); } PaymentRequestRefund refundInfo = await GetRefundInfoAsync(paymentRequest.WalletAddress); if (paymentRequest.Status != previousStatus || (paymentRequest.Status == PaymentRequestStatus.Error && paymentRequest.ProcessingError != previousProcessingError)) { await _paymentRequestPublisher.PublishAsync(paymentRequest, refundInfo); IAssetGeneralSettings assetSettings = await _assetSettingsService.GetGeneralAsync(paymentRequest.PaymentAssetId); // doing auto settlement only once // Some flows assume we can get updates from blockchain multiple times for the same transaction // which leads to the same payment request status if (paymentRequest.StatusValidForSettlement() && (assetSettings?.AutoSettle ?? false)) { if (paymentRequest.Status != PaymentRequestStatus.Confirmed && !_autoSettleSettingsResolver.AllowToMakePartialAutoSettle(paymentRequest.PaymentAssetId)) { return; } await SettleAsync(paymentRequest.MerchantId, paymentRequest.Id); } } }
public static InvoiceStatus Convert(PaymentRequestStatus status, PaymentRequestProcessingError error) { switch (status) { case PaymentRequestStatus.New: return(InvoiceStatus.Unpaid); case PaymentRequestStatus.Cancelled: return(InvoiceStatus.Removed); case PaymentRequestStatus.InProcess: return(InvoiceStatus.InProgress); case PaymentRequestStatus.Confirmed: return(InvoiceStatus.Paid); case PaymentRequestStatus.RefundInProgress: return(InvoiceStatus.RefundInProgress); case PaymentRequestStatus.Refunded: return(InvoiceStatus.Refunded); case PaymentRequestStatus.Error: switch (error) { case PaymentRequestProcessingError.PaymentExpired: return(InvoiceStatus.PastDue); case PaymentRequestProcessingError.LatePaid: return(InvoiceStatus.LatePaid); case PaymentRequestProcessingError.PaymentAmountBelow: return(InvoiceStatus.Underpaid); case PaymentRequestProcessingError.PaymentAmountAbove: return(InvoiceStatus.Overpaid); case PaymentRequestProcessingError.RefundNotConfirmed: return(InvoiceStatus.NotConfirmed); case PaymentRequestProcessingError.UnknownPayment: case PaymentRequestProcessingError.UnknownRefund: return(InvoiceStatus.InternalError); default: throw new Exception($"Unknown payment request error '{error}'"); } default: throw new Exception($"Unknown payment request status '{status}'"); } }
public static InvoiceStatus ToInvoiceStatus(this PaymentRequestStatus status, PaymentRequestProcessingError error) { switch (status) { case PaymentRequestStatus.New: return(InvoiceStatus.Unpaid); case PaymentRequestStatus.Cancelled: return(InvoiceStatus.Removed); case PaymentRequestStatus.InProcess: return(InvoiceStatus.InProgress); case PaymentRequestStatus.Confirmed: return(InvoiceStatus.Paid); case PaymentRequestStatus.RefundInProgress: return(InvoiceStatus.RefundInProgress); case PaymentRequestStatus.Refunded: return(InvoiceStatus.Refunded); case PaymentRequestStatus.Error: switch (error) { case PaymentRequestProcessingError.PaymentExpired: return(InvoiceStatus.PastDue); case PaymentRequestProcessingError.LatePaid: return(InvoiceStatus.LatePaid); case PaymentRequestProcessingError.PaymentAmountBelow: return(InvoiceStatus.Underpaid); case PaymentRequestProcessingError.PaymentAmountAbove: return(InvoiceStatus.Overpaid); case PaymentRequestProcessingError.RefundNotConfirmed: return(InvoiceStatus.NotConfirmed); case PaymentRequestProcessingError.UnknownPayment: case PaymentRequestProcessingError.UnknownRefund: return(InvoiceStatus.InternalError); default: return(InvoiceStatus.None); } default: return(InvoiceStatus.None); } }
public async Task <PaymentStatusUpdateErrorCodes> ApproveByReceptionistAsync(string paymentRequestId) { if (string.IsNullOrEmpty(paymentRequestId)) { throw new ArgumentNullException(nameof(paymentRequestId)); } return(await _transactionScopeHandler.WithTransactionAsync(async() => { var payment = await _paymentsRepository.GetByPaymentRequestIdAsync(paymentRequestId); if (payment == null) { return PaymentStatusUpdateErrorCodes.PaymentDoesNotExist; } if (payment.Status != PaymentRequestStatus.TokensTransferSucceeded) { return PaymentStatusUpdateErrorCodes.PaymentIsInInvalidStatus; } const PaymentRequestStatus newStatus = PaymentRequestStatus.TokensBurnStarted; await _paymentsRepository.SetStatusAsync(paymentRequestId, newStatus); await _statusUpdatePublisher.PublishAsync(new PartnersPaymentStatusUpdatedEvent { PaymentRequestId = paymentRequestId, Status = newStatus.ToContractModel() }); var encodedData = _blockchainEncodingService.EncodeAcceptRequestData (payment.PartnerId, payment.LocationId, payment.Timestamp.ConvertToLongMs(), payment.CustomerId, payment.PaymentRequestId); var pbfResponse = await _pbfClient.OperationsApi.AddGenericOperationAsync(new GenericOperationRequest { Data = encodedData, SourceAddress = _settingsService.GetMasterWalletAddress(), TargetAddress = _settingsService.GetPartnersPaymentsAddress() }); await _paymentRequestBlockchainRepository.UpsertAsync(paymentRequestId, pbfResponse.OperationId.ToString()); return PaymentStatusUpdateErrorCodes.None; })); }
/// <summary> /// Maps the <see cref="PaymentRequestStatus"/> to its corresponding Tikkie API string. /// </summary> /// <param name="paymentRequestStatus">The payment request status as enum.</param> /// <returns>The payment request status in string format.</returns> /// <exception cref="ArgumentException">When the payment request status enum is not recognized.</exception> public static string MapToString(this PaymentRequestStatus paymentRequestStatus) { switch (paymentRequestStatus) { case PaymentRequestStatus.Open: return("OPEN"); case PaymentRequestStatus.Closed: return("CLOSED"); case PaymentRequestStatus.Expired: return("EXPIRED"); case PaymentRequestStatus.MaxYieldReached: return("MAX_YIELD_REACHED"); case PaymentRequestStatus.MaxSuccessfulPaymentsReached: return("MAX_SUCCESSFUL_PAYMENTS_REACHED"); default: throw new ArgumentException($"Not recognized {nameof(paymentRequestStatus)}"); } }
public async Task <PaymentStatusUpdateErrorCodes> RejectByCustomerAsync(string paymentRequestId, string customerId) { if (string.IsNullOrEmpty(paymentRequestId)) { throw new ArgumentNullException(nameof(paymentRequestId)); } if (string.IsNullOrEmpty(customerId)) { throw new ArgumentNullException(nameof(customerId)); } return(await _transactionScopeHandler.WithTransactionAsync(async() => { var payment = await _paymentsRepository.GetByPaymentRequestIdAsync(paymentRequestId); if (payment == null) { return PaymentStatusUpdateErrorCodes.PaymentDoesNotExist; } if (payment.CustomerId != customerId) { return PaymentStatusUpdateErrorCodes.CustomerIdDoesNotMatch; } if (payment.Status != PaymentRequestStatus.Created) { return PaymentStatusUpdateErrorCodes.PaymentIsInInvalidStatus; } const PaymentRequestStatus newStatus = PaymentRequestStatus.RejectedByCustomer; await _paymentsRepository.SetStatusAsync(paymentRequestId, newStatus); await _statusUpdatePublisher.PublishAsync(new PartnersPaymentStatusUpdatedEvent { PaymentRequestId = paymentRequestId, Status = newStatus.ToContractModel() }); return PaymentStatusUpdateErrorCodes.None; })); }
public static PartnerPaymentPublicStatus ConvertToPublicStatus(this PaymentRequestStatus partnerPaymentStatus) { switch (partnerPaymentStatus) { case PaymentRequestStatus.Created: case PaymentRequestStatus.TokensTransferStarted: return(PartnerPaymentPublicStatus.Pending); case PaymentRequestStatus.RejectedByCustomer: case PaymentRequestStatus.TokensRefundSucceeded: case PaymentRequestStatus.CancelledByPartner: return(PartnerPaymentPublicStatus.Cancelled); case PaymentRequestStatus.TokensTransferSucceeded: case PaymentRequestStatus.TokensBurnStarted: case PaymentRequestStatus.TokensRefundStarted: return(PartnerPaymentPublicStatus.Confirmed); case PaymentRequestStatus.TokensBurnSucceeded: return(PartnerPaymentPublicStatus.Completed); case PaymentRequestStatus.TokensBurnFailed: case PaymentRequestStatus.TokensRefundFailed: case PaymentRequestStatus.TokensTransferFailed: case PaymentRequestStatus.ExpirationTokensRefundFailed: return(PartnerPaymentPublicStatus.Failed); case PaymentRequestStatus.RequestExpired: return(PartnerPaymentPublicStatus.RequestExpired); case PaymentRequestStatus.ExpirationTokensRefundStarted: case PaymentRequestStatus.ExpirationTokensRefundSucceeded: return(PartnerPaymentPublicStatus.PaymentExpired); default: throw new ArgumentOutOfRangeException(nameof(partnerPaymentStatus), partnerPaymentStatus, null); } }
public async Task SetStatusAsync(string paymentRequestId, PaymentRequestStatus status) { using (var context = _contextFactory.CreateDataContext()) { var entity = new PartnerPaymentEntity { PaymentRequestId = paymentRequestId }; context.PartnersPayments.Attach(entity); entity.Status = status; entity.LastUpdatedTimestamp = DateTime.UtcNow; try { await context.SaveChangesAsync(); } catch (DbUpdateException) { throw new InvalidOperationException("Entity was not found during status update"); } } }
public async Task <PaymentStatusUpdateErrorCodes> StartExpireRefundAsync(string paymentRequestId) { if (string.IsNullOrEmpty(paymentRequestId)) { throw new ArgumentNullException(nameof(paymentRequestId)); } return(await _transactionScopeHandler.WithTransactionAsync(async() => { var payment = await _paymentsRepository.GetByPaymentRequestIdAsync(paymentRequestId); if (payment == null) { return PaymentStatusUpdateErrorCodes.PaymentDoesNotExist; } if (payment.Status != PaymentRequestStatus.TokensTransferSucceeded) { return PaymentStatusUpdateErrorCodes.PaymentIsInInvalidStatus; } const PaymentRequestStatus newStatus = PaymentRequestStatus.ExpirationTokensRefundStarted; await _paymentsRepository.SetStatusAsync(paymentRequestId, newStatus); await _statusUpdatePublisher.PublishAsync(new PartnersPaymentStatusUpdatedEvent { PaymentRequestId = paymentRequestId, Status = newStatus.ToContractModel() }); await BlockchainRefundAsync(paymentRequestId, payment); return PaymentStatusUpdateErrorCodes.None; })); }
public NotAllowedStatusException(PaymentRequestStatus status) : base("Not allowed status") { Status = status; }
private async Task SaveRequestStatus(SqlConnection conn, int requestId, CheckPaymentRequestData data, PaymentRequestStatus status) { using (SqlCommand cmd = _sqlServer.GetSpCommand("payment.UpdateYandexKassaRequestStatus", conn)) { cmd.AddIntParam("@RequestId", requestId); cmd.AddTinyIntParam("@Status", (byte)status); cmd.AddVarCharParam("@KassaPaymentId", 50, data.ResponseData.Response.Id); await cmd.ExecuteNonQueryAsync(); } }
private async Task <ProcessESBResult> ValidateEsbResponse(ProcessESBResponse esbResponse, PaymentRequestStatus paymentRequestStatus) { if (paymentRequestStatus != null) { var interfaceStatus = (InterfaceStatus)paymentRequestStatus.DocumentStatus; if (!(interfaceStatus == InterfaceStatus.StandBy || interfaceStatus == InterfaceStatus.ReadyToTransmit || interfaceStatus == InterfaceStatus.Interfaced)) { string message = "The payment request " + esbResponse.DocumentReference + " is not in status 'ready to transmit' or 'stand by' or 'interfaced' (current status: " + interfaceStatus + " )"; processESBResult.Error = message; processESBResult.IsSuccess = false; } else if (paymentRequestStatus.CounterParty != esbResponse.Counterparty) { string message = "The Counterparty should be the same code as in the original payment order."; processESBResult.Error = message; processESBResult.IsSuccess = false; } else { processESBResult.IsSuccess = true; if (!string.IsNullOrEmpty(paymentRequestStatus.UUID)) { processESBResult.UUID = paymentRequestStatus.UUID; } } } else { string message = "Invalid Cash Document Reference"; processESBResult.Error = message; processESBResult.IsSuccess = false; } return(processESBResult); }
public void MapToPaymentRequestStatusEnum_FromString_ExpectedResult(string input, PaymentRequestStatus expectedResult) { // Arrange + Act var result = input.MapToPaymentRequestStatusEnum(); // Assert Assert.AreEqual(expectedResult, result); }
public async Task HandleAsync_PaymentIsNotInCorrectStatus_PaymentsStatusUpdaterNotCalled(PaymentRequestStatus status) { _paymentRequestBlockchainRepoMock.Setup(x => x.GetByOperationIdAsync(FakeOperationId)) .ReturnsAsync(new PaymentRequestBlockchainEntity { PaymentRequestId = FakePaymentRequestId }); _paymentsRepositoryMock.Setup(x => x.GetByPaymentRequestIdAsync(FakePaymentRequestId)) .ReturnsAsync(new PaymentModel { Status = status }); var sut = CreateSutInstance(); await sut.HandleAsync(FakeOperationId); _paymentsStatusUpdaterMock.Verify(); }
public async Task GetPaymentDetailsById_StatusIsNotCreated_ZeroIsReturnedForCustomerExpirationTimeLeft(PaymentRequestStatus status) { _paymentsRepositoryMock.Setup(x => x.GetByPaymentRequestIdAsync(FakePaymentId)) .ReturnsAsync(new PaymentModel { Status = status }); var sut = CreateSutInstance(); var result = await sut.GetPaymentDetailsByPaymentId(FakePaymentId); Assert.Equal(0, result.CustomerActionExpirationTimeLeftInSeconds); }