Skip to content

Actions

components.payment_gateway.subcomponents.rules.business_logic.actions.expense_limit_rule_actions

ExpenseLimitRuleActions

ExpenseLimitRuleActions(adyen_client)

This class contains all the actions related to expense limit rules.

Implements the following Nullable patterns: - Nullables: https://www.jamesshore.com/v2/projects/nullables/testing-without-mocks#nullables ⧉ - Parameterless instantiation: https://www.jamesshore.com/v2/projects/nullables/testing-without-mocks#instantiation ⧉

Tags
Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/expense_limit_rule_actions.py
def __init__(self, adyen_client: "AdyenTransactionRulesApiClient | None") -> None:
    self._adyen_client = adyen_client

adyen_client property

adyen_client

Ensures the Adyen client is available when accessing it.

create classmethod

create()

Normal factory

Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/expense_limit_rule_actions.py
@classmethod
def create(cls) -> "ExpenseLimitRuleActions":
    """Normal factory"""
    from shared.services.adyen.clients.adyen_transaction_rules_api_client import (
        AdyenTransactionRulesApiClient,
    )
    from shared.services.adyen.clients.exceptions import (
        AdyenClientMissingCredentialsException,
    )

    try:
        adyen_client = AdyenTransactionRulesApiClient.create()
    except AdyenClientMissingCredentialsException:
        adyen_client = None
    return cls(adyen_client)

create_expense_limit_rule

create_expense_limit_rule(
    session,
    /,
    description,
    reference,
    card_id,
    amount,
    currency,
    period,
    criteria,
    first_day=None,
    is_active=False,
    start=None,
    end=None,
)

Create an expense limit rule for a card.

Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/expense_limit_rule_actions.py
def create_expense_limit_rule(
    self,
    session: Session,
    /,
    description: str,
    reference: str,
    card_id: CardId,
    amount: int,
    currency: CurrencyCode,
    period: ExpenseLimitPeriod,
    criteria: list[RuleCriterion],
    first_day: int | None = None,
    is_active: bool = False,
    start: datetime | None = None,
    end: datetime | None = None,
) -> ExpenseLimitRuleId:
    """
    Create an expense limit rule for a card.
    """
    from components.payment_gateway.subcomponents.rules.adapters.adyen.helpers import (
        expense_limit_rule_to_transaction_rule_info,
    )

    with raise_if_card_not_found(card_id):
        card = CardModelBroker.get_card(session, id=card_id)

    raise_on_invalid_validity_period(start, end)

    # # 1. Create Adyen request payload from our model
    transaction_rule_info = expense_limit_rule_to_transaction_rule_info(
        description=description,
        reference=reference,
        external_card_id=card.external_id,
        amount=amount,
        currency=currency,
        period=period,
        criteria=criteria,
        first_day=first_day,
        is_active=is_active,
        start=start,
        end=end,
    )

    # # 2. Call Adyen API
    transaction_rule = self.adyen_client.create_transaction_rule(
        request=transaction_rule_info,
        idempotency_key=None,  # TODO use this for retries
    )

    # 3. Create our ExpenseLimit entity from API result
    expense_limit_rule = ExpenseLimitRuleModelBroker.create_expense_limit_rule(
        session,
        description=transaction_rule.description,
        reference=transaction_rule.reference,
        card_id=card_id,
        amount=amount,
        currency=currency,
        period=period,
        first_day=first_day,
        criteria=criteria,
        is_active=is_active,
        start=datetime.fromisoformat(transaction_rule.startDate)
        if transaction_rule.startDate
        else None,
        end=datetime.fromisoformat(transaction_rule.endDate)
        if transaction_rule.endDate
        else None,
        external_id=mandatory(transaction_rule.id),
    )
    return ExpenseLimitRuleId(expense_limit_rule.id)

create_null classmethod

create_null(track_adyen_requests=None)

Null factory

Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/expense_limit_rule_actions.py
@classmethod
def create_null(
    cls,
    track_adyen_requests: list[tuple[str, dict, dict]] | None = None,  # type: ignore[type-arg]
) -> "ExpenseLimitRuleActions":
    """Null factory"""
    from shared.services.adyen.clients.adyen_transaction_rules_api_client import (
        AdyenTransactionRulesApiClient,
    )

    return cls(
        AdyenTransactionRulesApiClient.create_null(
            track_requests=track_adyen_requests
        )
    )

