Skip to content

Policies

components.payment_gateway.subcomponents.merchants.business_logic.policies.merchant_registry

MerchantRegistryPolicy

This class is responsible for keeping the merchant registry up-to-date on incoming payment events.

upsert_merchant_info

upsert_merchant_info(data)

Upsert merchant info based on the incoming payment event data.

If an entry with the merchant ID already exists, update it with the incoming non-None data. Otherwise, create a new entry.

Log all non-None field changes. Unexpected changes (e.g. acquirer ID) are logged as warnings, expected changes (e.g. name) are logged as info.

Source code in components/payment_gateway/subcomponents/merchants/business_logic/policies/merchant_registry.py
@obs.api_call()
def upsert_merchant_info(
    self, data: "TransferNotificationMerchantData"
) -> MerchantInfo | None:
    """
    Upsert merchant info based on the incoming payment event data.

    If an entry with the merchant ID already exists, update it with the incoming non-None data. Otherwise, create a new entry.

    Log all non-None field changes. Unexpected changes (e.g. acquirer ID) are logged as warnings, expected changes (e.g. name) are logged as info.
    """

    if not data.merchantId:
        # Not much we can do without a merchantId
        current_logger.error(
            "No merchant ID found in incoming payment event data",
            data=data,
        )
        return None

    # Fetch existing data to log significant changes
    merchant_info = MerchantInfoModelBroker.find_merchant_info_by_merchant_id(
        current_session,
        merchant_id=data.merchantId,
    )

    # Upsert the existing entry with all non-None fields from the incoming data
    # What to do on existing non-None fields depends on the field type
    params = {}

    # First, fields that we don't expect to change => warning
    if data.acquirerId:
        params["acquirer_id"] = data.acquirerId
        if (
            merchant_info is not None
            and merchant_info.acquirer_id is not None
            and merchant_info.acquirer_id != data.acquirerId
        ):
            current_logger.warn(
                "Acquirer ID changed for merchant %s: %s -> %s",
                data.merchantId,
                merchant_info.acquirer_id,
                data.acquirerId,
            )
    if data.mcc:
        params["mcc"] = data.mcc
        if (
            merchant_info is not None
            and merchant_info.mcc is not None
            and merchant_info.mcc != data.mcc
        ):
            current_logger.warn(
                "MCC changed for merchant %s: %s -> %s",
                data.merchantId,
                merchant_info.mcc,
                data.mcc,
            )

    # Then fields that we may change => info
    if data.name:
        params["name"] = data.name
        if (
            merchant_info is not None
            and merchant_info.name is not None
            and merchant_info.name != data.name
        ):
            current_logger.info(
                "Name changed for merchant %s: %s -> %s",
                data.merchantId,
                merchant_info.name,
                data.name,
            )
    if data.postalCode:
        params["postal_code"] = data.postalCode
        if (
            merchant_info is not None
            and merchant_info.postal_code is not None
            and merchant_info.postal_code != data.postalCode
        ):
            current_logger.info(
                "Postal code changed for merchant %s: %s -> %s",
                data.merchantId,
                merchant_info.postal_code,
                data.postalCode,
            )
    if data.city:
        params["city"] = data.city
        if (
            merchant_info is not None
            and merchant_info.city is not None
            and merchant_info.city != data.city
        ):
            current_logger.info(
                "City changed for merchant %s: %s -> %s",
                data.merchantId,
                merchant_info.city,
                data.city,
            )
    if data.country:
        params["country"] = data.country
        if (
            merchant_info is not None
            and merchant_info.country is not None
            and merchant_info.country != data.country
        ):
            current_logger.info(
                "Country changed for merchant %s: %s -> %s",
                data.merchantId,
                merchant_info.country,
                data.country,
            )

    merchant_info = MerchantInfoModelBroker.upsert_merchant_info(
        current_session,
        merchant_id=data.merchantId,
        **params,
    )

    return _to_merchant_info(merchant_info)