From 494b3f18b6e49861d2531d080f71596bcf798ae2 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Wed, 20 Feb 2019 16:03:38 -0500 Subject: [PATCH] process credit from ipn --- src/Billing/Controllers/PayPalController.cs | 48 +++++++++++++++++-- src/Core/Services/IPaymentService.cs | 1 + .../Implementations/StripePaymentService.cs | 27 +++++++++++ 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/Billing/Controllers/PayPalController.cs b/src/Billing/Controllers/PayPalController.cs index 6834fd03eb..40c38c6194 100644 --- a/src/Billing/Controllers/PayPalController.cs +++ b/src/Billing/Controllers/PayPalController.cs @@ -1,6 +1,8 @@ using Bit.Billing.Utilities; using Bit.Core.Enums; +using Bit.Core.Models.Table; using Bit.Core.Repositories; +using Bit.Core.Services; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Newtonsoft.Json; @@ -18,17 +20,29 @@ namespace Bit.Billing.Controllers private readonly PayPalClient _paypalClient; private readonly PayPalIpnClient _paypalIpnClient; private readonly ITransactionRepository _transactionRepository; + private readonly IOrganizationRepository _organizationRepository; + private readonly IUserRepository _userRepository; + private readonly IMailService _mailService; + private readonly IPaymentService _paymentService; public PayPalController( IOptions billingSettings, PayPalClient paypalClient, PayPalIpnClient paypalIpnClient, - ITransactionRepository transactionRepository) + ITransactionRepository transactionRepository, + IOrganizationRepository organizationRepository, + IUserRepository userRepository, + IMailService mailService, + IPaymentService paymentService) { _billingSettings = billingSettings?.Value; _paypalClient = paypalClient; _paypalIpnClient = paypalIpnClient; _transactionRepository = transactionRepository; + _organizationRepository = organizationRepository; + _userRepository = userRepository; + _mailService = mailService; + _paymentService = paymentService; } [HttpPost("webhook")] @@ -197,7 +211,7 @@ namespace Bit.Billing.Controllers { try { - await _transactionRepository.CreateAsync(new Core.Models.Table.Transaction + var tx = new Transaction { Amount = ipnTransaction.McGross, CreationDate = ipnTransaction.PaymentDate, @@ -208,11 +222,35 @@ namespace Bit.Billing.Controllers GatewayId = ipnTransaction.TxnId, PaymentMethodType = PaymentMethodType.PayPal, Details = ipnTransaction.TxnId - }); + }; + await _transactionRepository.CreateAsync(tx); if(ipnTransaction.IsAccountCredit()) { - // TODO: Issue Stripe credit to user/org account + if(tx.OrganizationId.HasValue) + { + var org = await _organizationRepository.GetByIdAsync(tx.OrganizationId.Value); + if(org != null) + { + if(await _paymentService.CreditAccountAsync(org, tx.Amount)) + { + await _organizationRepository.ReplaceAsync(org); + } + } + } + else + { + var user = await _userRepository.GetByIdAsync(tx.UserId.Value); + if(user != null) + { + if(await _paymentService.CreditAccountAsync(user, tx.Amount)) + { + await _userRepository.ReplaceAsync(user); + } + } + } + + // TODO: Send email about credit added? } } // Catch foreign key violations because user/org could have been deleted. @@ -246,7 +284,7 @@ namespace Bit.Billing.Controllers } await _transactionRepository.ReplaceAsync(parentTransaction); - await _transactionRepository.CreateAsync(new Core.Models.Table.Transaction + await _transactionRepository.CreateAsync(new Transaction { Amount = ipnTransaction.McGross, CreationDate = ipnTransaction.PaymentDate, diff --git a/src/Core/Services/IPaymentService.cs b/src/Core/Services/IPaymentService.cs index 8f509644fc..4b6b7ca541 100644 --- a/src/Core/Services/IPaymentService.cs +++ b/src/Core/Services/IPaymentService.cs @@ -17,6 +17,7 @@ namespace Bit.Core.Services Task ReinstateSubscriptionAsync(ISubscriber subscriber); Task UpdatePaymentMethodAsync(ISubscriber subscriber, PaymentMethodType paymentMethodType, string paymentToken); + Task CreditAccountAsync(ISubscriber subscriber, decimal creditAmount); Task GetBillingAsync(ISubscriber subscriber); Task GetSubscriptionAsync(ISubscriber subscriber); } diff --git a/src/Core/Services/Implementations/StripePaymentService.cs b/src/Core/Services/Implementations/StripePaymentService.cs index d5aec2cfc3..1fee4c3711 100644 --- a/src/Core/Services/Implementations/StripePaymentService.cs +++ b/src/Core/Services/Implementations/StripePaymentService.cs @@ -915,6 +915,33 @@ namespace Bit.Core.Services return createdCustomer; } + public async Task CreditAccountAsync(ISubscriber subscriber, decimal creditAmount) + { + var customerService = new CustomerService(); + Customer customer = null; + var customerExists = subscriber.Gateway == GatewayType.Stripe && + !string.IsNullOrWhiteSpace(subscriber.GatewaySubscriptionId); + if(customerExists) + { + customer = await customerService.GetAsync(subscriber.GatewaySubscriptionId); + } + else + { + customer = await customerService.CreateAsync(new CustomerCreateOptions + { + Email = subscriber.BillingEmailAddress(), + Description = subscriber.BillingName(), + }); + subscriber.Gateway = GatewayType.Stripe; + subscriber.GatewayCustomerId = customer.Id; + } + await customerService.UpdateAsync(customer.Id, new CustomerUpdateOptions + { + AccountBalance = customer.AccountBalance - (long)(creditAmount * 100) + }); + return !customerExists; + } + public async Task GetBillingAsync(ISubscriber subscriber) { var billingInfo = new BillingInfo();