set_expense_limit_rule_status

set_expense_limit_rule_status(session, /, id, is_active)

Activate or deactivate an expense limit rule.

Activating a rule will also set the start date to the current date.

Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/expense_limit_rule_actions.py
def set_expense_limit_rule_status(
    self,
    session: Session,
    /,
    id: ExpenseLimitRuleId,
    is_active: bool,
) -> None:
    """
    Activate or deactivate an expense limit rule.

    Activating a rule will also set the start date to the current date.
    """
    from components.payment_gateway.subcomponents.rules.adapters.adyen.helpers import (
        expense_limit_rule_to_transaction_rule_info,
    )

    with raise_if_expense_limit_rule_not_found(id):
        expense_limit_rule = ExpenseLimitRuleModelBroker.get_expense_limit_rule(
            session, id=id
        )

    raise_on_terminated_expense_limit_rule(expense_limit_rule)

    # The Adyen API has some non-optional fields unfortunately, so we can't just update what we need
    # The request object requires description, reference, external_account_id (for entityKey) and criteria (for ruleRestrictions)
    # So to be extra safe we also send everything but the start/end dates as we don't know how Adyen handles partial updates
    transaction_rule_info = expense_limit_rule_to_transaction_rule_info(
        description=expense_limit_rule.description,
        reference=expense_limit_rule.reference,
        external_card_id=expense_limit_rule.card.external_id,  # type: ignore[union-attr]
        amount=expense_limit_rule.amount,
        currency=expense_limit_rule.currency,
        period=expense_limit_rule.period,
        criteria=_model_to_rule_criteria(expense_limit_rule.criteria),
        first_day=expense_limit_rule.first_day,
        is_active=is_active,
    )
    transaction_rule = self.adyen_client.update_transaction_rule(
        expense_limit_rule.external_id,
        request=transaction_rule_info,
        idempotency_key=None,  # TODO use this for retries
    )

    # Update validity period from API result, as Adyen will update either start or end date on status change
    # See https://docs.adyen.com/api-explorer/balanceplatform/2/patch/transactionRules/(transactionRuleId)
    ExpenseLimitRuleModelBroker.update_expense_limit_rule(
        session,
        id=id,
        is_active=is_active,
        start=datetime.fromisoformat(transaction_rule.startDate)
        if transaction_rule.startDate
        else None,
        end=datetime.fromisoformat(transaction_rule.endDate)
        if transaction_rule.endDate
        else None,
    )

set_expense_limit_rule_validity_period

set_expense_limit_rule_validity_period(
    session, /, id, start=None, end=None
)

Set an expense limit rule validity period.

Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/expense_limit_rule_actions.py
def set_expense_limit_rule_validity_period(
    self,
    session: Session,
    /,
    id: ExpenseLimitRuleId,
    start: datetime | None = None,
    end: datetime | None = None,
) -> None:
    """
    Set an expense limit rule validity period.
    """
    from components.payment_gateway.subcomponents.rules.adapters.adyen.helpers import (
        expense_limit_rule_to_transaction_rule_info,
    )

    with raise_if_expense_limit_rule_not_found(id):
        expense_limit_rule = ExpenseLimitRuleModelBroker.get_expense_limit_rule(
            session, id=id
        )

    raise_on_terminated_expense_limit_rule(expense_limit_rule)
    raise_on_invalid_validity_period(start, end)

    # The Adyen API has some non-optional fields unfortunately, so we can't just update what we need
    # The request object requires description, reference, external_account_id (for entityKey) and criteria (for ruleRestrictions)
    # So to be extra safe we also send everything but the status as we don't know how Adyen handles partial updates
    transaction_rule_info = expense_limit_rule_to_transaction_rule_info(
        description=expense_limit_rule.description,
        reference=expense_limit_rule.reference,
        external_card_id=expense_limit_rule.card.external_id,  # type: ignore[union-attr]
        amount=expense_limit_rule.amount,
        currency=expense_limit_rule.currency,
        period=expense_limit_rule.period,
        criteria=_model_to_rule_criteria(expense_limit_rule.criteria),
        first_day=expense_limit_rule.first_day,
        is_active=expense_limit_rule.is_active,
        start=start,
        end=end,
    )
    transaction_rule = self.adyen_client.update_transaction_rule(
        expense_limit_rule.external_id,
        request=transaction_rule_info,
        idempotency_key=None,  # TODO use this for retries
    )

    # Update entity dates from API result
    ExpenseLimitRuleModelBroker.update_expense_limit_rule(
        session,
        id=id,
        start=datetime.fromisoformat(transaction_rule.startDate)
        if transaction_rule.startDate
        else None,
        end=datetime.fromisoformat(transaction_rule.endDate)
        if transaction_rule.endDate
        else None,
    )

