diff --git a/corporate/tests/stripe_fixtures/attach_discount_to_realm:Charge.list.1.json b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Charge.list.1.json new file mode 100644 index 0000000000..c6837caf84 --- /dev/null +++ b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Charge.list.1.json @@ -0,0 +1,76 @@ +{ + "data": [ + { + "amount": 9600, + "amount_refunded": 0, + "application": null, + "application_fee": null, + "balance_transaction": "txn_1DasKCGh0CmXqmnwGpFYo8WR", + "captured": true, + "created": 1543270384, + "currency": "usd", + "customer": "cus_NORMALIZED0001", + "description": null, + "destination": null, + "dispute": null, + "failure_code": null, + "failure_message": null, + "fraud_details": {}, + "id": "ch_1DasKCGh0CmXqmnwR0PdCeDM", + "invoice": "in_1DasKCGh0CmXqmnw6gIFvxxy", + "livemode": false, + "metadata": {}, + "object": "charge", + "on_behalf_of": null, + "order": null, + "outcome": { + "network_status": "approved_by_network", + "reason": null, + "risk_level": "normal", + "risk_score": 1, + "seller_message": "Payment complete.", + "type": "authorized" + }, + "paid": true, + "payment_intent": null, + "receipt_email": "hamlet@zulip.com", + "receipt_number": null, + "refunded": false, + "refunds": {}, + "review": null, + "shipping": null, + "source": { + "address_city": "Pacific", + "address_country": "United States", + "address_line1": "Under the sea,", + "address_line1_check": "pass", + "address_line2": null, + "address_state": null, + "address_zip": "33333", + "address_zip_check": "pass", + "brand": "Visa", + "country": "US", + "customer": "cus_NORMALIZED0001", + "cvc_check": null, + "dynamic_last4": null, + "exp_month": 3, + "exp_year": 2033, + "fingerprint": "NORMALIZED000001", + "funding": "credit", + "id": "card_NORMALIZED00000000000001", + "last4": "4242", + "metadata": {}, + "name": "Ada Starr", + "object": "card", + "tokenization_method": null + }, + "source_transfer": null, + "statement_descriptor": "Zulip Cloud Premium", + "status": "succeeded", + "transfer_group": null + } + ], + "has_more": false, + "object": "list", + "url": "/v1/charges" +} diff --git a/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.create.1.json b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.create.1.json new file mode 100644 index 0000000000..18131f2ce6 --- /dev/null +++ b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.create.1.json @@ -0,0 +1,58 @@ +{ + "account_balance": 0, + "created": 1543270381, + "currency": null, + "default_source": null, + "delinquent": false, + "description": "zulip (Zulip Dev)", + "discount": { + "coupon": { + "amount_off": null, + "created": 1539831972, + "currency": null, + "duration": "forever", + "duration_in_months": null, + "id": "wqkGqs8t", + "livemode": false, + "max_redemptions": null, + "metadata": {}, + "name": "85% discount", + "object": "coupon", + "percent_off": 85.0, + "redeem_by": null, + "times_redeemed": 37, + "valid": true + }, + "customer": "cus_NORMALIZED0001", + "end": null, + "object": "discount", + "start": 1543270381, + "subscription": null + }, + "email": "hamlet@zulip.com", + "id": "cus_NORMALIZED0001", + "invoice_prefix": "NORMA01", + "livemode": false, + "metadata": { + "realm_id": "1", + "realm_str": "zulip" + }, + "object": "customer", + "shipping": null, + "sources": { + "data": [], + "has_more": false, + "object": "list", + "total_count": 0, + "url": "/v1/customers/cus_NORMALIZED0001/sources" + }, + "subscriptions": { + "data": [], + "has_more": false, + "object": "list", + "total_count": 0, + "url": "/v1/customers/cus_NORMALIZED0001/subscriptions" + }, + "tax_info": null, + "tax_info_verification": null +} diff --git a/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.retrieve.1.json b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.retrieve.1.json new file mode 100644 index 0000000000..18131f2ce6 --- /dev/null +++ b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.retrieve.1.json @@ -0,0 +1,58 @@ +{ + "account_balance": 0, + "created": 1543270381, + "currency": null, + "default_source": null, + "delinquent": false, + "description": "zulip (Zulip Dev)", + "discount": { + "coupon": { + "amount_off": null, + "created": 1539831972, + "currency": null, + "duration": "forever", + "duration_in_months": null, + "id": "wqkGqs8t", + "livemode": false, + "max_redemptions": null, + "metadata": {}, + "name": "85% discount", + "object": "coupon", + "percent_off": 85.0, + "redeem_by": null, + "times_redeemed": 37, + "valid": true + }, + "customer": "cus_NORMALIZED0001", + "end": null, + "object": "discount", + "start": 1543270381, + "subscription": null + }, + "email": "hamlet@zulip.com", + "id": "cus_NORMALIZED0001", + "invoice_prefix": "NORMA01", + "livemode": false, + "metadata": { + "realm_id": "1", + "realm_str": "zulip" + }, + "object": "customer", + "shipping": null, + "sources": { + "data": [], + "has_more": false, + "object": "list", + "total_count": 0, + "url": "/v1/customers/cus_NORMALIZED0001/sources" + }, + "subscriptions": { + "data": [], + "has_more": false, + "object": "list", + "total_count": 0, + "url": "/v1/customers/cus_NORMALIZED0001/subscriptions" + }, + "tax_info": null, + "tax_info_verification": null +} diff --git a/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.retrieve.2.json b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.retrieve.2.json new file mode 100644 index 0000000000..4bdce0f268 --- /dev/null +++ b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.retrieve.2.json @@ -0,0 +1,192 @@ +{ + "account_balance": 0, + "created": 1543270381, + "currency": "usd", + "default_source": { + "address_city": "Pacific", + "address_country": "United States", + "address_line1": "Under the sea,", + "address_line1_check": "pass", + "address_line2": null, + "address_state": null, + "address_zip": "33333", + "address_zip_check": "pass", + "brand": "Visa", + "country": "US", + "customer": "cus_NORMALIZED0001", + "cvc_check": "pass", + "dynamic_last4": null, + "exp_month": 3, + "exp_year": 2033, + "fingerprint": "NORMALIZED000001", + "funding": "credit", + "id": "card_NORMALIZED00000000000001", + "last4": "4242", + "metadata": {}, + "name": "Ada Starr", + "object": "card", + "tokenization_method": null + }, + "delinquent": false, + "description": "zulip (Zulip Dev)", + "discount": { + "coupon": { + "amount_off": null, + "created": 1539831972, + "currency": null, + "duration": "forever", + "duration_in_months": null, + "id": "wqkGqs8t", + "livemode": false, + "max_redemptions": null, + "metadata": {}, + "name": "85% discount", + "object": "coupon", + "percent_off": 85.0, + "redeem_by": null, + "times_redeemed": 37, + "valid": true + }, + "customer": "cus_NORMALIZED0001", + "end": null, + "object": "discount", + "start": 1543270381, + "subscription": null + }, + "email": "hamlet@zulip.com", + "id": "cus_NORMALIZED0001", + "invoice_prefix": "NORMA01", + "livemode": false, + "metadata": { + "realm_id": "1", + "realm_str": "zulip" + }, + "object": "customer", + "shipping": null, + "sources": { + "data": [ + { + "address_city": "Pacific", + "address_country": "United States", + "address_line1": "Under the sea,", + "address_line1_check": "pass", + "address_line2": null, + "address_state": null, + "address_zip": "33333", + "address_zip_check": "pass", + "brand": "Visa", + "country": "US", + "customer": "cus_NORMALIZED0001", + "cvc_check": "pass", + "dynamic_last4": null, + "exp_month": 3, + "exp_year": 2033, + "fingerprint": "NORMALIZED000001", + "funding": "credit", + "id": "card_NORMALIZED00000000000001", + "last4": "4242", + "metadata": {}, + "name": "Ada Starr", + "object": "card", + "tokenization_method": null + } + ], + "has_more": false, + "object": "list", + "total_count": 1, + "url": "/v1/customers/cus_NORMALIZED0001/sources" + }, + "subscriptions": { + "data": [ + { + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1543270384, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1543270384, + "current_period_end": 1574806384, + "current_period_start": 1543270384, + "customer": "cus_NORMALIZED0001", + "days_until_due": null, + "default_source": null, + "discount": null, + "ended_at": null, + "id": "sub_NORMALIZED0001", + "items": { + "data": [ + { + "created": 1543270384, + "id": "si_NORMALIZED0001", + "metadata": {}, + "object": "subscription_item", + "plan": { + "active": true, + "aggregate_usage": null, + "amount": 8000, + "billing_scheme": "per_unit", + "created": 1539831971, + "currency": "usd", + "id": "plan_Do3xCvbzO89OsR", + "interval": "year", + "interval_count": 1, + "livemode": false, + "metadata": {}, + "nickname": "annual", + "object": "plan", + "product": "prod_Do3x494SetTDpx", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 8, + "subscription": "sub_NORMALIZED0001" + } + ], + "has_more": false, + "object": "list", + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_NORMALIZED0001" + }, + "livemode": false, + "metadata": {}, + "object": "subscription", + "plan": { + "active": true, + "aggregate_usage": null, + "amount": 8000, + "billing_scheme": "per_unit", + "created": 1539831971, + "currency": "usd", + "id": "plan_Do3xCvbzO89OsR", + "interval": "year", + "interval_count": 1, + "livemode": false, + "metadata": {}, + "nickname": "annual", + "object": "plan", + "product": "prod_Do3x494SetTDpx", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 8, + "start": 1543270384, + "status": "active", + "tax_percent": 0.0, + "trial_end": null, + "trial_start": null + } + ], + "has_more": false, + "object": "list", + "total_count": 1, + "url": "/v1/customers/cus_NORMALIZED0001/subscriptions" + }, + "tax_info": null, + "tax_info_verification": null +} diff --git a/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.retrieve.3.json b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.retrieve.3.json new file mode 100644 index 0000000000..4bdce0f268 --- /dev/null +++ b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.retrieve.3.json @@ -0,0 +1,192 @@ +{ + "account_balance": 0, + "created": 1543270381, + "currency": "usd", + "default_source": { + "address_city": "Pacific", + "address_country": "United States", + "address_line1": "Under the sea,", + "address_line1_check": "pass", + "address_line2": null, + "address_state": null, + "address_zip": "33333", + "address_zip_check": "pass", + "brand": "Visa", + "country": "US", + "customer": "cus_NORMALIZED0001", + "cvc_check": "pass", + "dynamic_last4": null, + "exp_month": 3, + "exp_year": 2033, + "fingerprint": "NORMALIZED000001", + "funding": "credit", + "id": "card_NORMALIZED00000000000001", + "last4": "4242", + "metadata": {}, + "name": "Ada Starr", + "object": "card", + "tokenization_method": null + }, + "delinquent": false, + "description": "zulip (Zulip Dev)", + "discount": { + "coupon": { + "amount_off": null, + "created": 1539831972, + "currency": null, + "duration": "forever", + "duration_in_months": null, + "id": "wqkGqs8t", + "livemode": false, + "max_redemptions": null, + "metadata": {}, + "name": "85% discount", + "object": "coupon", + "percent_off": 85.0, + "redeem_by": null, + "times_redeemed": 37, + "valid": true + }, + "customer": "cus_NORMALIZED0001", + "end": null, + "object": "discount", + "start": 1543270381, + "subscription": null + }, + "email": "hamlet@zulip.com", + "id": "cus_NORMALIZED0001", + "invoice_prefix": "NORMA01", + "livemode": false, + "metadata": { + "realm_id": "1", + "realm_str": "zulip" + }, + "object": "customer", + "shipping": null, + "sources": { + "data": [ + { + "address_city": "Pacific", + "address_country": "United States", + "address_line1": "Under the sea,", + "address_line1_check": "pass", + "address_line2": null, + "address_state": null, + "address_zip": "33333", + "address_zip_check": "pass", + "brand": "Visa", + "country": "US", + "customer": "cus_NORMALIZED0001", + "cvc_check": "pass", + "dynamic_last4": null, + "exp_month": 3, + "exp_year": 2033, + "fingerprint": "NORMALIZED000001", + "funding": "credit", + "id": "card_NORMALIZED00000000000001", + "last4": "4242", + "metadata": {}, + "name": "Ada Starr", + "object": "card", + "tokenization_method": null + } + ], + "has_more": false, + "object": "list", + "total_count": 1, + "url": "/v1/customers/cus_NORMALIZED0001/sources" + }, + "subscriptions": { + "data": [ + { + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1543270384, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1543270384, + "current_period_end": 1574806384, + "current_period_start": 1543270384, + "customer": "cus_NORMALIZED0001", + "days_until_due": null, + "default_source": null, + "discount": null, + "ended_at": null, + "id": "sub_NORMALIZED0001", + "items": { + "data": [ + { + "created": 1543270384, + "id": "si_NORMALIZED0001", + "metadata": {}, + "object": "subscription_item", + "plan": { + "active": true, + "aggregate_usage": null, + "amount": 8000, + "billing_scheme": "per_unit", + "created": 1539831971, + "currency": "usd", + "id": "plan_Do3xCvbzO89OsR", + "interval": "year", + "interval_count": 1, + "livemode": false, + "metadata": {}, + "nickname": "annual", + "object": "plan", + "product": "prod_Do3x494SetTDpx", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 8, + "subscription": "sub_NORMALIZED0001" + } + ], + "has_more": false, + "object": "list", + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_NORMALIZED0001" + }, + "livemode": false, + "metadata": {}, + "object": "subscription", + "plan": { + "active": true, + "aggregate_usage": null, + "amount": 8000, + "billing_scheme": "per_unit", + "created": 1539831971, + "currency": "usd", + "id": "plan_Do3xCvbzO89OsR", + "interval": "year", + "interval_count": 1, + "livemode": false, + "metadata": {}, + "nickname": "annual", + "object": "plan", + "product": "prod_Do3x494SetTDpx", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 8, + "start": 1543270384, + "status": "active", + "tax_percent": 0.0, + "trial_end": null, + "trial_start": null + } + ], + "has_more": false, + "object": "list", + "total_count": 1, + "url": "/v1/customers/cus_NORMALIZED0001/subscriptions" + }, + "tax_info": null, + "tax_info_verification": null +} diff --git a/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.save.1.json b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.save.1.json new file mode 100644 index 0000000000..61dbdfc37d --- /dev/null +++ b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.save.1.json @@ -0,0 +1,84 @@ +{ + "account_balance": 0, + "created": 1543270381, + "currency": null, + "default_source": "card_NORMALIZED00000000000001", + "delinquent": false, + "description": "zulip (Zulip Dev)", + "discount": { + "coupon": { + "amount_off": null, + "created": 1539831972, + "currency": null, + "duration": "forever", + "duration_in_months": null, + "id": "wqkGqs8t", + "livemode": false, + "max_redemptions": null, + "metadata": {}, + "name": "85% discount", + "object": "coupon", + "percent_off": 85.0, + "redeem_by": null, + "times_redeemed": 37, + "valid": true + }, + "customer": "cus_NORMALIZED0001", + "end": null, + "object": "discount", + "start": 1543270381, + "subscription": null + }, + "email": "hamlet@zulip.com", + "id": "cus_NORMALIZED0001", + "invoice_prefix": "NORMA01", + "livemode": false, + "metadata": { + "realm_id": "1", + "realm_str": "zulip" + }, + "object": "customer", + "shipping": null, + "sources": { + "data": [ + { + "address_city": "Pacific", + "address_country": "United States", + "address_line1": "Under the sea,", + "address_line1_check": "pass", + "address_line2": null, + "address_state": null, + "address_zip": "33333", + "address_zip_check": "pass", + "brand": "Visa", + "country": "US", + "customer": "cus_NORMALIZED0001", + "cvc_check": "pass", + "dynamic_last4": null, + "exp_month": 3, + "exp_year": 2033, + "fingerprint": "NORMALIZED000001", + "funding": "credit", + "id": "card_NORMALIZED00000000000001", + "last4": "4242", + "metadata": {}, + "name": "Ada Starr", + "object": "card", + "tokenization_method": null + } + ], + "has_more": false, + "object": "list", + "total_count": 1, + "url": "/v1/customers/cus_NORMALIZED0001/sources" + }, + "subscriptions": { + "data": [], + "has_more": false, + "object": "list", + "total_count": 0, + "url": "/v1/customers/cus_NORMALIZED0001/subscriptions" + }, + "tax_info": null, + "tax_info_verification": null +} diff --git a/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.save.2.json b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.save.2.json new file mode 100644 index 0000000000..2e15484f70 --- /dev/null +++ b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Customer.save.2.json @@ -0,0 +1,168 @@ +{ + "account_balance": 0, + "created": 1543270381, + "currency": "usd", + "default_source": "card_NORMALIZED00000000000001", + "delinquent": false, + "description": "zulip (Zulip Dev)", + "discount": { + "coupon": { + "amount_off": null, + "created": 1539831971, + "currency": null, + "duration": "forever", + "duration_in_months": null, + "id": "00otHgC9", + "livemode": false, + "max_redemptions": null, + "metadata": {}, + "name": "25% discount", + "object": "coupon", + "percent_off": 25.0, + "redeem_by": null, + "times_redeemed": 19, + "valid": true + }, + "customer": "cus_NORMALIZED0001", + "end": null, + "object": "discount", + "start": 1543270387, + "subscription": null + }, + "email": "hamlet@zulip.com", + "id": "cus_NORMALIZED0001", + "invoice_prefix": "NORMA01", + "livemode": false, + "metadata": { + "realm_id": "1", + "realm_str": "zulip" + }, + "object": "customer", + "shipping": null, + "sources": { + "data": [ + { + "address_city": "Pacific", + "address_country": "United States", + "address_line1": "Under the sea,", + "address_line1_check": "pass", + "address_line2": null, + "address_state": null, + "address_zip": "33333", + "address_zip_check": "pass", + "brand": "Visa", + "country": "US", + "customer": "cus_NORMALIZED0001", + "cvc_check": "pass", + "dynamic_last4": null, + "exp_month": 3, + "exp_year": 2033, + "fingerprint": "NORMALIZED000001", + "funding": "credit", + "id": "card_NORMALIZED00000000000001", + "last4": "4242", + "metadata": {}, + "name": "Ada Starr", + "object": "card", + "tokenization_method": null + } + ], + "has_more": false, + "object": "list", + "total_count": 1, + "url": "/v1/customers/cus_NORMALIZED0001/sources" + }, + "subscriptions": { + "data": [ + { + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1543270384, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1543270384, + "current_period_end": 1574806384, + "current_period_start": 1543270384, + "customer": "cus_NORMALIZED0001", + "days_until_due": null, + "default_source": null, + "discount": null, + "ended_at": null, + "id": "sub_NORMALIZED0001", + "items": { + "data": [ + { + "created": 1543270384, + "id": "si_NORMALIZED0001", + "metadata": {}, + "object": "subscription_item", + "plan": { + "active": true, + "aggregate_usage": null, + "amount": 8000, + "billing_scheme": "per_unit", + "created": 1539831971, + "currency": "usd", + "id": "plan_Do3xCvbzO89OsR", + "interval": "year", + "interval_count": 1, + "livemode": false, + "metadata": {}, + "nickname": "annual", + "object": "plan", + "product": "prod_Do3x494SetTDpx", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 8, + "subscription": "sub_NORMALIZED0001" + } + ], + "has_more": false, + "object": "list", + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_NORMALIZED0001" + }, + "livemode": false, + "metadata": {}, + "object": "subscription", + "plan": { + "active": true, + "aggregate_usage": null, + "amount": 8000, + "billing_scheme": "per_unit", + "created": 1539831971, + "currency": "usd", + "id": "plan_Do3xCvbzO89OsR", + "interval": "year", + "interval_count": 1, + "livemode": false, + "metadata": {}, + "nickname": "annual", + "object": "plan", + "product": "prod_Do3x494SetTDpx", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 8, + "start": 1543270384, + "status": "active", + "tax_percent": 0.0, + "trial_end": null, + "trial_start": null + } + ], + "has_more": false, + "object": "list", + "total_count": 1, + "url": "/v1/customers/cus_NORMALIZED0001/subscriptions" + }, + "tax_info": null, + "tax_info_verification": null +} diff --git a/corporate/tests/stripe_fixtures/attach_discount_to_realm:Invoice.upcoming.1.json b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Invoice.upcoming.1.json new file mode 100644 index 0000000000..660f9f3b2c --- /dev/null +++ b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Invoice.upcoming.1.json @@ -0,0 +1,110 @@ +{ + "amount_due": 9600, + "amount_paid": 0, + "amount_remaining": 9600, + "application_fee": null, + "attempt_count": 0, + "attempted": false, + "billing": "charge_automatically", + "billing_reason": "upcoming", + "charge": null, + "currency": "usd", + "customer": "cus_NORMALIZED0001", + "date": 1574806384, + "default_source": null, + "description": "", + "discount": { + "coupon": { + "amount_off": null, + "created": 1539831972, + "currency": null, + "duration": "forever", + "duration_in_months": null, + "id": "wqkGqs8t", + "livemode": false, + "max_redemptions": null, + "metadata": {}, + "name": "85% discount", + "object": "coupon", + "percent_off": 85.0, + "redeem_by": null, + "times_redeemed": 37, + "valid": true + }, + "customer": "cus_NORMALIZED0001", + "end": null, + "object": "discount", + "start": 1543270381, + "subscription": null + }, + "due_date": null, + "ending_balance": 0, + "finalized_at": null, + "lines": { + "data": [ + { + "amount": 64000, + "currency": "usd", + "description": "8 user \u00d7 Zulip Cloud Premium (at $80.00 / year)", + "discountable": true, + "id": "sli_NORMALIZED0001", + "livemode": false, + "metadata": {}, + "object": "line_item", + "period": { + "end": 1606428784, + "start": 1574806384 + }, + "plan": { + "active": true, + "aggregate_usage": null, + "amount": 8000, + "billing_scheme": "per_unit", + "created": 1539831971, + "currency": "usd", + "id": "plan_Do3xCvbzO89OsR", + "interval": "year", + "interval_count": 1, + "livemode": false, + "metadata": {}, + "nickname": "annual", + "object": "plan", + "product": "prod_Do3x494SetTDpx", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "proration": false, + "quantity": 8, + "subscription": "sub_NORMALIZED0001", + "subscription_item": "si_NORMALIZED0001", + "type": "subscription" + } + ], + "has_more": false, + "object": "list", + "total_count": 1, + "url": "/v1/invoices/upcoming/lines?customer=cus_NORMALIZED0001" + }, + "livemode": false, + "metadata": {}, + "next_payment_attempt": 1574809984, + "number": "NORMALI-0001", + "object": "invoice", + "paid": false, + "payment_intent": null, + "period_end": 1574806384, + "period_start": 1543270384, + "receipt_number": null, + "starting_balance": 0, + "statement_descriptor": null, + "status": "draft", + "subscription": "sub_NORMALIZED0001", + "subtotal": 64000, + "tax": 0, + "tax_percent": 0.0, + "total": 9600, + "webhooks_delivered_at": null +} diff --git a/corporate/tests/stripe_fixtures/attach_discount_to_realm:Invoice.upcoming.2.json b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Invoice.upcoming.2.json new file mode 100644 index 0000000000..0dede69d4f --- /dev/null +++ b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Invoice.upcoming.2.json @@ -0,0 +1,110 @@ +{ + "amount_due": 48000, + "amount_paid": 0, + "amount_remaining": 48000, + "application_fee": null, + "attempt_count": 0, + "attempted": false, + "billing": "charge_automatically", + "billing_reason": "upcoming", + "charge": null, + "currency": "usd", + "customer": "cus_NORMALIZED0001", + "date": 1574806384, + "default_source": null, + "description": "", + "discount": { + "coupon": { + "amount_off": null, + "created": 1539831971, + "currency": null, + "duration": "forever", + "duration_in_months": null, + "id": "00otHgC9", + "livemode": false, + "max_redemptions": null, + "metadata": {}, + "name": "25% discount", + "object": "coupon", + "percent_off": 25.0, + "redeem_by": null, + "times_redeemed": 19, + "valid": true + }, + "customer": "cus_NORMALIZED0001", + "end": null, + "object": "discount", + "start": 1543270387, + "subscription": null + }, + "due_date": null, + "ending_balance": 0, + "finalized_at": null, + "lines": { + "data": [ + { + "amount": 64000, + "currency": "usd", + "description": "8 user \u00d7 Zulip Cloud Premium (at $80.00 / year)", + "discountable": true, + "id": "sli_NORMALIZED0001", + "livemode": false, + "metadata": {}, + "object": "line_item", + "period": { + "end": 1606428784, + "start": 1574806384 + }, + "plan": { + "active": true, + "aggregate_usage": null, + "amount": 8000, + "billing_scheme": "per_unit", + "created": 1539831971, + "currency": "usd", + "id": "plan_Do3xCvbzO89OsR", + "interval": "year", + "interval_count": 1, + "livemode": false, + "metadata": {}, + "nickname": "annual", + "object": "plan", + "product": "prod_Do3x494SetTDpx", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "proration": false, + "quantity": 8, + "subscription": "sub_NORMALIZED0001", + "subscription_item": "si_NORMALIZED0001", + "type": "subscription" + } + ], + "has_more": false, + "object": "list", + "total_count": 1, + "url": "/v1/invoices/upcoming/lines?customer=cus_NORMALIZED0001" + }, + "livemode": false, + "metadata": {}, + "next_payment_attempt": 1574809984, + "number": "NORMALI-0001", + "object": "invoice", + "paid": false, + "payment_intent": null, + "period_end": 1574806384, + "period_start": 1543270384, + "receipt_number": null, + "starting_balance": 0, + "statement_descriptor": null, + "status": "draft", + "subscription": "sub_NORMALIZED0001", + "subtotal": 64000, + "tax": 0, + "tax_percent": 0.0, + "total": 48000, + "webhooks_delivered_at": null +} diff --git a/corporate/tests/stripe_fixtures/attach_discount_to_realm:Subscription.create.1.json b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Subscription.create.1.json new file mode 100644 index 0000000000..060ed392ce --- /dev/null +++ b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Subscription.create.1.json @@ -0,0 +1,83 @@ +{ + "application_fee_percent": null, + "billing": "charge_automatically", + "billing_cycle_anchor": 1543270384, + "cancel_at_period_end": false, + "canceled_at": null, + "created": 1543270384, + "current_period_end": 1574806384, + "current_period_start": 1543270384, + "customer": "cus_NORMALIZED0001", + "days_until_due": null, + "default_source": null, + "discount": null, + "ended_at": null, + "id": "sub_NORMALIZED0001", + "items": { + "data": [ + { + "created": 1543270384, + "id": "si_NORMALIZED0001", + "metadata": {}, + "object": "subscription_item", + "plan": { + "active": true, + "aggregate_usage": null, + "amount": 8000, + "billing_scheme": "per_unit", + "created": 1539831971, + "currency": "usd", + "id": "plan_Do3xCvbzO89OsR", + "interval": "year", + "interval_count": 1, + "livemode": false, + "metadata": {}, + "nickname": "annual", + "object": "plan", + "product": "prod_Do3x494SetTDpx", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 8, + "subscription": "sub_NORMALIZED0001" + } + ], + "has_more": false, + "object": "list", + "total_count": 1, + "url": "/v1/subscription_items?subscription=sub_NORMALIZED0001" + }, + "livemode": false, + "metadata": {}, + "object": "subscription", + "plan": { + "active": true, + "aggregate_usage": null, + "amount": 8000, + "billing_scheme": "per_unit", + "created": 1539831971, + "currency": "usd", + "id": "plan_Do3xCvbzO89OsR", + "interval": "year", + "interval_count": 1, + "livemode": false, + "metadata": {}, + "nickname": "annual", + "object": "plan", + "product": "prod_Do3x494SetTDpx", + "tiers": null, + "tiers_mode": null, + "transform_usage": null, + "trial_period_days": null, + "usage_type": "licensed" + }, + "quantity": 8, + "start": 1543270384, + "status": "active", + "tax_percent": 0.0, + "trial_end": null, + "trial_start": null +} diff --git a/corporate/tests/stripe_fixtures/attach_discount_to_realm:Token.create.1.json b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Token.create.1.json new file mode 100644 index 0000000000..886506584a --- /dev/null +++ b/corporate/tests/stripe_fixtures/attach_discount_to_realm:Token.create.1.json @@ -0,0 +1,33 @@ +{ + "card": { + "address_city": "Pacific", + "address_country": "United States", + "address_line1": "Under the sea,", + "address_line1_check": "unchecked", + "address_line2": null, + "address_state": null, + "address_zip": "33333", + "address_zip_check": "unchecked", + "brand": "Visa", + "country": "US", + "cvc_check": "unchecked", + "dynamic_last4": null, + "exp_month": 3, + "exp_year": 2033, + "fingerprint": "NORMALIZED000001", + "funding": "credit", + "id": "card_NORMALIZED00000000000001", + "last4": "4242", + "metadata": {}, + "name": "Ada Starr", + "object": "card", + "tokenization_method": null + }, + "client_ip": "0.0.0.0", + "created": 1543270382, + "id": "tok_NORMALIZED00000000000001", + "livemode": false, + "object": "token", + "type": "card", + "used": false +} diff --git a/corporate/tests/test_stripe.py b/corporate/tests/test_stripe.py index b94576abb6..1755d8bc8b 100644 --- a/corporate/tests/test_stripe.py +++ b/corporate/tests/test_stripe.py @@ -740,24 +740,36 @@ class StripeTest(ZulipTestCase): stripe_customer = stripe_get_customer(Customer.objects.get(realm=user.realm).stripe_customer_id) self.assertIn('Unknown payment method.', payment_method_string(stripe_customer)) - @patch("stripe.Customer.retrieve", side_effect=mock_create_customer) - @patch("stripe.Customer.create", side_effect=mock_create_customer) - def test_attach_discount_to_realm(self, mock_create_customer: Mock, - mock_retrieve_customer: Mock) -> None: + @mock_stripe("Customer.save", "Customer.retrieve", "Customer.create", "Invoice.upcoming", + "Token.create", "Charge.list", "Subscription.create") + def test_attach_discount_to_realm(self, mock7: Mock, mock6: Mock, mock5: Mock, mock4: Mock, + mock3: Mock, mock2: Mock, mock1: Mock) -> None: + # Attach discount before Stripe customer exists user = self.example_user('hamlet') - # Before customer exists attach_discount_to_realm(user, 85) - mock_create_customer.assert_called_once_with( - description=Kandra(), email=self.example_email('hamlet'), metadata=Kandra(), - source=None, coupon=self.stripe_coupon_id) - mock_create_customer.reset_mock() - # For existing customer - Coupon.objects.create(percent_off=42, stripe_coupon_id='42OFF') - with patch.object( - stripe.Customer, 'save', autospec=True, - side_effect=lambda stripe_customer: self.assertEqual(stripe_customer.coupon, '42OFF')): - attach_discount_to_realm(user, 42) - mock_create_customer.assert_not_called() + self.login(user.email) + response = self.client_get("/upgrade/") + self.client_post("/upgrade/", {'stripeToken': stripe_create_token().id, + 'signed_seat_count': self.get_signed_seat_count_from_response(response), + 'salt': self.get_salt_from_response(response), + 'plan': Plan.CLOUD_ANNUAL, + 'billing_modality': 'charge_automatically'}) + stripe_customer = stripe_get_customer(Customer.objects.get(realm=user.realm).stripe_customer_id) + assert(stripe_customer.discount is not None) # for mypy + self.assertEqual(stripe_customer.discount.coupon.percent_off, 85.0) + # Check that the customer was charged the discounted amount + charges = stripe.Charge.list(customer=stripe_customer.id) + for charge in charges: + self.assertEqual(charge.amount, get_seat_count(user.realm) * 80 * 15) + # Check upcoming invoice reflects the discount + upcoming_invoice = stripe.Invoice.upcoming(customer=stripe_customer.id) + self.assertEqual(upcoming_invoice.amount_due, get_seat_count(user.realm) * 80 * 15) + + # Attach discount to existing Stripe customer + attach_discount_to_realm(user, 25) + # Check upcoming invoice reflects the new discount + upcoming_invoice = stripe.Invoice.upcoming(customer=stripe_customer.id) + self.assertEqual(upcoming_invoice.amount_due, get_seat_count(user.realm) * 80 * 75) @patch("stripe.Subscription.delete") @patch("stripe.Customer.save") diff --git a/stubs/stripe/__init__.pyi b/stubs/stripe/__init__.pyi index 8be2b715d9..d603eef828 100644 --- a/stubs/stripe/__init__.pyi +++ b/stubs/stripe/__init__.pyi @@ -124,3 +124,10 @@ class Token: @staticmethod def create(card: Dict[str, Any]) -> Token: ... + +class Charge: + amount: int + + @staticmethod + def list(customer: Optional[str]) -> List[Charge]: + ...