def update_currency(user: ExchangeUser, currency: str):
    # We can do this because only 1 currency right now
    user_limit = UserLimit.objects.filter(user=user).first()
    if user_limit:
        if user_limit.fiat_currency != currency:
            old_currency = user_limit.fiat_currency
            user_limit.fiat_currency = currency
            user_limit.usage = RateManagement.convert_currency(
                user_limit.usage, old_currency, currency)
            user_limit.limit = RateManagement.convert_currency(
                user_limit.limit, old_currency, currency)
            user_limit.save()
    def check_cod_limit(user, local_amount, fiat_currency):
        limit = {
            FIAT_CURRENCY.USD: {
                'min': Decimal('2000'),
                'max': Decimal('3000'),
            },
            FIAT_CURRENCY.HKD: {
                'min': Decimal('15000'),
                'max': Decimal('25000'),
            },
        }

        data = limit.get(fiat_currency)
        if data:
            exchange_user = user.exchange_user
            if exchange_user.currency != fiat_currency:
                check_amount = RateManagement.convert_currency(
                    local_amount, exchange_user.currency, fiat_currency)
                if not (data['min'] <= check_amount <= data['max']):
                    raise CoinUserOverLimitException
            now = get_now()
            order = Order.objects.filter(
                direction=DIRECTION.buy,
                order_type=ORDER_TYPE.cod,
                created_at__day=now.day,
                created_at__month=now.month,
                created_at__year=now.year,
            ).first()
            if order:
                raise CoinUserOverLimitException
        else:
            raise InvalidDataException
    def increase_limit(user, amount, currency, direction, fiat_local_amount,
                       fiat_local_currency):
        # Convert local currency to user currency
        update_amount = fiat_local_amount
        if user.currency != fiat_local_currency:
            update_amount = RateManagement.convert_currency(
                update_amount, fiat_local_currency, user.currency)
        UserLimit.objects.filter(user=user,
                                 direction=DIRECTION_ALL,
                                 fiat_currency=user.currency) \
            .update(usage=F('usage') + update_amount,
                    updated_at=get_now())

        Pool.objects.filter(direction=direction, currency=currency).update(
            usage=F('usage') + amount, updated_at=get_now())
 def check_user_limit(user, local_price, fiat_currency):
     # Get user limit to check
     try:
         exchange_user = user.exchange_user
         check_amount = local_price
         if exchange_user.currency != fiat_currency:
             check_amount = RateManagement.convert_currency(
                 local_price, exchange_user.currency, fiat_currency)
         user_limit = UserLimit.objects.get(
             user=exchange_user,
             direction=DIRECTION_ALL,
             fiat_currency=exchange_user.currency)
         if user_limit.usage + check_amount > user_limit.limit:
             raise CoinUserOverLimitException
     except UserLimit.DoesNotExist as e:
         logging.exception(e)
         raise InvalidDataException
    def decrease_limit(user, amount, currency, direction, fiat_local_amount,
                       fiat_local_currency):
        # Convert local currency to user currency
        update_amount = fiat_local_amount
        if user.currency != fiat_local_currency:
            update_amount = RateManagement.convert_currency(
                update_amount, fiat_local_currency, user.currency)

        user_limit = UserLimit.objects.get(user=user,
                                           direction=DIRECTION_ALL,
                                           fiat_currency=user.currency)
        if user_limit.usage < update_amount:
            user_limit.usage = 0
        else:
            user_limit.usage = F('usage') - update_amount
        user_limit.save()

        pool = Pool.objects.get(direction=direction, currency=currency)
        if pool.usage < amount:
            pool.usage = 0
        else:
            pool.usage = F('usage') - amount
        pool.save()
    def get_quote(user, params) -> QuoteSerializer:
        input_serializer = QuoteInputSerializer(
            data={
                'amount': params.get('amount'),
                'currency': params.get('currency'),
                'fiat_currency': params.get('fiat_currency',
                                            FIAT_CURRENCY.USD),
                'pool_check': params.get('check', False),
                'user_check': params.get('user_check', False),
                'direction': params.get('direction', DIRECTION.buy),
            })

        if input_serializer.is_valid(raise_exception=True):
            safe_data = input_serializer.validated_data
            direction = safe_data['direction']

            currency = safe_data['currency']
            amount = safe_data['amount']
            price = QuoteManagement.get_price(direction, safe_data)

            raw_fiat_amount = amount * price
            fiat_local_currency = safe_data['fiat_currency']

            if safe_data['user_check']:
                # request.user
                # User logged in
                if user and user.is_authenticated:
                    if fiat_local_currency != user.exchange_user.currency:
                        raw_fiat_local_amount = RateManagement.convert_currency(
                            raw_fiat_amount, fiat_local_currency,
                            user.exchange_user.currency)
                    else:
                        raw_fiat_local_amount = RateManagement.convert_to_local_currency(
                            raw_fiat_amount, fiat_local_currency)

                    QuoteManagement.check_user_limit(
                        user, raw_fiat_local_amount,
                        user.exchange_user.currency)
                else:
                    raise NotAuthenticated

            if safe_data['pool_check']:
                QuoteManagement.check_pool(direction, amount, currency)

            if direction == DIRECTION.buy:
                fiat_amount, fiat_amount_fee = markup_fee(
                    raw_fiat_amount, FEE_COIN_ORDER_BANK)
            else:
                fiat_amount, fiat_amount_fee = markup_fee(
                    raw_fiat_amount, FEE_COIN_SELLING_ORDER_BANK)

            fiat_local_amount = RateManagement.convert_to_local_currency(
                fiat_amount, fiat_local_currency)
            fee_local = RateManagement.convert_to_local_currency(
                fiat_amount_fee, fiat_local_currency)

            if direction == DIRECTION.buy:
                fiat_amount_cod, fiat_amount_fee_cod = markup_fee(
                    raw_fiat_amount, FEE_COIN_ORDER_COD)
                fiat_local_amount_cod = RateManagement.convert_to_local_currency(
                    fiat_amount_cod, fiat_local_currency)
                fee_local_cod = RateManagement.convert_to_local_currency(
                    fiat_amount_fee_cod, fiat_local_currency)
            else:
                fiat_amount_cod, fiat_amount_fee_cod = markup_fee(
                    raw_fiat_amount, FEE_COIN_SELLING_ORDER_COD)
                fiat_local_amount_cod = RateManagement.convert_to_local_currency(
                    fiat_amount_cod, fiat_local_currency)
                fee_local_cod = RateManagement.convert_to_local_currency(
                    fiat_amount_fee_cod, fiat_local_currency)

            serializer = QuoteSerializer(
                data={
                    'fiat_amount': round_currency(fiat_amount),
                    'fiat_currency': FIAT_CURRENCY.USD,
                    'fiat_local_amount': round_currency(fiat_local_amount),
                    'fiat_local_currency': fiat_local_currency,
                    'fiat_amount_cod': round_currency(fiat_amount_cod),
                    'fiat_local_amount_cod': round_currency(
                        fiat_local_amount_cod),
                    'fee': round_currency(fiat_amount_fee),
                    'fee_cod': round_currency(fiat_amount_fee_cod),
                    'fee_local': round_currency(fee_local),
                    'fee_local_cod': round_currency(fee_local_cod),
                    'raw_fiat_amount': round_currency(raw_fiat_amount),
                    'price': round_currency(price),
                    'amount': round_crypto_currency(amount),
                    'currency': safe_data['currency'],
                    'direction': safe_data['direction']
                })
            serializer.is_valid(raise_exception=True)

            return serializer
    def get_quote_reverse(user, params) -> QuoteReverseSerializer:
        input_serializer = QuoteReverseInputSerializer(
            data={
                'fiat_amount': params.get('fiat_amount'),
                'currency': params.get('currency'),
                'fiat_currency': params.get('fiat_currency',
                                            FIAT_CURRENCY.USD),
                'pool_check': params.get('check', False),
                'user_check': params.get('user_check', False),
                'direction': params.get('direction', DIRECTION.buy),
                'order_type': params.get('type', ORDER_TYPE.bank)
            })

        order_type = input_serializer.initial_data['order_type']
        if order_type not in ORDER_TYPE:
            raise ValidationError

        if input_serializer.is_valid(raise_exception=True):
            safe_data = input_serializer.validated_data
            direction = safe_data['direction']
            currency = safe_data['currency']

            fiat_local_amount = safe_data['fiat_amount']
            fiat_local_currency = safe_data['fiat_currency']
            fiat_amount = RateManagement.convert_from_local_currency(
                fiat_local_amount, fiat_local_currency)

            if direction == DIRECTION.buy:
                if order_type == ORDER_TYPE.bank:
                    raw_fiat_amount, fiat_amount_fee = remove_markup_fee(
                        fiat_amount, FEE_COIN_ORDER_BANK)
                else:
                    raw_fiat_amount, fiat_amount_fee = remove_markup_fee(
                        fiat_amount, FEE_COIN_ORDER_COD)
            else:
                if order_type == ORDER_TYPE.bank:
                    raw_fiat_amount, fiat_amount_fee = remove_markup_fee(
                        fiat_amount, FEE_COIN_SELLING_ORDER_BANK)
                else:
                    raw_fiat_amount, fiat_amount_fee = remove_markup_fee(
                        fiat_amount, FEE_COIN_SELLING_ORDER_COD)

            price = QuoteManagement.get_price(direction, safe_data)
            amount = raw_fiat_amount / price

            if safe_data['user_check']:
                # request.user
                # User logged in
                if user and user.is_authenticated:
                    if fiat_local_currency != user.exchange_user.currency:
                        raw_fiat_local_amount = RateManagement.convert_currency(
                            raw_fiat_amount, fiat_local_currency,
                            user.exchange_user.currency)
                    else:
                        raw_fiat_local_amount = RateManagement.convert_to_local_currency(
                            raw_fiat_amount, fiat_local_currency)

                    QuoteManagement.check_user_limit(
                        user, raw_fiat_local_amount,
                        user.exchange_user.currency)
                else:
                    raise NotAuthenticated

            if safe_data['pool_check']:
                QuoteManagement.check_pool(direction, amount, currency)

            fiat_local_amount = RateManagement.convert_to_local_currency(
                fiat_amount, fiat_local_currency)

            serializer = QuoteReverseSerializer(
                data={
                    'fiat_amount': round_currency(fiat_amount),
                    'fiat_currency': FIAT_CURRENCY.USD,
                    'fiat_local_amount': round_currency(fiat_local_amount),
                    'fiat_local_currency': fiat_local_currency,
                    'raw_fiat_amount': round_currency(raw_fiat_amount),
                    'price': round_currency(price),
                    'amount': round_crypto_currency(amount),
                    'currency': safe_data['currency'],
                    'direction': safe_data['direction']
                })
            serializer.is_valid(raise_exception=True)

            return serializer