terminate_expense_limit_rule

terminate_expense_limit_rule(session, /, id)

Terminate an expense limit rule.

The operation is idempotent, i.e. it has no effect on already terminated entities.

Rules in terminal state cannot be modified or used anymore. Any attempt to use or retrieve a terminated expense limit rule will raise an ExpenseLimitRuleTerminatedException.

Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/expense_limit_rule_actions.py
def terminate_expense_limit_rule(
    self,
    session: Session,
    /,
    id: ExpenseLimitRuleId,
) -> None:
    """
    Terminate an expense limit rule.

    The operation is idempotent, i.e. it has no effect on already terminated
    entities.

    Rules in terminal state cannot be modified or used anymore. Any attempt
    to use or retrieve a terminated expense limit rule will raise an
    `ExpenseLimitRuleTerminatedException`.
    """
    from components.payment_gateway.subcomponents.rules.adapters.adyen.helpers import (
        expense_limit_rule_to_transaction_rule_info,
    )

    with raise_if_expense_limit_rule_not_found(id):
        expense_limit_rule = ExpenseLimitRuleModelBroker.get_expense_limit_rule(
            session, id=id
        )

    if expense_limit_rule.is_active:
        # Terminating an expense limit should deactivate it at Adyen
        # The Adyen API has some non-optional fields unfortunately, so we can't just update what we need
        # The request object requires description, reference, external_account_id (for entityKey) and criteria (for ruleRestrictions)
        # So to be extra safe we also send everything but the start/end dates as we don't know how Adyen handles partial updates
        transaction_rule_info = expense_limit_rule_to_transaction_rule_info(
            description=expense_limit_rule.description,
            reference=expense_limit_rule.reference,
            external_card_id=expense_limit_rule.card.external_id,  # type: ignore[union-attr]
            amount=expense_limit_rule.amount,
            currency=expense_limit_rule.currency,
            period=expense_limit_rule.period,
            criteria=_model_to_rule_criteria(expense_limit_rule.criteria),
            first_day=expense_limit_rule.first_day,
            is_active=False,
        )
        self.adyen_client.update_transaction_rule(
            expense_limit_rule.external_id,
            request=transaction_rule_info,
            idempotency_key=None,  # TODO use this for retries
        )
        ExpenseLimitRuleModelBroker.update_expense_limit_rule(
            session,
            id=id,
            is_active=False,
        )

    if not expense_limit_rule.is_terminated:
        # Terminating an expense limit should set its termination date on first call only
        ExpenseLimitRuleModelBroker.terminate_expense_limit_rule(session, id=id)

update_expense_limit_rule_amount

update_expense_limit_rule_amount(session, /, id, amount)

Update the amount of an expense limit rule.

