def timestamp_from_datetime(dt):
    """
    Compute timestamp from a datetime object that could be timezone aware
    or unaware.
    """
    try:
        utc_dt = dt.astimezone(pytz.utc)
    except ValueError:
        utc_dt = dt.replace(tzinfo=pytz.utc)
    return timegm(utc_dt.timetuple()) def timestamp_from_date(date):
    epoch = datetime.date(1970, 1, 1)
    diff = date - epoch
    return diff.days * 24 * 3600 + diff.seconds class Money(object):
    __hash__ = None

    def __init__(self, amount="0", currency=None):
        try:
            self.amount = decimal.Decimal(amount)
        except decimal.InvalidOperation:
            raise ValueError("amount value could not be converted to "
                             "Decimal(): '{}'".format(amount))
        self.currency = currency

    def __repr__(self):
        return "{} {}".format(self.currency, self.amount)

    def __str__(self):
        return force_text("{} {:,.2f}".format(self.currency, self.amount))

    def __lt__(self, other):
        if isinstance(other, Money):
            if other.currency != self.currency:
                raise CurrencyMismatch(self.currency, other.currency, '<')
            other = other.amount
        return self.amount < other

    def __le__(self, other):
        if isinstance(other, Money):
            if other.currency != self.currency:
                raise CurrencyMismatch(self.currency, other.currency, '<=')
            other = other.amount
        return self.amount <= other

    def __eq__(self, other):
        if isinstance(other, Money):
            return ((self.amount == other.amount) and
                    (self.currency == other.currency))
        return False

    def __ne__(self, other):
        return not self == other

    def __gt__(self, other):
        if isinstance(other, Money):
            if other.currency != self.currency:
                raise CurrencyMismatch(self.currency, other.currency, '>')
            other = other.amount
        return self.amount > other

    def __ge__(self, other):
        if isinstance(other, Money):
            if other.currency != self.currency:
                raise CurrencyMismatch(self.currency, other.currency, '>=')
            other = other.amount
        return self.amount >= other

    def __bool__(self):
        return bool(self.amount)

    def __add__(self, other):
        if isinstance(other, Money):
            if other.currency != self.currency:
                raise CurrencyMismatch(self.currency, other.currency, '+')
            other = other.amount
        amount = self.amount + other
        return self.__class__(amount, self.currency)

    def __radd__(self, other):
        return self.__add__(other)

    def __sub__(self, other):
        if isinstance(other, Money):
            if other.currency != self.currency:
                raise CurrencyMismatch(self.currency, other.currency, '-')
            other = other.amount
        amount = self.amount - other
        return self.__class__(amount, self.currency)

    def __rsub__(self, other):
        return (-self).__add__(other)

    def __mul__(self, other):
        if isinstance(other, Money):
            raise TypeError("multiplication is unsupported between "
                            "two money objects")
        amount = self.amount * other
        return self.__class__(amount, self.currency)

    def __rmul__(self, other):
        return self.__mul__(other)

    def __truediv__(self, other):
        if isinstance(other, Money):
            if other.currency != self.currency:
                raise CurrencyMismatch(self.currency, other.currency, '/')

            if other.amount == 0:
                raise ZeroDivisionError()

            return self.amount / other.amount

        if other == 0:
            raise ZeroDivisionError()

        amount = self.amount / other

        return self.__class__(amount, self.currency)

    def __floordiv__(self, other):
        if isinstance(other, Money):
            if other.currency != self.currency:
                raise CurrencyMismatch(self.currency, other.currency, '//')

            if other.amount == 0:
                raise ZeroDivisionError()
            return self.amount // other.amount

        if other == 0:
            raise ZeroDivisionError()

        amount = self.amount // other
        return self.__class__(amount, self.currency)

    def __mod__(self, other):
        if isinstance(other, Money):
            raise TypeError("modulo is unsupported between two '{}' "
                            "objects".format(self.__class__.__name__))
        if other == 0:
            raise ZeroDivisionError()

        amount = self.amount % other
        return self.__class__(amount, self.currency)

    def __divmod__(self, other):
        if isinstance(other, Money):
            if other.currency != self.currency:
                raise CurrencyMismatch(self.currency, other.currency, 'divmod')

            if other.amount == 0:
                raise ZeroDivisionError()

            return divmod(self.amount, other.amount)

        if other == 0:
            raise ZeroDivisionError()

        whole, remainder = divmod(self.amount, other)

        return (self.__class__(whole, self.currency),
                self.__class__(remainder, self.currency))

    def __pow__(self, other):
        if isinstance(other, Money):
            raise TypeError("power operator is unsupported between two '{}' "
                            "objects".format(self.__class__.__name__))
        amount = self.amount ** other
        return self.__class__(amount, self.currency)

    def __neg__(self):
        return self.__class__(-self.amount, self.currency)

    def __pos__(self):
        return self.__class__(+self.amount, self.currency)

    def __abs__(self):
        return self.__class__(abs(self.amount), self.currency)

    def __int__(self):
        return int(self.amount)

    def __float__(self):
        return float(self.amount)

    def __round__(self, ndigits=0):
        return self.__class__(round(self.amount, ndigits), self.currency) class DebitedBankAccount(object):
    def __init__(self, owner_name=None, account_number=None, iban=None,
                 bic=None, type=None, country=None):
        self.owner_name = owner_name
        self.account_number = account_number
        self.iban = iban
        self.bic = bic
        self.type = type
        self.country = country

    def __str__(self):
        return 'DebitedBankAccount: %s' % \
               (self.owner_name, self.account_number, self.iban, self.bic, self.type, self.country)

    def __eq__(self, other):
        if isinstance(other, DebitedBankAccount):
            stat = (self.owner_name == other.owner_name and
                    self.account_number == other.account_number and
                    self.iban == other.iban and
                    self.bic == other.bic and
                    self.type == other.type and
                    self.country == other.country)

            return stat
        return False class Address(object):
    def __init__(self, address_line_1=None, address_line_2=None, city=None, region=None,
                 postal_code=None, country=None):
        self.address_line_1 = address_line_1
        self.address_line_2 = address_line_2
        self.city = city
        self.region = region
        self.postal_code = postal_code
        self.country = country

    def __str__(self):
        return 'Address: %s, %s , %s, %s, %s , %s' % \
               (self.address_line_1, self.address_line_2, self.postal_code, self.city, self.region, self.country)

    def __eq__(self, other):
        if isinstance(other, Address):
            stat = ((self.address_line_1 == other.address_line_1) and
                    (self.address_line_2 == other.address_line_2) and
                    (self.postal_code == other.postal_code) and
                    (self.city == other.city) and
                    (self.region == other.region) and
                    (self.country == other.country))
            return stat
        return False

    def to_api_json(self):
        return {
            "AddressLine1": self.address_line_1,
            "AddressLine2": self.address_line_2,
            "PostalCode": self.postal_code,
            "City": self.city,
            "Region": self.region,
            "Country": self.country,
        } class ShippingAddress(object):
    def __init__(self, recipient_name=None, address=None):
        self.recipient_name = recipient_name
        self.address = address

    def __str__(self):
        return 'Recipient name: %s, %s' % (self.recipient_name, self.address)

    def __eq__(self, other):
        if isinstance(other, ShippingAddress):
            return self.recipient_name == other.recipient_name and self.address == other.address
        return False class Reason(object):
    def __init__(self, type=None, message=None):
        self.type = type
        self.message = message

    def __str__(self):
        return 'Reason: %s Message: %s' % (self.type, self.message)

    def __eq__(self, other):
        if isinstance(other, Reason):
            return ((self.type == other.type) and
                    (self.message == other.message))
        return False class ReportTransactionsFilters(object):
    def __init__(self, before_date=None, after_date=None, transaction_type=None, status=None, nature=None,
                 min_debited_funds_amount=None, min_debited_funds_currency=None, max_debited_funds_amount=None,
                 max_debited_funds_currency=None, author_id=None, wallet_id=None):
        self.before_date = before_date
        self.after_date = after_date
        self.transaction_type = transaction_type
        self.status = status
        self.nature = nature
        self.min_debited_funds_amount = min_debited_funds_amount
        self.min_debited_funds_currency = min_debited_funds_currency
        self.max_debited_funds_amount = max_debited_funds_amount
        self.max_debited_funds_currency = max_debited_funds_currency
        self.author_id = author_id
        self.wallet_id = wallet_id

    def __eq__(self, other):
        if isinstance(other, ReportTransactionsFilters):
            stat = ((self.before_date == other.before_date) and
                    (self.after_date == other.after_date) and
                    (self.transaction_type == other.transaction_type) and
                    (self.status == other.status) and
                    (self.nature == other.nature) and
                    (self.min_debited_funds_amount == other.min_debited_funds_amount) and
                    (self.min_debited_funds_currency == other.min_debited_funds_currency) and
                    (self.max_debited_funds_amount == other.max_debited_funds_amount) and
                    (self.max_debited_funds_currency == other.max_debited_funds_currency) and
                    (self.author_id == other.author_id) and
                    (self.wallet_id == other.wallet_id)
                    )
            return stat
        return False class ReportWalletsFilters(object):
    def __init__(self, before_date=None, after_date=None, owner_id=None, currency=None,
                 min_balance_amount=None, min_balance_currency=None, max_balance_amount=None,
                 max_balance_currency=None):
        self.before_date = before_date
        self.after_date = after_date
        self.owner_id = owner_id
        self.currency = currency
        self.min_balance_amount = min_balance_amount
        self.min_balance_currency = min_balance_currency
        self.max_balance_amount = max_balance_amount
        self.max_balance_currency = max_balance_currency

    def __eq__(self, other):
        if isinstance(other, ReportWalletsFilters):
            stat = ((self.before_date == other.before_date) and
                    (self.after_date == other.after_date) and
                    (self.owner_id == other.owner_id) and
                    (self.currency == other.currency) and
                    (self.min_balance_amount == other.min_balance_amount) and
                    (self.min_balance_currency == other.min_balance_currency) and
                    (self.max_balance_amount == other.max_balance_amount) and
                    (self.max_balance_currency == other.max_balance_currency)
                    )
            return stat
        return False class PlatformCategorization(object):
    def __init__(self, business_type=None, sector=None):
        self.business_type = business_type
        self.sector = sector

    def __str__(self):
        return 'PlatformCategorization: %s %s' % (self.business_type, self.sector) class Billing(object):
    def __init__(self, first_name=None, last_name=None, address=None):
        self.first_name = first_name
        self.last_name = last_name
        self.address = address

    def __str__(self):
        return 'Billing: %s' % \
               (self.first_name, self.last_name, self.address) class SecurityInfo(object):
    def __init__(self, avs_result=None):
        self.avs_result = avs_result

    def __str__(self):
        return 'AVS Result: %s' % self.avs_result class Birthplace(object):
    def __init__(self, city=None, country=None):
        self.city = city
        self.country = country

    def __str__(self):
        return 'Birthplace: %s, %s' % (self.city, self.country)

    def __eq__(self, other):
        if isinstance(other, Birthplace):
            stat = ((self.city == other.city) and
                    (self.country == other.country))
            return stat
        return False

    def to_api_json(self):
        return {
            "City": self.city,
            "Country": self.country,
        } class ApplepayPaymentData(object):
    def __init__(self, transaction_id=None, network=None, token_data=None):
        self.transaction_id = transaction_id
        self.network = network
        self.token_data = token_data

    def __eq__(self, other):
        if isinstance(other, ApplepayPaymentData):
            return self.transaction_id == other.transaction_id and self.network == other.network and self.token_data == other.token_data
        return False class GooglepayPaymentData(object):
    def __init__(self, transaction_id=None, network=None, token_data=None):
        self.transaction_id = transaction_id
        self.network = network
        self.token_data = token_data

    def __eq__(self, other):
        if isinstance(other, GooglepayPaymentData):
            return self.transaction_id == other.transaction_id and self.network == other.network and self.token_data == other.token_data
        return False class ScopeBlocked(object):
    def __init__(self, inflows=None, outflows=None):
        self.inflows = inflows
        self.outflows = outflows

    def __str__(self):
        return 'ScopeBlocked: %s, %s' % (self.inflows, self.outflows)

    def __eq__(self, other):
        if isinstance(other, ScopeBlocked):
            stat = ((self.inflows == other.inflows) and
                    (self.outflows == other.outflows))
            return stat
        return False

    def to_api_json(self):
        return {
            "Inflows": self.inflows,
            "Outflows": self.outflows,
        } class BrowserInfo(object):
    def __init__(self, accept_header=None, java_enabled=None, javascript_enabled=None,
                 language=None, color_depth=None, screen_height=None, screen_width=None,
                 timezone_offset=None, user_agent=None):
        self.user_agent = user_agent
        self.timezone_offset = timezone_offset
        self.screen_width = screen_width
        self.screen_height = screen_height
        self.color_depth = color_depth
        self.language = language
        self.accept_header = accept_header
        self.java_enabled = java_enabled
        self.javascript_enabled = javascript_enabled

    def __str__(self):
        return 'BrowserInfo: %s %s %s %s %s %s %s %s %s' % (self.java_enabled, self.accept_header, self.language,
                                                            self.color_depth, self.screen_height, self.screen_width,
                                                            self.timezone_offset, self.user_agent,
                                                            self.javascript_enabled)

    def __eq__(self, other):
        if isinstance(other, BrowserInfo):
            stat = ((self.user_agent == other.user_agent) and
                    (self.timezone_offset == other.timezone_offset) and
                    (self.screen_width == other.screen_width) and
                    (self.screen_height == other.screen_height) and
                    (self.color_depth == other.color_depth) and
                    (self.language == other.language) and
                    (self.accept_header == other.accept_header) and
                    (self.java_enabled == other.java_enabled) and
                    (self.javascript_enabled == other.javascript_enabled))
            return stat
        return False

    def to_api_json(self):
        return {
            "AcceptHeader": self.accept_header,
            "JavaEnabled": self.java_enabled,
            "JavascriptEnabled": self.javascript_enabled,
            "Language": self.language,
            "ColorDepth": self.color_depth,
            "ScreenHeight": self.screen_height,
            "ScreenWidth": self.screen_width,
            "TimeZoneOffset": self.timezone_offset,
            "UserAgent": self.user_agent
        } class Shipping(object):
    def __init__(self, first_name=None, last_name=None, address=None):
        self.first_name = first_name
        self.last_name = last_name
        self.address = address

    def __str__(self):
        return 'Shipping: %s' % \
               (self.first_name, self.last_name, self.address) class CurrentState(object):
    def __init__(self, payins_linked=None, cumulated_debited_amount=None, cumulated_debited_fees=None,
                 last_payin_id=None):
        self.payins_linked = payins_linked
        self.cumulated_debited_amount = cumulated_debited_amount
        self.cumulated_debited_fees = cumulated_debited_fees
        self.last_payin_id = last_payin_id

    def __str__(self):
        return 'CurrentState: %s' % \
               (self.cumulated_debited_amount, self.cumulated_debited_fees, self.last_payin_id, self.payins_linked) class FallbackReason(object):
    def __init__(self, code=None, message=None):
        self.code = code
        self.message = message

    def __str__(self):
        return 'FallbackReason: %s' % \
            (self.code, self.last_name, self.message)
