def get_balance(self, currency=None, with_bonus=False): # type: (Currency, bool) -> Tuple[float, Currency] from platforms.converter import convert_currency balance = normalize(self, self.api.account_balance(self)) #if we should return value as it is, return with original currency if not currency: return balance, self.currency return convert_currency(balance, self.currency, currency)
def clean(self): amount = convert_currency(self.cleaned_data["amount"], self.cleaned_data["currency"], "RUR")[0] if amount > 15000: self.add_error( "amount", ValidationError( _("You cannot withdraw more than %(amount)s in one request" ) % { "amount": display_amount(15000), })) return super(WithdrawForm, self).clean()
def clean(self): if 'currency' in self.cleaned_data and 'amount' in self.cleaned_data: amount = convert_currency(self.cleaned_data['amount'], self.cleaned_data['currency'], 'RUB', for_date=datetime.now().date())[0] # if amount > 15000: # self.add_error('amount', _("QIWI doesn't support one-time payments of more " # "than 15000 roubles. If you need to deposit more " # "money via QIWI, just commit several payments.")) if amount < 5: self.add_error('amount', _("Amount should be above 5 roubles")) return super(DepositForm, self).clean()
def save(self, **kwargs): if not self.pk: try: # This can fail at a query to MT4 (for example Webmoney fails like this) self._is_automatic = self.automatic except: # But we nevertheless should save it no matter what pass if self.account.currency != self.currency: self.conversion_rate = convert_currency( 1, self.currency, self.account.currency)[0] if isinstance(self, DepositRequest): c = self.payment_system.DepositForm.calculate_commission(self) self.commission = c.commission self.currency = c.currency return super(BaseRequest, self).save(**kwargs)
def _calculate_commission(cls, request): from decimal import Decimal from platforms.converter import convert_currency commission = 40 commission = Decimal( convert_currency(commission, from_currency=EUR, to_currency=request.currency, for_date=request.creation_ts)[0]) return CommissionCalculationResult(amount=request.amount, commission=commission, currency=request.currency)
def to(self, currency, for_date=None, cache_key=None): currency = get_currency(currency) # ensure currency object if self.currency == currency: return copy(self) try: amount = float(convert_currency( self.amount, from_currency=self.currency, to_currency=currency, for_date=for_date, cache_key=cache_key or self._convert_cache_key)[0]) except Exception as e: from django.conf import settings if not settings.DEBUG: raise e print e return NoneMoney() return Money(amount, currency)
def convert_balances(accounts, to_currency): results = {} for acc_id, acc in accounts.iteritems(): if acc["balance"] is None: continue elif to_currency is None: b, c = acc["balance"], acc["currency"] else: b, c = convert_currency(acc["balance"], acc["currency"], to_currency) results[acc_id] = { "balance": c.display_amount(b, with_slug=c.slug) if b is not None else "", "currency": c.slug } return results
def get_account_requests_stats(account=None): from collections import defaultdict from datetime import datetime, timedelta from payments.models import DepositRequest from platforms.models import TradingAccount from platforms.converter import convert_currency if account.is_ib: agents = account.agent_clients.values_list("login", flat=True) accounts_list = TradingAccount.objects.filter(mt4_id__in=list(agents)) else: accounts_list = account.user.accounts.all() stats = defaultdict(float) systems = {} for acc in accounts_list: x = [(x.payment_system, x.amount, x.currency) for x in DepositRequest.objects.filter(account=acc, is_committed=True)] for system, amount, currency in x: if isinstance(system, basestring): system = load_payment_system("payments.system.%s" % system) if system is None: continue sys_name = unicode(system) stats[sys_name] += float(convert_currency(amount=amount, from_currency=currency, to_currency="USD", for_date=datetime.today()-timedelta(2))[0]) if sys_name not in systems: systems[sys_name] = system summ = sum(stats.values()) res = [] for system in stats: percent = int(stats[system]/summ*100) if summ > 0 else 0 res.append((systems[system], round(stats[system], 2), percent)) return res
def clean(self): log.debug("Form clean") if self.errors: log.debug("There are errors!") return self.cleaned_data sender = self.cleaned_data["sender"] amount = self.cleaned_data["amount"] mode = self.cleaned_data["mode"] currency = get_currency(self.cleaned_data["currency"]) log.debug("sender={} amount={} mode={} curr={}".format( sender, amount, mode, currency)) # Delete in Arum? if sender.group == RealIBAccountType and not sender.verification.exists( ): self._errors["sender"] = [ mark_safe( _('You should <a href="%(link)s" target="_blank">complete the verification process</a> ' 'before withdrawing from account %(account)s') % { 'account': sender.mt4_id, 'link': reverse("referral_verify_partner") + "?next=" + self.request.path }) ] return self.cleaned_data try: log.debug("Checking sender balance") from payments.systems.base import WithdrawForm withdraw_limit, bonuses = WithdrawForm.get_withdraw_limit_data( sender) withdraw_limit = withdraw_limit.to(currency) except: log.error("Can't get balance for sender {}".format(sender)) self._errors["sender"] = [ _("Error while getting allowed transfer amount for the " "chosen account. Contact the administrator.") ] return self.cleaned_data if amount > Decimal(withdraw_limit.amount).quantize(Decimal("0.01")): log.warn("User asked sum greater then available ({}>{})".format( amount, withdraw_limit)) self._errors["amount"] = [ _("The maximum amount of money you can transfer from the chosen " "account is %(limit_value)s ") % { "limit_value": withdraw_limit } ] log.debug("Converting currency") converted_amount, currency = convert_currency(amount, currency, sender.currency, silent=False) if converted_amount < 0.01: log.warn("Sum is less then one cent after conversion!") self._errors["amount"] = [ _("You cannot transfer less than 0.01 in chosen currency") ] if mode == "manual": log.debug("Manual mode") recipient_field_name = "recipient_manual" if self.internal else "recipient_auto" if not self.cleaned_data[recipient_field_name]: self._errors[recipient_field_name] = [ _("This field is required") ] return self.cleaned_data # ♿ the problem is we sent other data type when we use self.internal through admin panel recipient_id = self.cleaned_data[ recipient_field_name] if self.internal else self.cleaned_data[ recipient_field_name].mt4_id recipients = TradingAccount.objects.filter(mt4_id=recipient_id) if recipients: recipient = recipients[0] log.debug("Recepient: {}".format(recipient)) else: self._errors["recipient_manual"] = [ _("This account seems not to be registered in the private office. Register it first." ) ] return self.cleaned_data else: log.debug("Auto mode") recipient_field_name = "recipient_auto" if not self.cleaned_data[recipient_field_name]: self._errors[recipient_field_name] = [ _("This field is required") ] return self.cleaned_data recipient = self.cleaned_data[recipient_field_name] log.debug("Recepient: {}".format(recipient)) if recipient.is_demo or recipient.no_inout: self._errors[recipient_field_name] = [ _("You can't transfer money to demo account") ] if recipient.group is None: log.warn("Cant find group for recepient acc: {}".format(recipient)) self._errors[recipient_field_name] = [ _('Cannot determine the group of recipient account') ] # Making sure that a user can't request a transfer, using a single # account as both recipient and sender. if sender.mt4_id == recipient.mt4_id: self._errors[recipient_field_name] = [ _("Using the same account for both " "recipient and sender is not allowed.") ] self.recipient = recipient self.cleaned_data["recipient"] = recipient.mt4_id return self.cleaned_data
def utm_report(request): if request.POST: form = UtmReportForm(request.POST) if form.is_valid(): utms = UtmAnalytics.objects.all() if form.cleaned_data['utm_source']: utms = utms.filter( utm_source__in=form.cleaned_data['utm_source']) if form.cleaned_data['utm_medium']: utms = utms.filter( utm_medium__in=form.cleaned_data['utm_medium']) if form.cleaned_data['utm_campaign']: utms = utms.filter( utm_campaign__in=form.cleaned_data['utm_campaign']) user_count = utms.filter( user__date_joined__gte=form.cleaned_data['date_from'], user__date_joined__lte=form.cleaned_data['date_to'], ).count() mt4_accounts = TradingAccount.objects.filter( user__utm_analytics__in=utms, creation_ts__gte=form.cleaned_data['date_from'], creation_ts__lte=form.cleaned_data['date_to'], ) groups_accounts = {} # Okay, that seems like a slow code, but we don't have any better means to reliably determine group for mt4_acc in mt4_accounts: groups_accounts.setdefault(mt4_acc.group, []).append(mt4_acc) groups_count = { group: len(accounts) for group, accounts in groups_accounts.iteritems() } groups_deposit = {} for group, accs in groups_accounts.iteritems(): deposits = DepositRequest.objects.filter( is_committed=True, is_payed=True, account__pk__in=map(lambda x: x.pk, accs), ) sum_usd = 0 for deposit in deposits: sum_usd += convert_currency( deposit.amount, from_currency=deposit.currency, to_currency='USD', for_date=form.cleaned_data['date_from'])[0] groups_deposit[group] = sum_usd groups = sorted(groups_count.keys()) return { 'form': form, 'should_show_form': True, 'report': { 'data': { 'groups': groups, 'user_count': user_count, 'groups_count': (groups_count[group] for group in groups), 'groups_deposit': (groups_deposit[group] for group in groups), } } } else: form = UtmReportForm() return {'form': form, 'should_show_form': True}
def clean(self): for key in ('account', 'amount', 'currency'): if key not in self.cleaned_data: return self.cleaned_data account = self.cleaned_data["account"] if account.is_ib and not account.verification.exists(): self._errors["account"] = [ mark_safe( _('You should <a href="%(link)s" target="_blank">complete the verification process</a> ' 'before withdrawing from account %(account)s') % { 'account': account.mt4_id, 'link': reverse("referral_verify_partner") + "?next=" + self.request.path }) ] if account.is_disabled: self._errors["account"] = [ _("You can't withdraw funds from this account") ] # Allow withdrawals only to systems which had successful deposits or to bank if not (self.payment_system.slug in ("bankusd", "bankeur", "bankrur") or DepositRequest.objects.filter( payment_system=self.payment_system, account__user=account.user, is_committed=True).exists()): self._errors["account"] = [ _("Please withdraw funds using the system which you used for deposit, or " "using wire transfer") ] # для вебмани все конвертируем в валюту счета, # для остальных валюта выбирается в форме if self.payment_system.slug == "webmoney": to_currency = account.currency else: to_currency = currencies.get_currency( self.cleaned_data["currency"]) amount = self.cleaned_data['amount'] min_amount = self._get_min_amount(account) if min_amount: # получаем минимальное число средств в некоторой валюте min_amount, currency = min_amount # его нужно сконвертировать в валюту платежной системы min_amount, currency = convert_currency(min_amount, currency, to_currency, silent=False) if amount < min_amount: self._errors["amount"] = [ _("Minimal amount of money you can withdraw " "with this payment system is %(limit_value)s%(currency)s" ) % { "limit_value": currencies.round_floor(min_amount), "currency": currency.slug } ] else: if not amount > 0: self._errors["amount"] = [_("Enter amount more than %s") % 0] try: withdraw_limit, bonuses = WithdrawForm.get_withdraw_limit_data( account) if amount > Decimal(withdraw_limit.amount).quantize( Decimal("0.01")): self._errors["amount"] = [_( "Maximal amount of money you can withdraw for a chosen " "account is %(limit_value)s%(currency)s ") % \ {"limit_value": withdraw_limit.amount, "currency": withdraw_limit.currency.slug}] except: self._errors["account"] = [ _('Cannot determine the account balance. Try again later or contact support' ) ] return self.cleaned_data
def clean(self): """ Validate deposit request. """ account = (self.cleaned_data["account"]) # if not DepositRequest.objects.filter(account=account, is_committed=True).exists(): if self.MAX_AMOUNT and "amount" in self.cleaned_data and "currency" in self.cleaned_data: amount = self.cleaned_data["amount"] currency = self.cleaned_data["currency"] max_amount, max_amount_currency = self.MAX_AMOUNT converted_max_amount = convert_currency(max_amount, max_amount_currency, currency) if converted_max_amount[0] < Decimal( amount) - self.total_commision().commission: self._errors["amount"] = [ _("You cant deposit more than %(amount)s with %(system)s") % { "amount": converted_max_amount[1].display_amount( converted_max_amount[0]), "system": self.payment_system.name } ] if self.MIN_AMOUNT and "amount" in self.cleaned_data and "currency" in self.cleaned_data: amount = self.cleaned_data["amount"] currency = self.cleaned_data["currency"] min_amount, min_amount_currency = self.MIN_AMOUNT converted_min_amount = convert_currency(min_amount, min_amount_currency, currency) if converted_min_amount[0] > Decimal( amount) - self.total_commision().commission: self._errors["amount"] = [ _("You cant deposit less than %(amount)s with %(system)s") % { "amount": converted_min_amount[1].display_amount( converted_min_amount[0]), "system": self.payment_system.name } ] cleaned_amount = self.cleaned_data.get("amount") cleaned_account = self.cleaned_data.get("account") cleaned_currency = self.cleaned_data.get("currency") is_first_deposit = not DepositRequest.objects.filter( account=account, is_committed=True).exists() if cleaned_amount is not None and cleaned_account and cleaned_currency: cleaned_amount = float(cleaned_amount) if cleaned_amount <= 0: self._errors["amount"] = [_('Wrong amount')] if cleaned_account.group.min_deposit and self.payment_system.slug != "qiwi": # If minimum deposit is defined for the account to_currency = currencies.get_currency(cleaned_currency) account_balance = cleaned_account.get_balance( currency=to_currency, with_bonus=True)[0] if account_balance is not None: min_deposit = convert_currency( cleaned_account.group.min_deposit, 'USD', to_currency)[0] if not self.request.user.is_superuser and ( account_balance < min_deposit or not is_first_deposit): min_deposit_amount = min_deposit - account_balance if Decimal(cleaned_amount) - self.total_commision( ).commission < min_deposit_amount: self._errors["amount"] = [ _('Minimum deposit amount is %(amount)s %(currency)s' ) % { 'amount': str(round(min_deposit_amount)), 'currency': str(to_currency) } ] else: self._errors["account"] = [ _('Cannot determine the account balance. Try again later or contact support' ) ] return super(DepositForm, self).clean()
def make_payment(self, comment=None): log.debug("Making payment ID = %s..." % self.id) if self.is_committed: log.debug("Oops, already committed; terminating") return if isinstance(self, DepositRequest): form = self.payment_system.DepositForm is_deposit = True self.is_committed = True # We must take all care to not process same deposit twice self.save(refresh_state=True) c = self.payment_system.DepositForm.calculate_commission(self) c_full = self.payment_system.DepositForm.calculate_commission( self, full_commission=True) amount = c_full.amount - c_full.commission # Will be deposited as ExternalPay bonus_amount = c.amount - c.commission - amount # Commission compensation, deposited as BonusPaid if bonus_amount < Decimal("0.01"): bonus_amount = 0 elif isinstance(self, WithdrawRequest): is_deposit = False amount = -self.amount bonus_amount = 0 form = self.payment_system.WithdrawForm else: log.debug("Oops, unknown request type; terminating") raise TypeError("Unknown request type: %r" % type(self)) if self.account.currency != self.currency: if self.conversion_rate: amount = float(amount) * self.conversion_rate bonus_amount = float(bonus_amount) * self.conversion_rate else: amount = convert_currency(amount, from_currency=self.currency, to_currency=self.account.currency)[0] bonus_amount = convert_currency( bonus_amount, from_currency=self.currency, to_currency=self.account.currency)[0] mail_admins( u"Payment request id={} processed without saved exchange rate!" .format(self.pk), "") try: comment = comment or form.generate_mt4_comment(self) except Exception as e: log.debug("Oops, couldnt generate comment: %s; terminating" % unicode(e)) comment = unicode(self.id) try: log.debug("Sending change_balance command to TradingAccount...") res = self.account.change_balance( amount=amount, request_id=form.generate_mt4_request_id(self), comment=comment, transaction_type="ExternalPay") if bonus_amount: self.account.change_balance( amount=bonus_amount, request_id=form.generate_mt4_request_id(self) + 'B', comment=comment, transaction_type="BonusPaid") if is_deposit \ and self.needs_verification \ and not (self.params.get('cardnumber') and self.account.user.profile.is_card_verified(self.params['cardnumber'])): self.account.block( block_reason=TradingAccount.REASON_CHARGEBACK) self.params['chargeback_suspect'] = True user_profile = self.account.user.profile if not user_profile.manager: user_profile.autoassign_manager(force=True) # self.account.user.gcrm_contact.add_task(u"Client's account blocked to prevent chargeback. " # u"Monitor the situation.") notification.send( [self.account.user], "deposit_needs_verification", { "paymentrequest": self, 'usd_amount': self.amount_money.to("USD") }) except PlatformError as e: log.debug("Command change_balance failed: %s" % unicode(e)) if is_deposit: self.is_committed = None else: self.is_payed = False send_mail( u"Withdraw request failed", u"Withdraw request failed:\n" u"https://%s%s\n\n" u"Error: %s" % (settings.ROOT_HOSTNAME, get_admin_url(self), unicode(e)), from_email=settings.SERVER_EMAIL, recipient_list=[x[1] for x in settings.ADMINS]) Logger(user=None, content_object=self, ip=None, event=Events.WITHDRAW_REQUEST_FAILED, params={ 'error': e.message }).save() self.save() raise e else: if res is not None: self.refresh_state() self.trade_id = res.get("order_id") self.save(refresh_state=False) log.debug("Payment OK. OrderID = %s" % self.trade_id) else: log.debug("Payment OK, but OrderID is unknown :(") Logger(user=None, content_object=self, ip=None, event=Events.WITHDRAW_REQUEST_PAYED).save()
def init_data(self, request): if not request.user.accounts.alive().non_demo().exists(): return Response({"has_no_accounts": True}) most_recent_deposit = DepositRequest.objects \ .filter(account__in=request.user.accounts.all()) \ .exclude(payment_system="office").last() if most_recent_deposit: most_recent_deposit = most_recent_deposit.payment_system most_recent_withdraw = WithdrawRequest.objects \ .filter(account__in=request.user.accounts.all()) \ .exclude(payment_system="office").last() if most_recent_withdraw: most_recent_withdraw = most_recent_withdraw.payment_system symbols = Mt4Quote.objects \ .filter(symbol__in=['USDEURconv', 'USDRUBconv']) \ .only('symbol', 'bid', 'ask', 'digits') columns = [ s[3:6] for s in symbols.exclude( symbol='USDUAHconv').values_list('symbol', flat=True) ] columns.insert(0, u'USD') table = {} for row in [u'USD', u'RUB', u'EUR']: table[row] = [] for column in columns: if row == column: value = (1, 1) else: if column == "XAG": column = "SILVER" elif column == "XAU": column = "GOLD" try: value = ( round(convert_currency(1, row, column)[0], 4), round(1 / convert_currency(1, column, row)[0], 4), ) except: value = (0, 0) table[row].append(value) systems_list = get_payment_systems() # Convers payment system objects to simple object for op, op_data in systems_list.items(): for psgroup, psgroup_data in op_data.items(): for sys, sys_data in psgroup_data["systems"].items(): psgroup_data["systems"][sys] = { 'slug': sys, 'name': u'%s' % sys_data.name, 'deposit_redirect': sys_data.deposit_redirect } return Response({ "systems_list": systems_list, "most_recent": { "deposit": most_recent_deposit, "withdraw": most_recent_withdraw }, "conversionTable": table, "columns": columns, "PAYMENTS_RECEIVER": settings.PAYMENTS_RECEIVER })