This operation can be safely performed in the middle of a validity period. The new limit will be applied to all future transactions.

Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/expense_limit_rule_actions.py
def update_expense_limit_rule_amount(
    self,
    session: Session,
    /,
    id: ExpenseLimitRuleId,
    amount: int,
) -> None:
    """
    Update the amount of an expense limit rule.

    This operation can be safely performed in the middle of a validity
    period. The new limit will be applied to all future transactions.
    """
    from components.payment_gateway.subcomponents.rules.adapters.adyen.helpers import (
        expense_limit_rule_to_transaction_rule_info,
    )

    with raise_if_expense_limit_rule_not_found(id):
        expense_limit_rule = ExpenseLimitRuleModelBroker.get_expense_limit_rule(
            session, id=id
        )

    raise_on_terminated_expense_limit_rule(expense_limit_rule)

    # The Adyen API has some non-optional fields unfortunately, so we can't just update what we need
    # The request object requires description, reference, external_account_id (for entityKey) and criteria (for ruleRestrictions)
    # So to be extra safe we also send everything but the status/start/end dates as we don't know how Adyen handles partial updates
    transaction_rule_info = expense_limit_rule_to_transaction_rule_info(
        description=expense_limit_rule.description,
        reference=expense_limit_rule.reference,
        external_card_id=expense_limit_rule.card.external_id,  # type: ignore[union-attr]
        amount=amount,
        currency=expense_limit_rule.currency,
        period=expense_limit_rule.period,
        criteria=_model_to_rule_criteria(expense_limit_rule.criteria),
        first_day=expense_limit_rule.first_day,
        is_active=expense_limit_rule.is_active,
    )
    self.adyen_client.update_transaction_rule(
        expense_limit_rule.external_id,
        request=transaction_rule_info,
        idempotency_key=None,  # TODO use this for retries
    )
    ExpenseLimitRuleModelBroker.update_expense_limit_rule(
        session,
        id=id,
        amount=amount,
    )

update_expense_limit_rule_criteria

update_expense_limit_rule_criteria(
    session, /, id, criteria
)

Update the criteria of an expense limit rule.

Warning: we don't know yet how this will behave when performed in the middle of a validity period with respect to the cumulated amount so far. Use with caution.

Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/expense_limit_rule_actions.py
def update_expense_limit_rule_criteria(
    self,
    session: Session,
    /,
    id: ExpenseLimitRuleId,
    criteria: list[RuleCriterion],
) -> None:
    """
    Update the criteria of an expense limit rule.

    Warning: we don't know yet how this will behave when performed in the
    middle of a validity period with respect to the cumulated amount so far.
    Use with caution.
    """
    from components.payment_gateway.subcomponents.rules.adapters.adyen.helpers import (
        expense_limit_rule_to_transaction_rule_info,
    )

    with raise_if_expense_limit_rule_not_found(id):
        expense_limit_rule = ExpenseLimitRuleModelBroker.get_expense_limit_rule(
            session, id=id
        )

    raise_on_terminated_expense_limit_rule(expense_limit_rule)

    # The Adyen API has some non-optional fields unfortunately, so we can't just update what we need
    # The request object requires description, reference, external_account_id (for entityKey) and criteria (for ruleRestrictions)
    # So to be extra safe we also send everything but the status/start/end dates as we don't know how Adyen handles partial updates
    transaction_rule_info = expense_limit_rule_to_transaction_rule_info(
        description=expense_limit_rule.description,
        reference=expense_limit_rule.reference,
        external_card_id=expense_limit_rule.card.external_id,  # type: ignore[union-attr]
        amount=expense_limit_rule.amount,
        currency=expense_limit_rule.currency,
        period=expense_limit_rule.period,
        criteria=criteria,
        first_day=expense_limit_rule.first_day,
        is_active=expense_limit_rule.is_active,
    )
    self.adyen_client.update_transaction_rule(
        expense_limit_rule.external_id,
        request=transaction_rule_info,
        idempotency_key=None,  # TODO use this for retries
    )
    ExpenseLimitRuleModelBroker.update_expense_limit_rule(
        session,
        id=id,
        criteria=criteria,
    )

components.payment_gateway.subcomponents.rules.business_logic.actions.usage_restriction_rule_actions

UsageRestrictionRuleActions

UsageRestrictionRuleActions(adyen_client)

This class contains all the actions related to usage restriction rules.

Implements the following Nullable patterns: - Nullables: https://www.jamesshore.com/v2/projects/nullables/testing-without-mocks#nullables ⧉ - Parameterless instantiation: https://www.jamesshore.com/v2/projects/nullables/testing-without-mocks#instantiation ⧉