import datetime
import json
import re
import sys
import time
import six
from .utils import timestamp_from_datetime, timestamp_from_date, Money, DebitedBankAccount, Address, ShippingAddress, \
    Reason, ReportTransactionsFilters, ReportWalletsFilters, \
    PlatformCategorization, Billing, SecurityInfo, Birthplace, ApplepayPaymentData, GooglepayPaymentData, \
    ScopeBlocked, BrowserInfo, Shipping, CurrentState, FallbackReason
        from .base import BaseApiModel
        from .base import BaseApiModel
        klass._meta.rel_fields[name] = self.name
        setattr(klass, self.descriptor, ManyToManyRelatedObject(self.to, self.name))
        setattr(klass, self.name, None)

        reverse_rel = ManyToManyRelatedObject(klass, self.name)

        setattr(self.to, self.related_name, reverse_rel)
        self.to._meta.reverse_relations[self.related_name] = klass

    def api_value(self, value):

        values = super(ManyToManyField, self).api_value(value)

        for i in range(len(values)):
            if isinstance(value, BaseApiModel):
                value = value.get_pk()
                values[i] = value

        return values


class ManyToManyRelatedObject(object):
    def __init__(self, related_model, name):
        self.related_model = related_model
        self.field_name = name

    def __get__(self, instance, instance_type=None):
        return instance.list(self.related_model)

    def __set__(self, instance, objs):
        setattr(instance, self.field_name, [obj.get_pk() for obj in objs])


