189 lines
6.2 KiB
Python
189 lines
6.2 KiB
Python
#
|
|
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
|
|
#
|
|
|
|
from dataclasses import dataclass
|
|
from typing import List, Union
|
|
|
|
import requests
|
|
from braintree.attribute_getter import AttributeGetter
|
|
from braintree.customer import Customer as BCustomer
|
|
from braintree.discount import Discount as BDiscount
|
|
from braintree.dispute import Dispute as BDispute
|
|
from braintree.merchant_account.merchant_account import MerchantAccount as BMerchantAccount
|
|
from braintree.plan import Plan as BPlan
|
|
from braintree.subscription import Subscription as BSubscription
|
|
from braintree.transaction import Transaction as BTransaction
|
|
from braintree.util.xml_util import XmlUtil
|
|
|
|
from airbyte_cdk.sources.declarative.extractors.record_extractor import RecordExtractor
|
|
from airbyte_cdk.sources.declarative.types import Record
|
|
from airbyte_cdk.sources.declarative.yaml_declarative_source import YamlDeclarativeSource
|
|
from source_braintree.schemas import Customer, Discount, Dispute, MerchantAccount, Plan, Subscription, Transaction
|
|
|
|
|
|
"""
|
|
This file provides the necessary constructs to interpret a provided declarative YAML configuration file into
|
|
source connector.
|
|
|
|
WARNING: Do not modify this file.
|
|
"""
|
|
|
|
|
|
@dataclass
|
|
class BraintreeExtractor(RecordExtractor):
|
|
"""
|
|
Extractor Template for all BrainTree streams.
|
|
"""
|
|
|
|
@staticmethod
|
|
def _extract_as_array(results, attribute):
|
|
if attribute not in results:
|
|
return []
|
|
|
|
value = results[attribute]
|
|
if not isinstance(value, list):
|
|
value = [value]
|
|
return value
|
|
|
|
def _get_json_from_resource(self, resource_obj: Union[AttributeGetter, List[AttributeGetter]]):
|
|
if isinstance(resource_obj, list):
|
|
return [obj if not isinstance(obj, AttributeGetter) else self._get_json_from_resource(obj) for obj in resource_obj]
|
|
obj_dict = resource_obj.__dict__
|
|
result = dict()
|
|
for attr in obj_dict:
|
|
if not attr.startswith("_"):
|
|
if callable(obj_dict[attr]):
|
|
continue
|
|
result[attr] = (
|
|
self._get_json_from_resource(obj_dict[attr]) if isinstance(obj_dict[attr], (AttributeGetter, list)) else obj_dict[attr]
|
|
)
|
|
return result
|
|
|
|
|
|
@dataclass
|
|
class MerchantAccountExtractor(BraintreeExtractor):
|
|
"""
|
|
Extractor for Merchant Accounts stream.
|
|
It parses output XML and finds all `Merchant Account` occurrences in it.
|
|
"""
|
|
|
|
def extract_records(
|
|
self,
|
|
response: requests.Response,
|
|
) -> List[Record]:
|
|
data = XmlUtil.dict_from_xml(response.text)["merchant_accounts"]
|
|
merchant_accounts = self._extract_as_array(data, "merchant_account")
|
|
return [
|
|
MerchantAccount(**self._get_json_from_resource(BMerchantAccount(None, merchant_account))).dict(exclude_unset=True)
|
|
for merchant_account in merchant_accounts
|
|
]
|
|
|
|
|
|
@dataclass
|
|
class CustomerExtractor(BraintreeExtractor):
|
|
"""
|
|
Extractor for Customers stream.
|
|
It parses output XML and finds all `Customer` occurrences in it.
|
|
"""
|
|
|
|
def extract_records(
|
|
self,
|
|
response: requests.Response,
|
|
) -> List[Record]:
|
|
data = XmlUtil.dict_from_xml(response.text)["customers"]
|
|
customers = self._extract_as_array(data, "customer")
|
|
return [Customer(**self._get_json_from_resource(BCustomer(None, customer))).dict(exclude_unset=True) for customer in customers]
|
|
|
|
|
|
@dataclass
|
|
class DiscountExtractor(BraintreeExtractor):
|
|
"""
|
|
Extractor for Discounts stream.
|
|
It parses output XML and finds all `Discount` occurrences in it.
|
|
"""
|
|
|
|
def extract_records(
|
|
self,
|
|
response: requests.Response,
|
|
) -> List[Record]:
|
|
data = XmlUtil.dict_from_xml(response.text)
|
|
discounts = self._extract_as_array(data, "discounts")
|
|
return [Discount(**self._get_json_from_resource(BDiscount(None, discount))).dict(exclude_unset=True) for discount in discounts]
|
|
|
|
|
|
@dataclass
|
|
class TransactionExtractor(BraintreeExtractor):
|
|
"""
|
|
Extractor for Transactions stream.
|
|
It parses output XML and finds all `Transaction` occurrences in it.
|
|
"""
|
|
|
|
def extract_records(
|
|
self,
|
|
response: requests.Response,
|
|
) -> List[Record]:
|
|
data = XmlUtil.dict_from_xml(response.text)["credit_card_transactions"]
|
|
transactions = self._extract_as_array(data, "transaction")
|
|
return [
|
|
Transaction(**self._get_json_from_resource(BTransaction(None, transaction))).dict(exclude_unset=True)
|
|
for transaction in transactions
|
|
]
|
|
|
|
|
|
@dataclass
|
|
class SubscriptionExtractor(BraintreeExtractor):
|
|
"""
|
|
Extractor for Subscriptions stream.
|
|
It parses output XML and finds all `Subscription` occurrences in it.
|
|
"""
|
|
|
|
def extract_records(
|
|
self,
|
|
response: requests.Response,
|
|
) -> List[Record]:
|
|
data = XmlUtil.dict_from_xml(response.text)["subscriptions"]
|
|
subscriptions = self._extract_as_array(data, "subscription")
|
|
return [
|
|
Subscription(**self._get_json_from_resource(BSubscription(None, subscription))).dict(exclude_unset=True)
|
|
for subscription in subscriptions
|
|
]
|
|
|
|
|
|
@dataclass
|
|
class PlanExtractor(BraintreeExtractor):
|
|
"""
|
|
Extractor for Plans stream.
|
|
It parses output XML and finds all `Plan` occurrences in it.
|
|
"""
|
|
|
|
def extract_records(
|
|
self,
|
|
response: requests.Response,
|
|
) -> List[Record]:
|
|
data = XmlUtil.dict_from_xml(response.text)
|
|
plans = self._extract_as_array(data, "plans")
|
|
return [Plan(**self._get_json_from_resource(BPlan(None, plan))).dict(exclude_unset=True) for plan in plans]
|
|
|
|
|
|
@dataclass
|
|
class DisputeExtractor(BraintreeExtractor):
|
|
"""
|
|
Extractor for Disputes stream.
|
|
It parses output XML and finds all `Dispute` occurrences in it.
|
|
"""
|
|
|
|
def extract_records(
|
|
self,
|
|
response: requests.Response,
|
|
) -> List[Record]:
|
|
data = XmlUtil.dict_from_xml(response.text)["disputes"]
|
|
disputes = self._extract_as_array(data, "dispute")
|
|
return [Dispute(**self._get_json_from_resource(BDispute(dispute))).dict(exclude_unset=True) for dispute in disputes]
|
|
|
|
|
|
# Declarative Source
|
|
class SourceBraintree(YamlDeclarativeSource):
|
|
def __init__(self):
|
|
super().__init__(**{"path_to_yaml": "manifest.yaml"})
|