Tags
Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/usage_restriction_rule_actions.py
def __init__(self, adyen_client: "AdyenTransactionRulesApiClient | None") -> None:
    self._adyen_client = adyen_client

adyen_client property

adyen_client

Ensures the Adyen client is available when accessing it.

create classmethod

create()

Normal factory

Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/usage_restriction_rule_actions.py
@classmethod
def create(cls) -> "UsageRestrictionRuleActions":
    """Normal factory"""
    from shared.services.adyen.clients.adyen_transaction_rules_api_client import (
        AdyenTransactionRulesApiClient,
    )
    from shared.services.adyen.clients.exceptions import (
        AdyenClientMissingCredentialsException,
    )

    try:
        adyen_client = AdyenTransactionRulesApiClient.create()
    except AdyenClientMissingCredentialsException:
        adyen_client = None
    return cls(adyen_client)

create_null classmethod

create_null(track_adyen_requests=None)

Null factory

Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/usage_restriction_rule_actions.py
@classmethod
def create_null(
    cls,
    track_adyen_requests: list[tuple[str, dict, dict]] | None = None,  # type: ignore[type-arg]
) -> "UsageRestrictionRuleActions":
    """Null factory"""
    from shared.services.adyen.clients.adyen_transaction_rules_api_client import (
        AdyenTransactionRulesApiClient,
    )

    return cls(
        AdyenTransactionRulesApiClient.create_null(
            track_requests=track_adyen_requests
        )
    )

create_usage_restriction_rule

create_usage_restriction_rule(
    session,
    /,
    description,
    reference,
    account_id,
    criteria,
    is_active=False,
    start=None,
    end=None,
)

Create a usage restriction rule for an account.

Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/usage_restriction_rule_actions.py
def create_usage_restriction_rule(
    self,
    session: Session,
    /,
    description: str,
    reference: str,
    account_id: AccountId,
    criteria: list[RuleCriterion],
    is_active: bool = False,
    start: datetime | None = None,
    end: datetime | None = None,
) -> UsageRestrictionRuleId:
    """
    Create a usage restriction rule for an account.
    """
    from components.payment_gateway.subcomponents.rules.adapters.adyen.helpers import (
        usage_restriction_rule_to_transaction_rule_info,
    )

    with raise_if_account_not_found(account_id):
        account = AccountModelBroker.get_account(session, id=account_id)

    raise_on_invalid_validity_period(start, end)

    # # 1. Create Adyen request payload from our model
    transaction_rule_info = usage_restriction_rule_to_transaction_rule_info(
        description=description,
        reference=reference,
        external_account_id=account.external_id,
        criteria=criteria,
        is_active=is_active,
        start=start,
        end=end,
    )

    # # 2. Call Adyen API
    transaction_rule = self.adyen_client.create_transaction_rule(
        request=transaction_rule_info,
        idempotency_key=None,  # TODO use this for retries
    )

    # 3. Create our UsageRestriction entity from API result
    usage_restriction_rule = (
        UsageRestrictionRuleModelBroker.create_usage_restriction_rule(
            session,
            description=transaction_rule.description,
            reference=transaction_rule.reference,
            account_id=account_id,
            criteria=criteria,
            is_active=is_active,
            start=datetime.fromisoformat(transaction_rule.startDate)
            if transaction_rule.startDate
            else None,
            end=datetime.fromisoformat(transaction_rule.endDate)
            if transaction_rule.endDate
            else None,
            external_id=mandatory(transaction_rule.id),
        )
    )
    return UsageRestrictionRuleId(usage_restriction_rule.id)

set_usage_restriction_rule_status

set_usage_restriction_rule_status(
    session, /, id, is_active
)

Activate or deactivate a usage restriction rule.