class ApplepayPaymentDataField(Field):
    def python_value(self, value):
        if value is not None:
            return ApplepayPaymentData(transaction_id=value['TransactionId'], network=value['Network'],
                                       token_data=value['TokenData'])
        return value

    def api_value(self, value):
        value = super(ApplepayPaymentDataField, self).api_value(value)

        if isinstance(value, ApplepayPaymentData):
            value = {
                'TransactionId': value.transaction_id,
                'Network': value.network,
                'TokenData': value.token_data
            }
        return value


class GooglepayPaymentDataField(Field):
    def python_value(self, value):
        if value is not None:
            return GooglepayPaymentData(transaction_id=value['TransactionId'], network=value['Network'],
                                        token_data=value['TokenData'])
        return value

    def api_value(self, value):
        value = {
            'TransactionId': value.transaction_id,
            'Network': value.network,
            'TokenData': value.token_data
        }
        return value


class BirthplaceField(Field):
    def python_value(self, value):
        if value is not None:
            return Birthplace(city=value['City'], country=value['Country'])

        return value

    def api_value(self, value):
        value = super(BirthplaceField, self).api_value(value)

        if isinstance(value, Birthplace):
            value = {
                'City': value.city,
                'Country': value.country,
            }

        return value


class BrowserInfoField(Field):
    def python_value(self, value):
        if value is not None:
            return BrowserInfo(accept_header=value['AcceptHeader'], java_enabled=value['JavaEnabled'],
                               javascript_enabled=value['JavascriptEnabled'], language=value['Language'],
                               color_depth=value['ColorDepth'], screen_width=value['ScreenWidth'],
                               screen_height=value['ScreenHeight'], timezone_offset=value['TimeZoneOffset'],
                               user_agent=value['UserAgent'])

        return value

    def api_value(self, value):
        value = super(BrowserInfoField, self).api_value(value)

        if isinstance(value, BrowserInfo):
            value = {
                "AcceptHeader": value.accept_header,
                "JavaEnabled": value.java_enabled,
                "JavascriptEnabled": value.javascript_enabled,
                "Language": value.language,
                "ColorDepth": value.color_depth,
                "ScreenHeight": value.screen_height,
                "ScreenWidth": value.screen_width,
                "TimeZoneOffset": value.timezone_offset,
                "UserAgent": value.user_agent
            }

            return value


class ScopeBlockedField(Field):
    def python_value(self, value):
        if value is not None:

            return ScopeBlocked(inflows=value['Inflows'], outflows=value['Outflows'])