Example #8
0
    def create_promotion(order: Order):
        referrer = order.user.referral
        user = order.user

        # Pre-check if user already has bonus
        if PromotionOrder.objects.filter(user=user, referrer=False).first():
            return

        referrer_promotion = PromotionUser.objects.filter(
            user=referrer).first()
        currency = referrer.currency
        if referrer_promotion:
            currency = referrer_promotion.currency

        user_promotion = PromotionUser.objects.filter(user=user).first()

        # Referral
        referrer_rule = PromotionRule.objects.filter(country=referrer.country,
                                                     currency=currency,
                                                     active=True).first()
        if referrer_rule:
            if not referrer_promotion:
                referrer_promotion = PromotionUser.objects.create(
                    user=referrer,
                    currency=currency,
                    referral_count=0,
                )
            else:
                # Don't need do anymore if violating below rules
                if referrer_promotion.referral_count >= referrer_rule.first_referral_count > 0:
                    return

            if not user_promotion:
                user_promotion = PromotionUser.objects.create(
                    user=user,
                    currency=user.currency,
                    referral_amount=Decimal('0'))

            first_referral_count = referrer_promotion.referral_count
            org_amount = RateManagement.convert_currency(
                user_promotion.referral_amount, user.currency,
                referrer_promotion.currency)
            check_amount = RateManagement.convert_currency(
                order.fiat_local_amount, order.fiat_local_currency,
                referrer_promotion.currency)

            referrer_promotion.referral_count = F('referral_count') + 1
            referrer_promotion.save()

            user_promotion.referral_amount = F(
                'referral_amount') + check_amount
            user_promotion.save()

            if referrer_rule.first_referral_referrer_bonus > 0 and \
                    ((referrer_rule.first_referral_count < 0 or
                      first_referral_count + 1 <= referrer_rule.first_referral_count)
                     and org_amount + check_amount >= referrer_rule.first_referral_amount):
                PromotionOrder.objects.create(
                    order=order,
                    user=referrer,
                    amount=referrer_rule.first_referral_referrer_bonus,
                    currency=referrer_rule.currency,
                    status=REFERRAL_STATUS.pending,
                    referrer=True,
                    note=PROMOTION.referrer)

            if referrer_rule.first_referral_referee_bonus > 0 and \
                    org_amount + check_amount >= referrer_rule.first_referral_amount:
                PromotionOrder.objects.create(
                    order=order,
                    user=user,
                    amount=RateManagement.convert_currency(
                        referrer_rule.first_referral_referee_bonus,
                        referrer_rule.currency, user.currency),
                    currency=user.currency,
                    status=REFERRAL_STATUS.pending,
                    referrer=False,
                    note=PROMOTION.referee)
Example #9
0
    def post(self, request, format=None):
        RateManagement.save_rates()

        return Response(True)