Activating a rule will also set the start date to the current date.

Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/usage_restriction_rule_actions.py
def set_usage_restriction_rule_status(
    self,
    session: Session,
    /,
    id: UsageRestrictionRuleId,
    is_active: bool,
) -> None:
    """
    Activate or deactivate a usage restriction rule.

    Activating a rule will also set the start date to the current date.
    """
    from components.payment_gateway.subcomponents.rules.adapters.adyen.helpers import (
        usage_restriction_rule_to_transaction_rule_info,
    )

    with raise_if_usage_restriction_rule_not_found(id):
        usage_restriction_rule = (
            UsageRestrictionRuleModelBroker.get_usage_restriction_rule(
                session, id=id
            )
        )

    raise_on_terminated_usage_restriction_rule(usage_restriction_rule)

    # The Adyen API has some non-optional fields unfortunately, so we can't just update what we need
    # The request object requires description, reference, external_account_id (for entityKey) and criteria (for ruleRestrictions)
    # So to be extra safe we also send everything but the start/end dates as we don't know how Adyen handles partial updates
    transaction_rule_info = usage_restriction_rule_to_transaction_rule_info(
        description=usage_restriction_rule.description,
        reference=usage_restriction_rule.reference,
        external_account_id=usage_restriction_rule.account.external_id,  # type: ignore[union-attr]
        criteria=_model_to_rule_criteria(usage_restriction_rule.criteria),
        is_active=is_active,
    )
    transaction_rule = self.adyen_client.update_transaction_rule(
        usage_restriction_rule.external_id,
        request=transaction_rule_info,
        idempotency_key=None,  # TODO use this for retries
    )

    # Update validity period from API result, as Adyen will update either start or end date on status change
    # See https://docs.adyen.com/api-explorer/balanceplatform/2/patch/transactionRules/(transactionRuleId)
    UsageRestrictionRuleModelBroker.update_usage_restriction_rule(
        session,
        id=id,
        is_active=is_active,
        start=datetime.fromisoformat(transaction_rule.startDate)
        if transaction_rule.startDate
        else None,
        end=datetime.fromisoformat(transaction_rule.endDate)
        if transaction_rule.endDate
        else None,
    )

set_usage_restriction_rule_validity_period

set_usage_restriction_rule_validity_period(
    session, /, id, start=None, end=None
)

Set a usage restriction rule validity period.

Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/usage_restriction_rule_actions.py
def set_usage_restriction_rule_validity_period(
    self,
    session: Session,
    /,
    id: UsageRestrictionRuleId,
    start: datetime | None = None,
    end: datetime | None = None,
) -> None:
    """
    Set a usage restriction rule validity period.
    """
    from components.payment_gateway.subcomponents.rules.adapters.adyen.helpers import (
        usage_restriction_rule_to_transaction_rule_info,
    )

    with raise_if_usage_restriction_rule_not_found(id):
        usage_restriction_rule = (
            UsageRestrictionRuleModelBroker.get_usage_restriction_rule(
                session, id=id
            )
        )

    raise_on_terminated_usage_restriction_rule(usage_restriction_rule)
    raise_on_invalid_validity_period(start, end)

    # The Adyen API has some non-optional fields unfortunately, so we can't just update what we need
    # The request object requires description, reference, external_account_id (for entityKey) and criteria (for ruleRestrictions)
    # So to be extra safe we also send everything but the status as we don't know how Adyen handles partial updates
    transaction_rule_info = usage_restriction_rule_to_transaction_rule_info(
        description=usage_restriction_rule.description,
        reference=usage_restriction_rule.reference,
        external_account_id=usage_restriction_rule.account.external_id,  # type: ignore[union-attr]
        criteria=_model_to_rule_criteria(usage_restriction_rule.criteria),
        start=start,
        end=end,
    )
    transaction_rule = self.adyen_client.update_transaction_rule(
        usage_restriction_rule.external_id,
        request=transaction_rule_info,
        idempotency_key=None,  # TODO use this for retries
    )

    # Update entity dates from API result
    UsageRestrictionRuleModelBroker.update_usage_restriction_rule(
        session,
        id=id,
        start=datetime.fromisoformat(transaction_rule.startDate)
        if transaction_rule.startDate
        else None,
        end=datetime.fromisoformat(transaction_rule.endDate)
        if transaction_rule.endDate
        else None,
    )

terminate_usage_restriction_rule

terminate_usage_restriction_rule(session, /, id)

Terminate a usage restriction rule.

The operation is idempotent, i.e. it has no effect on already terminated entities.

