Exemple #1
0
        public async Task <Result <PaymentResponse> > Authorize(NewCreditCardPaymentRequest request,
                                                                string languageCode, string ipAddress, IPaymentCallbackService paymentCallbackService, AgentContext agent)
        {
            _logger.LogCreditCardAuthorizationStarted(request.ReferenceCode);

            var(_, isFailure, servicePrice, error) = await paymentCallbackService.GetChargingAmount(request.ReferenceCode);

            if (isFailure)
            {
                _logger.LogCreditCardAuthorizationFailure(request.ReferenceCode, error);
                return(Result.Failure <PaymentResponse>(error));
            }

            return(await Validate(request)
                   .Bind(Authorize)
                   .TapIf(IsSaveCardNeeded, SaveCard)
                   .Bind(StorePaymentResults)
                   .Finally(WriteLog));
        public async Task <Result <PaymentResponse> > Charge(string referenceCode, ApiCaller apiCaller, IPaymentCallbackService paymentCallbackService)
        {
            return(await GetChargingAccountId()
                   .Bind(GetChargingAccount)
                   .Bind(GetChargingAmount)
                   .Check(ChargeMoney)
                   .Tap(SendNotificationIfRequired)
                   .Bind(StorePayment)
                   .Bind(ProcessPaymentResults)
                   .Map(CreateResult));


            Task <Result <int> > GetChargingAccountId()
            => paymentCallbackService.GetChargingAccountId(referenceCode);


            async Task <Result <AgencyAccount> > GetChargingAccount(int accountId)
            => await _context.AgencyAccounts.SingleOrDefaultAsync(a => a.Id == accountId)
            ?? Result.Failure <AgencyAccount>("Could not find agency account");


            async Task <Result <(AgencyAccount, MoneyAmount)> > GetChargingAmount(AgencyAccount account)
            {
                var(_, isFailure, amount, error) = await paymentCallbackService.GetChargingAmount(referenceCode);

                if (isFailure)
                {
                    return(Result.Failure <(AgencyAccount, MoneyAmount)>(error));
                }

                return(account, amount);
            }

            Task <Result> ChargeMoney((AgencyAccount account, MoneyAmount amount) chargeInfo)
            {
                var(account, amount) = chargeInfo;
                return(_accountPaymentProcessingService.ChargeMoney(account.Id, new ChargedMoneyData(
                                                                        currency: amount.Currency,
                                                                        amount: amount.Amount,
                                                                        reason: $"Charge money for service '{referenceCode}'",
                                                                        referenceCode: referenceCode),
                                                                    apiCaller));
            }

            async Task <Result <Payment> > StorePayment((AgencyAccount account, MoneyAmount amount) chargeInfo)
            {
                var(account, amount) = chargeInfo;
                var(paymentExistsForBooking, _, _, _) = await GetPayment(referenceCode);

                if (paymentExistsForBooking)
                {
                    return(Result.Failure <Payment>("Payment for current booking already exists"));
                }

                var now     = _dateTimeProvider.UtcNow();
                var info    = new AccountPaymentInfo(string.Empty);
                var payment = new Payment
                {
                    Amount        = amount.Amount,
                    AccountNumber = account.Id.ToString(),
                    Currency      = amount.Currency,
                    Created       = now,
                    Modified      = now,
                    Status        = PaymentStatuses.Captured,
                    Data          = JsonConvert.SerializeObject(info),
                    AccountId     = account.Id,
                    PaymentMethod = PaymentTypes.VirtualAccount,
                    ReferenceCode = referenceCode
                };

                _context.Payments.Add(payment);
                await _context.SaveChangesAsync();

                _context.Detach(payment);

                return(payment);
            }

            Task <Result> ProcessPaymentResults(Payment payment)
            => paymentCallbackService.ProcessPaymentChanges(payment);


            Task SendNotificationIfRequired((AgencyAccount account, MoneyAmount amount) chargeInfo)
            => _balanceManagementNotificationsService.SendNotificationIfRequired(chargeInfo.account, chargeInfo.amount);


            PaymentResponse CreateResult()
            => new(string.Empty, CreditCardPaymentStatuses.Success, string.Empty);
        }