1
0
mirror of https://github.com/bitwarden/server.git synced 2025-05-03 02:32:16 -05:00

stripe invoice handling. return credit amount.

This commit is contained in:
Kyle Spearrin 2019-01-29 17:44:31 -05:00
parent a34ca4700d
commit abb1751bfe
3 changed files with 96 additions and 43 deletions

View File

@ -12,6 +12,7 @@ namespace Bit.Core.Models.Api
public BillingResponseModel(User user, BillingInfo billing, UserLicense license)
: base("billing")
{
CreditAmount = billing.CreditAmount;
PaymentSource = billing.PaymentSource != null ? new BillingSource(billing.PaymentSource) : null;
Subscription = billing.Subscription != null ? new BillingSubscription(billing.Subscription) : null;
Charges = billing.Charges.Select(c => new BillingCharge(c));
@ -37,6 +38,7 @@ namespace Bit.Core.Models.Api
}
}
public decimal CreditAmount { get; set; }
public string StorageName { get; set; }
public double? StorageGb { get; set; }
public short? MaxStorageGb { get; set; }

View File

@ -8,6 +8,7 @@ namespace Bit.Core.Models.Business
{
public class BillingInfo
{
public decimal CreditAmount { get; set; }
public BillingSource PaymentSource { get; set; }
public BillingSubscription Subscription { get; set; }
public BillingInvoice UpcomingInvoice { get; set; }

View File

@ -105,6 +105,7 @@ namespace Bit.Core.Services
if(stripeSubscriptionBilling == Billing.SendInvoice)
{
var invoicePayOptions = new InvoicePayOptions();
var invoiceService = new InvoiceService();
var invoices = await invoiceService.ListAsync(new InvoiceListOptions
{
@ -119,40 +120,54 @@ namespace Bit.Core.Services
if(braintreeCustomer != null)
{
var btInvoiceAmount = (invoice.AmountDue / 100M);
var transactionResult = await _btGateway.Transaction.SaleAsync(new Braintree.TransactionRequest
invoicePayOptions.PaidOutOfBand = true;
Braintree.Transaction braintreeTransaction = null;
try
{
Amount = btInvoiceAmount,
CustomerId = braintreeCustomer.Id
});
var btInvoiceAmount = (invoice.AmountDue / 100M);
var transactionResult = await _btGateway.Transaction.SaleAsync(
new Braintree.TransactionRequest
{
Amount = btInvoiceAmount,
CustomerId = braintreeCustomer.Id,
Options = new Braintree.TransactionOptionsRequest { SubmitForSettlement = true }
});
if(!transactionResult.IsSuccess() || transactionResult.Target.Amount != btInvoiceAmount)
{
throw new GatewayException("Failed to charge PayPal customer.");
}
var invoiceItemService = new InvoiceItemService();
await invoiceItemService.CreateAsync(new InvoiceItemCreateOptions
{
Currency = "USD",
CustomerId = customer.Id,
InvoiceId = invoice.Id,
Amount = -1 * invoice.AmountDue,
Description = $"PayPal Credit, Transaction ID " +
transactionResult.Target.PayPalDetails.AuthorizationId,
Metadata = new Dictionary<string, string>
if(!transactionResult.IsSuccess())
{
["btTransactionId"] = transactionResult.Target.Id,
["btPayPalTransactionId"] = transactionResult.Target.PayPalDetails.AuthorizationId
throw new GatewayException("Failed to charge PayPal customer.");
}
});
braintreeTransaction = transactionResult.Target;
if(transactionResult.Target.Amount != btInvoiceAmount)
{
throw new GatewayException("PayPal charge mismatch.");
}
await invoiceService.UpdateAsync(invoice.Id, new InvoiceUpdateOptions
{
Metadata = new Dictionary<string, string>
{
["btTransactionId"] = braintreeTransaction.Id,
["btPayPalTransactionId"] = braintreeTransaction.PayPalDetails.AuthorizationId
}
});
}
catch(Exception e)
{
if(braintreeTransaction != null)
{
await _btGateway.Transaction.RefundAsync(braintreeTransaction.Id);
}
throw e;
}
}
else
{
throw new GatewayException("No payment was able to be collected.");
}
await invoiceService.PayAsync(invoice.Id, new InvoicePayOptions { });
await invoiceService.PayAsync(invoice.Id, invoicePayOptions);
}
}
catch(Exception e)
@ -271,41 +286,65 @@ namespace Bit.Core.Services
SubscriptionId = subscriber.GatewaySubscriptionId
});
var invoicePayOptions = new InvoicePayOptions();
if(invoice.AmountDue > 0)
{
var customerService = new CustomerService();
var customer = await customerService.GetAsync(subscriber.GatewayCustomerId);
if(customer != null)
{
Braintree.Transaction braintreeTransaction = null;
if(customer.Metadata.ContainsKey("btCustomerId"))
{
var invoiceAmount = (invoice.AmountDue / 100M);
var transactionResult = await _btGateway.Transaction.SaleAsync(
new Braintree.TransactionRequest
{
Amount = invoiceAmount,
CustomerId = customer.Metadata["btCustomerId"]
});
if(!transactionResult.IsSuccess() || transactionResult.Target.Amount != invoiceAmount)
invoicePayOptions.PaidOutOfBand = true;
try
{
var btInvoiceAmount = (invoice.AmountDue / 100M);
var transactionResult = await _btGateway.Transaction.SaleAsync(
new Braintree.TransactionRequest
{
Amount = btInvoiceAmount,
CustomerId = customer.Metadata["btCustomerId"],
Options = new Braintree.TransactionOptionsRequest
{
SubmitForSettlement = true
}
});
if(!transactionResult.IsSuccess())
{
throw new GatewayException("Failed to charge PayPal customer.");
}
braintreeTransaction = transactionResult.Target;
if(transactionResult.Target.Amount != btInvoiceAmount)
{
throw new GatewayException("PayPal charge mismatch.");
}
await invoiceService.UpdateAsync(invoice.Id, new InvoiceUpdateOptions
{
Closed = true
Metadata = new Dictionary<string, string>
{
["btTransactionId"] = braintreeTransaction.Id,
["btPayPalTransactionId"] =
braintreeTransaction.PayPalDetails.AuthorizationId
}
});
throw new GatewayException("Failed to charge PayPal customer.");
}
await customerService.UpdateAsync(customer.Id, new CustomerUpdateOptions
catch(Exception e)
{
AccountBalance = customer.AccountBalance - invoice.AmountDue,
Metadata = customer.Metadata
});
if(braintreeTransaction != null)
{
await _btGateway.Transaction.RefundAsync(braintreeTransaction.Id);
}
throw e;
}
}
}
await invoiceService.PayAsync(invoice.Id, new InvoicePayOptions());
}
await invoiceService.PayAsync(invoice.Id, invoicePayOptions);
}
catch(StripeException) { }
}
@ -502,7 +541,18 @@ namespace Bit.Core.Services
var customer = await customerService.GetAsync(subscriber.GatewayCustomerId);
if(customer != null)
{
if(!string.IsNullOrWhiteSpace(customer.DefaultSourceId) && customer.Sources?.Data != null)
billingInfo.CreditAmount = customer.AccountBalance / 100M;
if(customer.Metadata?.ContainsKey("btCustomerId") ?? false)
{
var braintreeCustomer = await _btGateway.Customer.FindAsync(customer.Metadata["btCustomerId"]);
if(braintreeCustomer?.DefaultPaymentMethod != null)
{
billingInfo.PaymentSource = new BillingInfo.BillingSource(
braintreeCustomer.DefaultPaymentMethod);
}
}
else if(!string.IsNullOrWhiteSpace(customer.DefaultSourceId) && customer.Sources?.Data != null)
{
if(customer.DefaultSourceId.StartsWith("card_") || customer.DefaultSourceId.StartsWith("ba_"))
{