def _stripe_object_to_record(
        cls,
        data: dict,
        current_ids=None,
        pending_relations: list = None,
        stripe_account: str = None,
        api_key=djstripe_settings.STRIPE_SECRET_KEY,
    ) -> Dict:
        """
        This takes an object, as it is formatted in Stripe's current API for our object
        type. In return, it provides a dict. The dict can be used to create a record or
        to update a record

        This function takes care of mapping from one field name to another, converting
        from cents to dollars, converting timestamps, and eliminating unused fields
        (so that an objects.create() call would not fail).

        :param data: the object, as sent by Stripe. Parsed from JSON, into a dict
        :param current_ids: stripe ids of objects that are currently being processed
        :type current_ids: set
        :param pending_relations: list of tuples of relations to be attached post-save
        :param stripe_account: The optional connected account \
            for which this request is being made.
        :return: All the members from the input, translated, mutated, etc
        """
        from .webhooks import WebhookEndpoint

        manipulated_data = cls._manipulate_stripe_object_hook(data)
        if not cls.is_valid_object(manipulated_data):
            object_type = manipulated_data.get("object", "")
            raise ValueError(
                f"Trying to fit {object_type!r} into {cls.__name__!r}. Aborting."
            )

        # By default we put the  raw stripe data in the stripe_data json field
        result = {"stripe_data": data}

        if current_ids is None:
            current_ids = set()

        # Iterate over all the fields that we know are related to Stripe,
        # let each field work its own magic
        ignore_fields = [
            "date_purged",
            "subscriber",
            "stripe_data",
        ]  # XXX: Customer hack

        # get all forward and reverse relations for given cls
        for field in cls._meta.get_fields():
            if field.name.startswith("djstripe_") or field.name in ignore_fields:
                continue

            # todo add support reverse ManyToManyField sync
            if isinstance(
                field, (models.ManyToManyRel, models.ManyToOneRel)
            ) and not isinstance(field, models.OneToOneRel):
                # We don't currently support syncing from
                # reverse side of Many relationship
                continue

            # todo for ManyToManyField one would also need to handle the case of an intermediate model being used
            # todo add support ManyToManyField sync
            if field.many_to_many:
                # We don't currently support syncing ManyToManyField
                continue

            # will work for Forward FK and OneToOneField relations and reverse OneToOneField relations
            if isinstance(field, (models.ForeignKey, models.OneToOneRel)):
                field_data, skip, is_nulled = cls._stripe_object_field_to_foreign_key(
                    field=field,
                    manipulated_data=manipulated_data,
                    current_ids=current_ids,
                    pending_relations=pending_relations,
                    stripe_account=stripe_account,
                    api_key=api_key,
                )

                if skip and not is_nulled:
                    continue
            else:
                if hasattr(field, "stripe_to_db"):
                    field_data = field.stripe_to_db(manipulated_data)
                else:
                    field_data = manipulated_data.get(field.name)

                if (
                    isinstance(field, (models.CharField, models.TextField))
                    and field_data is None
                ):
                    # do not add empty secret field for WebhookEndpoint model
                    # as stripe does not return the secret except for the CREATE call
                    if cls is WebhookEndpoint and field.name == "secret":
                        continue
                    else:
                        # TODO - this applies to StripeEnumField as well, since it
                        #  sub-classes CharField, is that intentional?
                        field_data = ""

            result[field.name] = field_data

        # For all objects other than the account object itself, get the API key
        # attached to the request, and get the matching Account for that key.
        owner_account = cls._find_owner_account(data, api_key=api_key)
        if owner_account:
            result["djstripe_owner_account"] = owner_account

        return result

        This takes an object, as it is formatted in Stripe's current API for our object
        type. In return, it provides a dict. The dict can be used to create a record or
        to update a record

        This function takes care of mapping from one field name to another, converting
        from cents to dollars, converting timestamps, and eliminating unused fields
        (so that an objects.create() call would not fail).

        :param data: the object, as sent by Stripe. Parsed from JSON, into a dict
        :param current_ids: stripe ids of objects that are currently being processed
        :type current_ids: set
        :param pending_relations: list of tuples of relations to be attached post-save
        :param stripe_account: The optional connected account             for which this request is being made.
        :return: All the members from the input, translated, mutated, etc
        
djstripe/models/base.py