creating sync with billing

This commit is contained in:
olegphenomenon 2023-01-11 12:25:49 +02:00
parent 162647acba
commit 0a4444b556
9 changed files with 577 additions and 60 deletions

View file

@ -0,0 +1,71 @@
module EisBilling
class InvoicesController < BaseController
TYPE = 'PaymentOrders::EveryPay'.freeze
before_action :load_invoice, only: :update
def update
if @invoice.update(modified_params)
payment_orders_handler
render json: {
message: 'Invoice data was successfully updated'
}, status: :ok
else
render json: {
error: @message.errors.full_messages
}, status: :unprocessable_entity
end
end
private
def payment_orders_handler
if @invoice.payment_orders.present?
return if (@invoice.paid? && status == 'paid') || (@invoice.cancelled? && status == 'cancelled')
if status == 'cancelled' || status == 'failed'
@invoice.cancel_manualy
elsif status == 'paid'
@invoice.autobind_manually
end
else
return unless status == 'paid'
@invoice.autobind_manually
end
end
def status
case params[:invoice][:status]
when 'paid'
'paid'
when 'cancelled'
'cancelled'
when 'failed'
'failed'
else
'issued'
end
end
def load_invoice
@invoice = Invoice.find_by(number: params[:invoice][:invoice_number])
if @invoice.nil?
render json: {
error: {
message: "Invoice with #{params[:invoice][:invoice_number]} number not found"
}
}, status: :not_found and return
end
end
def modified_params
{
in_directo: params[:invoice][:in_directo],
e_invoice_sent_at: params[:invoice][:sent_at_omniva]
}
end
end
end

View file

@ -3,19 +3,20 @@ module EisBilling
TYPE = 'PaymentOrders::EveryPay'.freeze TYPE = 'PaymentOrders::EveryPay'.freeze
def update def update
payment_status = define_payment_status(params[:payment_state])
invoice = Invoice.find_by(number: params[:order_reference]) invoice = Invoice.find_by(number: params[:order_reference])
return if invoice.paid? if invoice.paid?
render json: { message: 'Invoice already paid' }, status: :ok
else
invoice.process_payment(
payment_type: TYPE,
everypay_response: params,
payment_status: define_payment_status(params[:payment_state]),
sum: params[:standing_amount],
transaction_time: params[:transaction_time]
)
bank = create_bank_transfer(invoice: invoice, sum: params[:standing_amount], paid_at: params[:transaction_time]) render json: { message: 'Payment is proccessing' }, status: :ok
create_payment_order(invoice: invoice, everypay_response: params, payment_status: payment_status)
bank.bind_invoice(params[:order_reference])
respond_to do |format|
format.json do
render status: :ok, content_type: 'application/json', layout: false, json: { message: 'ok' }
end
end end
end end
@ -26,30 +27,5 @@ module EisBilling
:failed :failed
end end
def create_payment_order(invoice:, everypay_response:, payment_status:)
payment = PaymentOrder.new
payment.type = TYPE
payment.invoice = invoice
payment.response = everypay_response
payment.status = payment_status
payment.save
payment
end
def create_bank_transfer(invoice:, sum:, paid_at:)
bank = BankTransaction.new
bank.description = invoice.order
bank.reference_no = invoice.reference_no
bank.currency = invoice.currency
bank.iban = invoice.seller_iban
bank.sum = sum
bank.paid_at = paid_at
bank.buyer_name = invoice.buyer_name
bank.save
bank
end
end end
end end

View file

@ -31,4 +31,22 @@ module Invoice::Cancellable
def not_cancelled? def not_cancelled?
!cancelled? !cancelled?
end end
def cancel_manualy
account_activity = AccountActivity.find_by(invoice_id: id)
account_activity_dup = account_activity.dup
account_activity_dup.sum = -account_activity.sum.to_i
account_activity_dup.save
account_activity.update(invoice_id: nil)
account_activity_dup.update(invoice_id: nil)
mark_cancelled_payment_order
account_activity.save && account_activity_dup.save
end
private
def mark_cancelled_payment_order
payment_order = payment_orders.last
payment_order.update(notes: 'Cancelled')
end
end end