Rules in terminal state cannot be modified or used anymore. Any attempt to use or retrieve a terminated usage restriction rule will raise a UsageRestrictionRuleTerminatedException.

Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/usage_restriction_rule_actions.py
def terminate_usage_restriction_rule(
    self,
    session: Session,
    /,
    id: UsageRestrictionRuleId,
) -> None:
    """
    Terminate a usage restriction rule.

    The operation is idempotent, i.e. it has no effect on already terminated
    entities.

    Rules in terminal state cannot be modified or used anymore. Any attempt
    to use or retrieve a terminated usage restriction rule will raise a
    `UsageRestrictionRuleTerminatedException`.
    """
    from components.payment_gateway.subcomponents.rules.adapters.adyen.helpers import (
        usage_restriction_rule_to_transaction_rule_info,
    )

    with raise_if_usage_restriction_rule_not_found(id):
        usage_restriction_rule = (
            UsageRestrictionRuleModelBroker.get_usage_restriction_rule(
                session, id=id
            )
        )

    if usage_restriction_rule.is_active:
        # Terminating a usage restriction should deactivate it at Adyen
        # The Adyen API has some non-optional fields unfortunately, so we can't just update what we need
        # The request object requires description, reference, external_account_id (for entityKey) and criteria (for ruleRestrictions)
        # So to be extra safe we also send everything but the start/end dates as we don't know how Adyen handles partial updates
        transaction_rule_info = usage_restriction_rule_to_transaction_rule_info(
            description=usage_restriction_rule.description,
            reference=usage_restriction_rule.reference,
            external_account_id=usage_restriction_rule.account.external_id,  # type: ignore[union-attr]
            criteria=_model_to_rule_criteria(usage_restriction_rule.criteria),
            is_active=False,
        )
        self.adyen_client.update_transaction_rule(
            usage_restriction_rule.external_id,
            request=transaction_rule_info,
            idempotency_key=None,  # TODO use this for retries
        )
        UsageRestrictionRuleModelBroker.update_usage_restriction_rule(
            session,
            id=id,
            is_active=False,
        )

    if not usage_restriction_rule.is_terminated:
        # Terminating a usage restriction should set its termination date on first call only
        UsageRestrictionRuleModelBroker.terminate_usage_restriction_rule(
            session, id=id
        )

update_usage_restriction_rule_criteria

update_usage_restriction_rule_criteria(
    session, /, id, criteria
)

Update the criteria of a usage restriction rule.

Source code in components/payment_gateway/subcomponents/rules/business_logic/actions/usage_restriction_rule_actions.py
def update_usage_restriction_rule_criteria(
    self,
    session: Session,
    /,
    id: UsageRestrictionRuleId,
    criteria: list[RuleCriterion],
) -> None:
    """
    Update the criteria of a usage restriction rule.
    """
    from components.payment_gateway.subcomponents.rules.adapters.adyen.helpers import (
        usage_restriction_rule_to_transaction_rule_info,
    )

    with raise_if_usage_restriction_rule_not_found(id):
        usage_restriction_rule = (
            UsageRestrictionRuleModelBroker.get_usage_restriction_rule(
                session, id=id
            )
        )

    raise_on_terminated_usage_restriction_rule(usage_restriction_rule)

    # The Adyen API has some non-optional fields unfortunately, so we can't just update what we need
    # The request object requires description, reference, external_account_id (for entityKey) and criteria (for ruleRestrictions)
    # So to be extra safe we also send everything but the start/end dates as we don't know how Adyen handles partial updates
    transaction_rule_info = usage_restriction_rule_to_transaction_rule_info(
        description=usage_restriction_rule.description,
        reference=usage_restriction_rule.reference,
        external_account_id=usage_restriction_rule.account.external_id,  # type: ignore[union-attr]
        criteria=criteria,
    )
    self.adyen_client.update_transaction_rule(
        usage_restriction_rule.external_id,
        request=transaction_rule_info,
        idempotency_key=None,  # TODO use this for retries
    )
    UsageRestrictionRuleModelBroker.update_usage_restriction_rule(
        session,
        id=id,
        criteria=criteria,
    )