mirror of
https://github.com/bitwarden/server.git
synced 2025-04-16 02:28:13 -05:00
change payment API
This commit is contained in:
parent
6467cafde3
commit
18d2715c71
@ -115,6 +115,19 @@ namespace Bit.Api.Controllers
|
|||||||
return new OrganizationResponseModel(organization);
|
return new OrganizationResponseModel(organization);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPut("{id}/payment")]
|
||||||
|
[HttpPost("{id}/payment")]
|
||||||
|
public async Task PutPayment(string id, [FromBody]OrganizationPaymentRequestModel model)
|
||||||
|
{
|
||||||
|
var orgIdGuid = new Guid(id);
|
||||||
|
if(!_currentContext.OrganizationOwner(orgIdGuid))
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
await _organizationService.ReplacePaymentMethodAsync(orgIdGuid, model.PaymentToken);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpDelete("{id}")]
|
[HttpDelete("{id}")]
|
||||||
[HttpPost("{id}/delete")]
|
[HttpPost("{id}/delete")]
|
||||||
public async Task Delete(string id)
|
public async Task Delete(string id)
|
||||||
|
@ -19,7 +19,7 @@ namespace Bit.Core.Models.Api
|
|||||||
public PlanType PlanType { get; set; }
|
public PlanType PlanType { get; set; }
|
||||||
[Required]
|
[Required]
|
||||||
public string Key { get; set; }
|
public string Key { get; set; }
|
||||||
public string CardToken { get; set; }
|
public string PaymentToken { get; set; }
|
||||||
[Range(0, double.MaxValue)]
|
[Range(0, double.MaxValue)]
|
||||||
public short AdditionalUsers { get; set; }
|
public short AdditionalUsers { get; set; }
|
||||||
public bool Monthly { get; set; }
|
public bool Monthly { get; set; }
|
||||||
@ -32,7 +32,7 @@ namespace Bit.Core.Models.Api
|
|||||||
OwnerKey = Key,
|
OwnerKey = Key,
|
||||||
Name = Name,
|
Name = Name,
|
||||||
Plan = PlanType,
|
Plan = PlanType,
|
||||||
PaymentToken = CardToken,
|
PaymentToken = PaymentToken,
|
||||||
AdditionalUsers = AdditionalUsers,
|
AdditionalUsers = AdditionalUsers,
|
||||||
BillingEmail = BillingEmail,
|
BillingEmail = BillingEmail,
|
||||||
BusinessName = BusinessName,
|
BusinessName = BusinessName,
|
||||||
@ -42,9 +42,9 @@ namespace Bit.Core.Models.Api
|
|||||||
|
|
||||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||||
{
|
{
|
||||||
if(PlanType != PlanType.Free && string.IsNullOrWhiteSpace(CardToken))
|
if(PlanType != PlanType.Free && string.IsNullOrWhiteSpace(PaymentToken))
|
||||||
{
|
{
|
||||||
yield return new ValidationResult("Card required.", new string[] { nameof(CardToken) });
|
yield return new ValidationResult("Payment required.", new string[] { nameof(PaymentToken) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Api
|
||||||
|
{
|
||||||
|
public class OrganizationPaymentRequestModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string PaymentToken { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -58,7 +58,8 @@ namespace Bit.Core.Models.Api
|
|||||||
switch(source.Type)
|
switch(source.Type)
|
||||||
{
|
{
|
||||||
case SourceType.Card:
|
case SourceType.Card:
|
||||||
Description = $"{source.Card.Brand}, *{source.Card.Last4}";
|
Description = $"{source.Card.Brand}, *{source.Card.Last4}, " +
|
||||||
|
$"{source.Card.ExpirationMonth}/{source.Card.ExpirationYear}";
|
||||||
CardBrand = source.Card.Brand;
|
CardBrand = source.Card.Brand;
|
||||||
break;
|
break;
|
||||||
case SourceType.BankAccount:
|
case SourceType.BankAccount:
|
||||||
|
@ -9,6 +9,7 @@ namespace Bit.Core.Services
|
|||||||
public interface IOrganizationService
|
public interface IOrganizationService
|
||||||
{
|
{
|
||||||
Task<OrganizationBilling> GetBillingAsync(Organization organization);
|
Task<OrganizationBilling> GetBillingAsync(Organization organization);
|
||||||
|
Task ReplacePaymentMethodAsync(Guid organizationId, string paymentToken);
|
||||||
Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationSignup organizationSignup);
|
Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationSignup organizationSignup);
|
||||||
Task<OrganizationUser> InviteUserAsync(Guid organizationId, Guid invitingUserId, string email,
|
Task<OrganizationUser> InviteUserAsync(Guid organizationId, Guid invitingUserId, string email,
|
||||||
Enums.OrganizationUserType type, IEnumerable<SubvaultUser> subvaults);
|
Enums.OrganizationUserType type, IEnumerable<SubvaultUser> subvaults);
|
||||||
|
@ -51,7 +51,19 @@ namespace Bit.Core.Services
|
|||||||
var customer = await customerService.GetAsync(organization.StripeCustomerId);
|
var customer = await customerService.GetAsync(organization.StripeCustomerId);
|
||||||
if(customer != null)
|
if(customer != null)
|
||||||
{
|
{
|
||||||
orgBilling.PaymentSource = customer.DefaultSource;
|
if(!string.IsNullOrWhiteSpace(customer.DefaultSourceId) && customer.Sources?.Data != null)
|
||||||
|
{
|
||||||
|
if(customer.DefaultSourceId.StartsWith("card_"))
|
||||||
|
{
|
||||||
|
orgBilling.PaymentSource =
|
||||||
|
customer.Sources.Data.FirstOrDefault(s => s.Card?.Id == customer.DefaultSourceId);
|
||||||
|
}
|
||||||
|
else if(customer.DefaultSourceId.StartsWith("ba_"))
|
||||||
|
{
|
||||||
|
orgBilling.PaymentSource =
|
||||||
|
customer.Sources.Data.FirstOrDefault(s => s.BankAccount?.Id == customer.DefaultSourceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var charges = await chargeService.ListAsync(new StripeChargeListOptions
|
var charges = await chargeService.ListAsync(new StripeChargeListOptions
|
||||||
{
|
{
|
||||||
@ -74,6 +86,47 @@ namespace Bit.Core.Services
|
|||||||
return orgBilling;
|
return orgBilling;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task ReplacePaymentMethodAsync(Guid organizationId, string paymentToken)
|
||||||
|
{
|
||||||
|
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||||
|
if(organization == null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var cardService = new StripeCardService();
|
||||||
|
var customerService = new StripeCustomerService();
|
||||||
|
StripeCustomer customer = null;
|
||||||
|
|
||||||
|
if(!string.IsNullOrWhiteSpace(organization.StripeCustomerId))
|
||||||
|
{
|
||||||
|
customer = await customerService.GetAsync(organization.StripeCustomerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(customer == null)
|
||||||
|
{
|
||||||
|
customer = await customerService.CreateAsync(new StripeCustomerCreateOptions
|
||||||
|
{
|
||||||
|
Description = organization.BusinessName,
|
||||||
|
Email = organization.BillingEmail,
|
||||||
|
SourceToken = paymentToken
|
||||||
|
});
|
||||||
|
|
||||||
|
organization.StripeCustomerId = customer.Id;
|
||||||
|
await _organizationRepository.ReplaceAsync(organization);
|
||||||
|
}
|
||||||
|
|
||||||
|
await cardService.CreateAsync(customer.Id, new StripeCardCreateOptions
|
||||||
|
{
|
||||||
|
SourceToken = paymentToken
|
||||||
|
});
|
||||||
|
|
||||||
|
if(!string.IsNullOrWhiteSpace(customer.DefaultSourceId))
|
||||||
|
{
|
||||||
|
await cardService.DeleteAsync(customer.Id, customer.DefaultSourceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationSignup signup)
|
public async Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationSignup signup)
|
||||||
{
|
{
|
||||||
var plan = StaticStore.Plans.FirstOrDefault(p => p.Type == signup.Plan && !p.Disabled);
|
var plan = StaticStore.Plans.FirstOrDefault(p => p.Type == signup.Plan && !p.Disabled);
|
||||||
@ -87,7 +140,8 @@ namespace Bit.Core.Services
|
|||||||
StripeCustomer customer = null;
|
StripeCustomer customer = null;
|
||||||
StripeSubscription subscription = null;
|
StripeSubscription subscription = null;
|
||||||
|
|
||||||
if(signup.AdditionalUsers > plan.MaxAdditionalUsers.GetValueOrDefault(0))
|
if(plan.CanBuyAdditionalUsers && plan.MaxAdditionalUsers.HasValue &&
|
||||||
|
signup.AdditionalUsers > plan.MaxAdditionalUsers.Value)
|
||||||
{
|
{
|
||||||
throw new BadRequestException($"Selected plan allows a maximum of " +
|
throw new BadRequestException($"Selected plan allows a maximum of " +
|
||||||
$"{plan.MaxAdditionalUsers.GetValueOrDefault(0)} additional users.");
|
$"{plan.MaxAdditionalUsers.GetValueOrDefault(0)} additional users.");
|
||||||
@ -143,7 +197,7 @@ namespace Bit.Core.Services
|
|||||||
PlanType = plan.Type,
|
PlanType = plan.Type,
|
||||||
MaxUsers = (short)(plan.BaseUsers + (plan.CanBuyAdditionalUsers ? signup.AdditionalUsers : 0)),
|
MaxUsers = (short)(plan.BaseUsers + (plan.CanBuyAdditionalUsers ? signup.AdditionalUsers : 0)),
|
||||||
MaxSubvaults = plan.MaxSubvaults,
|
MaxSubvaults = plan.MaxSubvaults,
|
||||||
Plan = plan.ToString(),
|
Plan = plan.Name,
|
||||||
StripeCustomerId = customer?.Id,
|
StripeCustomerId = customer?.Id,
|
||||||
StripeSubscriptionId = subscription?.Id,
|
StripeSubscriptionId = subscription?.Id,
|
||||||
CreationDate = DateTime.UtcNow,
|
CreationDate = DateTime.UtcNow,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user