View file

@ -23,4 +23,34 @@ module Invoice::Payable
def unpaid? def unpaid?
!paid? !paid?
end end
def process_payment(**options)
payment = options[:payment_type].constantize.new(invoice: self)
payment.response = options[:everypay_response]
payment.status = options[:payment_status]
payment.save!
bank_transaction = payment.base_transaction(sum: options[:sum],
paid_at: options[:transaction_time] || Time.zone.now,
buyer_name: buyer_name)
bank_transaction.bind_invoice(number)
end
def autobind_manually
return if paid?
bank_statement = BankStatement.new(
bank_code: Setting.registry_bank_code,
iban: Setting.registry_iban
)
bank_statement.bank_transactions.build(
description: description,
sum: total,
reference_no: reference_no,
paid_at: Time.zone.now.to_date,
currency: 'EUR'
)
bank_statement.save!
bank_statement.bind_invoices(manual: true)
end
end end

View file

@ -16,6 +16,7 @@ Rails.application.routes.draw do
put '/directo_response', to: 'directo_response#update', as: 'directo_response' put '/directo_response', to: 'directo_response#update', as: 'directo_response'
put '/e_invoice_response', to: 'e_invoice_response#update', as: 'e_invoice_response' put '/e_invoice_response', to: 'e_invoice_response#update', as: 'e_invoice_response'
post '/lhv_connect_transactions', to: 'lhv_connect_transactions#create', as: 'lhv_connect_transactions' post '/lhv_connect_transactions', to: 'lhv_connect_transactions#create', as: 'lhv_connect_transactions'
resource :invoices, only: [:update]
end end
namespace :epp do namespace :epp do

View file

