def convert_currency_mt4(amount, from_currency, to_currency='USD'): """Convert amount from one currency to another, no caching""" from platforms.mt4.external.models_other import Mt4Quote def get_quote(currency): try: return Mt4Quote.objects.get( symbol="USD{}".format(currency.instrument_name)) except Mt4Quote.DoesNotExist: pass quote = Mt4Quote.objects.get( symbol="{}USD".format(currency.instrument_name)) return Mt4Quote(ask=1.0 / quote.bid, bid=1.0 / quote.ask) to_currency = currencies.get_currency(to_currency) from_currency = currencies.get_currency(from_currency) if to_currency.slug == "USD": rate = 1.0 / get_quote(from_currency).ask elif from_currency.slug == "USD": rate = get_quote(to_currency).bid else: rate = get_quote(to_currency).bid / get_quote(from_currency).ask if rate == 0: raise ValueError("Conversion rate cannot be 0") return amount * rate, to_currency
def convert_currency(amount, from_currency, to_currency, silent=True, for_date=None, cache_key=None): """Convert amount from one currency to another, with caching for old rates """ from_currency = currencies.get_currency(from_currency) to_currency = currencies.get_currency(to_currency) # пришли некорректные валюты if from_currency is None or to_currency is None: return None, None if amount is None: log.error( 'Recieved ammout for currency convert is None most likely connect to accounts db is broken' ) amount = float(amount) if from_currency == to_currency: return amount, from_currency if amount == 0: return 0, to_currency if for_date is not None and type(for_date) is datetime: for_date = for_date.date() return convert_currency_mt4(amount, from_currency, to_currency)
def test_has_all_attributes(self): attrs = ["slug", "verbose_name", "group_regex", "instrument_name", "symbol"] r = c.get_currency("USD") self.assertTrue(all(map(lambda a: hasattr(r, a), attrs))) r = c.get_currency("KUKU") self.assertFalse(all(map(lambda a: hasattr(r, a), attrs)))
def test_get_currency(self): r = c.get_currency("USD") self.assertEqual(r, c.USD) r = c.get_currency("KUKU") self.assertEqual(r, None) r = c.get_currency("KUKU", create=True) self.assertEqual(r, c.Currency.register["KUKU"])
def balance(request): """ Returns balance for a given account in the requested currency, which defaults to USD, unless no_default_currency is set """ only_digits = re.compile("^[0-9]+$") accounts = map( int, [x for x in request.GET.getlist("accounts[]") if only_digits.match(x)]) currency = currencies.get_currency(request.GET.get("currency", "USD")) accounts = TradingAccount.objects.filter( mt4_id__in=accounts, user=request.user).order_by("mt4_id") if accounts: accounts = { account.mt4_id: { "balance": account.balance_money.amount, "currency": account.currency } for account in accounts } else: accounts = None return convert_balances(accounts, currency) if accounts else None
def render(self, context): try: amount = self.amount.resolve(context) # This happens if the balance cannot be calculated except (AttributeError, VariableDoesNotExist): return '' if amount is None: return '' currency = self.currency.resolve(context) currency = currencies.get_currency(currency) precision = self.extra_context['precision'] if isinstance(precision, FilterExpression): precision = precision.var.resolve(context) return currency.display_amount(amount, precision=precision)
def bank_preview_items(self, form): items = [] currency = get_currency(self.currency) key = _("Sender") val = [self.params["name"]] if self.params.get("bank"): val.append([ self.params["country"], self.params["city"], self.params["address"] ]) items.append([key, ", ".join(val)]) if self.params.get("passport_data"): items.append([_("Passport data"), self.params["passport_data"]]) key = _("Amount") items.append([key, currency.display_amount(self.amount)]) for param, value in form.get_bank(): items.append([_(param), value]) if self.params.get("bank"): items.append([_("Intermediary Bank’s code"), self.params["swift"]]) items.append([ _("Payment Details"), "According to client agreement %s" % self.account.mt4_id ]) else: items.append([ _("Payment Details"), u"%s №%s" % (form.get_bank_base(self.account)[5][1], self.account.mt4_id) ]) return [[unicode(k), v] for k, v in items]
def save(self, **kwargs): log.info("Saving internal transfer issue") amount = self.cleaned_data['amount'] recipient = self.recipient sender = self.cleaned_data['sender'] currency = get_currency(self.cleaned_data["currency"]) manual = self.cleaned_data["mode"] == "manual" log.info( "Transfering {amount} {curr} from {sender} to {recipient}".format( amount=amount, curr=currency, sender=sender, recipient=recipient)) if manual and not self.internal: # If manual then only issue is created result = super(InternalTransferForm, self).save(**kwargs) log.debug("Notification: manual_transfer_submitted") notification.send( [sender.user], "manual_transfer_submitted", { 'sender': sender, 'recipient': recipient, 'amount': amount, 'issue': result, }) send_mail( "New issue for internal transfer created", 'sender: {}, recipient: {}\namount: {}, issuetracker: {}'. format( sender, recipient, amount, 'arumcapital.eu' + reverse("admin:issuetracker_internaltransferissue_change", args=(result.pk, ))), settings.SERVER_EMAIL, settings.BACKOFFICE) return result withdraw_done = False deposit_done = False bonus_amount = -1 try: sender.check() recipient.check() log.info("Withdrawing {}".format(sender)) sender.change_balance(-float(amount), amount_currency=currency, comment="Wdraw IT '%s'" % recipient.mt4_id, request_id=0, transaction_type="InternalTransfer") withdraw_done = True log.info("Depositing {}".format(recipient)) recipient.change_balance(float(amount), amount_currency=currency, comment="Deposit IT '%s'" % sender.mt4_id, request_id=0, transaction_type="InternalTransfer") deposit_done = True # нужно вернуть что-то отличное от None return "ok" except PlatformError as e: log.error("Error transfering funds: {}".format(e.message)) if e.code == e.NOT_ENOUGH_MONEY: if self.internal: self.errors["__all__"] = _( "Sender equity level is insufficient for this operation." ) msg = "During funds transfer %(from)s => %(to)s error happened. Exactly:\n\n" if withdraw_done: msg += "- successful withdrawal of %(from_amount)s from %(from)s\n" if deposit_done: msg += "- successful deposition of %(to_amount)s to %(to)s\n" else: msg += "- failed deposition of %(to_amount)s to %(to)s [" + unicode( e) + u"]\n" else: msg += "- failed withdrawal of %(from_amount)s from %(from)s [" + unicode( e) + u"]\n" kwargs = { "from": sender, "to": recipient, "from_amount": currency.display_amount(amount), "to_amount": currency.display_amount(amount), "bonus_amount": sender.currency.display_amount(bonus_amount) if bonus_amount is not None else "", } log.info("Sending emails about failed transfer") log.debug("To: {}".format(settings.MANAGERS)) log.debug("Text: {}".format(msg % kwargs)) send_mail("Internal transfer %(from)s -> %(to)s FAIL" % kwargs, msg % kwargs, settings.SERVER_EMAIL, [x[1] for x in settings.MANAGERS]) if self.internal: self.errors["__all__"] = (msg % kwargs)
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 clean_currency(self): value = self.cleaned_data['currency'] return currencies.get_currency(value)
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()