mirror of
https://github.com/bitwarden/server
synced 2025-12-29 14:43:39 +00:00
[PM-21638] Stripe .NET v48 (#6202)
* Upgrade Stripe.net to v48.4.0 * Update PreviewTaxAmountCommand * Remove unused UpcomingInvoiceOptionExtensions * Added SubscriptionExtensions with GetCurrentPeriodEnd * Update PremiumUserBillingService * Update OrganizationBillingService * Update GetOrganizationWarningsQuery * Update BillingHistoryInfo * Update SubscriptionInfo * Remove unused Sql Billing folder * Update StripeAdapter * Update StripePaymentService * Update InvoiceCreatedHandler * Update PaymentFailedHandler * Update PaymentSucceededHandler * Update ProviderEventService * Update StripeEventUtilityService * Update SubscriptionDeletedHandler * Update SubscriptionUpdatedHandler * Update UpcomingInvoiceHandler * Update ProviderSubscriptionResponse * Remove unused Stripe Subscriptions Admin Tool * Update RemoveOrganizationFromProviderCommand * Update ProviderBillingService * Update RemoveOrganizatinoFromProviderCommandTests * Update PreviewTaxAmountCommandTests * Update GetCloudOrganizationLicenseQueryTests * Update GetOrganizationWarningsQueryTests * Update StripePaymentServiceTests * Update ProviderBillingControllerTests * Update ProviderEventServiceTests * Update SubscriptionDeletedHandlerTests * Update SubscriptionUpdatedHandlerTests * Resolve Billing test failures I completely removed tests for the StripeEventService as they were using a system I setup a while back that read JSON files of the Stripe event structure. I did not anticipate how frequently these structures would change with each API version and the cost of trying to update these specific JSON files to test a very static data retrieval service far outweigh the benefit. * Resolve Core test failures * Run dotnet format * Remove unused provider migration * Fixed failing tests * Run dotnet format * Replace the old webhook secret key with new one (#6223) * Fix compilation failures in additions * Run dotnet format * Bump Stripe API version * Fix recent addition: CreatePremiumCloudHostedSubscriptionCommand * Fix new code in main according to Stripe update * Fix InvoiceExtensions * Bump SDK version to match API Version * Fix provider invoice generation validation * More QA fixes * Fix tests * QA defect resolutions * QA defect resolutions * Run dotnet format * Fix tests --------- Co-authored-by: cyprain-okeke <108260115+cyprain-okeke@users.noreply.github.com>
This commit is contained in:
@@ -27,24 +27,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\Events\charge.succeeded.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Resources\Events\customer.subscription.updated.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Resources\Events\customer.updated.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Resources\Events\invoice.created.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Resources\Events\invoice.upcoming.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Resources\Events\payment_method.attached.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Resources\IPN\echeck-payment.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
@@ -73,9 +55,6 @@
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
<None Remove="Resources\Events\invoice.finalized.json" />
|
||||
<EmbeddedResource Include="Resources\Events\invoice.finalized.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
{
|
||||
"id": "evt_3NvKgBIGBnsLynRr0pJJqudS",
|
||||
"object": "event",
|
||||
"api_version": "2024-06-20",
|
||||
"created": 1695909300,
|
||||
"data": {
|
||||
"object": {
|
||||
"id": "ch_3NvKgBIGBnsLynRr0ZyvP9AN",
|
||||
"object": "charge",
|
||||
"amount": 7200,
|
||||
"amount_captured": 7200,
|
||||
"amount_refunded": 0,
|
||||
"application": null,
|
||||
"application_fee": null,
|
||||
"application_fee_amount": null,
|
||||
"balance_transaction": "txn_3NvKgBIGBnsLynRr0KbYEz76",
|
||||
"billing_details": {
|
||||
"address": {
|
||||
"city": null,
|
||||
"country": null,
|
||||
"line1": null,
|
||||
"line2": null,
|
||||
"postal_code": null,
|
||||
"state": null
|
||||
},
|
||||
"email": null,
|
||||
"name": null,
|
||||
"phone": null
|
||||
},
|
||||
"calculated_statement_descriptor": "BITWARDEN",
|
||||
"captured": true,
|
||||
"created": 1695909299,
|
||||
"currency": "usd",
|
||||
"customer": "cus_OimAwOzQmThNXx",
|
||||
"description": "Subscription update",
|
||||
"destination": null,
|
||||
"dispute": null,
|
||||
"disputed": false,
|
||||
"failure_balance_transaction": null,
|
||||
"failure_code": null,
|
||||
"failure_message": null,
|
||||
"fraud_details": {
|
||||
},
|
||||
"invoice": "in_1NvKgBIGBnsLynRrmRFHAcoV",
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"on_behalf_of": null,
|
||||
"order": null,
|
||||
"outcome": {
|
||||
"network_status": "approved_by_network",
|
||||
"reason": null,
|
||||
"risk_level": "normal",
|
||||
"risk_score": 37,
|
||||
"seller_message": "Payment complete.",
|
||||
"type": "authorized"
|
||||
},
|
||||
"paid": true,
|
||||
"payment_intent": "pi_3NvKgBIGBnsLynRr09Ny3Heu",
|
||||
"payment_method": "pm_1NvKbpIGBnsLynRrcOwez4A1",
|
||||
"payment_method_details": {
|
||||
"card": {
|
||||
"amount_authorized": 7200,
|
||||
"brand": "visa",
|
||||
"checks": {
|
||||
"address_line1_check": null,
|
||||
"address_postal_code_check": null,
|
||||
"cvc_check": "pass"
|
||||
},
|
||||
"country": "US",
|
||||
"exp_month": 6,
|
||||
"exp_year": 2033,
|
||||
"extended_authorization": {
|
||||
"status": "disabled"
|
||||
},
|
||||
"fingerprint": "0VgUBpvqcUUnuSmK",
|
||||
"funding": "credit",
|
||||
"incremental_authorization": {
|
||||
"status": "unavailable"
|
||||
},
|
||||
"installments": null,
|
||||
"last4": "4242",
|
||||
"mandate": null,
|
||||
"multicapture": {
|
||||
"status": "unavailable"
|
||||
},
|
||||
"network": "visa",
|
||||
"network_token": {
|
||||
"used": false
|
||||
},
|
||||
"overcapture": {
|
||||
"maximum_amount_capturable": 7200,
|
||||
"status": "unavailable"
|
||||
},
|
||||
"three_d_secure": null,
|
||||
"wallet": null
|
||||
},
|
||||
"type": "card"
|
||||
},
|
||||
"receipt_email": "cturnbull@bitwarden.com",
|
||||
"receipt_number": null,
|
||||
"receipt_url": "https://pay.stripe.com/receipts/invoices/CAcaFwoVYWNjdF8xOXNtSVhJR0Juc0x5blJyKLSL1qgGMgYTnk_JOUA6LBY_SDEZNtuae1guQ6Dlcuev1TUHwn712t-UNnZdIc383zS15bXv_1dby8e4?s=ap",
|
||||
"refunded": false,
|
||||
"refunds": {
|
||||
"object": "list",
|
||||
"data": [
|
||||
],
|
||||
"has_more": false,
|
||||
"total_count": 0,
|
||||
"url": "/v1/charges/ch_3NvKgBIGBnsLynRr0ZyvP9AN/refunds"
|
||||
},
|
||||
"review": null,
|
||||
"shipping": null,
|
||||
"source": null,
|
||||
"source_transfer": null,
|
||||
"statement_descriptor": null,
|
||||
"statement_descriptor_suffix": null,
|
||||
"status": "succeeded",
|
||||
"transfer_data": null,
|
||||
"transfer_group": null
|
||||
}
|
||||
},
|
||||
"livemode": false,
|
||||
"pending_webhooks": 9,
|
||||
"request": {
|
||||
"id": "req_rig8N5Ca8EXYRy",
|
||||
"idempotency_key": "db75068d-5d90-4c65-a410-4e2ed8347509"
|
||||
},
|
||||
"type": "charge.succeeded"
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
{
|
||||
"id": "evt_1NvLMDIGBnsLynRr6oBxebrE",
|
||||
"object": "event",
|
||||
"api_version": "2024-06-20",
|
||||
"created": 1695911902,
|
||||
"data": {
|
||||
"object": {
|
||||
"id": "sub_1NvKoKIGBnsLynRrcLIAUWGf",
|
||||
"object": "subscription",
|
||||
"application": null,
|
||||
"application_fee_percent": null,
|
||||
"automatic_tax": {
|
||||
"enabled": false
|
||||
},
|
||||
"billing_cycle_anchor": 1695911900,
|
||||
"billing_thresholds": null,
|
||||
"cancel_at": null,
|
||||
"cancel_at_period_end": false,
|
||||
"canceled_at": null,
|
||||
"cancellation_details": {
|
||||
"comment": null,
|
||||
"feedback": null,
|
||||
"reason": null
|
||||
},
|
||||
"collection_method": "charge_automatically",
|
||||
"created": 1695909804,
|
||||
"currency": "usd",
|
||||
"current_period_end": 1727534300,
|
||||
"current_period_start": 1695911900,
|
||||
"customer": "cus_OimNNCC3RiI2HQ",
|
||||
"days_until_due": null,
|
||||
"default_payment_method": null,
|
||||
"default_source": null,
|
||||
"default_tax_rates": [
|
||||
],
|
||||
"description": null,
|
||||
"discount": null,
|
||||
"ended_at": null,
|
||||
"items": {
|
||||
"object": "list",
|
||||
"data": [
|
||||
{
|
||||
"id": "si_OimNgVtrESpqus",
|
||||
"object": "subscription_item",
|
||||
"billing_thresholds": null,
|
||||
"created": 1695909805,
|
||||
"metadata": {
|
||||
},
|
||||
"plan": {
|
||||
"id": "enterprise-org-seat-annually",
|
||||
"object": "plan",
|
||||
"active": true,
|
||||
"aggregate_usage": null,
|
||||
"amount": 3600,
|
||||
"amount_decimal": "3600",
|
||||
"billing_scheme": "per_unit",
|
||||
"created": 1494268677,
|
||||
"currency": "usd",
|
||||
"interval": "year",
|
||||
"interval_count": 1,
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"nickname": "2019 Enterprise Seat (Annually)",
|
||||
"product": "prod_BUtogGemxnTi9z",
|
||||
"tiers_mode": null,
|
||||
"transform_usage": null,
|
||||
"trial_period_days": null,
|
||||
"usage_type": "licensed"
|
||||
},
|
||||
"price": {
|
||||
"id": "enterprise-org-seat-annually",
|
||||
"object": "price",
|
||||
"active": true,
|
||||
"billing_scheme": "per_unit",
|
||||
"created": 1494268677,
|
||||
"currency": "usd",
|
||||
"custom_unit_amount": null,
|
||||
"livemode": false,
|
||||
"lookup_key": null,
|
||||
"metadata": {
|
||||
},
|
||||
"nickname": "2019 Enterprise Seat (Annually)",
|
||||
"product": "prod_BUtogGemxnTi9z",
|
||||
"recurring": {
|
||||
"aggregate_usage": null,
|
||||
"interval": "year",
|
||||
"interval_count": 1,
|
||||
"trial_period_days": null,
|
||||
"usage_type": "licensed"
|
||||
},
|
||||
"tax_behavior": "unspecified",
|
||||
"tiers_mode": null,
|
||||
"transform_quantity": null,
|
||||
"type": "recurring",
|
||||
"unit_amount": 3600,
|
||||
"unit_amount_decimal": "3600"
|
||||
},
|
||||
"quantity": 1,
|
||||
"subscription": "sub_1NvKoKIGBnsLynRrcLIAUWGf",
|
||||
"tax_rates": [
|
||||
]
|
||||
}
|
||||
],
|
||||
"has_more": false,
|
||||
"total_count": 1,
|
||||
"url": "/v1/subscription_items?subscription=sub_1NvKoKIGBnsLynRrcLIAUWGf"
|
||||
},
|
||||
"latest_invoice": "in_1NvLM9IGBnsLynRrOysII07d",
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
"organizationId": "84a569ea-4643-474a-83a9-b08b00e7a20d"
|
||||
},
|
||||
"next_pending_invoice_item_invoice": null,
|
||||
"on_behalf_of": null,
|
||||
"pause_collection": null,
|
||||
"payment_settings": {
|
||||
"payment_method_options": null,
|
||||
"payment_method_types": null,
|
||||
"save_default_payment_method": "off"
|
||||
},
|
||||
"pending_invoice_item_interval": null,
|
||||
"pending_setup_intent": null,
|
||||
"pending_update": null,
|
||||
"plan": {
|
||||
"id": "enterprise-org-seat-annually",
|
||||
"object": "plan",
|
||||
"active": true,
|
||||
"aggregate_usage": null,
|
||||
"amount": 3600,
|
||||
"amount_decimal": "3600",
|
||||
"billing_scheme": "per_unit",
|
||||
"created": 1494268677,
|
||||
"currency": "usd",
|
||||
"interval": "year",
|
||||
"interval_count": 1,
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"nickname": "2019 Enterprise Seat (Annually)",
|
||||
"product": "prod_BUtogGemxnTi9z",
|
||||
"tiers_mode": null,
|
||||
"transform_usage": null,
|
||||
"trial_period_days": null,
|
||||
"usage_type": "licensed"
|
||||
},
|
||||
"quantity": 1,
|
||||
"schedule": null,
|
||||
"start_date": 1695909804,
|
||||
"status": "active",
|
||||
"test_clock": null,
|
||||
"transfer_data": null,
|
||||
"trial_end": 1695911899,
|
||||
"trial_settings": {
|
||||
"end_behavior": {
|
||||
"missing_payment_method": "create_invoice"
|
||||
}
|
||||
},
|
||||
"trial_start": 1695909804
|
||||
},
|
||||
"previous_attributes": {
|
||||
"billing_cycle_anchor": 1696514604,
|
||||
"current_period_end": 1696514604,
|
||||
"current_period_start": 1695909804,
|
||||
"latest_invoice": "in_1NvKoKIGBnsLynRrSNRC6oYI",
|
||||
"status": "trialing",
|
||||
"trial_end": 1696514604
|
||||
}
|
||||
},
|
||||
"livemode": false,
|
||||
"pending_webhooks": 8,
|
||||
"request": {
|
||||
"id": "req_DMZPUU3BI66zAx",
|
||||
"idempotency_key": "3fd8b4a5-6a20-46ab-9f45-b37b02a8017f"
|
||||
},
|
||||
"type": "customer.subscription.updated"
|
||||
}
|
||||
@@ -1,311 +0,0 @@
|
||||
{
|
||||
"id": "evt_1NvKjSIGBnsLynRrS3MTK4DZ",
|
||||
"object": "event",
|
||||
"account": "acct_19smIXIGBnsLynRr",
|
||||
"api_version": "2024-06-20",
|
||||
"created": 1695909502,
|
||||
"data": {
|
||||
"object": {
|
||||
"id": "cus_Of54kUr3gV88lM",
|
||||
"object": "customer",
|
||||
"address": {
|
||||
"city": null,
|
||||
"country": "US",
|
||||
"line1": "",
|
||||
"line2": null,
|
||||
"postal_code": "33701",
|
||||
"state": null
|
||||
},
|
||||
"balance": 0,
|
||||
"created": 1695056798,
|
||||
"currency": "usd",
|
||||
"default_source": "src_1NtAfeIGBnsLynRrYDrceax7",
|
||||
"delinquent": false,
|
||||
"description": "Premium User",
|
||||
"discount": null,
|
||||
"email": "premium@bitwarden.com",
|
||||
"invoice_prefix": "C506E8CE",
|
||||
"invoice_settings": {
|
||||
"custom_fields": [
|
||||
{
|
||||
"name": "Subscriber",
|
||||
"value": "Premium User"
|
||||
}
|
||||
],
|
||||
"default_payment_method": "pm_1Nrku9IGBnsLynRrcsQ3hy6C",
|
||||
"footer": null,
|
||||
"rendering_options": null
|
||||
},
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
"region": "US"
|
||||
},
|
||||
"name": null,
|
||||
"next_invoice_sequence": 2,
|
||||
"phone": null,
|
||||
"preferred_locales": [
|
||||
],
|
||||
"shipping": null,
|
||||
"tax_exempt": "none",
|
||||
"test_clock": null,
|
||||
"account_balance": 0,
|
||||
"cards": {
|
||||
"object": "list",
|
||||
"data": [
|
||||
],
|
||||
"has_more": false,
|
||||
"total_count": 0,
|
||||
"url": "/v1/customers/cus_Of54kUr3gV88lM/cards"
|
||||
},
|
||||
"default_card": null,
|
||||
"default_currency": "usd",
|
||||
"sources": {
|
||||
"object": "list",
|
||||
"data": [
|
||||
{
|
||||
"id": "src_1NtAfeIGBnsLynRrYDrceax7",
|
||||
"object": "source",
|
||||
"ach_credit_transfer": {
|
||||
"account_number": "test_b2d1c6415f6f",
|
||||
"routing_number": "110000000",
|
||||
"fingerprint": "ePO4hBQanSft3gvU",
|
||||
"swift_code": "TSTEZ122",
|
||||
"bank_name": "TEST BANK",
|
||||
"refund_routing_number": null,
|
||||
"refund_account_holder_type": null,
|
||||
"refund_account_holder_name": null
|
||||
},
|
||||
"amount": null,
|
||||
"client_secret": "src_client_secret_bUAP2uDRw6Pwj0xYk32LmJ3K",
|
||||
"created": 1695394170,
|
||||
"currency": "usd",
|
||||
"customer": "cus_Of54kUr3gV88lM",
|
||||
"flow": "receiver",
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"owner": {
|
||||
"address": null,
|
||||
"email": "amount_0@stripe.com",
|
||||
"name": null,
|
||||
"phone": null,
|
||||
"verified_address": null,
|
||||
"verified_email": null,
|
||||
"verified_name": null,
|
||||
"verified_phone": null
|
||||
},
|
||||
"receiver": {
|
||||
"address": "110000000-test_b2d1c6415f6f",
|
||||
"amount_charged": 0,
|
||||
"amount_received": 0,
|
||||
"amount_returned": 0,
|
||||
"refund_attributes_method": "email",
|
||||
"refund_attributes_status": "missing"
|
||||
},
|
||||
"statement_descriptor": null,
|
||||
"status": "pending",
|
||||
"type": "ach_credit_transfer",
|
||||
"usage": "reusable"
|
||||
}
|
||||
],
|
||||
"has_more": false,
|
||||
"total_count": 1,
|
||||
"url": "/v1/customers/cus_Of54kUr3gV88lM/sources"
|
||||
},
|
||||
"subscriptions": {
|
||||
"object": "list",
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_1NrkuBIGBnsLynRrzjFGIjEw",
|
||||
"object": "subscription",
|
||||
"application": null,
|
||||
"application_fee_percent": null,
|
||||
"automatic_tax": {
|
||||
"enabled": false
|
||||
},
|
||||
"billing": "charge_automatically",
|
||||
"billing_cycle_anchor": 1695056799,
|
||||
"billing_thresholds": null,
|
||||
"cancel_at": null,
|
||||
"cancel_at_period_end": false,
|
||||
"canceled_at": null,
|
||||
"cancellation_details": {
|
||||
"comment": null,
|
||||
"feedback": null,
|
||||
"reason": null
|
||||
},
|
||||
"collection_method": "charge_automatically",
|
||||
"created": 1695056799,
|
||||
"currency": "usd",
|
||||
"current_period_end": 1726679199,
|
||||
"current_period_start": 1695056799,
|
||||
"customer": "cus_Of54kUr3gV88lM",
|
||||
"days_until_due": null,
|
||||
"default_payment_method": null,
|
||||
"default_source": null,
|
||||
"default_tax_rates": [
|
||||
],
|
||||
"description": null,
|
||||
"discount": null,
|
||||
"ended_at": null,
|
||||
"invoice_customer_balance_settings": {
|
||||
"consume_applied_balance_on_void": true
|
||||
},
|
||||
"items": {
|
||||
"object": "list",
|
||||
"data": [
|
||||
{
|
||||
"id": "si_Of54i3aK9I5Wro",
|
||||
"object": "subscription_item",
|
||||
"billing_thresholds": null,
|
||||
"created": 1695056800,
|
||||
"metadata": {
|
||||
},
|
||||
"plan": {
|
||||
"id": "premium-annually",
|
||||
"object": "plan",
|
||||
"active": true,
|
||||
"aggregate_usage": null,
|
||||
"amount": 1000,
|
||||
"amount_decimal": "1000",
|
||||
"billing_scheme": "per_unit",
|
||||
"created": 1499289328,
|
||||
"currency": "usd",
|
||||
"interval": "year",
|
||||
"interval_count": 1,
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"name": "Premium (Annually)",
|
||||
"nickname": "Premium (Annually)",
|
||||
"product": "prod_BUqgYr48VzDuCg",
|
||||
"statement_description": null,
|
||||
"statement_descriptor": null,
|
||||
"tiers": null,
|
||||
"tiers_mode": null,
|
||||
"transform_usage": null,
|
||||
"trial_period_days": null,
|
||||
"usage_type": "licensed"
|
||||
},
|
||||
"price": {
|
||||
"id": "premium-annually",
|
||||
"object": "price",
|
||||
"active": true,
|
||||
"billing_scheme": "per_unit",
|
||||
"created": 1499289328,
|
||||
"currency": "usd",
|
||||
"custom_unit_amount": null,
|
||||
"livemode": false,
|
||||
"lookup_key": null,
|
||||
"metadata": {
|
||||
},
|
||||
"nickname": "Premium (Annually)",
|
||||
"product": "prod_BUqgYr48VzDuCg",
|
||||
"recurring": {
|
||||
"aggregate_usage": null,
|
||||
"interval": "year",
|
||||
"interval_count": 1,
|
||||
"trial_period_days": null,
|
||||
"usage_type": "licensed"
|
||||
},
|
||||
"tax_behavior": "unspecified",
|
||||
"tiers_mode": null,
|
||||
"transform_quantity": null,
|
||||
"type": "recurring",
|
||||
"unit_amount": 1000,
|
||||
"unit_amount_decimal": "1000"
|
||||
},
|
||||
"quantity": 1,
|
||||
"subscription": "sub_1NrkuBIGBnsLynRrzjFGIjEw",
|
||||
"tax_rates": [
|
||||
]
|
||||
}
|
||||
],
|
||||
"has_more": false,
|
||||
"total_count": 1,
|
||||
"url": "/v1/subscription_items?subscription=sub_1NrkuBIGBnsLynRrzjFGIjEw"
|
||||
},
|
||||
"latest_invoice": "in_1NrkuBIGBnsLynRr40gyJTVU",
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
"userId": "91f40b6d-ac3b-4348-804b-b0810119ac6a"
|
||||
},
|
||||
"next_pending_invoice_item_invoice": null,
|
||||
"on_behalf_of": null,
|
||||
"pause_collection": null,
|
||||
"payment_settings": {
|
||||
"payment_method_options": null,
|
||||
"payment_method_types": null,
|
||||
"save_default_payment_method": "off"
|
||||
},
|
||||
"pending_invoice_item_interval": null,
|
||||
"pending_setup_intent": null,
|
||||
"pending_update": null,
|
||||
"plan": {
|
||||
"id": "premium-annually",
|
||||
"object": "plan",
|
||||
"active": true,
|
||||
"aggregate_usage": null,
|
||||
"amount": 1000,
|
||||
"amount_decimal": "1000",
|
||||
"billing_scheme": "per_unit",
|
||||
"created": 1499289328,
|
||||
"currency": "usd",
|
||||
"interval": "year",
|
||||
"interval_count": 1,
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"name": "Premium (Annually)",
|
||||
"nickname": "Premium (Annually)",
|
||||
"product": "prod_BUqgYr48VzDuCg",
|
||||
"statement_description": null,
|
||||
"statement_descriptor": null,
|
||||
"tiers": null,
|
||||
"tiers_mode": null,
|
||||
"transform_usage": null,
|
||||
"trial_period_days": null,
|
||||
"usage_type": "licensed"
|
||||
},
|
||||
"quantity": 1,
|
||||
"schedule": null,
|
||||
"start": 1695056799,
|
||||
"start_date": 1695056799,
|
||||
"status": "active",
|
||||
"tax_percent": null,
|
||||
"test_clock": null,
|
||||
"transfer_data": null,
|
||||
"trial_end": null,
|
||||
"trial_settings": {
|
||||
"end_behavior": {
|
||||
"missing_payment_method": "create_invoice"
|
||||
}
|
||||
},
|
||||
"trial_start": null
|
||||
}
|
||||
],
|
||||
"has_more": false,
|
||||
"total_count": 1,
|
||||
"url": "/v1/customers/cus_Of54kUr3gV88lM/subscriptions"
|
||||
},
|
||||
"tax_ids": {
|
||||
"object": "list",
|
||||
"data": [
|
||||
],
|
||||
"has_more": false,
|
||||
"total_count": 0,
|
||||
"url": "/v1/customers/cus_Of54kUr3gV88lM/tax_ids"
|
||||
},
|
||||
"tax_info": null,
|
||||
"tax_info_verification": null
|
||||
},
|
||||
"previous_attributes": {
|
||||
"email": "premium-new@bitwarden.com"
|
||||
}
|
||||
},
|
||||
"livemode": false,
|
||||
"pending_webhooks": 5,
|
||||
"request": "req_2RtGdXCfiicFLx",
|
||||
"type": "customer.updated",
|
||||
"user_id": "acct_19smIXIGBnsLynRr"
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
{
|
||||
"id": "evt_1NvKzfIGBnsLynRr0SkwrlkE",
|
||||
"object": "event",
|
||||
"api_version": "2024-06-20",
|
||||
"created": 1695910506,
|
||||
"data": {
|
||||
"object": {
|
||||
"id": "in_1NvKzdIGBnsLynRr8fE8cpbg",
|
||||
"object": "invoice",
|
||||
"account_country": "US",
|
||||
"account_name": "Bitwarden Inc.",
|
||||
"account_tax_ids": null,
|
||||
"amount_due": 0,
|
||||
"amount_paid": 0,
|
||||
"amount_remaining": 0,
|
||||
"amount_shipping": 0,
|
||||
"application": null,
|
||||
"application_fee_amount": null,
|
||||
"attempt_count": 0,
|
||||
"attempted": true,
|
||||
"auto_advance": false,
|
||||
"automatic_tax": {
|
||||
"enabled": false,
|
||||
"status": null
|
||||
},
|
||||
"billing_reason": "subscription_create",
|
||||
"charge": null,
|
||||
"collection_method": "charge_automatically",
|
||||
"created": 1695910505,
|
||||
"currency": "usd",
|
||||
"custom_fields": [
|
||||
{
|
||||
"name": "Organization",
|
||||
"value": "teams 2023 monthly - 2"
|
||||
}
|
||||
],
|
||||
"customer": "cus_OimYrxnMTMMK1E",
|
||||
"customer_address": {
|
||||
"city": null,
|
||||
"country": "US",
|
||||
"line1": "",
|
||||
"line2": null,
|
||||
"postal_code": "12345",
|
||||
"state": null
|
||||
},
|
||||
"customer_email": "cturnbull@bitwarden.com",
|
||||
"customer_name": null,
|
||||
"customer_phone": null,
|
||||
"customer_shipping": null,
|
||||
"customer_tax_exempt": "none",
|
||||
"customer_tax_ids": [
|
||||
],
|
||||
"default_payment_method": null,
|
||||
"default_source": null,
|
||||
"default_tax_rates": [
|
||||
],
|
||||
"description": null,
|
||||
"discount": null,
|
||||
"discounts": [
|
||||
],
|
||||
"due_date": null,
|
||||
"effective_at": 1695910505,
|
||||
"ending_balance": 0,
|
||||
"footer": null,
|
||||
"from_invoice": null,
|
||||
"hosted_invoice_url": "https://invoice.stripe.com/i/acct_19smIXIGBnsLynRr/test_YWNjdF8xOXNtSVhJR0Juc0x5blJyLF9PaW1ZVlo4dFRtbkNQQVY5aHNpckQxN1QzRHBPcVBOLDg2NDUxMzA30200etYRHca2?s=ap",
|
||||
"invoice_pdf": "https://pay.stripe.com/invoice/acct_19smIXIGBnsLynRr/test_YWNjdF8xOXNtSVhJR0Juc0x5blJyLF9PaW1ZVlo4dFRtbkNQQVY5aHNpckQxN1QzRHBPcVBOLDg2NDUxMzA30200etYRHca2/pdf?s=ap",
|
||||
"last_finalization_error": null,
|
||||
"latest_revision": null,
|
||||
"lines": {
|
||||
"object": "list",
|
||||
"data": [
|
||||
{
|
||||
"id": "il_1NvKzdIGBnsLynRr2pS4ZA8e",
|
||||
"object": "line_item",
|
||||
"amount": 0,
|
||||
"amount_excluding_tax": 0,
|
||||
"currency": "usd",
|
||||
"description": "Trial period for Teams Organization Seat",
|
||||
"discount_amounts": [
|
||||
],
|
||||
"discountable": true,
|
||||
"discounts": [
|
||||
],
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
"organizationId": "3fbc84ce-102d-4919-b89b-b08b00ead71a"
|
||||
},
|
||||
"period": {
|
||||
"end": 1696515305,
|
||||
"start": 1695910505
|
||||
},
|
||||
"plan": {
|
||||
"id": "2020-teams-org-seat-monthly",
|
||||
"object": "plan",
|
||||
"active": true,
|
||||
"aggregate_usage": null,
|
||||
"amount": 400,
|
||||
"amount_decimal": "400",
|
||||
"billing_scheme": "per_unit",
|
||||
"created": 1595263113,
|
||||
"currency": "usd",
|
||||
"interval": "month",
|
||||
"interval_count": 1,
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"nickname": "Teams Organization Seat (Monthly) 2023",
|
||||
"product": "prod_HgOooYXDr2DDAA",
|
||||
"tiers_mode": null,
|
||||
"transform_usage": null,
|
||||
"trial_period_days": null,
|
||||
"usage_type": "licensed"
|
||||
},
|
||||
"price": {
|
||||
"id": "2020-teams-org-seat-monthly",
|
||||
"object": "price",
|
||||
"active": true,
|
||||
"billing_scheme": "per_unit",
|
||||
"created": 1595263113,
|
||||
"currency": "usd",
|
||||
"custom_unit_amount": null,
|
||||
"livemode": false,
|
||||
"lookup_key": null,
|
||||
"metadata": {
|
||||
},
|
||||
"nickname": "Teams Organization Seat (Monthly) 2023",
|
||||
"product": "prod_HgOooYXDr2DDAA",
|
||||
"recurring": {
|
||||
"aggregate_usage": null,
|
||||
"interval": "month",
|
||||
"interval_count": 1,
|
||||
"trial_period_days": null,
|
||||
"usage_type": "licensed"
|
||||
},
|
||||
"tax_behavior": "unspecified",
|
||||
"tiers_mode": null,
|
||||
"transform_quantity": null,
|
||||
"type": "recurring",
|
||||
"unit_amount": 400,
|
||||
"unit_amount_decimal": "400"
|
||||
},
|
||||
"proration": false,
|
||||
"proration_details": {
|
||||
"credited_items": null
|
||||
},
|
||||
"quantity": 1,
|
||||
"subscription": "sub_1NvKzdIGBnsLynRrKIHQamZc",
|
||||
"subscription_item": "si_OimYNSbvuqdtTr",
|
||||
"tax_amounts": [
|
||||
],
|
||||
"tax_rates": [
|
||||
],
|
||||
"type": "subscription",
|
||||
"unit_amount_excluding_tax": "0"
|
||||
}
|
||||
],
|
||||
"has_more": false,
|
||||
"total_count": 1,
|
||||
"url": "/v1/invoices/in_1NvKzdIGBnsLynRr8fE8cpbg/lines"
|
||||
},
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"next_payment_attempt": null,
|
||||
"number": "3E96D078-0001",
|
||||
"on_behalf_of": null,
|
||||
"paid": true,
|
||||
"paid_out_of_band": false,
|
||||
"payment_intent": null,
|
||||
"payment_settings": {
|
||||
"default_mandate": null,
|
||||
"payment_method_options": null,
|
||||
"payment_method_types": null
|
||||
},
|
||||
"period_end": 1695910505,
|
||||
"period_start": 1695910505,
|
||||
"post_payment_credit_notes_amount": 0,
|
||||
"pre_payment_credit_notes_amount": 0,
|
||||
"quote": null,
|
||||
"receipt_number": null,
|
||||
"rendering": null,
|
||||
"rendering_options": null,
|
||||
"shipping_cost": null,
|
||||
"shipping_details": null,
|
||||
"starting_balance": 0,
|
||||
"statement_descriptor": null,
|
||||
"status": "paid",
|
||||
"status_transitions": {
|
||||
"finalized_at": 1695910505,
|
||||
"marked_uncollectible_at": null,
|
||||
"paid_at": 1695910505,
|
||||
"voided_at": null
|
||||
},
|
||||
"subscription": "sub_1NvKzdIGBnsLynRrKIHQamZc",
|
||||
"subscription_details": {
|
||||
"metadata": {
|
||||
"organizationId": "3fbc84ce-102d-4919-b89b-b08b00ead71a"
|
||||
}
|
||||
},
|
||||
"subtotal": 0,
|
||||
"subtotal_excluding_tax": 0,
|
||||
"tax": null,
|
||||
"test_clock": null,
|
||||
"total": 0,
|
||||
"total_discount_amounts": [
|
||||
],
|
||||
"total_excluding_tax": 0,
|
||||
"total_tax_amounts": [
|
||||
],
|
||||
"transfer_data": null,
|
||||
"webhooks_delivered_at": null
|
||||
}
|
||||
},
|
||||
"livemode": false,
|
||||
"pending_webhooks": 8,
|
||||
"request": {
|
||||
"id": "req_roIwONfgyfZdr4",
|
||||
"idempotency_key": "dd2a171b-b9c7-4d2d-89d5-1ceae3c0595d"
|
||||
},
|
||||
"type": "invoice.created"
|
||||
}
|
||||
@@ -1,400 +0,0 @@
|
||||
{
|
||||
"id": "evt_1PQaABIGBnsLynRrhoJjGnyz",
|
||||
"object": "event",
|
||||
"account": "acct_19smIXIGBnsLynRr",
|
||||
"api_version": "2024-06-20",
|
||||
"created": 1718133319,
|
||||
"data": {
|
||||
"object": {
|
||||
"id": "in_1PQa9fIGBnsLynRraYIqTdBs",
|
||||
"object": "invoice",
|
||||
"account_country": "US",
|
||||
"account_name": "Bitwarden Inc.",
|
||||
"account_tax_ids": null,
|
||||
"amount_due": 84240,
|
||||
"amount_paid": 0,
|
||||
"amount_remaining": 84240,
|
||||
"amount_shipping": 0,
|
||||
"application": null,
|
||||
"attempt_count": 0,
|
||||
"attempted": false,
|
||||
"auto_advance": true,
|
||||
"automatic_tax": {
|
||||
"enabled": true,
|
||||
"liability": {
|
||||
"type": "self"
|
||||
},
|
||||
"status": "complete"
|
||||
},
|
||||
"billing_reason": "subscription_update",
|
||||
"charge": null,
|
||||
"collection_method": "send_invoice",
|
||||
"created": 1718133291,
|
||||
"currency": "usd",
|
||||
"custom_fields": [
|
||||
{
|
||||
"name": "Provider",
|
||||
"value": "MSP"
|
||||
}
|
||||
],
|
||||
"customer": "cus_QH8QVKyTh2lfcG",
|
||||
"customer_address": {
|
||||
"city": null,
|
||||
"country": "US",
|
||||
"line1": null,
|
||||
"line2": null,
|
||||
"postal_code": "12345",
|
||||
"state": null
|
||||
},
|
||||
"customer_email": "billing@msp.com",
|
||||
"customer_name": null,
|
||||
"customer_phone": null,
|
||||
"customer_shipping": null,
|
||||
"customer_tax_exempt": "none",
|
||||
"customer_tax_ids": [
|
||||
],
|
||||
"default_payment_method": null,
|
||||
"default_source": null,
|
||||
"default_tax_rates": [
|
||||
],
|
||||
"description": null,
|
||||
"discount": {
|
||||
"id": "di_1PQa9eIGBnsLynRrwwYr2bGD",
|
||||
"object": "discount",
|
||||
"checkout_session": null,
|
||||
"coupon": {
|
||||
"id": "msp-discount-35",
|
||||
"object": "coupon",
|
||||
"amount_off": null,
|
||||
"created": 1678805729,
|
||||
"currency": null,
|
||||
"duration": "forever",
|
||||
"duration_in_months": null,
|
||||
"livemode": false,
|
||||
"max_redemptions": null,
|
||||
"metadata": {
|
||||
},
|
||||
"name": "MSP Discount - 35%",
|
||||
"percent_off": 35,
|
||||
"redeem_by": null,
|
||||
"times_redeemed": 515,
|
||||
"valid": true,
|
||||
"percent_off_precise": 35
|
||||
},
|
||||
"customer": "cus_QH8QVKyTh2lfcG",
|
||||
"end": null,
|
||||
"invoice": null,
|
||||
"invoice_item": null,
|
||||
"promotion_code": null,
|
||||
"start": 1718133290,
|
||||
"subscription": null,
|
||||
"subscription_item": null
|
||||
},
|
||||
"discounts": [
|
||||
"di_1PQa9eIGBnsLynRrwwYr2bGD"
|
||||
],
|
||||
"due_date": 1720725291,
|
||||
"effective_at": 1718136893,
|
||||
"ending_balance": 0,
|
||||
"footer": null,
|
||||
"from_invoice": null,
|
||||
"hosted_invoice_url": "https://invoice.stripe.com/i/acct_19smIXIGBnsLynRr/test_YWNjdF8xOXNtSVhJR0Juc0x5blJyLF9RSDhRYVNIejNDMXBMVXAzM0M3S2RwaUt1Z3NuVHVzLDEwODY3NDEyMg0200RT8cC2nw?s=ap",
|
||||
"invoice_pdf": "https://pay.stripe.com/invoice/acct_19smIXIGBnsLynRr/test_YWNjdF8xOXNtSVhJR0Juc0x5blJyLF9RSDhRYVNIejNDMXBMVXAzM0M3S2RwaUt1Z3NuVHVzLDEwODY3NDEyMg0200RT8cC2nw/pdf?s=ap",
|
||||
"issuer": {
|
||||
"type": "self"
|
||||
},
|
||||
"last_finalization_error": null,
|
||||
"latest_revision": null,
|
||||
"lines": {
|
||||
"object": "list",
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_1PQa9fIGBnsLynRr83lNrFHa",
|
||||
"object": "line_item",
|
||||
"amount": 50000,
|
||||
"amount_excluding_tax": 50000,
|
||||
"currency": "usd",
|
||||
"description": null,
|
||||
"discount_amounts": [
|
||||
{
|
||||
"amount": 17500,
|
||||
"discount": "di_1PQa9eIGBnsLynRrwwYr2bGD"
|
||||
}
|
||||
],
|
||||
"discountable": true,
|
||||
"discounts": [
|
||||
],
|
||||
"invoice": "in_1PQa9fIGBnsLynRraYIqTdBs",
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"period": {
|
||||
"end": 1720725291,
|
||||
"start": 1718133291
|
||||
},
|
||||
"plan": {
|
||||
"id": "2023-teams-org-seat-monthly",
|
||||
"object": "plan",
|
||||
"active": true,
|
||||
"aggregate_usage": null,
|
||||
"amount": 500,
|
||||
"amount_decimal": "500",
|
||||
"billing_scheme": "per_unit",
|
||||
"created": 1695839010,
|
||||
"currency": "usd",
|
||||
"interval": "month",
|
||||
"interval_count": 1,
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"meter": null,
|
||||
"nickname": "Teams Organization Seat (Monthly)",
|
||||
"product": "prod_HgOooYXDr2DDAA",
|
||||
"tiers_mode": null,
|
||||
"transform_usage": null,
|
||||
"trial_period_days": null,
|
||||
"usage_type": "licensed",
|
||||
"name": "Password Manager - Teams Plan",
|
||||
"statement_description": null,
|
||||
"statement_descriptor": null,
|
||||
"tiers": null
|
||||
},
|
||||
"price": {
|
||||
"id": "2023-teams-org-seat-monthly",
|
||||
"object": "price",
|
||||
"active": true,
|
||||
"billing_scheme": "per_unit",
|
||||
"created": 1695839010,
|
||||
"currency": "usd",
|
||||
"custom_unit_amount": null,
|
||||
"livemode": false,
|
||||
"lookup_key": null,
|
||||
"metadata": {
|
||||
},
|
||||
"nickname": "Teams Organization Seat (Monthly)",
|
||||
"product": "prod_HgOooYXDr2DDAA",
|
||||
"recurring": {
|
||||
"aggregate_usage": null,
|
||||
"interval": "month",
|
||||
"interval_count": 1,
|
||||
"meter": null,
|
||||
"trial_period_days": null,
|
||||
"usage_type": "licensed"
|
||||
},
|
||||
"tax_behavior": "exclusive",
|
||||
"tiers_mode": null,
|
||||
"transform_quantity": null,
|
||||
"type": "recurring",
|
||||
"unit_amount": 500,
|
||||
"unit_amount_decimal": "500"
|
||||
},
|
||||
"proration": false,
|
||||
"proration_details": {
|
||||
"credited_items": null
|
||||
},
|
||||
"quantity": 100,
|
||||
"subscription": null,
|
||||
"subscription_item": "si_QH8Qo4WEJxOVwx",
|
||||
"tax_amounts": [
|
||||
{
|
||||
"amount": 2600,
|
||||
"inclusive": false,
|
||||
"tax_rate": "txr_1OZyBuIGBnsLynRrX0PJLuMC",
|
||||
"taxability_reason": "standard_rated",
|
||||
"taxable_amount": 32500
|
||||
}
|
||||
],
|
||||
"tax_rates": [
|
||||
],
|
||||
"type": "subscription",
|
||||
"unit_amount_excluding_tax": "500",
|
||||
"unique_id": "il_1PQa9fIGBnsLynRrSJ3cxrdU",
|
||||
"unique_line_item_id": "sli_1acb3eIGBnsLynRr4b9c2f48"
|
||||
},
|
||||
{
|
||||
"id": "sub_1PQa9fIGBnsLynRr83lNrFHa",
|
||||
"object": "line_item",
|
||||
"amount": 70000,
|
||||
"amount_excluding_tax": 70000,
|
||||
"currency": "usd",
|
||||
"description": null,
|
||||
"discount_amounts": [
|
||||
{
|
||||
"amount": 24500,
|
||||
"discount": "di_1PQa9eIGBnsLynRrwwYr2bGD"
|
||||
}
|
||||
],
|
||||
"discountable": true,
|
||||
"discounts": [
|
||||
],
|
||||
"invoice": "in_1PQa9fIGBnsLynRraYIqTdBs",
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"period": {
|
||||
"end": 1720725291,
|
||||
"start": 1718133291
|
||||
},
|
||||
"plan": {
|
||||
"id": "2023-enterprise-seat-monthly",
|
||||
"object": "plan",
|
||||
"active": true,
|
||||
"aggregate_usage": null,
|
||||
"amount": 700,
|
||||
"amount_decimal": "700",
|
||||
"billing_scheme": "per_unit",
|
||||
"created": 1695152194,
|
||||
"currency": "usd",
|
||||
"interval": "month",
|
||||
"interval_count": 1,
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"meter": null,
|
||||
"nickname": "Enterprise Organization (Monthly)",
|
||||
"product": "prod_HgSOgzUlYDFOzf",
|
||||
"tiers_mode": null,
|
||||
"transform_usage": null,
|
||||
"trial_period_days": null,
|
||||
"usage_type": "licensed",
|
||||
"name": "Password Manager - Enterprise Plan",
|
||||
"statement_description": null,
|
||||
"statement_descriptor": null,
|
||||
"tiers": null
|
||||
},
|
||||
"price": {
|
||||
"id": "2023-enterprise-seat-monthly",
|
||||
"object": "price",
|
||||
"active": true,
|
||||
"billing_scheme": "per_unit",
|
||||
"created": 1695152194,
|
||||
"currency": "usd",
|
||||
"custom_unit_amount": null,
|
||||
"livemode": false,
|
||||
"lookup_key": null,
|
||||
"metadata": {
|
||||
},
|
||||
"nickname": "Enterprise Organization (Monthly)",
|
||||
"product": "prod_HgSOgzUlYDFOzf",
|
||||
"recurring": {
|
||||
"aggregate_usage": null,
|
||||
"interval": "month",
|
||||
"interval_count": 1,
|
||||
"meter": null,
|
||||
"trial_period_days": null,
|
||||
"usage_type": "licensed"
|
||||
},
|
||||
"tax_behavior": "exclusive",
|
||||
"tiers_mode": null,
|
||||
"transform_quantity": null,
|
||||
"type": "recurring",
|
||||
"unit_amount": 700,
|
||||
"unit_amount_decimal": "700"
|
||||
},
|
||||
"proration": false,
|
||||
"proration_details": {
|
||||
"credited_items": null
|
||||
},
|
||||
"quantity": 100,
|
||||
"subscription": null,
|
||||
"subscription_item": "si_QH8QUjtceXvcis",
|
||||
"tax_amounts": [
|
||||
{
|
||||
"amount": 3640,
|
||||
"inclusive": false,
|
||||
"tax_rate": "txr_1OZyBuIGBnsLynRrX0PJLuMC",
|
||||
"taxability_reason": "standard_rated",
|
||||
"taxable_amount": 45500
|
||||
}
|
||||
],
|
||||
"tax_rates": [
|
||||
],
|
||||
"type": "subscription",
|
||||
"unit_amount_excluding_tax": "700",
|
||||
"unique_id": "il_1PQa9fIGBnsLynRrVviet37m",
|
||||
"unique_line_item_id": "sli_11b229IGBnsLynRr837b79d0"
|
||||
}
|
||||
],
|
||||
"has_more": false,
|
||||
"total_count": 2,
|
||||
"url": "/v1/invoices/in_1PQa9fIGBnsLynRraYIqTdBs/lines"
|
||||
},
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"next_payment_attempt": null,
|
||||
"number": "525EB050-0001",
|
||||
"on_behalf_of": null,
|
||||
"paid": false,
|
||||
"paid_out_of_band": false,
|
||||
"payment_intent": "pi_3PQaA7IGBnsLynRr1swr9XJE",
|
||||
"payment_settings": {
|
||||
"default_mandate": null,
|
||||
"payment_method_options": null,
|
||||
"payment_method_types": null
|
||||
},
|
||||
"period_end": 1718133291,
|
||||
"period_start": 1718133291,
|
||||
"post_payment_credit_notes_amount": 0,
|
||||
"pre_payment_credit_notes_amount": 0,
|
||||
"quote": null,
|
||||
"receipt_number": null,
|
||||
"rendering": null,
|
||||
"rendering_options": null,
|
||||
"shipping_cost": null,
|
||||
"shipping_details": null,
|
||||
"starting_balance": 0,
|
||||
"statement_descriptor": null,
|
||||
"status": "open",
|
||||
"status_transitions": {
|
||||
"finalized_at": 1718136893,
|
||||
"marked_uncollectible_at": null,
|
||||
"paid_at": null,
|
||||
"voided_at": null
|
||||
},
|
||||
"subscription": "sub_1PQa9fIGBnsLynRr83lNrFHa",
|
||||
"subscription_details": {
|
||||
"metadata": {
|
||||
"providerId": "655bc5a3-2332-4201-a9a6-b18c013d0572"
|
||||
}
|
||||
},
|
||||
"subtotal": 120000,
|
||||
"subtotal_excluding_tax": 120000,
|
||||
"tax": 6240,
|
||||
"test_clock": "clock_1PQaA4IGBnsLynRrptkZjgxc",
|
||||
"total": 84240,
|
||||
"total_discount_amounts": [
|
||||
{
|
||||
"amount": 42000,
|
||||
"discount": "di_1PQa9eIGBnsLynRrwwYr2bGD"
|
||||
}
|
||||
],
|
||||
"total_excluding_tax": 78000,
|
||||
"total_tax_amounts": [
|
||||
{
|
||||
"amount": 6240,
|
||||
"inclusive": false,
|
||||
"tax_rate": "txr_1OZyBuIGBnsLynRrX0PJLuMC",
|
||||
"taxability_reason": "standard_rated",
|
||||
"taxable_amount": 78000
|
||||
}
|
||||
],
|
||||
"transfer_data": null,
|
||||
"webhooks_delivered_at": 1718133293,
|
||||
"application_fee": null,
|
||||
"billing": "send_invoice",
|
||||
"closed": false,
|
||||
"date": 1718133291,
|
||||
"finalized_at": 1718136893,
|
||||
"forgiven": false,
|
||||
"payment": null,
|
||||
"statement_description": null,
|
||||
"tax_percent": 8
|
||||
}
|
||||
},
|
||||
"livemode": false,
|
||||
"pending_webhooks": 5,
|
||||
"request": null,
|
||||
"type": "invoice.finalized",
|
||||
"user_id": "acct_19smIXIGBnsLynRr"
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
{
|
||||
"id": "evt_1Nv0w8IGBnsLynRrZoDVI44u",
|
||||
"object": "event",
|
||||
"api_version": "2024-06-20",
|
||||
"created": 1695833408,
|
||||
"data": {
|
||||
"object": {
|
||||
"object": "invoice",
|
||||
"account_country": "US",
|
||||
"account_name": "Bitwarden Inc.",
|
||||
"account_tax_ids": null,
|
||||
"amount_due": 0,
|
||||
"amount_paid": 0,
|
||||
"amount_remaining": 0,
|
||||
"amount_shipping": 0,
|
||||
"application": null,
|
||||
"application_fee_amount": null,
|
||||
"attempt_count": 0,
|
||||
"attempted": false,
|
||||
"automatic_tax": {
|
||||
"enabled": true,
|
||||
"status": "complete"
|
||||
},
|
||||
"billing_reason": "upcoming",
|
||||
"charge": null,
|
||||
"collection_method": "charge_automatically",
|
||||
"created": 1697128681,
|
||||
"currency": "usd",
|
||||
"custom_fields": null,
|
||||
"customer": "cus_M8DV9wiyNa2JxQ",
|
||||
"customer_address": {
|
||||
"city": null,
|
||||
"country": "US",
|
||||
"line1": "",
|
||||
"line2": null,
|
||||
"postal_code": "90019",
|
||||
"state": null
|
||||
},
|
||||
"customer_email": "vphan@bitwarden.com",
|
||||
"customer_name": null,
|
||||
"customer_phone": null,
|
||||
"customer_shipping": null,
|
||||
"customer_tax_exempt": "none",
|
||||
"customer_tax_ids": [
|
||||
],
|
||||
"default_payment_method": null,
|
||||
"default_source": null,
|
||||
"default_tax_rates": [
|
||||
],
|
||||
"description": null,
|
||||
"discount": null,
|
||||
"discounts": [
|
||||
],
|
||||
"due_date": null,
|
||||
"effective_at": null,
|
||||
"ending_balance": -6779,
|
||||
"footer": null,
|
||||
"from_invoice": null,
|
||||
"last_finalization_error": null,
|
||||
"latest_revision": null,
|
||||
"lines": {
|
||||
"object": "list",
|
||||
"data": [
|
||||
{
|
||||
"id": "il_tmp_12b5e8IGBnsLynRr1996ac3a",
|
||||
"object": "line_item",
|
||||
"amount": 2000,
|
||||
"amount_excluding_tax": 2000,
|
||||
"currency": "usd",
|
||||
"description": "5 × 2019 Enterprise Seat (Monthly) (at $4.00 / month)",
|
||||
"discount_amounts": [
|
||||
],
|
||||
"discountable": true,
|
||||
"discounts": [
|
||||
],
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"period": {
|
||||
"end": 1699807081,
|
||||
"start": 1697128681
|
||||
},
|
||||
"plan": {
|
||||
"id": "enterprise-org-seat-monthly",
|
||||
"object": "plan",
|
||||
"active": true,
|
||||
"aggregate_usage": null,
|
||||
"amount": 400,
|
||||
"amount_decimal": "400",
|
||||
"billing_scheme": "per_unit",
|
||||
"created": 1494268635,
|
||||
"currency": "usd",
|
||||
"interval": "month",
|
||||
"interval_count": 1,
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"nickname": "2019 Enterprise Seat (Monthly)",
|
||||
"product": "prod_BVButYytPSlgs6",
|
||||
"tiers_mode": null,
|
||||
"transform_usage": null,
|
||||
"trial_period_days": null,
|
||||
"usage_type": "licensed"
|
||||
},
|
||||
"price": {
|
||||
"id": "enterprise-org-seat-monthly",
|
||||
"object": "price",
|
||||
"active": true,
|
||||
"billing_scheme": "per_unit",
|
||||
"created": 1494268635,
|
||||
"currency": "usd",
|
||||
"custom_unit_amount": null,
|
||||
"livemode": false,
|
||||
"lookup_key": null,
|
||||
"metadata": {
|
||||
},
|
||||
"nickname": "2019 Enterprise Seat (Monthly)",
|
||||
"product": "prod_BVButYytPSlgs6",
|
||||
"recurring": {
|
||||
"aggregate_usage": null,
|
||||
"interval": "month",
|
||||
"interval_count": 1,
|
||||
"trial_period_days": null,
|
||||
"usage_type": "licensed"
|
||||
},
|
||||
"tax_behavior": "unspecified",
|
||||
"tiers_mode": null,
|
||||
"transform_quantity": null,
|
||||
"type": "recurring",
|
||||
"unit_amount": 400,
|
||||
"unit_amount_decimal": "400"
|
||||
},
|
||||
"proration": false,
|
||||
"proration_details": {
|
||||
"credited_items": null
|
||||
},
|
||||
"quantity": 5,
|
||||
"subscription": "sub_1NQxz4IGBnsLynRr1KbitG7v",
|
||||
"subscription_item": "si_ODOmLnPDHBuMxX",
|
||||
"tax_amounts": [
|
||||
{
|
||||
"amount": 0,
|
||||
"inclusive": false,
|
||||
"tax_rate": "txr_1N6XCyIGBnsLynRr0LHs4AUD",
|
||||
"taxability_reason": "product_exempt",
|
||||
"taxable_amount": 0
|
||||
}
|
||||
],
|
||||
"tax_rates": [
|
||||
],
|
||||
"type": "subscription",
|
||||
"unit_amount_excluding_tax": "400"
|
||||
}
|
||||
],
|
||||
"has_more": false,
|
||||
"total_count": 1,
|
||||
"url": "/v1/invoices/upcoming/lines?customer=cus_M8DV9wiyNa2JxQ&subscription=sub_1NQxz4IGBnsLynRr1KbitG7v"
|
||||
},
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"next_payment_attempt": 1697132281,
|
||||
"number": null,
|
||||
"on_behalf_of": null,
|
||||
"paid": false,
|
||||
"paid_out_of_band": false,
|
||||
"payment_intent": null,
|
||||
"payment_settings": {
|
||||
"default_mandate": null,
|
||||
"payment_method_options": null,
|
||||
"payment_method_types": null
|
||||
},
|
||||
"period_end": 1697128681,
|
||||
"period_start": 1694536681,
|
||||
"post_payment_credit_notes_amount": 0,
|
||||
"pre_payment_credit_notes_amount": 0,
|
||||
"quote": null,
|
||||
"receipt_number": null,
|
||||
"rendering": null,
|
||||
"rendering_options": null,
|
||||
"shipping_cost": null,
|
||||
"shipping_details": null,
|
||||
"starting_balance": -8779,
|
||||
"statement_descriptor": null,
|
||||
"status": "draft",
|
||||
"status_transitions": {
|
||||
"finalized_at": null,
|
||||
"marked_uncollectible_at": null,
|
||||
"paid_at": null,
|
||||
"voided_at": null
|
||||
},
|
||||
"subscription": "sub_1NQxz4IGBnsLynRr1KbitG7v",
|
||||
"subscription_details": {
|
||||
"metadata": {
|
||||
}
|
||||
},
|
||||
"subtotal": 2000,
|
||||
"subtotal_excluding_tax": 2000,
|
||||
"tax": 0,
|
||||
"test_clock": null,
|
||||
"total": 2000,
|
||||
"total_discount_amounts": [
|
||||
],
|
||||
"total_excluding_tax": 2000,
|
||||
"total_tax_amounts": [
|
||||
{
|
||||
"amount": 0,
|
||||
"inclusive": false,
|
||||
"tax_rate": "txr_1N6XCyIGBnsLynRr0LHs4AUD",
|
||||
"taxability_reason": "product_exempt",
|
||||
"taxable_amount": 0
|
||||
}
|
||||
],
|
||||
"transfer_data": null,
|
||||
"webhooks_delivered_at": null
|
||||
}
|
||||
},
|
||||
"livemode": false,
|
||||
"pending_webhooks": 5,
|
||||
"request": {
|
||||
"id": null,
|
||||
"idempotency_key": null
|
||||
},
|
||||
"type": "invoice.upcoming"
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
{
|
||||
"id": "evt_1NvKzcIGBnsLynRrPJ3hybkd",
|
||||
"object": "event",
|
||||
"api_version": "2024-06-20",
|
||||
"created": 1695910504,
|
||||
"data": {
|
||||
"object": {
|
||||
"id": "pm_1NvKzbIGBnsLynRry6x7Buvc",
|
||||
"object": "payment_method",
|
||||
"billing_details": {
|
||||
"address": {
|
||||
"city": null,
|
||||
"country": null,
|
||||
"line1": null,
|
||||
"line2": null,
|
||||
"postal_code": null,
|
||||
"state": null
|
||||
},
|
||||
"email": null,
|
||||
"name": null,
|
||||
"phone": null
|
||||
},
|
||||
"card": {
|
||||
"brand": "visa",
|
||||
"checks": {
|
||||
"address_line1_check": null,
|
||||
"address_postal_code_check": null,
|
||||
"cvc_check": "pass"
|
||||
},
|
||||
"country": "US",
|
||||
"exp_month": 6,
|
||||
"exp_year": 2033,
|
||||
"fingerprint": "0VgUBpvqcUUnuSmK",
|
||||
"funding": "credit",
|
||||
"generated_from": null,
|
||||
"last4": "4242",
|
||||
"networks": {
|
||||
"available": [
|
||||
"visa"
|
||||
],
|
||||
"preferred": null
|
||||
},
|
||||
"three_d_secure_usage": {
|
||||
"supported": true
|
||||
},
|
||||
"wallet": null
|
||||
},
|
||||
"created": 1695910503,
|
||||
"customer": "cus_OimYrxnMTMMK1E",
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
},
|
||||
"livemode": false,
|
||||
"pending_webhooks": 7,
|
||||
"request": {
|
||||
"id": "req_2WslNSBD9wAV5v",
|
||||
"idempotency_key": "db1a648a-3445-47b3-a403-9f3d1303a880"
|
||||
},
|
||||
"type": "payment_method.attached"
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using Bit.Billing.Services;
|
||||
using Bit.Billing.Services.Implementations;
|
||||
using Bit.Billing.Test.Utilities;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Data.Provider;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
@@ -59,29 +58,69 @@ public class ProviderEventServiceTests
|
||||
public async Task TryRecordInvoiceLineItems_EventTypeNotInvoiceCreatedOrInvoiceFinalized_NoOp()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.PaymentMethodAttached);
|
||||
var stripeEvent = new Event { Type = "payment_method.attached" };
|
||||
|
||||
// Act
|
||||
await _providerEventService.TryRecordInvoiceLineItems(stripeEvent);
|
||||
|
||||
// Assert
|
||||
await _stripeEventService.DidNotReceiveWithAnyArgs().GetInvoice(Arg.Any<Event>());
|
||||
await _stripeEventService.DidNotReceiveWithAnyArgs().GetInvoice(Arg.Any<Event>(), Arg.Any<bool>(), Arg.Any<List<string>?>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TryRecordInvoiceLineItems_InvoiceParentTypeNotSubscriptionDetails_NoOp()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = new Event
|
||||
{
|
||||
Type = "invoice.created"
|
||||
};
|
||||
|
||||
var invoice = new Invoice
|
||||
{
|
||||
Parent = new InvoiceParent
|
||||
{
|
||||
Type = "credit_note",
|
||||
SubscriptionDetails = new InvoiceParentSubscriptionDetails
|
||||
{
|
||||
SubscriptionId = "sub_1"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_stripeEventService.GetInvoice(stripeEvent, true, Arg.Any<List<string>?>()).Returns(invoice);
|
||||
|
||||
// Act
|
||||
await _providerEventService.TryRecordInvoiceLineItems(stripeEvent);
|
||||
|
||||
// Assert
|
||||
await _stripeFacade.DidNotReceiveWithAnyArgs().GetSubscription(Arg.Any<string>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TryRecordInvoiceLineItems_EventNotProviderRelated_NoOp()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.InvoiceCreated);
|
||||
var stripeEvent = new Event
|
||||
{
|
||||
Type = "invoice.created"
|
||||
};
|
||||
|
||||
const string subscriptionId = "sub_1";
|
||||
|
||||
var invoice = new Invoice
|
||||
{
|
||||
SubscriptionId = subscriptionId
|
||||
Parent = new InvoiceParent
|
||||
{
|
||||
Type = "subscription_details",
|
||||
SubscriptionDetails = new InvoiceParentSubscriptionDetails
|
||||
{
|
||||
SubscriptionId = subscriptionId
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_stripeEventService.GetInvoice(stripeEvent).Returns(invoice);
|
||||
_stripeEventService.GetInvoice(stripeEvent, true, Arg.Any<List<string>?>()).Returns(invoice);
|
||||
|
||||
var subscription = new Subscription
|
||||
{
|
||||
@@ -101,7 +140,10 @@ public class ProviderEventServiceTests
|
||||
public async Task TryRecordInvoiceLineItems_InvoiceCreated_Succeeds()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.InvoiceCreated);
|
||||
var stripeEvent = new Event
|
||||
{
|
||||
Type = "invoice.created"
|
||||
};
|
||||
|
||||
const string subscriptionId = "sub_1";
|
||||
var providerId = Guid.NewGuid();
|
||||
@@ -110,17 +152,26 @@ public class ProviderEventServiceTests
|
||||
{
|
||||
Id = "invoice_1",
|
||||
Number = "A",
|
||||
SubscriptionId = subscriptionId,
|
||||
Discount = new Discount
|
||||
Parent = new InvoiceParent
|
||||
{
|
||||
Coupon = new Coupon
|
||||
Type = "subscription_details",
|
||||
SubscriptionDetails = new InvoiceParentSubscriptionDetails
|
||||
{
|
||||
PercentOff = 35
|
||||
SubscriptionId = subscriptionId
|
||||
}
|
||||
}
|
||||
},
|
||||
Discounts = [
|
||||
new Discount
|
||||
{
|
||||
Coupon = new Coupon
|
||||
{
|
||||
PercentOff = 35
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
_stripeEventService.GetInvoice(stripeEvent).Returns(invoice);
|
||||
_stripeEventService.GetInvoice(stripeEvent, true, Arg.Any<List<string>?>()).Returns(invoice);
|
||||
|
||||
var subscription = new Subscription
|
||||
{
|
||||
@@ -249,7 +300,10 @@ public class ProviderEventServiceTests
|
||||
public async Task TryRecordInvoiceLineItems_InvoiceFinalized_Succeeds()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.InvoiceFinalized);
|
||||
var stripeEvent = new Event
|
||||
{
|
||||
Type = "invoice.finalized"
|
||||
};
|
||||
|
||||
const string subscriptionId = "sub_1";
|
||||
var providerId = Guid.NewGuid();
|
||||
@@ -258,10 +312,17 @@ public class ProviderEventServiceTests
|
||||
{
|
||||
Id = "invoice_1",
|
||||
Number = "A",
|
||||
SubscriptionId = subscriptionId
|
||||
Parent = new InvoiceParent
|
||||
{
|
||||
Type = "subscription_details",
|
||||
SubscriptionDetails = new InvoiceParentSubscriptionDetails
|
||||
{
|
||||
SubscriptionId = subscriptionId
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
_stripeEventService.GetInvoice(stripeEvent).Returns(invoice);
|
||||
_stripeEventService.GetInvoice(stripeEvent, true, Arg.Any<List<string>?>()).Returns(invoice);
|
||||
|
||||
var subscription = new Subscription
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Bit.Billing.Services;
|
||||
using Bit.Billing.Services.Implementations;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces;
|
||||
using Bit.Core.Billing.Extensions;
|
||||
using Bit.Core.Services;
|
||||
using NSubstitute;
|
||||
using Stripe;
|
||||
@@ -38,7 +39,13 @@ public class SubscriptionDeletedHandlerTests
|
||||
var subscription = new Subscription
|
||||
{
|
||||
Status = "active",
|
||||
CurrentPeriodEnd = DateTime.UtcNow.AddDays(30),
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = DateTime.UtcNow.AddDays(30) }
|
||||
]
|
||||
},
|
||||
Metadata = new Dictionary<string, string>()
|
||||
};
|
||||
|
||||
@@ -63,11 +70,14 @@ public class SubscriptionDeletedHandlerTests
|
||||
var subscription = new Subscription
|
||||
{
|
||||
Status = StripeSubscriptionStatus.Canceled,
|
||||
CurrentPeriodEnd = DateTime.UtcNow.AddDays(30),
|
||||
Metadata = new Dictionary<string, string>
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
{ "organizationId", organizationId.ToString() }
|
||||
}
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = DateTime.UtcNow.AddDays(30) }
|
||||
]
|
||||
},
|
||||
Metadata = new Dictionary<string, string> { { "organizationId", organizationId.ToString() } }
|
||||
};
|
||||
|
||||
_stripeEventService.GetSubscription(stripeEvent, true).Returns(subscription);
|
||||
@@ -79,7 +89,7 @@ public class SubscriptionDeletedHandlerTests
|
||||
|
||||
// Assert
|
||||
await _organizationDisableCommand.Received(1)
|
||||
.DisableAsync(organizationId, subscription.CurrentPeriodEnd);
|
||||
.DisableAsync(organizationId, subscription.GetCurrentPeriodEnd());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -91,11 +101,14 @@ public class SubscriptionDeletedHandlerTests
|
||||
var subscription = new Subscription
|
||||
{
|
||||
Status = StripeSubscriptionStatus.Canceled,
|
||||
CurrentPeriodEnd = DateTime.UtcNow.AddDays(30),
|
||||
Metadata = new Dictionary<string, string>
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
{ "userId", userId.ToString() }
|
||||
}
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = DateTime.UtcNow.AddDays(30) }
|
||||
]
|
||||
},
|
||||
Metadata = new Dictionary<string, string> { { "userId", userId.ToString() } }
|
||||
};
|
||||
|
||||
_stripeEventService.GetSubscription(stripeEvent, true).Returns(subscription);
|
||||
@@ -107,7 +120,7 @@ public class SubscriptionDeletedHandlerTests
|
||||
|
||||
// Assert
|
||||
await _userService.Received(1)
|
||||
.DisablePremiumAsync(userId, subscription.CurrentPeriodEnd);
|
||||
.DisablePremiumAsync(userId, subscription.GetCurrentPeriodEnd());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -119,11 +132,14 @@ public class SubscriptionDeletedHandlerTests
|
||||
var subscription = new Subscription
|
||||
{
|
||||
Status = StripeSubscriptionStatus.Canceled,
|
||||
CurrentPeriodEnd = DateTime.UtcNow.AddDays(30),
|
||||
Metadata = new Dictionary<string, string>
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
{ "organizationId", organizationId.ToString() }
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = DateTime.UtcNow.AddDays(30) }
|
||||
]
|
||||
},
|
||||
Metadata = new Dictionary<string, string> { { "organizationId", organizationId.ToString() } },
|
||||
CancellationDetails = new SubscriptionCancellationDetails
|
||||
{
|
||||
Comment = "Cancelled as part of provider migration to Consolidated Billing"
|
||||
@@ -151,11 +167,14 @@ public class SubscriptionDeletedHandlerTests
|
||||
var subscription = new Subscription
|
||||
{
|
||||
Status = StripeSubscriptionStatus.Canceled,
|
||||
CurrentPeriodEnd = DateTime.UtcNow.AddDays(30),
|
||||
Metadata = new Dictionary<string, string>
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
{ "organizationId", organizationId.ToString() }
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = DateTime.UtcNow.AddDays(30) }
|
||||
]
|
||||
},
|
||||
Metadata = new Dictionary<string, string> { { "organizationId", organizationId.ToString() } },
|
||||
CancellationDetails = new SubscriptionCancellationDetails
|
||||
{
|
||||
Comment = "Organization was added to Provider"
|
||||
|
||||
@@ -96,7 +96,13 @@ public class SubscriptionUpdatedHandlerTests
|
||||
{
|
||||
Id = subscriptionId,
|
||||
Status = StripeSubscriptionStatus.Unpaid,
|
||||
CurrentPeriodEnd = currentPeriodEnd,
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = currentPeriodEnd }
|
||||
]
|
||||
},
|
||||
Metadata = new Dictionary<string, string> { { "organizationId", organizationId.ToString() } },
|
||||
LatestInvoice = new Invoice { BillingReason = "subscription_cycle" }
|
||||
};
|
||||
@@ -142,7 +148,13 @@ public class SubscriptionUpdatedHandlerTests
|
||||
{
|
||||
Id = subscriptionId,
|
||||
Status = StripeSubscriptionStatus.Unpaid,
|
||||
CurrentPeriodEnd = DateTime.UtcNow.AddDays(30),
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = DateTime.UtcNow.AddDays(30) }
|
||||
]
|
||||
},
|
||||
Metadata = new Dictionary<string, string>
|
||||
{
|
||||
["providerId"] = providerId.ToString(),
|
||||
@@ -206,7 +218,13 @@ public class SubscriptionUpdatedHandlerTests
|
||||
{
|
||||
Id = subscriptionId,
|
||||
Status = StripeSubscriptionStatus.Unpaid,
|
||||
CurrentPeriodEnd = DateTime.UtcNow.AddDays(30),
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = DateTime.UtcNow.AddDays(30) }
|
||||
]
|
||||
},
|
||||
Metadata = new Dictionary<string, string> { ["providerId"] = providerId.ToString() },
|
||||
LatestInvoice = new Invoice { BillingReason = "subscription_cycle" },
|
||||
TestClock = null
|
||||
@@ -257,6 +275,13 @@ public class SubscriptionUpdatedHandlerTests
|
||||
var subscription = new Subscription
|
||||
{
|
||||
Id = subscriptionId,
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = DateTime.UtcNow.AddDays(30) }
|
||||
]
|
||||
},
|
||||
Status = StripeSubscriptionStatus.Unpaid,
|
||||
Metadata = new Dictionary<string, string> { { "providerId", providerId.ToString() } },
|
||||
LatestInvoice = new Invoice { BillingReason = "subscription_cycle" }
|
||||
@@ -306,6 +331,13 @@ public class SubscriptionUpdatedHandlerTests
|
||||
var subscription = new Subscription
|
||||
{
|
||||
Id = subscriptionId,
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = DateTime.UtcNow.AddDays(30) }
|
||||
]
|
||||
},
|
||||
Status = StripeSubscriptionStatus.Unpaid,
|
||||
Metadata = new Dictionary<string, string> { { "providerId", providerId.ToString() } },
|
||||
LatestInvoice = new Invoice { BillingReason = "subscription_cycle" }
|
||||
@@ -348,7 +380,13 @@ public class SubscriptionUpdatedHandlerTests
|
||||
{
|
||||
Id = subscriptionId,
|
||||
Status = StripeSubscriptionStatus.IncompleteExpired,
|
||||
CurrentPeriodEnd = currentPeriodEnd,
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = currentPeriodEnd }
|
||||
]
|
||||
},
|
||||
Metadata = new Dictionary<string, string> { { "providerId", providerId.ToString() } },
|
||||
LatestInvoice = new Invoice { BillingReason = "renewal" }
|
||||
};
|
||||
@@ -390,7 +428,13 @@ public class SubscriptionUpdatedHandlerTests
|
||||
{
|
||||
Id = subscriptionId,
|
||||
Status = StripeSubscriptionStatus.Unpaid,
|
||||
CurrentPeriodEnd = currentPeriodEnd,
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = currentPeriodEnd }
|
||||
]
|
||||
},
|
||||
Metadata = new Dictionary<string, string> { { "providerId", providerId.ToString() } },
|
||||
LatestInvoice = new Invoice { BillingReason = "subscription_cycle" }
|
||||
};
|
||||
@@ -426,7 +470,13 @@ public class SubscriptionUpdatedHandlerTests
|
||||
{
|
||||
Id = subscriptionId,
|
||||
Status = StripeSubscriptionStatus.Unpaid,
|
||||
CurrentPeriodEnd = currentPeriodEnd,
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = currentPeriodEnd }
|
||||
]
|
||||
},
|
||||
Metadata = new Dictionary<string, string> { { "providerId", providerId.ToString() } },
|
||||
LatestInvoice = new Invoice { BillingReason = "subscription_cycle" }
|
||||
};
|
||||
@@ -464,13 +514,16 @@ public class SubscriptionUpdatedHandlerTests
|
||||
{
|
||||
Id = subscriptionId,
|
||||
Status = StripeSubscriptionStatus.Unpaid,
|
||||
CurrentPeriodEnd = currentPeriodEnd,
|
||||
Metadata = new Dictionary<string, string> { { "userId", userId.ToString() } },
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { Price = new Price { Id = IStripeEventUtilityService.PremiumPlanId } }
|
||||
new SubscriptionItem
|
||||
{
|
||||
CurrentPeriodEnd = currentPeriodEnd,
|
||||
Price = new Price { Id = IStripeEventUtilityService.PremiumPlanId }
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -508,7 +561,13 @@ public class SubscriptionUpdatedHandlerTests
|
||||
var subscription = new Subscription
|
||||
{
|
||||
Status = StripeSubscriptionStatus.Active,
|
||||
CurrentPeriodEnd = currentPeriodEnd,
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = currentPeriodEnd }
|
||||
]
|
||||
},
|
||||
Metadata = new Dictionary<string, string> { { "organizationId", organizationId.ToString() } }
|
||||
};
|
||||
|
||||
@@ -552,7 +611,13 @@ public class SubscriptionUpdatedHandlerTests
|
||||
var subscription = new Subscription
|
||||
{
|
||||
Status = StripeSubscriptionStatus.Active,
|
||||
CurrentPeriodEnd = currentPeriodEnd,
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = currentPeriodEnd }
|
||||
]
|
||||
},
|
||||
Metadata = new Dictionary<string, string> { { "userId", userId.ToString() } }
|
||||
};
|
||||
|
||||
@@ -583,7 +648,13 @@ public class SubscriptionUpdatedHandlerTests
|
||||
var subscription = new Subscription
|
||||
{
|
||||
Status = StripeSubscriptionStatus.Active,
|
||||
CurrentPeriodEnd = currentPeriodEnd,
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = currentPeriodEnd }
|
||||
]
|
||||
},
|
||||
Metadata = new Dictionary<string, string> { { "organizationId", organizationId.ToString() } }
|
||||
};
|
||||
|
||||
@@ -616,18 +687,24 @@ public class SubscriptionUpdatedHandlerTests
|
||||
{
|
||||
Id = "sub_123",
|
||||
Status = StripeSubscriptionStatus.Active,
|
||||
CurrentPeriodEnd = DateTime.UtcNow.AddDays(10),
|
||||
CustomerId = "cus_123",
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
Data = [new SubscriptionItem { Plan = new Plan { Id = "2023-enterprise-org-seat-annually" } }]
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem
|
||||
{
|
||||
CurrentPeriodEnd = DateTime.UtcNow.AddDays(10),
|
||||
Plan = new Plan { Id = "2023-enterprise-org-seat-annually" }
|
||||
}
|
||||
]
|
||||
},
|
||||
Customer = new Customer
|
||||
{
|
||||
Balance = 0,
|
||||
Discount = new Discount { Coupon = new Coupon { Id = "sm-standalone" } }
|
||||
},
|
||||
Discount = new Discount { Coupon = new Coupon { Id = "sm-standalone" } },
|
||||
Discounts = [new Discount { Coupon = new Coupon { Id = "sm-standalone" } }],
|
||||
Metadata = new Dictionary<string, string> { { "organizationId", organizationId.ToString() } }
|
||||
};
|
||||
|
||||
@@ -728,7 +805,6 @@ public class SubscriptionUpdatedHandlerTests
|
||||
.IsEnabled(FeatureFlagKeys.PM21821_ProviderPortalTakeover);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task
|
||||
HandleAsync_ActiveProviderSubscriptionEvent_AndPreviousSubscriptionStatusWasCanceled_EnableProvider()
|
||||
@@ -998,6 +1074,13 @@ public class SubscriptionUpdatedHandlerTests
|
||||
var newSubscription = new Subscription
|
||||
{
|
||||
Id = previousSubscription?.Id ?? "sub_123",
|
||||
Items = new StripeList<SubscriptionItem>
|
||||
{
|
||||
Data =
|
||||
[
|
||||
new SubscriptionItem { CurrentPeriodEnd = DateTime.UtcNow.AddDays(30) }
|
||||
]
|
||||
},
|
||||
Status = StripeSubscriptionStatus.Active,
|
||||
Metadata = new Dictionary<string, string> { { "providerId", providerId.ToString() } }
|
||||
};
|
||||
@@ -1021,7 +1104,10 @@ public class SubscriptionUpdatedHandlerTests
|
||||
{
|
||||
new object[] { new Subscription { Id = "sub_123", Status = StripeSubscriptionStatus.Unpaid } },
|
||||
new object[] { new Subscription { Id = "sub_123", Status = StripeSubscriptionStatus.Incomplete } },
|
||||
new object[] { new Subscription { Id = "sub_123", Status = StripeSubscriptionStatus.IncompleteExpired } },
|
||||
new object[]
|
||||
{
|
||||
new Subscription { Id = "sub_123", Status = StripeSubscriptionStatus.IncompleteExpired }
|
||||
},
|
||||
new object[] { new Subscription { Id = "sub_123", Status = StripeSubscriptionStatus.Paused } }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
using Stripe;
|
||||
|
||||
namespace Bit.Billing.Test.Utilities;
|
||||
|
||||
public enum StripeEventType
|
||||
{
|
||||
ChargeSucceeded,
|
||||
CustomerSubscriptionUpdated,
|
||||
CustomerUpdated,
|
||||
InvoiceCreated,
|
||||
InvoiceFinalized,
|
||||
InvoiceUpcoming,
|
||||
PaymentMethodAttached
|
||||
}
|
||||
|
||||
public static class StripeTestEvents
|
||||
{
|
||||
public static async Task<Event> GetAsync(StripeEventType eventType)
|
||||
{
|
||||
var fileName = eventType switch
|
||||
{
|
||||
StripeEventType.ChargeSucceeded => "charge.succeeded.json",
|
||||
StripeEventType.CustomerSubscriptionUpdated => "customer.subscription.updated.json",
|
||||
StripeEventType.CustomerUpdated => "customer.updated.json",
|
||||
StripeEventType.InvoiceCreated => "invoice.created.json",
|
||||
StripeEventType.InvoiceFinalized => "invoice.finalized.json",
|
||||
StripeEventType.InvoiceUpcoming => "invoice.upcoming.json",
|
||||
StripeEventType.PaymentMethodAttached => "payment_method.attached.json"
|
||||
};
|
||||
|
||||
var resource = await EmbeddedResourceReader.ReadAsync("Events", fileName);
|
||||
|
||||
return EventUtility.ParseEvent(resource);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user