mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-02 19:04:33 -04:00
Merge branch 'v2' into v2
This commit is contained in:
commit
7e85ee0be3
@ -73,9 +73,10 @@ class PaymentController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function process()
|
public function process()
|
||||||
{
|
{
|
||||||
|
|
||||||
$gateway = CompanyGateway::find(request()->input('company_gateway_id'));
|
$gateway = CompanyGateway::find(request()->input('company_gateway_id'));
|
||||||
|
|
||||||
/*find invoices*/
|
/*find invoices*/
|
||||||
|
|
||||||
$payable_invoices = request()->payable_invoices;
|
$payable_invoices = request()->payable_invoices;
|
||||||
$invoices = Invoice::whereIn('id', $this->transformKeys(array_column($payable_invoices, 'invoice_id')))->get();
|
$invoices = Invoice::whereIn('id', $this->transformKeys(array_column($payable_invoices, 'invoice_id')))->get();
|
||||||
|
|
||||||
@ -91,9 +92,11 @@ class PaymentController extends Controller
|
|||||||
->with(['warning' => 'No payable invoices selected.']);
|
->with(['warning' => 'No payable invoices selected.']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*iterate through invoices and add gateway fees and other payment metadata*/
|
$settings = auth()->user()->client->getMergedSettings();
|
||||||
|
|
||||||
|
/*iterate through invoices and add gateway fees and other payment metadata*/
|
||||||
foreach ($payable_invoices as $key => $payable_invoice) {
|
foreach ($payable_invoices as $key => $payable_invoice) {
|
||||||
|
|
||||||
$payable_invoices[$key]['amount'] = Number::parseFloat($payable_invoice['amount']);
|
$payable_invoices[$key]['amount'] = Number::parseFloat($payable_invoice['amount']);
|
||||||
$payable_invoice['amount'] = $payable_invoices[$key]['amount'];
|
$payable_invoice['amount'] = $payable_invoices[$key]['amount'];
|
||||||
|
|
||||||
@ -101,6 +104,41 @@ class PaymentController extends Controller
|
|||||||
return $payable_invoice['invoice_id'] == $inv->hashed_id;
|
return $payable_invoice['invoice_id'] == $inv->hashed_id;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Check if company supports over & under payments.
|
||||||
|
// In case it doesn't this is where process should stop.
|
||||||
|
|
||||||
|
$payable_amount = Number::roundValue(Number::parseFloat($payable_invoice['amount']), auth()->user()->client->currency()->precision);
|
||||||
|
$invoice_amount = Number::roundValue($invoice->amount, auth()->user()->client->currency()->precision);
|
||||||
|
|
||||||
|
if ($settings->client_portal_allow_under_payment == false && $settings->client_portal_allow_over_payment == false) {
|
||||||
|
$payable_invoice['amount'] = $invoice->amount;
|
||||||
|
} // We don't allow either of these, reset the amount to default invoice (to prevent inspect element payments).
|
||||||
|
|
||||||
|
if ($settings->client_portal_allow_under_payment) {
|
||||||
|
if ($payable_invoice['amount'] < $settings->client_portal_under_payment_minimum) {
|
||||||
|
return redirect()
|
||||||
|
->route('client.invoices.index')
|
||||||
|
->with('message', ctrans('texts.minimum_required_payment', ['amount' => $settings->client_portal_under_payment_minimum]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$payable_amount = Number::roundValue(Number::parseFloat($payable_invoice['amount']), auth()->user()->client->currency()->precision);
|
||||||
|
$invoice_amount = Number::roundValue($invoice->amount, auth()->user()->client->currency()->precision);
|
||||||
|
|
||||||
|
if ($payable_amount < $invoice_amount) {
|
||||||
|
return redirect()
|
||||||
|
->route('client.invoices.index')
|
||||||
|
->with('message', ctrans('texts.under_payments_disabled'));
|
||||||
|
}
|
||||||
|
} // Make sure 'amount' from form is not lower than 'amount' from invoice.
|
||||||
|
|
||||||
|
if ($settings->client_portal_allow_over_payment == false) {
|
||||||
|
if ($payable_amount > $invoice_amount) {
|
||||||
|
return redirect()
|
||||||
|
->route('client.invoices.index')
|
||||||
|
->with('message', ctrans('texts.over_payments_disabled'));
|
||||||
|
}
|
||||||
|
} // Make sure 'amount' from form is not higher than 'amount' from invoice.
|
||||||
|
|
||||||
$payable_invoices[$key]['due_date'] = $this->formatDate($invoice->due_date, $invoice->client->date_format());
|
$payable_invoices[$key]['due_date'] = $this->formatDate($invoice->due_date, $invoice->client->date_format());
|
||||||
$payable_invoices[$key]['invoice_number'] = $invoice->number;
|
$payable_invoices[$key]['invoice_number'] = $invoice->number;
|
||||||
|
|
||||||
@ -129,7 +167,7 @@ class PaymentController extends Controller
|
|||||||
$first_invoice = $invoices->first();
|
$first_invoice = $invoices->first();
|
||||||
$fee_totals = round($gateway->calcGatewayFee($invoice_totals, true), $first_invoice->client->currency()->precision);
|
$fee_totals = round($gateway->calcGatewayFee($invoice_totals, true), $first_invoice->client->currency()->precision);
|
||||||
|
|
||||||
if (! $first_invoice->uses_inclusive_taxes) {
|
if (!$first_invoice->uses_inclusive_taxes) {
|
||||||
$fee_tax = 0;
|
$fee_tax = 0;
|
||||||
$fee_tax += round(($first_invoice->tax_rate1 / 100) * $fee_totals, $first_invoice->client->currency()->precision);
|
$fee_tax += round(($first_invoice->tax_rate1 / 100) * $fee_totals, $first_invoice->client->currency()->precision);
|
||||||
$fee_tax += round(($first_invoice->tax_rate2 / 100) * $fee_totals, $first_invoice->client->currency()->precision);
|
$fee_tax += round(($first_invoice->tax_rate2 / 100) * $fee_totals, $first_invoice->client->currency()->precision);
|
||||||
|
@ -49,10 +49,14 @@ class StripePaymentDriver extends BasePaymentDriver
|
|||||||
|
|
||||||
public $can_authorise_credit_card = true;
|
public $can_authorise_credit_card = true;
|
||||||
|
|
||||||
|
/** @var \Stripe\StripeClient */
|
||||||
|
protected $stripe;
|
||||||
|
|
||||||
protected $customer_reference = 'customerReferenceParam';
|
protected $customer_reference = 'customerReferenceParam';
|
||||||
|
|
||||||
protected $payment_method;
|
protected $payment_method;
|
||||||
|
|
||||||
|
|
||||||
public static $methods = [
|
public static $methods = [
|
||||||
GatewayType::CREDIT_CARD => CreditCard::class,
|
GatewayType::CREDIT_CARD => CreditCard::class,
|
||||||
GatewayType::BANK_TRANSFER => ACH::class,
|
GatewayType::BANK_TRANSFER => ACH::class,
|
||||||
@ -81,6 +85,10 @@ class StripePaymentDriver extends BasePaymentDriver
|
|||||||
*/
|
*/
|
||||||
public function init(): void
|
public function init(): void
|
||||||
{
|
{
|
||||||
|
$this->stripe = new \Stripe\StripeClient(
|
||||||
|
$this->company_gateway->getConfigField('apiKey')
|
||||||
|
);
|
||||||
|
|
||||||
Stripe::setApiKey($this->company_gateway->getConfigField('apiKey'));
|
Stripe::setApiKey($this->company_gateway->getConfigField('apiKey'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,36 +321,38 @@ class StripePaymentDriver extends BasePaymentDriver
|
|||||||
|
|
||||||
public function refund(Payment $payment, $amount)
|
public function refund(Payment $payment, $amount)
|
||||||
{
|
{
|
||||||
$this->gateway();
|
$this->init();
|
||||||
|
|
||||||
$response = $this->gateway
|
$response = $this->stripe
|
||||||
->refund(['transactionReference' => $payment->transaction_reference, 'amount' => $amount, 'currency' => $payment->client->getCurrencyCode()])
|
->refunds
|
||||||
->send();
|
->create(['charge' => $payment->transaction_reference, 'amount' => $amount]);
|
||||||
|
|
||||||
if ($response->isSuccessful()) {
|
// $response = $this->gateway
|
||||||
SystemLogger::dispatch([
|
// ->refund(['transactionReference' => $payment->transaction_reference, 'amount' => $amount, 'currency' => $payment->client->getCurrencyCode()])
|
||||||
'server_response' => $response->getMessage(), 'data' => request()->all(),
|
// ->send();
|
||||||
|
|
||||||
|
if ($response->status == $response::STATUS_SUCCEEDED) {
|
||||||
|
SystemLogger::dispatch(['server_response' => $response, 'data' => request()->all(),
|
||||||
], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_STRIPE, $this->client);
|
], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_STRIPE, $this->client);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'transaction_reference' => $response->getData()['id'],
|
'transaction_reference' => $response->charge,
|
||||||
'transaction_response' => json_encode($response->getData()),
|
'transaction_response' => json_encode($response),
|
||||||
'success' => $response->getData()['refunded'],
|
'success' => $response->status == $response::STATUS_SUCCEEDED ? true : false,
|
||||||
'description' => $response->getData()['description'],
|
'description' => $response->metadata,
|
||||||
'code' => $response->getCode(),
|
'code' => $response,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemLogger::dispatch([
|
SystemLogger::dispatch(['server_response' => $response, 'data' => request()->all(),
|
||||||
'server_response' => $response->getMessage(), 'data' => request()->all(),
|
|
||||||
], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_STRIPE, $this->client);
|
], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_STRIPE, $this->client);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'transaction_reference' => null,
|
'transaction_reference' => null,
|
||||||
'transaction_response' => json_encode($response->getData()),
|
'transaction_response' => json_encode($response),
|
||||||
'success' => false,
|
'success' => false,
|
||||||
'description' => $response->getData()['error']['message'],
|
'description' => $response->failure_reason,
|
||||||
'code' => $response->getData()['error']['code'],
|
'code' => 422,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,17 +73,16 @@ class RefundPayment
|
|||||||
if ($this->refund_data['gateway_refund'] !== false && $this->total_refund > 0) {
|
if ($this->refund_data['gateway_refund'] !== false && $this->total_refund > 0) {
|
||||||
if ($this->payment->company_gateway) {
|
if ($this->payment->company_gateway) {
|
||||||
|
|
||||||
$response = $gateway->driver($this->payment->client)->refund($this->payment, $this->total_refund);
|
$response = $this->payment->company_gateway->driver($this->payment->client)->refund($this->payment, $this->total_refund);
|
||||||
|
|
||||||
if ($response['success']) {
|
|
||||||
|
if ($response['success'] == false) {
|
||||||
throw new PaymentRefundFailed();
|
throw new PaymentRefundFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->payment->refunded += $this->total_refund;
|
$this->payment->refunded += $this->total_refund;
|
||||||
|
|
||||||
$this
|
$this->createActivity($this->payment);
|
||||||
->createActivity($gateway)
|
|
||||||
->updateCreditNoteBalance();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->payment->refunded += $this->total_refund;
|
$this->payment->refunded += $this->total_refund;
|
||||||
@ -107,7 +106,7 @@ class RefundPayment
|
|||||||
$fields->user_id = $this->payment->user_id;
|
$fields->user_id = $this->payment->user_id;
|
||||||
$fields->company_id = $this->payment->company_id;
|
$fields->company_id = $this->payment->company_id;
|
||||||
$fields->activity_type_id = Activity::REFUNDED_PAYMENT;
|
$fields->activity_type_id = Activity::REFUNDED_PAYMENT;
|
||||||
$fields->credit_id = $this->credit_note->id;
|
// $fields->credit_id = $this->credit_note->id; // TODO
|
||||||
$fields->notes = json_encode($notes);
|
$fields->notes = json_encode($notes);
|
||||||
|
|
||||||
if (isset($this->refund_data['invoices'])) {
|
if (isset($this->refund_data['invoices'])) {
|
||||||
|
@ -3272,5 +3272,11 @@ return [
|
|||||||
'password_strength' => 'Password strength too weak',
|
'password_strength' => 'Password strength too weak',
|
||||||
|
|
||||||
'thanks' => 'Thanks',
|
'thanks' => 'Thanks',
|
||||||
|
|
||||||
|
'minimum_required_payment' => 'Minimum required payment is :amount',
|
||||||
|
|
||||||
|
'under_payments_disabled' => 'Company doesn\'t support under payments.',
|
||||||
|
'over_payments_disabled' => 'Company doesn\'t support over payments.',
|
||||||
|
|
||||||
'paused' => 'Paused',
|
'paused' => 'Paused',
|
||||||
];
|
];
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
<div class="bg-white rounded-md shadow-xs">
|
<div class="bg-white rounded-md shadow-xs">
|
||||||
<div class="py-1">
|
<div class="py-1">
|
||||||
@foreach($payment_methods as $payment_method)
|
@foreach($payment_methods as $payment_method)
|
||||||
<a data-turbolinks="false" href="#" @click="{ open = false }" data-company-gateway-id="{{ $payment_method['company_gateway_id'] }}" data-gateway-type-id="{{ $payment_method['gateway_type_id'] }}" class="block px-4 py-2 text-sm leading-5 text-gray-700 dropdown-gateway-button hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900">
|
<a href="#" @click="{ open = false }" data-company-gateway-id="{{ $payment_method['company_gateway_id'] }}" data-gateway-type-id="{{ $payment_method['gateway_type_id'] }}" class="block px-4 py-2 text-sm leading-5 text-gray-700 dropdown-gateway-button hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900">
|
||||||
{{ $payment_method['label'] }}
|
{{ $payment_method['label'] }}
|
||||||
</a>
|
</a>
|
||||||
@endforeach
|
@endforeach
|
||||||
@ -108,9 +108,25 @@
|
|||||||
<dt class="text-sm font-medium leading-5 text-gray-500">
|
<dt class="text-sm font-medium leading-5 text-gray-500">
|
||||||
{{ ctrans('texts.amount') }}
|
{{ ctrans('texts.amount') }}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="mt-1 text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2">
|
<dd class="text-sm leading-5 text-gray-900 sm:mt-0 sm:col-span-2 flex flex-col">
|
||||||
<!-- 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 }}">
|
<!-- Disabled input field don't send it's value with request. -->
|
||||||
|
@if(!$settings->client_portal_allow_under_payment && !$settings->client_portal_allow_over_payment)
|
||||||
|
<span class="mt-1 text-sm text-gray-800">{{ App\Utils\Number::formatMoney($invoice->amount, $invoice->client) }}</span>
|
||||||
|
@else
|
||||||
|
<div class="flex items-center">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input mt-0 mr-4 relative"
|
||||||
|
name="payable_invoices[{{$key}}][amount]"
|
||||||
|
value="{{ $invoice->partial > 0 ? $invoice->partial : $invoice->balance }}"/>
|
||||||
|
<span class="mt-2">{{ $invoice->client->currency()->code }} ({{ $invoice->client->currency()->symbol }})</span>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($settings->client_portal_allow_under_payment)
|
||||||
|
<span class="mt-1 text-sm text-gray-800">{{ ctrans('texts.minimum_payment') }}: {{ $settings->client_portal_under_payment_minimum }}</span>
|
||||||
|
@endif
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@ -122,10 +138,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@include('portal.ninja2020.invoices.includes.terms')
|
@include('portal.ninja2020.invoices.includes.terms')
|
||||||
@include('portal.ninja2020.invoices.includes.signature')
|
@include('portal.ninja2020.invoices.includes.signature')
|
||||||
|
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@push('footer')
|
@push('footer')
|
||||||
<script src="{{ asset('js/clients/invoices/payment.js') }}"></script>
|
<script src="{{ asset('js/clients/invoices/payment.js') }}"></script>
|
||||||
@endpush
|
@endpush
|
Loading…
x
Reference in New Issue
Block a user