-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PM-13999] Show estimated tax for taxable countries (#5077)
- Loading branch information
1 parent
44b6879
commit 94fdfa4
Showing
30 changed files
with
1,791 additions
and
529 deletions.
There are no files selected for viewing
151 changes: 151 additions & 0 deletions
151
bitwarden_license/test/Commercial.Core.Test/Billing/TaxServiceTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
using Bit.Core.Billing.Services; | ||
using Bit.Test.Common.AutoFixture; | ||
using Bit.Test.Common.AutoFixture.Attributes; | ||
using Xunit; | ||
|
||
namespace Bit.Commercial.Core.Test.Billing; | ||
|
||
[SutProviderCustomize] | ||
public class TaxServiceTests | ||
{ | ||
[Theory] | ||
[BitAutoData("AD", "A-123456-Z", "ad_nrt")] | ||
[BitAutoData("AD", "A123456Z", "ad_nrt")] | ||
[BitAutoData("AR", "20-12345678-9", "ar_cuit")] | ||
[BitAutoData("AR", "20123456789", "ar_cuit")] | ||
[BitAutoData("AU", "01259983598", "au_abn")] | ||
[BitAutoData("AU", "123456789123", "au_arn")] | ||
[BitAutoData("AT", "ATU12345678", "eu_vat")] | ||
[BitAutoData("BH", "123456789012345", "bh_vat")] | ||
[BitAutoData("BY", "123456789", "by_tin")] | ||
[BitAutoData("BE", "BE0123456789", "eu_vat")] | ||
[BitAutoData("BO", "123456789", "bo_tin")] | ||
[BitAutoData("BR", "01.234.456/5432-10", "br_cnpj")] | ||
[BitAutoData("BR", "01234456543210", "br_cnpj")] | ||
[BitAutoData("BR", "123.456.789-87", "br_cpf")] | ||
[BitAutoData("BR", "12345678987", "br_cpf")] | ||
[BitAutoData("BG", "123456789", "bg_uic")] | ||
[BitAutoData("BG", "BG012100705", "eu_vat")] | ||
[BitAutoData("CA", "100728494", "ca_bn")] | ||
[BitAutoData("CA", "123456789RT0001", "ca_gst_hst")] | ||
[BitAutoData("CA", "PST-1234-1234", "ca_pst_bc")] | ||
[BitAutoData("CA", "123456-7", "ca_pst_mb")] | ||
[BitAutoData("CA", "1234567", "ca_pst_sk")] | ||
[BitAutoData("CA", "1234567890TQ1234", "ca_qst")] | ||
[BitAutoData("CL", "11.121.326-1", "cl_tin")] | ||
[BitAutoData("CL", "11121326-1", "cl_tin")] | ||
[BitAutoData("CL", "23.121.326-K", "cl_tin")] | ||
[BitAutoData("CL", "43651326-K", "cl_tin")] | ||
[BitAutoData("CN", "123456789012345678", "cn_tin")] | ||
[BitAutoData("CN", "123456789012345", "cn_tin")] | ||
[BitAutoData("CO", "123.456.789-0", "co_nit")] | ||
[BitAutoData("CO", "1234567890", "co_nit")] | ||
[BitAutoData("CR", "1-234-567890", "cr_tin")] | ||
[BitAutoData("CR", "1234567890", "cr_tin")] | ||
[BitAutoData("HR", "HR12345678912", "eu_vat")] | ||
[BitAutoData("HR", "12345678901", "hr_oib")] | ||
[BitAutoData("CY", "CY12345678X", "eu_vat")] | ||
[BitAutoData("CZ", "CZ12345678", "eu_vat")] | ||
[BitAutoData("DK", "DK12345678", "eu_vat")] | ||
[BitAutoData("DO", "123-4567890-1", "do_rcn")] | ||
[BitAutoData("DO", "12345678901", "do_rcn")] | ||
[BitAutoData("EC", "1234567890001", "ec_ruc")] | ||
[BitAutoData("EG", "123456789", "eg_tin")] | ||
[BitAutoData("SV", "1234-567890-123-4", "sv_nit")] | ||
[BitAutoData("SV", "12345678901234", "sv_nit")] | ||
[BitAutoData("EE", "EE123456789", "eu_vat")] | ||
[BitAutoData("EU", "EU123456789", "eu_oss_vat")] | ||
[BitAutoData("FI", "FI12345678", "eu_vat")] | ||
[BitAutoData("FR", "FR12345678901", "eu_vat")] | ||
[BitAutoData("GE", "123456789", "ge_vat")] | ||
[BitAutoData("DE", "1234567890", "de_stn")] | ||
[BitAutoData("DE", "DE123456789", "eu_vat")] | ||
[BitAutoData("GR", "EL123456789", "eu_vat")] | ||
[BitAutoData("HK", "12345678", "hk_br")] | ||
[BitAutoData("HU", "HU12345678", "eu_vat")] | ||
[BitAutoData("HU", "12345678-1-23", "hu_tin")] | ||
[BitAutoData("HU", "12345678123", "hu_tin")] | ||
[BitAutoData("IS", "123456", "is_vat")] | ||
[BitAutoData("IN", "12ABCDE1234F1Z5", "in_gst")] | ||
[BitAutoData("IN", "12ABCDE3456FGZH", "in_gst")] | ||
[BitAutoData("ID", "012.345.678.9-012.345", "id_npwp")] | ||
[BitAutoData("ID", "0123456789012345", "id_npwp")] | ||
[BitAutoData("IE", "IE1234567A", "eu_vat")] | ||
[BitAutoData("IE", "IE1234567AB", "eu_vat")] | ||
[BitAutoData("IL", "000012345", "il_vat")] | ||
[BitAutoData("IL", "123456789", "il_vat")] | ||
[BitAutoData("IT", "IT12345678901", "eu_vat")] | ||
[BitAutoData("JP", "1234567890123", "jp_cn")] | ||
[BitAutoData("JP", "12345", "jp_rn")] | ||
[BitAutoData("KZ", "123456789012", "kz_bin")] | ||
[BitAutoData("KE", "P000111111A", "ke_pin")] | ||
[BitAutoData("LV", "LV12345678912", "eu_vat")] | ||
[BitAutoData("LI", "CHE123456789", "li_uid")] | ||
[BitAutoData("LI", "12345", "li_vat")] | ||
[BitAutoData("LT", "LT123456789123", "eu_vat")] | ||
[BitAutoData("LU", "LU12345678", "eu_vat")] | ||
[BitAutoData("MY", "12345678", "my_frp")] | ||
[BitAutoData("MY", "C 1234567890", "my_itn")] | ||
[BitAutoData("MY", "C1234567890", "my_itn")] | ||
[BitAutoData("MY", "A12-3456-78912345", "my_sst")] | ||
[BitAutoData("MY", "A12345678912345", "my_sst")] | ||
[BitAutoData("MT", "MT12345678", "eu_vat")] | ||
[BitAutoData("MX", "ABC010203AB9", "mx_rfc")] | ||
[BitAutoData("MD", "1003600", "md_vat")] | ||
[BitAutoData("MA", "12345678", "ma_vat")] | ||
[BitAutoData("NL", "NL123456789B12", "eu_vat")] | ||
[BitAutoData("NZ", "123456789", "nz_gst")] | ||
[BitAutoData("NG", "12345678-0001", "ng_tin")] | ||
[BitAutoData("NO", "123456789MVA", "no_vat")] | ||
[BitAutoData("NO", "1234567", "no_voec")] | ||
[BitAutoData("OM", "OM1234567890", "om_vat")] | ||
[BitAutoData("PE", "12345678901", "pe_ruc")] | ||
[BitAutoData("PH", "123456789012", "ph_tin")] | ||
[BitAutoData("PL", "PL1234567890", "eu_vat")] | ||
[BitAutoData("PT", "PT123456789", "eu_vat")] | ||
[BitAutoData("RO", "RO1234567891", "eu_vat")] | ||
[BitAutoData("RO", "1234567890123", "ro_tin")] | ||
[BitAutoData("RU", "1234567891", "ru_inn")] | ||
[BitAutoData("RU", "123456789", "ru_kpp")] | ||
[BitAutoData("SA", "123456789012345", "sa_vat")] | ||
[BitAutoData("RS", "123456789", "rs_pib")] | ||
[BitAutoData("SG", "M12345678X", "sg_gst")] | ||
[BitAutoData("SG", "123456789F", "sg_uen")] | ||
[BitAutoData("SK", "SK1234567891", "eu_vat")] | ||
[BitAutoData("SI", "SI12345678", "eu_vat")] | ||
[BitAutoData("SI", "12345678", "si_tin")] | ||
[BitAutoData("ZA", "4123456789", "za_vat")] | ||
[BitAutoData("KR", "123-45-67890", "kr_brn")] | ||
[BitAutoData("KR", "1234567890", "kr_brn")] | ||
[BitAutoData("ES", "A12345678", "es_cif")] | ||
[BitAutoData("ES", "ESX1234567X", "eu_vat")] | ||
[BitAutoData("SE", "SE123456789012", "eu_vat")] | ||
[BitAutoData("CH", "CHE-123.456.789 HR", "ch_uid")] | ||
[BitAutoData("CH", "CHE123456789HR", "ch_uid")] | ||
[BitAutoData("CH", "CHE-123.456.789 MWST", "ch_vat")] | ||
[BitAutoData("CH", "CHE123456789MWST", "ch_vat")] | ||
[BitAutoData("TW", "12345678", "tw_vat")] | ||
[BitAutoData("TH", "1234567890123", "th_vat")] | ||
[BitAutoData("TR", "0123456789", "tr_tin")] | ||
[BitAutoData("UA", "123456789", "ua_vat")] | ||
[BitAutoData("AE", "123456789012345", "ae_trn")] | ||
[BitAutoData("GB", "XI123456789", "eu_vat")] | ||
[BitAutoData("GB", "GB123456789", "gb_vat")] | ||
[BitAutoData("US", "12-3456789", "us_ein")] | ||
[BitAutoData("UY", "123456789012", "uy_ruc")] | ||
[BitAutoData("UZ", "123456789", "uz_tin")] | ||
[BitAutoData("UZ", "123456789012", "uz_vat")] | ||
[BitAutoData("VE", "A-12345678-9", "ve_rif")] | ||
[BitAutoData("VE", "A123456789", "ve_rif")] | ||
[BitAutoData("VN", "1234567890", "vn_tin")] | ||
public void GetStripeTaxCode_WithValidCountryAndTaxId_ReturnsExpectedTaxIdType( | ||
string country, | ||
string taxId, | ||
string expected, | ||
SutProvider<TaxService> sutProvider) | ||
{ | ||
var result = sutProvider.Sut.GetStripeTaxCode(country, taxId); | ||
|
||
Assert.Equal(expected, result); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
using Bit.Core.AdminConsole.Entities; | ||
using Bit.Core.Billing.Models.Api.Requests.Organizations; | ||
using Bit.Core.Context; | ||
using Bit.Core.Repositories; | ||
using Bit.Core.Services; | ||
using Microsoft.AspNetCore.Authorization; | ||
using Microsoft.AspNetCore.Mvc; | ||
|
||
namespace Bit.Api.Billing.Controllers; | ||
|
||
[Route("invoices")] | ||
[Authorize("Application")] | ||
public class InvoicesController : BaseBillingController | ||
{ | ||
[HttpPost("preview-organization")] | ||
public async Task<IResult> PreviewInvoiceAsync( | ||
[FromBody] PreviewOrganizationInvoiceRequestBody model, | ||
[FromServices] ICurrentContext currentContext, | ||
[FromServices] IOrganizationRepository organizationRepository, | ||
[FromServices] IPaymentService paymentService) | ||
{ | ||
Organization organization = null; | ||
if (model.OrganizationId != default) | ||
{ | ||
if (!await currentContext.EditPaymentMethods(model.OrganizationId)) | ||
{ | ||
return Error.Unauthorized(); | ||
} | ||
|
||
organization = await organizationRepository.GetByIdAsync(model.OrganizationId); | ||
if (organization == null) | ||
{ | ||
return Error.NotFound(); | ||
} | ||
} | ||
|
||
var invoice = await paymentService.PreviewInvoiceAsync(model, organization?.GatewayCustomerId, | ||
organization?.GatewaySubscriptionId); | ||
|
||
return TypedResults.Ok(invoice); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
namespace Bit.Core.Billing.Extensions; | ||
|
||
public static class CurrencyExtensions | ||
{ | ||
/// <summary> | ||
/// Converts a currency amount in major units to minor units. | ||
/// </summary> | ||
/// <example>123.99 USD returns 12399 in minor units.</example> | ||
public static long ToMinor(this decimal amount) | ||
{ | ||
return Convert.ToInt64(amount * 100); | ||
} | ||
|
||
/// <summary> | ||
/// Converts a currency amount in minor units to major units. | ||
/// </summary> | ||
/// <param name="amount"></param> | ||
/// <example>12399 in minor units returns 123.99 USD.</example> | ||
public static decimal? ToMajor(this long? amount) | ||
{ | ||
return amount?.ToMajor(); | ||
} | ||
|
||
/// <summary> | ||
/// Converts a currency amount in minor units to major units. | ||
/// </summary> | ||
/// <param name="amount"></param> | ||
/// <example>12399 in minor units returns 123.99 USD.</example> | ||
public static decimal ToMajor(this long amount) | ||
{ | ||
return Convert.ToDecimal(amount) / 100; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
src/Core/Billing/Models/Api/Requests/Accounts/PreviewIndividualInvoiceRequestModel.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using System.ComponentModel.DataAnnotations; | ||
|
||
namespace Bit.Core.Billing.Models.Api.Requests.Accounts; | ||
|
||
public class PreviewIndividualInvoiceRequestBody | ||
{ | ||
[Required] | ||
public PasswordManagerRequestModel PasswordManager { get; set; } | ||
|
||
[Required] | ||
public TaxInformationRequestModel TaxInformation { get; set; } | ||
} | ||
|
||
public class PasswordManagerRequestModel | ||
{ | ||
[Range(0, int.MaxValue)] | ||
public int AdditionalStorage { get; set; } | ||
} |
37 changes: 37 additions & 0 deletions
37
src/Core/Billing/Models/Api/Requests/Organizations/PreviewOrganizationInvoiceRequestModel.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using System.ComponentModel.DataAnnotations; | ||
using Bit.Core.Billing.Enums; | ||
|
||
namespace Bit.Core.Billing.Models.Api.Requests.Organizations; | ||
|
||
public class PreviewOrganizationInvoiceRequestBody | ||
{ | ||
public Guid OrganizationId { get; set; } | ||
|
||
[Required] | ||
public PasswordManagerRequestModel PasswordManager { get; set; } | ||
|
||
public SecretsManagerRequestModel SecretsManager { get; set; } | ||
|
||
[Required] | ||
public TaxInformationRequestModel TaxInformation { get; set; } | ||
} | ||
|
||
public class PasswordManagerRequestModel | ||
{ | ||
public PlanType Plan { get; set; } | ||
|
||
[Range(0, int.MaxValue)] | ||
public int Seats { get; set; } | ||
|
||
[Range(0, int.MaxValue)] | ||
public int AdditionalStorage { get; set; } | ||
} | ||
|
||
public class SecretsManagerRequestModel | ||
{ | ||
[Range(0, int.MaxValue)] | ||
public int Seats { get; set; } | ||
|
||
[Range(0, int.MaxValue)] | ||
public int AdditionalMachineAccounts { get; set; } | ||
} |
14 changes: 14 additions & 0 deletions
14
src/Core/Billing/Models/Api/Requests/TaxInformationRequestModel.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
using System.ComponentModel.DataAnnotations; | ||
|
||
namespace Bit.Core.Billing.Models.Api.Requests; | ||
|
||
public class TaxInformationRequestModel | ||
{ | ||
[Length(2, 2), Required] | ||
public string Country { get; set; } | ||
|
||
[Required] | ||
public string PostalCode { get; set; } | ||
|
||
public string TaxId { get; set; } | ||
} |
7 changes: 7 additions & 0 deletions
7
src/Core/Billing/Models/Api/Responses/PreviewInvoiceResponseModel.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace Bit.Core.Billing.Models.Api.Responses; | ||
|
||
public record PreviewInvoiceResponseModel( | ||
decimal EffectiveTaxRate, | ||
decimal TaxableBaseAmount, | ||
decimal TaxAmount, | ||
decimal TotalAmount); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace Bit.Core.Billing.Models; | ||
|
||
public record PreviewInvoiceInfo( | ||
decimal EffectiveTaxRate, | ||
decimal TaxableBaseAmount, | ||
decimal TaxAmount, | ||
decimal TotalAmount); |
Oops, something went wrong.