mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	stripe: Ensure required_plan_tier is set before setting discount.
This commit is contained in:
		@@ -1278,26 +1278,25 @@ class BillingSession(ABC):
 | 
				
			|||||||
    def attach_discount_to_customer(self, new_discount: Decimal) -> str:
 | 
					    def attach_discount_to_customer(self, new_discount: Decimal) -> str:
 | 
				
			||||||
        # Remove flat discount if giving customer a percentage discount.
 | 
					        # Remove flat discount if giving customer a percentage discount.
 | 
				
			||||||
        customer = self.get_customer()
 | 
					        customer = self.get_customer()
 | 
				
			||||||
        old_discount = None
 | 
					
 | 
				
			||||||
        if customer is not None:
 | 
					        # We set required plan tier before setting a discount for the customer, so it's always defined.
 | 
				
			||||||
            old_discount = customer.default_discount
 | 
					        assert customer is not None
 | 
				
			||||||
            customer.default_discount = new_discount
 | 
					        assert customer.required_plan_tier is not None
 | 
				
			||||||
            customer.flat_discounted_months = 0
 | 
					
 | 
				
			||||||
            customer.save(update_fields=["default_discount", "flat_discounted_months"])
 | 
					        old_discount = customer.default_discount
 | 
				
			||||||
        else:
 | 
					        customer.default_discount = new_discount
 | 
				
			||||||
            customer = self.update_or_create_customer(
 | 
					        customer.flat_discounted_months = 0
 | 
				
			||||||
                defaults={"default_discount": new_discount, "flat_discounted_months": 0}
 | 
					        customer.save(update_fields=["default_discount", "flat_discounted_months"])
 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        plan = get_current_plan_by_customer(customer)
 | 
					        plan = get_current_plan_by_customer(customer)
 | 
				
			||||||
        if plan is not None:
 | 
					        if plan is not None and plan.tier == customer.required_plan_tier:
 | 
				
			||||||
            self.apply_discount_to_plan(plan, new_discount)
 | 
					            self.apply_discount_to_plan(plan, new_discount)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # If the customer has a next plan, apply discount to that plan as well.
 | 
					        # If the customer has a next plan, apply discount to that plan as well.
 | 
				
			||||||
            # Make this a check on CustomerPlan.SWITCH_PLAN_TIER_AT_PLAN_END status
 | 
					        # Make this a check on CustomerPlan.SWITCH_PLAN_TIER_AT_PLAN_END status
 | 
				
			||||||
            # if we support this for other plans.
 | 
					        # if we support this for other plans.
 | 
				
			||||||
            next_plan = self.get_legacy_remote_server_next_plan(customer)
 | 
					        next_plan = self.get_legacy_remote_server_next_plan(customer)
 | 
				
			||||||
            if next_plan is not None:  # nocoverage
 | 
					        if next_plan is not None and next_plan.tier == customer.required_plan_tier:
 | 
				
			||||||
                self.apply_discount_to_plan(next_plan, new_discount)
 | 
					            self.apply_discount_to_plan(next_plan, new_discount)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.write_to_audit_log(
 | 
					        self.write_to_audit_log(
 | 
				
			||||||
            event_type=AuditLogEventType.DISCOUNT_CHANGED,
 | 
					            event_type=AuditLogEventType.DISCOUNT_CHANGED,
 | 
				
			||||||
@@ -1366,10 +1365,15 @@ class BillingSession(ABC):
 | 
				
			|||||||
            raise SupportRequestError(f"Invalid plan tier for {self.billing_entity_display_name}.")
 | 
					            raise SupportRequestError(f"Invalid plan tier for {self.billing_entity_display_name}.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if customer is not None:
 | 
					        if customer is not None:
 | 
				
			||||||
 | 
					            if new_plan_tier is None and customer.default_discount:
 | 
				
			||||||
 | 
					                raise SupportRequestError(
 | 
				
			||||||
 | 
					                    f"Discount for {self.billing_entity_display_name} must be 0 before setting required plan tier to None."
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
            previous_required_plan_tier = customer.required_plan_tier
 | 
					            previous_required_plan_tier = customer.required_plan_tier
 | 
				
			||||||
            customer.required_plan_tier = new_plan_tier
 | 
					            customer.required_plan_tier = new_plan_tier
 | 
				
			||||||
            customer.save(update_fields=["required_plan_tier"])
 | 
					            customer.save(update_fields=["required_plan_tier"])
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
 | 
					            assert new_plan_tier is not None
 | 
				
			||||||
            customer = self.update_or_create_customer(
 | 
					            customer = self.update_or_create_customer(
 | 
				
			||||||
                defaults={"required_plan_tier": new_plan_tier}
 | 
					                defaults={"required_plan_tier": new_plan_tier}
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4531,6 +4531,7 @@ class StripeTest(StripeTestCase):
 | 
				
			|||||||
        billing_session = RealmBillingSession(
 | 
					        billing_session = RealmBillingSession(
 | 
				
			||||||
            user=self.example_user("iago"), realm=realm, support_session=True
 | 
					            user=self.example_user("iago"), realm=realm, support_session=True
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					        billing_session.set_required_plan_tier(CustomerPlan.TIER_CLOUD_STANDARD)
 | 
				
			||||||
        billing_session.attach_discount_to_customer(Decimal(20))
 | 
					        billing_session.attach_discount_to_customer(Decimal(20))
 | 
				
			||||||
        rows.append(Row(realm, Realm.PLAN_TYPE_SELF_HOSTED, None, None, 0, False))
 | 
					        rows.append(Row(realm, Realm.PLAN_TYPE_SELF_HOSTED, None, None, 0, False))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6025,6 +6026,16 @@ class TestSupportBillingHelpers(StripeTestCase):
 | 
				
			|||||||
        support_admin = self.example_user("iago")
 | 
					        support_admin = self.example_user("iago")
 | 
				
			||||||
        user = self.example_user("hamlet")
 | 
					        user = self.example_user("hamlet")
 | 
				
			||||||
        billing_session = RealmBillingSession(support_admin, realm=user.realm, support_session=True)
 | 
					        billing_session = RealmBillingSession(support_admin, realm=user.realm, support_session=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Cannot attach discount without a required_plan_tier set.
 | 
				
			||||||
 | 
					        with self.assertRaises(AssertionError):
 | 
				
			||||||
 | 
					            billing_session.attach_discount_to_customer(Decimal(85))
 | 
				
			||||||
 | 
					        billing_session.update_or_create_customer()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.assertRaises(AssertionError):
 | 
				
			||||||
 | 
					            billing_session.attach_discount_to_customer(Decimal(85))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        billing_session.set_required_plan_tier(CustomerPlan.TIER_CLOUD_STANDARD)
 | 
				
			||||||
        billing_session.attach_discount_to_customer(Decimal(85))
 | 
					        billing_session.attach_discount_to_customer(Decimal(85))
 | 
				
			||||||
        realm_audit_log = RealmAuditLog.objects.filter(
 | 
					        realm_audit_log = RealmAuditLog.objects.filter(
 | 
				
			||||||
            event_type=RealmAuditLog.REALM_DISCOUNT_CHANGED
 | 
					            event_type=RealmAuditLog.REALM_DISCOUNT_CHANGED
 | 
				
			||||||
@@ -6055,6 +6066,7 @@ class TestSupportBillingHelpers(StripeTestCase):
 | 
				
			|||||||
        plan.status = CustomerPlan.ENDED
 | 
					        plan.status = CustomerPlan.ENDED
 | 
				
			||||||
        plan.save(update_fields=["status"])
 | 
					        plan.save(update_fields=["status"])
 | 
				
			||||||
        billing_session = RealmBillingSession(support_admin, realm=user.realm, support_session=True)
 | 
					        billing_session = RealmBillingSession(support_admin, realm=user.realm, support_session=True)
 | 
				
			||||||
 | 
					        billing_session.set_required_plan_tier(CustomerPlan.TIER_CLOUD_STANDARD)
 | 
				
			||||||
        billing_session.attach_discount_to_customer(Decimal(25))
 | 
					        billing_session.attach_discount_to_customer(Decimal(25))
 | 
				
			||||||
        with time_machine.travel(self.now, tick=False):
 | 
					        with time_machine.travel(self.now, tick=False):
 | 
				
			||||||
            self.add_card_and_upgrade(
 | 
					            self.add_card_and_upgrade(
 | 
				
			||||||
@@ -6122,6 +6134,7 @@ class TestSupportBillingHelpers(StripeTestCase):
 | 
				
			|||||||
        ):
 | 
					        ):
 | 
				
			||||||
            billing_session.process_support_view_request(support_view_request)
 | 
					            billing_session.process_support_view_request(support_view_request)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        billing_session.set_required_plan_tier(CustomerPlan.TIER_CLOUD_STANDARD)
 | 
				
			||||||
        billing_session.attach_discount_to_customer(Decimal(50))
 | 
					        billing_session.attach_discount_to_customer(Decimal(50))
 | 
				
			||||||
        message = billing_session.process_support_view_request(support_view_request)
 | 
					        message = billing_session.process_support_view_request(support_view_request)
 | 
				
			||||||
        self.assertEqual("Minimum licenses for zulip changed to 25 from 0.", message)
 | 
					        self.assertEqual("Minimum licenses for zulip changed to 25 from 0.", message)
 | 
				
			||||||
@@ -6197,10 +6210,17 @@ class TestSupportBillingHelpers(StripeTestCase):
 | 
				
			|||||||
        with self.assertRaisesRegex(SupportRequestError, "Invalid plan tier for zulip."):
 | 
					        with self.assertRaisesRegex(SupportRequestError, "Invalid plan tier for zulip."):
 | 
				
			||||||
            billing_session.process_support_view_request(support_view_request)
 | 
					            billing_session.process_support_view_request(support_view_request)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Set plan tier to None and check that discount is applied to all plan tiers
 | 
					        # Cannot set required plan tier to None before setting discount to 0.
 | 
				
			||||||
        support_view_request = SupportViewRequest(
 | 
					        support_view_request = SupportViewRequest(
 | 
				
			||||||
            support_type=SupportType.update_required_plan_tier, required_plan_tier=0
 | 
					            support_type=SupportType.update_required_plan_tier, required_plan_tier=0
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					        with self.assertRaisesRegex(
 | 
				
			||||||
 | 
					            SupportRequestError,
 | 
				
			||||||
 | 
					            "Discount for zulip must be 0 before setting required plan tier to None.",
 | 
				
			||||||
 | 
					        ):
 | 
				
			||||||
 | 
					            billing_session.process_support_view_request(support_view_request)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        billing_session.attach_discount_to_customer(Decimal(0))
 | 
				
			||||||
        message = billing_session.process_support_view_request(support_view_request)
 | 
					        message = billing_session.process_support_view_request(support_view_request)
 | 
				
			||||||
        self.assertEqual("Required plan tier for zulip set to None.", message)
 | 
					        self.assertEqual("Required plan tier for zulip set to None.", message)
 | 
				
			||||||
        customer.refresh_from_db()
 | 
					        customer.refresh_from_db()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -523,7 +523,39 @@ class TestRemoteServerSupportEndpoint(ZulipTestCase):
 | 
				
			|||||||
        iago = self.example_user("iago")
 | 
					        iago = self.example_user("iago")
 | 
				
			||||||
        self.login_user(iago)
 | 
					        self.login_user(iago)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # A required plan tier for a customer can be set when an upgrade
 | 
				
			||||||
 | 
					        # is scheduled which is different than the one customer is upgrading to,
 | 
				
			||||||
 | 
					        # but won't change either pre-existing plan tiers.
 | 
				
			||||||
 | 
					        self.assertIsNone(customer.required_plan_tier)
 | 
				
			||||||
 | 
					        result = self.client_post(
 | 
				
			||||||
 | 
					            "/activity/remote/support",
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "remote_realm_id": f"{remote_realm.id}",
 | 
				
			||||||
 | 
					                "required_plan_tier": f"{CustomerPlan.TIER_SELF_HOSTED_BUSINESS}",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assert_in_success_response(
 | 
				
			||||||
 | 
					            ["Required plan tier for realm-name-4 set to Zulip Business."],
 | 
				
			||||||
 | 
					            result,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        customer.refresh_from_db()
 | 
				
			||||||
 | 
					        next_plan.refresh_from_db()
 | 
				
			||||||
 | 
					        self.assertEqual(customer.required_plan_tier, CustomerPlan.TIER_SELF_HOSTED_BUSINESS)
 | 
				
			||||||
 | 
					        self.assertEqual(plan.tier, CustomerPlan.TIER_SELF_HOSTED_LEGACY)
 | 
				
			||||||
 | 
					        self.assertEqual(next_plan.tier, CustomerPlan.TIER_SELF_HOSTED_BASIC)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # A default discount can be added when an upgrade is scheduled.
 | 
					        # A default discount can be added when an upgrade is scheduled.
 | 
				
			||||||
 | 
					        result = self.client_post(
 | 
				
			||||||
 | 
					            "/activity/remote/support",
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "remote_realm_id": f"{remote_realm.id}",
 | 
				
			||||||
 | 
					                "required_plan_tier": f"{CustomerPlan.TIER_SELF_HOSTED_BASIC}",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assert_in_success_response(
 | 
				
			||||||
 | 
					            ["Required plan tier for realm-name-4 set to Zulip Basic."],
 | 
				
			||||||
 | 
					            result,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        result = self.client_post(
 | 
					        result = self.client_post(
 | 
				
			||||||
            "/activity/remote/support",
 | 
					            "/activity/remote/support",
 | 
				
			||||||
            {"remote_realm_id": f"{remote_realm.id}", "discount": "50"},
 | 
					            {"remote_realm_id": f"{remote_realm.id}", "discount": "50"},
 | 
				
			||||||
@@ -535,7 +567,8 @@ class TestRemoteServerSupportEndpoint(ZulipTestCase):
 | 
				
			|||||||
        plan.refresh_from_db()
 | 
					        plan.refresh_from_db()
 | 
				
			||||||
        next_plan.refresh_from_db()
 | 
					        next_plan.refresh_from_db()
 | 
				
			||||||
        self.assertEqual(customer.default_discount, Decimal(50))
 | 
					        self.assertEqual(customer.default_discount, Decimal(50))
 | 
				
			||||||
        self.assertEqual(plan.discount, Decimal(50))
 | 
					        # Discount for current plan stays None since it is not the same as required tier for discount.
 | 
				
			||||||
 | 
					        self.assertEqual(plan.discount, None)
 | 
				
			||||||
        self.assertEqual(next_plan.discount, Decimal(50))
 | 
					        self.assertEqual(next_plan.discount, Decimal(50))
 | 
				
			||||||
        self.assertEqual(plan.tier, CustomerPlan.TIER_SELF_HOSTED_LEGACY)
 | 
					        self.assertEqual(plan.tier, CustomerPlan.TIER_SELF_HOSTED_LEGACY)
 | 
				
			||||||
        self.assertEqual(next_plan.tier, CustomerPlan.TIER_SELF_HOSTED_BASIC)
 | 
					        self.assertEqual(next_plan.tier, CustomerPlan.TIER_SELF_HOSTED_BASIC)
 | 
				
			||||||
@@ -556,26 +589,6 @@ class TestRemoteServerSupportEndpoint(ZulipTestCase):
 | 
				
			|||||||
        customer.refresh_from_db()
 | 
					        customer.refresh_from_db()
 | 
				
			||||||
        self.assertIsNone(customer.minimum_licenses)
 | 
					        self.assertIsNone(customer.minimum_licenses)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # A required plan tier for a customer can be set when an upgrade
 | 
					 | 
				
			||||||
        # is scheduled, but won't change either pre-existing plan tiers.
 | 
					 | 
				
			||||||
        self.assertIsNone(customer.required_plan_tier)
 | 
					 | 
				
			||||||
        result = self.client_post(
 | 
					 | 
				
			||||||
            "/activity/remote/support",
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                "remote_realm_id": f"{remote_realm.id}",
 | 
					 | 
				
			||||||
                "required_plan_tier": f"{CustomerPlan.TIER_SELF_HOSTED_BUSINESS}",
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        self.assert_in_success_response(
 | 
					 | 
				
			||||||
            ["Required plan tier for realm-name-4 set to Zulip Business."],
 | 
					 | 
				
			||||||
            result,
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        customer.refresh_from_db()
 | 
					 | 
				
			||||||
        next_plan.refresh_from_db()
 | 
					 | 
				
			||||||
        self.assertEqual(customer.required_plan_tier, CustomerPlan.TIER_SELF_HOSTED_BUSINESS)
 | 
					 | 
				
			||||||
        self.assertEqual(plan.tier, CustomerPlan.TIER_SELF_HOSTED_LEGACY)
 | 
					 | 
				
			||||||
        self.assertEqual(next_plan.tier, CustomerPlan.TIER_SELF_HOSTED_BASIC)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_support_deactivate_remote_server(self) -> None:
 | 
					    def test_support_deactivate_remote_server(self) -> None:
 | 
				
			||||||
        iago = self.example_user("iago")
 | 
					        iago = self.example_user("iago")
 | 
				
			||||||
        self.login_user(iago)
 | 
					        self.login_user(iago)
 | 
				
			||||||
@@ -1104,6 +1117,17 @@ class TestSupportEndpoint(ZulipTestCase):
 | 
				
			|||||||
        iago = self.example_user("iago")
 | 
					        iago = self.example_user("iago")
 | 
				
			||||||
        self.login_user(iago)
 | 
					        self.login_user(iago)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = self.client_post(
 | 
				
			||||||
 | 
					            "/activity/support",
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "realm_id": f"{lear_realm.id}",
 | 
				
			||||||
 | 
					                "required_plan_tier": f"{CustomerPlan.TIER_CLOUD_STANDARD}",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assert_in_success_response(
 | 
				
			||||||
 | 
					            ["Required plan tier for lear set to Zulip Cloud Standard."],
 | 
				
			||||||
 | 
					            result,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        result = self.client_post(
 | 
					        result = self.client_post(
 | 
				
			||||||
            "/activity/support", {"realm_id": f"{lear_realm.id}", "discount": "25"}
 | 
					            "/activity/support", {"realm_id": f"{lear_realm.id}", "discount": "25"}
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,31 +20,6 @@
 | 
				
			|||||||
</form>
 | 
					</form>
 | 
				
			||||||
{% endif %}
 | 
					{% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<form method="POST" class="remote-form">
 | 
					 | 
				
			||||||
    <b>Discount percentage</b>:<br />
 | 
					 | 
				
			||||||
    <i>Updates will change pre-existing plans and scheduled upgrades.</i><br />
 | 
					 | 
				
			||||||
    <i>Any prorated licenses for the current billing cycle will be billed at the updated discounted rate.</i><br />
 | 
					 | 
				
			||||||
    {{ csrf_input }}
 | 
					 | 
				
			||||||
    <input type="hidden" name="{{ remote_type }}" value="{{ remote_id }}" />
 | 
					 | 
				
			||||||
    {% if has_fixed_price %}
 | 
					 | 
				
			||||||
    <input type="number" name="discount" value="{{ format_discount(sponsorship_data.default_discount) }}" step="0.01" min="0" max="99.99" disabled />
 | 
					 | 
				
			||||||
    <button type="submit" class="support-submit-button" disabled>Update</button>
 | 
					 | 
				
			||||||
    {% else %}
 | 
					 | 
				
			||||||
    <input type="number" name="discount" value="{{ format_discount(sponsorship_data.default_discount) }}" step="0.01" min="0" max="99.99" required />
 | 
					 | 
				
			||||||
    <button type="submit" class="support-submit-button">Update</button>
 | 
					 | 
				
			||||||
    {% endif %}
 | 
					 | 
				
			||||||
</form>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{% if not has_fixed_price and (sponsorship_data.default_discount or sponsorship_data.minimum_licenses) %}
 | 
					 | 
				
			||||||
<form method="POST" class="remote-form">
 | 
					 | 
				
			||||||
    <b>Minimum licenses</b>:<br />
 | 
					 | 
				
			||||||
    {{ csrf_input }}
 | 
					 | 
				
			||||||
    <input type="hidden" name="{{ remote_type }}" value="{{ remote_id }}" />
 | 
					 | 
				
			||||||
    <input type="number" name="minimum_licenses" value="{{ sponsorship_data.minimum_licenses }}" required />
 | 
					 | 
				
			||||||
    <button type="submit" class="support-submit-button">Update</button>
 | 
					 | 
				
			||||||
</form>
 | 
					 | 
				
			||||||
{% endif %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<form method="POST" class="remote-form">
 | 
					<form method="POST" class="remote-form">
 | 
				
			||||||
    <b>Required plan tier for discounts and fixed prices</b>:<br />
 | 
					    <b>Required plan tier for discounts and fixed prices</b>:<br />
 | 
				
			||||||
    <i>Updates will not change any pre-existing plans or scheduled upgrades.</i><br />
 | 
					    <i>Updates will not change any pre-existing plans or scheduled upgrades.</i><br />
 | 
				
			||||||
@@ -62,6 +37,38 @@
 | 
				
			|||||||
    <button type="submit" class="support-submit-button">Update</button>
 | 
					    <button type="submit" class="support-submit-button">Update</button>
 | 
				
			||||||
</form>
 | 
					</form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<form method="POST" class="remote-form">
 | 
				
			||||||
 | 
					    <b>Discount percentage</b>:<br />
 | 
				
			||||||
 | 
					    <i>Needs required plan tier to be set.</i><br />
 | 
				
			||||||
 | 
					    <i>Updates will change pre-existing plans and scheduled upgrades.</i><br />
 | 
				
			||||||
 | 
					    <i>Any prorated licenses for the current billing cycle will be billed at the updated discounted rate.</i><br />
 | 
				
			||||||
 | 
					    {{ csrf_input }}
 | 
				
			||||||
 | 
					    <input type="hidden" name="{{ remote_type }}" value="{{ remote_id }}" />
 | 
				
			||||||
 | 
					    {% if has_fixed_price %}
 | 
				
			||||||
 | 
					    <input type="number" name="discount" value="{{ format_discount(sponsorship_data.default_discount) }}" step="0.01" min="0" max="99.99" disabled />
 | 
				
			||||||
 | 
					    <button type="submit" class="support-submit-button" disabled>Update</button>
 | 
				
			||||||
 | 
					    {% else %}
 | 
				
			||||||
 | 
					    <input type="number" name="discount" value="{{ format_discount(sponsorship_data.default_discount) }}" step="0.01" min="0" max="99.99"
 | 
				
			||||||
 | 
					      {% if sponsorship_data.required_plan_tier %}
 | 
				
			||||||
 | 
					      required
 | 
				
			||||||
 | 
					      {% else %}
 | 
				
			||||||
 | 
					      disabled
 | 
				
			||||||
 | 
					      {% endif %}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    <button type="submit" class="support-submit-button">Update</button>
 | 
				
			||||||
 | 
					    {% endif %}
 | 
				
			||||||
 | 
					</form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% if not has_fixed_price and (sponsorship_data.default_discount or sponsorship_data.minimum_licenses) %}
 | 
				
			||||||
 | 
					<form method="POST" class="remote-form">
 | 
				
			||||||
 | 
					    <b>Minimum licenses</b>:<br />
 | 
				
			||||||
 | 
					    {{ csrf_input }}
 | 
				
			||||||
 | 
					    <input type="hidden" name="{{ remote_type }}" value="{{ remote_id }}" />
 | 
				
			||||||
 | 
					    <input type="number" name="minimum_licenses" value="{{ sponsorship_data.minimum_licenses }}" required />
 | 
				
			||||||
 | 
					    <button type="submit" class="support-submit-button">Update</button>
 | 
				
			||||||
 | 
					</form>
 | 
				
			||||||
 | 
					{% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% if sponsorship_data.sponsorship_pending %}
 | 
					{% if sponsorship_data.sponsorship_pending %}
 | 
				
			||||||
    {% with %}
 | 
					    {% with %}
 | 
				
			||||||
        {% set latest_sponsorship_request = sponsorship_data.latest_sponsorship_request %}
 | 
					        {% set latest_sponsorship_request = sponsorship_data.latest_sponsorship_request %}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user