mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-05 18:52:44 +01:00
Convert currency string to float
This commit is contained in:
parent
37c5a7adb5
commit
79e0fa56e2
@ -96,7 +96,8 @@ class InvoiceController extends Controller
|
||||
}
|
||||
|
||||
$invoices->map(function ($invoice) {
|
||||
$invoice->balance = Number::formatMoney($invoice->balance, $invoice->client);
|
||||
$invoice->balance = Number::formatValue($invoice->balance, $invoice->client->currency());
|
||||
$invoice->partial = Number::formatValue($invoice->partial, $invoice->client->currency());
|
||||
return $invoice;
|
||||
});
|
||||
|
||||
|
@ -18,12 +18,14 @@ use App\Jobs\Invoice\InjectSignature;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentHash;
|
||||
use App\Utils\Number;
|
||||
use App\Utils\Traits\MakesDates;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Cache;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Str;
|
||||
use Yajra\DataTables\Facades\DataTables;
|
||||
|
||||
/**
|
||||
@ -77,24 +79,12 @@ class PaymentController extends Controller
|
||||
// This is tagged with a type_id of 3 which is for a pending gateway fee.
|
||||
//REFACTOR - In order to preserve state we should save the array of invoices and amounts and store it in db/cache and use a HASH
|
||||
// to rehydrate these values in the payment response.
|
||||
// [
|
||||
// 'invoices' =>
|
||||
// [
|
||||
// 'invoice_id' => 'xx',
|
||||
// 'amount' => 'yy',
|
||||
// ]
|
||||
// ]
|
||||
|
||||
//old
|
||||
// $invoices = Invoice::whereIn('id', $this->transformKeys(request()->invoices))
|
||||
// ->where('company_id', auth('contact')->user()->company->id)
|
||||
// ->get();
|
||||
// dd(request()->all());
|
||||
|
||||
$gateway = CompanyGateway::find(request()->input('company_gateway_id'));
|
||||
/*find invoices*/
|
||||
$invoices = Invoice::whereIn('id', $this->transformKeys(array_column(request()->invoices, 'invoice_id')))->get();
|
||||
|
||||
//old
|
||||
// $amount = $invoices->sum('balance');
|
||||
$payable_invoices = request()->payable_invoices;
|
||||
$invoices = Invoice::whereIn('id', $this->transformKeys(array_column($payable_invoices, 'invoice_id')))->get();
|
||||
|
||||
/*filter only payable invoices*/
|
||||
$invoices = $invoices->filter(function ($invoice) {
|
||||
@ -109,24 +99,37 @@ class PaymentController extends Controller
|
||||
->with(['warning' => 'No payable invoices selected.']);
|
||||
}
|
||||
|
||||
/*iterate through invoices and add gateway fees*/
|
||||
foreach(request()->invoices as $payable_invoice)
|
||||
/*iterate through invoices and add gateway fees and other payment metadata*/
|
||||
|
||||
foreach($payable_invoices as $key => $payable_invoice)
|
||||
{
|
||||
$payable_invoice[$key]['amount'] = Number::parseFloat($payable_invoice[$key]['amount']);
|
||||
|
||||
$invoice = $invoices->first(function ($inv) use($payable_invoice) {
|
||||
return $payable_invoice['invoice_id'] == $inv->hashed_id;
|
||||
return $payable_invoice[$key]['invoice_id'] == $inv->hashed_id;
|
||||
});
|
||||
|
||||
if($invoice)
|
||||
$invoice->service()->addGatewayFee($payable_invoice['amount'])->save();
|
||||
}
|
||||
$invoice->service()->addGatewayFee($gateway, $payable_invoice[$key]['amount'])->save();
|
||||
|
||||
/*Format invoices we need to use fresh() here to bring in the gateway fees*/
|
||||
$invoices->fresh()->map(function ($invoice) {
|
||||
$invoice->balance = Number::formatMoney($invoice->balance, $invoice->client);
|
||||
$invoice->due_date = $this->formatDate($invoice->due_date, $invoice->client->date_format());
|
||||
|
||||
return $invoice;
|
||||
});
|
||||
/*Update the payable amount to include the fee*/
|
||||
$gateway_fee = $gateway->calcGatewayFee($payable_invoice[$key]['amount']);
|
||||
|
||||
$payable_invoice[$key]['amount_with_fee'] += $gateway_fee;
|
||||
$payable_invoice[$key]['fee'] = $gateway_fee;
|
||||
$payable_invoice[$key]['due_date'] = $this->formatDate($invoice->due_date, $invoice->client->date_format());
|
||||
$payable_invoice[$key]['invoice_number'] = $invoice->number;
|
||||
|
||||
if(isset($invoice->po_number))
|
||||
$additional_info = $invoice->po_number;
|
||||
elseif(isset($invoice->public_notes))
|
||||
$additional_info = $invoice->public_notes;
|
||||
else
|
||||
$additional_info = $invoice->date;
|
||||
|
||||
$payable_invoice[$key]['additional_info'] = $additional_info;
|
||||
|
||||
}
|
||||
|
||||
if ((bool) request()->signature) {
|
||||
$invoices->each(function ($invoice) {
|
||||
@ -135,19 +138,25 @@ class PaymentController extends Controller
|
||||
}
|
||||
|
||||
$payment_methods = auth()->user()->client->getPaymentMethods($amount);
|
||||
$gateway = CompanyGateway::find(request()->input('company_gateway_id'));
|
||||
$payment_method_id = request()->input('payment_method_id');
|
||||
|
||||
// Place to calculate gateway fee.
|
||||
$payment_hash = new PaymentHash;
|
||||
$payment_hash->hash = Str::random(128);
|
||||
$payment_hash->data = $payable_invoices;
|
||||
$payment_hash->save();
|
||||
|
||||
$totals = [
|
||||
'invoice_totals' => array_sum(array_column($payable_invoices,'amount')),
|
||||
'fee_totals' => array_sum(array_column($payable_invoices, 'fee')),
|
||||
'amount_with_fee' => array_sum(array_column($payable_invoices, 'amount_with_fee')),
|
||||
];
|
||||
|
||||
$data = [
|
||||
'invoices' => $invoices,
|
||||
'amount' => $amount,
|
||||
'fee' => $gateway->calcGatewayFee($amount),
|
||||
'amount_with_fee' => $amount + $gateway->calcGatewayFee($amount),
|
||||
'payment_hash' => $payment_hash->hash,
|
||||
'total' => $totals,
|
||||
'invoices' => $payable_invoices,
|
||||
'token' => auth()->user()->client->gateway_token($gateway->id, $payment_method_id),
|
||||
'payment_method_id' => $payment_method_id,
|
||||
'hashed_ids' => request()->invoices,
|
||||
];
|
||||
|
||||
return $gateway
|
||||
|
@ -33,12 +33,12 @@ class Number
|
||||
/**
|
||||
* Formats a given value based on the clients currency
|
||||
*
|
||||
* @param float $value The number to be formatted
|
||||
* @param float $value The number to be formatted
|
||||
* @param object $currency The client currency object
|
||||
*
|
||||
* @return float The formatted value
|
||||
* @return string The formatted value
|
||||
*/
|
||||
public static function formatValue($value, $currency) : float
|
||||
public static function formatValue($value, $currency) :string
|
||||
{
|
||||
$value = floatval($value);
|
||||
|
||||
@ -49,6 +49,30 @@ class Number
|
||||
return number_format($value, $precision, $decimal, $thousand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a given value based on the clients currency
|
||||
* BACK to a float
|
||||
*
|
||||
* @param string $value The formatted number to be converted back to float
|
||||
* @param object $currency The client currency object
|
||||
*
|
||||
* @return float The formatted value
|
||||
*/
|
||||
public static function parseFloat($value)
|
||||
{
|
||||
// convert "," to "."
|
||||
$s = str_replace(',', '.', $value);
|
||||
|
||||
// remove everything except numbers and dot "."
|
||||
$s = preg_replace("/[^0-9\.]/", "", $s);
|
||||
|
||||
// remove all seperators from first part and keep the end
|
||||
$s = str_replace('.', '',substr($s, 0, -3)) . substr($s, -3);
|
||||
|
||||
// return float
|
||||
return (float) $s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a given value based on the clients currency AND country
|
||||
*
|
||||
|
@ -13,9 +13,7 @@
|
||||
@section('body')
|
||||
<form action="{{ route('client.payments.response') }}" method="post" id="server_response">
|
||||
@csrf
|
||||
@foreach($invoices as $invoice)
|
||||
<input type="hidden" name="hashed_ids[]" value="{{ $invoice->hashed_id }}">
|
||||
@endforeach
|
||||
<input type="hidden" name="payment_hash" value="{{ $payment_hash }}">
|
||||
<input type="hidden" name="company_gateway_id" value="{{ $gateway->id }}">
|
||||
<input type="hidden" name="payment_method_id" value="1">
|
||||
<input type="hidden" name="gateway_response" id="gateway_response">
|
||||
@ -23,7 +21,7 @@
|
||||
<input type="hidden" name="dataDescriptor" id="dataDescriptor" />
|
||||
<input type="hidden" name="token" id="token" />
|
||||
<input type="hidden" name="store_card" id="store_card" />
|
||||
<input type="hidden" name="amount_with_fee" id="amount_with_fee" value="{{ $amount_with_fee }}" />
|
||||
<input type="hidden" name="amount_with_fee" id="amount_with_fee" value="{{ $total['amount_with_fee'] }}" />
|
||||
</form>
|
||||
<div class="container mx-auto">
|
||||
<div class="grid grid-cols-6 gap-4">
|
||||
@ -39,11 +37,23 @@
|
||||
@if($tokens->count() == 0)
|
||||
<dl>
|
||||
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<dt class="text-sm leading-5 font-medium text-gray-500">
|
||||
{{ ctrans('texts.totals') }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
{{ App\Utils\Number::formatMoney($total['invoice_totals'], $client) }}
|
||||
</dd>
|
||||
<dt class="text-sm leading-5 font-medium text-gray-500">
|
||||
{{ ctrans('texts.gateway_fees') }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
{{ App\Utils\Number::formatMoney($total['fee_totals'], $client) }}
|
||||
</dd>
|
||||
<dt class="text-sm leading-5 font-medium text-gray-500">
|
||||
{{ ctrans('texts.amount') }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
{{ App\Utils\Number::formatMoney($amount_with_fee, $client) }}
|
||||
{{ App\Utils\Number::formatMoney($total['amount_with_fee'], $client) }}
|
||||
</dd>
|
||||
</div>
|
||||
|
||||
@ -67,11 +77,23 @@
|
||||
<div>
|
||||
<dl>
|
||||
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<dt class="text-sm leading-5 font-medium text-gray-500">
|
||||
{{ ctrans('texts.totals') }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
{{ App\Utils\Number::formatMoney($total['invoice_totals'], $client) }}
|
||||
</dd>
|
||||
<dt class="text-sm leading-5 font-medium text-gray-500">
|
||||
{{ ctrans('texts.gateway_fees') }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
{{ App\Utils\Number::formatMoney($total['fee_totals'], $client) }}
|
||||
</dd>
|
||||
<dt class="text-sm leading-5 font-medium text-gray-500">
|
||||
{{ ctrans('texts.amount') }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
{{ App\Utils\Number::formatMoney($amount_with_fee, $client) }}
|
||||
{{ App\Utils\Number::formatMoney($total['amount_with_fee'], $client) }}
|
||||
</dd>
|
||||
</div>
|
||||
@foreach($tokens as $token)
|
||||
|
@ -10,13 +10,10 @@
|
||||
@section('body')
|
||||
<form action="{{ route('client.payments.process') }}" method="post" id="payment-form">
|
||||
@csrf
|
||||
@foreach($invoices as $invoice)
|
||||
<input type="hidden" name="invoices[]" value="{{ $invoice->hashed_id }}">
|
||||
@endforeach
|
||||
<input type="hidden" name="company_gateway_id" id="company_gateway_id">
|
||||
<input type="hidden" name="payment_method_id" id="payment_method_id">
|
||||
<input type="hidden" name="signature">
|
||||
</form>
|
||||
|
||||
<div class="container mx-auto">
|
||||
<div class="grid grid-cols-6 gap-4">
|
||||
<div class="col-span-6 md:col-start-2 md:col-span-4">
|
||||
@ -63,7 +60,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@foreach($invoices as $invoice)
|
||||
@foreach($invoices as $key => $invoice)
|
||||
<input type="hidden" name="payable_invoices[{{$key}}][invoice_id]" value="{{ $invoice->hashed_id }}">
|
||||
<div class="bg-white shadow overflow-hidden sm:rounded-lg mb-4">
|
||||
<div class="px-4 py-5 border-b border-gray-200 sm:px-6">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
@ -104,7 +102,7 @@
|
||||
@elseif($invoice->public_notes)
|
||||
{{ $invoice->public_notes }}
|
||||
@else
|
||||
{{ $invoice->invoice_date}}
|
||||
{{ $invoice->date}}
|
||||
@endif
|
||||
</dd>
|
||||
</div>
|
||||
@ -113,7 +111,8 @@
|
||||
{{ ctrans('texts.amount') }}
|
||||
</dt>
|
||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
||||
{{ App\Utils\Number::formatMoney($invoice->amount, $invoice->client) }}
|
||||
<!-- App\Utils\Number::formatMoney($invoice->amount, $invoice->client) -->
|
||||
<input type="text" name="payable_invoices[{{$key}}][amount]" value="{{ $invoice->partial > 0 ? $invoice->partial : $invoice->balance }}">
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
@ -123,7 +122,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
@include('portal.ninja2020.invoices.includes.terms')
|
||||
@include('portal.ninja2020.invoices.includes.signature')
|
||||
@endsection
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\Currency;
|
||||
use App\Utils\Number;
|
||||
use Tests\TestCase;
|
||||
|
||||
@ -31,4 +32,31 @@ class NumberTest extends TestCase
|
||||
|
||||
$this->assertEquals(2.15, $rounded);
|
||||
}
|
||||
|
||||
public function testParsingFloats()
|
||||
{
|
||||
|
||||
Currency::all()->each(function ($currency){
|
||||
|
||||
$amount = 123456789.12;
|
||||
|
||||
$formatted_amount = Number::formatValue($amount, $currency);
|
||||
|
||||
info($formatted_amount);
|
||||
|
||||
$float_amount = Number::parseFloat($formatted_amount);
|
||||
|
||||
info($float_amount);
|
||||
info($currency->id);
|
||||
info($currency->code);
|
||||
|
||||
if($currency->precision == 0){
|
||||
$this->assertEquals(123456789, $float_amount);
|
||||
}
|
||||
else
|
||||
$this->assertEquals($amount, $float_amount);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user