@ -4447,6 +4447,7 @@ CREATE INDEX index_log_domains_on_object ON public.log_domains USING gin (object
-- --
<<<<<<< HEAD
-- Name: index_log_domains_on_object_changes; Type: INDEX; Schema: public; Owner: - -- Name: index_log_domains_on_object_changes; Type: INDEX; Schema: public; Owner: -
-- --
@ -4454,6 +4455,8 @@ CREATE INDEX index_log_domains_on_object_changes ON public.log_domains USING gin
-- --
=======
>>>>>>> creating sync with billing
-- Name: index_log_domains_on_whodunnit; Type: INDEX; Schema: public; Owner: - -- Name: index_log_domains_on_whodunnit; Type: INDEX; Schema: public; Owner: -
-- --

View file

@ -0,0 +1,306 @@
require 'test_helper'
class StubAuthorization < ApplicationController
skip_authorization_check
def authorized
true
end
end
EisBilling::BaseController = StubAuthorization
class EInvoiceResponseTest < ApplicationIntegrationTest
setup do
sign_in users(:api_bestnames)
@invoice = invoices(:one)
response_message = {
message: 'got it'
}
stub_request(:post, 'https://eis_billing_system:3000/api/v1/invoice_generator/invoice_status')
.to_return(status: 200, body: response_message.to_json, headers: {})
end
test 'it should update status of invoice if payment order is existed' do
@invoice.update(total: 120.0)
@invoice.reload
incoming_params = {
invoice: {
invoice_number: @invoice.number,
initiator: 'registry',
payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349',
transaction_amount: 120.0,
status: 'paid',
in_directo: false,
everypay_response: {
'some' => 'some'
},
sent_at_omniva: Time.zone.now - 10.minutes
}
}
@invoice.account_activity.delete && @invoice.reload
assert_equal @invoice.payment_orders.pluck(:status), %w[issued issued]
put eis_billing_invoices_path, params: incoming_params
@invoice.reload
@invoice.payment_orders.each(&:reload)
invoice = Invoice.find(@invoice.id)
assert_equal invoice.payment_orders.pluck(:status), %w[issued issued paid]
end
test 'it should update invoice data as directo and omniva' do
incoming_params = {
invoice: {
invoice_number: @invoice.number,
initiator: 'registry',
payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349',
transaction_amount: 270.0,
status: 'unpaid',
in_directo: true,
everypay_response: {
'some' => 'some'
},
sent_at_omniva: Time.zone.now - 10.minutes
}
}
assert_equal @invoice.payment_orders.pluck(:status), %w[issued issued]
assert_nil @invoice.e_invoice_sent_at
refute @invoice.in_directo
put eis_billing_invoices_path, params: incoming_params
@invoice.payment_orders.each(&:reload)
@invoice.reload
assert_equal @invoice.payment_orders.pluck(:status), %w[issued issued]
assert @invoice.in_directo
assert_not_nil @invoice.e_invoice_sent_at
end
test 'it should create new payment order if payment order and activity are missing, but status has paid status' do
invoice = invoices(:one)
invoice.payment_orders.destroy_all and invoice.account_activity.destroy
invoice.update(total: 120.0)
invoice.reload
incoming_params = {
invoice: {
invoice_number: invoice.number,
initiator: 'registry',
payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349',
transaction_amount: 120.0,
status: 'paid',
in_directo: false,
everypay_response: {
'some' => 'some'
},
sent_at_omniva: Time.zone.now - 10.minutes
}
}
assert invoice.payment_orders.empty?
assert_nil invoice.account_activity
put eis_billing_invoices_path, params: incoming_params
invoice.reload
invoice.payment_orders.each(&:reload)
assert_equal invoice.payment_orders.count, 1
assert invoice.payment_orders.first.paid?
assert invoice.account_activity
end
test 'it should ignore payment order creation if payment status is not paid and payment order not existed' do
incoming_params = {
invoice: {
invoice_number: @invoice.number,
initiator: 'registry',
payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349',
transaction_amount: 270.0,
status: 'cancelled',
in_directo: false,
everypay_response: {
'some' => 'some'
},
sent_at_omniva: Time.zone.now - 10.minutes
}
}
@invoice.payment_orders.destroy_all and @invoice.account_activity.destroy
@invoice.reload
assert @invoice.payment_orders.empty?
assert_nil @invoice.account_activity
put eis_billing_invoices_path, params: incoming_params and @invoice.reload
assert @invoice.payment_orders.empty?
assert_nil @invoice.account_activity
end
test 'it should add balance if payment order mark as paid' do
invoice = invoices(:one)
item = invoice.items.first
invoice.payment_orders.destroy_all and invoice.account_activity.destroy
invoice.update(total: 120.0) && invoice.reload
item.update(price: 100.0) && item.reload
incoming_params = {
invoice: {
invoice_number: invoice.number,
initiator: 'registry',
payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349',
transaction_amount: 120.0,
status: 'paid',
in_directo: false,
everypay_response: {
'some' => 'some'
},
sent_at_omniva: Time.zone.now - 10.minutes
}
}
assert invoice.payment_orders.empty?
assert_nil invoice.account_activity
account = invoice.buyer.accounts.first
assert_equal account.balance.to_f, 100.0
put eis_billing_invoices_path, params: incoming_params
invoice.reload
invoice.payment_orders.each(&:reload)
account.reload
assert_equal invoice.payment_orders.count, 1
assert invoice.payment_orders.first.paid?
assert invoice.account_activity
assert_equal account.balance.to_f, 200.0
end
test 'should change nothing if invoice is already paid' do
assert @invoice.account_activity.present?
assert @invoice.payment_orders.present?
account = @invoice.buyer.accounts.first
assert_equal account.balance.to_f, 100.0
assert @invoice.paid?
incoming_params = {
invoice: {
invoice_number: @invoice.number,
initiator: 'registry',
payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349',
transaction_amount: @invoice.total,
status: 'paid',
in_directo: false,
everypay_response: {
'some' => 'some'
},
sent_at_omniva: Time.zone.now - 10.minutes
}
}
put eis_billing_invoices_path, params: incoming_params
account.reload
assert_equal account.balance.to_f, 100.0
end
test 'it should decrease balance and again add if user change paid invoice to cancel and then again to paid' do
invoice = invoices(:one)
item = invoice.items.first
invoice.payment_orders.destroy_all and invoice.account_activity.destroy
invoice.update(total: 120.0) && invoice.reload
item.update(price: 100.0) && item.reload
add_balance_params = {
invoice: {
invoice_number: invoice.number,
initiator: 'registry',
payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349',
transaction_amount: 120.0,
status: 'paid',
in_directo: false,
everypay_response: {
'some' => 'some'
},
sent_at_omniva: Time.zone.now - 10.minutes
}
}
assert invoice.payment_orders.empty?
assert_nil invoice.account_activity
account = invoice.buyer.accounts.first
assert_equal account.balance.to_f, 100.0
put eis_billing_invoices_path, params: add_balance_params
invoice.reload
invoice.payment_orders.each(&:reload)
account.reload
assert_equal invoice.payment_orders.count, 1
assert invoice.payment_orders.first.paid?
assert invoice.account_activity
assert_equal account.balance.to_f, 200.0
decrease_balance_params = {
invoice: {
invoice_number: invoice.number,
initiator: 'registry',
payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349',
transaction_amount: 120.0,
status: 'cancelled',
in_directo: false,
everypay_response: {
'some' => 'some'
},
sent_at_omniva: Time.zone.now - 10.minutes
}
}
put eis_billing_invoices_path, params: decrease_balance_params
invoice.reload
invoice.payment_orders.each(&:reload)
account.reload
assert_equal account.balance.to_f, 100.0
end
test 'it should return an error if invoice not existing' do
incoming_params = {
invoice: {
invoice_number: 'nonexisted-invoice',
initiator: 'registry',
payment_reference: '93b29d54ae08f7728e72ee3fe0e88855cd1d266912039d7d23fa2b54b7e1b349',
transaction_amount: 120.0,
status: 'paid',
in_directo: false,
everypay_response: {
'some' => 'some'
},
sent_at_omniva: Time.zone.now - 10.minutes
}
}
put eis_billing_invoices_path, params: incoming_params
registry_response = JSON.parse(response.body).with_indifferent_access[:error]
assert_equal registry_response[:message], 'Invoice with nonexisted-invoice number not found'
end
end

View file

@ -9,10 +9,7 @@ class PaymentStatusTest < ApplicationIntegrationTest
Spy.on_instance_method(EisBilling::BaseController, :authorized).and_return(true) Spy.on_instance_method(EisBilling::BaseController, :authorized).and_return(true)
end end
def shoudl_update_buyer_balance test 'should mark an invoice as paid' do
assert @invoice.paid?
assert_equal @invoice.buyer.balance.to_f, 100.0
payload = { payload = {
payment_state: 'settled', payment_state: 'settled',
order_reference: @unpaid.number, order_reference: @unpaid.number,
@ -20,13 +17,57 @@ class PaymentStatusTest < ApplicationIntegrationTest
transaction_time: Time.zone.now, transaction_time: Time.zone.now,
} }
put eis_billing_payment_status_path, params: payload item = @unpaid.items.first
@invoice.reload refute @unpaid.paid?
@invoice.buyer.reload assert_equal @unpaid.buyer.balance.to_f, 100.0
@registrar.reload assert_equal item.price, 5.0
put eis_billing_payment_status_path, params: payload
@unpaid.reload
assert_equal @unpaid.buyer.balance.to_f, 105.0
end
test 'ignore additonal callbacks if invoice is already paid' do
payload = {
payment_state: 'settled',
order_reference: @unpaid.number,
standing_amount: @unpaid.total,
transaction_time: Time.zone.now,
}
item = @unpaid.items.first
refute @unpaid.paid?
assert_equal @unpaid.buyer.balance.to_f, 100.0
assert_equal item.price, 5.0
put eis_billing_payment_status_path, params: payload
@unpaid.reload
assert_equal @unpaid.buyer.balance.to_f, 105.0
assert @unpaid.paid?
put eis_billing_payment_status_path, params: payload
@unpaid.reload
assert_equal @unpaid.buyer.balance.to_f, 105.0
assert @unpaid.paid?
end
test 'send callback to already paid invoice' do
payload = {
payment_state: 'settled',
order_reference: @invoice.number,
standing_amount: @invoice.total,
transaction_time: Time.zone.now,
}
assert @invoice.paid? assert @invoice.paid?
assert_equal @invoice.buyer.balance.to_f, 100.0 assert_equal @invoice.buyer.balance.to_f, 100.0
put eis_billing_payment_status_path, params: payload
@invoice.reload
assert_equal @invoice.buyer.balance.to_f, 100.0
assert @invoice.paid?
end end
end end

View file

@ -6,6 +6,8 @@ class InvoiceTest < ActiveSupport::TestCase
setup do setup do
@invoice = invoices(:one) @invoice = invoices(:one)
Spy.on_instance_method(EisBilling::BaseController, :authorized).and_return(true) Spy.on_instance_method(EisBilling::BaseController, :authorized).and_return(true)
stub_request(:post, 'https://eis_billing_system:3000/api/v1/invoice_generator/invoice_status')
.to_return(status: :ok, headers: {})
end end
def test_fixture_is_valid def test_fixture_is_valid
@ -124,32 +126,32 @@ class InvoiceTest < ActiveSupport::TestCase
transaction.sum = 250 transaction.sum = 250
invoice_n = Invoice.order(number: :desc).last.number invoice_n = Invoice.order(number: :desc).last.number
stub_request(:post, "https://eis_billing_system:3000/api/v1/invoice_generator/invoice_number_generator") stub_request(:post, 'https://eis_billing_system:3000/api/v1/invoice_generator/invoice_number_generator')
.to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}", headers: {}) .to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}", headers: {})
stub_request(:post, "https://eis_billing_system:3000/api/v1/invoice_generator/invoice_generator") stub_request(:post, 'https://eis_billing_system:3000/api/v1/invoice_generator/invoice_generator')
.to_return(status: 200, body: "{\"everypay_link\":\"http://link.test\"}", headers: {}) .to_return(status: 200, body: '{"everypay_link":"http://link.test"}', headers: {})
stub_request(:put, "https://registry:3000/eis_billing/e_invoice_response"). stub_request(:put, 'https://registry:3000/eis_billing/e_invoice_response')
to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}, {\"date\":\"#{Time.zone.now-10.minutes}\"}", headers: {}) .to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}, {\"date\":\"#{Time.zone.now - 10.minutes}\"}", headers: {})
stub_request(:post, "https://eis_billing_system:3000/api/v1/e_invoice/e_invoice"). stub_request(:post, 'https://eis_billing_system:3000/api/v1/e_invoice/e_invoice')
to_return(status: 200, body: "", headers: {}) .to_return(status: 200, body: '', headers: {})
invoice = Invoice.create_from_transaction!(transaction) invoice = Invoice.create_from_transaction!(transaction)
assert_equal 250, invoice.total assert_equal 250, invoice.total
invoice_n = Invoice.order(number: :desc).last.number invoice_n = Invoice.order(number: :desc).last.number
stub_request(:post, "https://eis_billing_system:3000/api/v1/invoice_generator/invoice_number_generator"). stub_request(:post, 'https://eis_billing_system:3000/api/v1/invoice_generator/invoice_number_generator')
to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 4}\"}", headers: {}) .to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 4}\"}", headers: {})
transaction.sum = 146.88 transaction.sum = 146.88
invoice = Invoice.create_from_transaction!(transaction) invoice = Invoice.create_from_transaction!(transaction)
assert_equal 146.88, invoice.total assert_equal 146.88, invoice.total
invoice_n = Invoice.order(number: :desc).last.number invoice_n = Invoice.order(number: :desc).last.number
stub_request(:post, "https://eis_billing_system:3000/api/v1/invoice_generator/invoice_number_generator"). stub_request(:post, 'https://eis_billing_system:3000/api/v1/invoice_generator/invoice_number_generator')
to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 5}\"}", headers: {}) .to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 5}\"}", headers: {})
transaction.sum = 0.99 transaction.sum = 0.99
invoice = Invoice.create_from_transaction!(transaction) invoice = Invoice.create_from_transaction!(transaction)
@ -158,14 +160,14 @@ class InvoiceTest < ActiveSupport::TestCase
def test_emails_invoice_after_creating_topup_invoice def test_emails_invoice_after_creating_topup_invoice
invoice_n = Invoice.order(number: :desc).last.number invoice_n = Invoice.order(number: :desc).last.number
stub_request(:post, "https://eis_billing_system:3000/api/v1/invoice_generator/invoice_generator"). stub_request(:post, 'https://eis_billing_system:3000/api/v1/invoice_generator/invoice_generator')
to_return(status: 200, body: "{\"everypay_link\":\"http://link.test\"}", headers: {}) .to_return(status: 200, body: '{"everypay_link":"http://link.test"}', headers: {})
stub_request(:put, "https://registry:3000/eis_billing/e_invoice_response"). stub_request(:put, 'https://registry:3000/eis_billing/e_invoice_response')
to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}, {\"date\":\"#{Time.zone.now-10.minutes}\"}", headers: {}) .to_return(status: 200, body: "{\"invoice_number\":\"#{invoice_n + 3}\"}, {\"date\":\"#{Time.zone.now - 10.minutes}\"}", headers: {})
stub_request(:post, "https://eis_billing_system:3000/api/v1/e_invoice/e_invoice"). stub_request(:post, 'https://eis_billing_system:3000/api/v1/e_invoice/e_invoice')
to_return(status: 200, body: "", headers: {}) .to_return(status: 200, body: '', headers: {})
registrar = registrars(:bestnames) registrar = registrars(:bestnames)
transaction = bank_transactions(:one).dup transaction = bank_transactions(:one).dup
@ -179,4 +181,73 @@ class InvoiceTest < ActiveSupport::TestCase
Invoice.create_from_transaction!(transaction) Invoice.create_from_transaction!(transaction)
end end
end end
def test_create_payment_order
everypay_response = {
'some' => 'some'
}
@invoice.payment_orders.delete_all
@invoice.account_activity.delete and @invoice.reload
assert @invoice.payment_orders.empty?
assert_nil @invoice.account_activity
@invoice.process_payment(payment_type: 'PaymentOrders::EveryPay',
everypay_response: everypay_response,
payment_status: 'paid',
sum: @invoice.total,
transaction_time: Time.zone.now - 10.minutes - 23.seconds)
@invoice.reload
assert_equal @invoice.payment_orders.count, 1
assert @invoice.account_activity.present?
end
def test_should_raise_error_if_bill_already_paid
everypay_response = {
'some' => 'some'
}
assert @invoice.payment_orders.present?
assert_raises(ActiveRecord::RecordInvalid) do
@invoice.process_payment(payment_type: 'PaymentOrders::EveryPay',
everypay_response: everypay_response,
payment_status: 'paid',
sum: @invoice.total,
transaction_time: Time.zone.now - 10.minutes - 23.seconds)
end
end
def test_should_manually_autobin_invoice
@invoice.payment_orders.destroy_all && @invoice.account_activity.destroy
@invoice.reload
account = @invoice.buyer.accounts.first
item = @invoice.items.first
assert @invoice.payment_orders.empty?
assert @invoice.account_activity.nil?
assert_equal account.balance.to_f, 100.0
assert_equal item.price, 5.0
@invoice.autobind_manually
@invoice.reload
account.reload
assert_equal account.balance.to_f, 105.0
assert @invoice.payment_orders.present?
assert @invoice.account_activity.present?
end
def test_cannot_to_increase_balance_already_paid_invoice_by_manually_autobind
assert @invoice.paid?
account = @invoice.buyer.accounts.first
assert_equal account.balance.to_f, 100.0
@invoice.autobind_manually
@invoice.reload
assert_equal account.balance.to_f, 100.0
end
end end