diff --git a/app/Http/Controllers/ClientPortal/PaymentController.php b/app/Http/Controllers/ClientPortal/PaymentController.php index 489c441d5df6..658ad9ff562f 100644 --- a/app/Http/Controllers/ClientPortal/PaymentController.php +++ b/app/Http/Controllers/ClientPortal/PaymentController.php @@ -73,9 +73,10 @@ class PaymentController extends Controller */ public function process() { - $gateway = CompanyGateway::find(request()->input('company_gateway_id')); + /*find invoices*/ + $payable_invoices = request()->payable_invoices; $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.']); } - /*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) { + $payable_invoices[$key]['amount'] = Number::parseFloat($payable_invoice['amount']); $payable_invoice['amount'] = $payable_invoices[$key]['amount']; @@ -101,6 +104,41 @@ class PaymentController extends Controller 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]['invoice_number'] = $invoice->number; @@ -129,7 +167,7 @@ class PaymentController extends Controller $first_invoice = $invoices->first(); $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 += 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); diff --git a/app/PaymentDrivers/StripePaymentDriver.php b/app/PaymentDrivers/StripePaymentDriver.php index 8fb9199df543..caf7be6f0494 100644 --- a/app/PaymentDrivers/StripePaymentDriver.php +++ b/app/PaymentDrivers/StripePaymentDriver.php @@ -49,10 +49,14 @@ class StripePaymentDriver extends BasePaymentDriver public $can_authorise_credit_card = true; + /** @var \Stripe\StripeClient */ + protected $stripe; + protected $customer_reference = 'customerReferenceParam'; protected $payment_method; + public static $methods = [ GatewayType::CREDIT_CARD => CreditCard::class, GatewayType::BANK_TRANSFER => ACH::class, @@ -81,6 +85,10 @@ class StripePaymentDriver extends BasePaymentDriver */ public function init(): void { + $this->stripe = new \Stripe\StripeClient( + $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) { - $this->gateway(); + $this->init(); - $response = $this->gateway - ->refund(['transactionReference' => $payment->transaction_reference, 'amount' => $amount, 'currency' => $payment->client->getCurrencyCode()]) - ->send(); + $response = $this->stripe + ->refunds + ->create(['charge' => $payment->transaction_reference, 'amount' => $amount]); - if ($response->isSuccessful()) { - SystemLogger::dispatch([ - 'server_response' => $response->getMessage(), 'data' => request()->all(), + // $response = $this->gateway + // ->refund(['transactionReference' => $payment->transaction_reference, 'amount' => $amount, 'currency' => $payment->client->getCurrencyCode()]) + // ->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); return [ - 'transaction_reference' => $response->getData()['id'], - 'transaction_response' => json_encode($response->getData()), - 'success' => $response->getData()['refunded'], - 'description' => $response->getData()['description'], - 'code' => $response->getCode(), + 'transaction_reference' => $response->charge, + 'transaction_response' => json_encode($response), + 'success' => $response->status == $response::STATUS_SUCCEEDED ? true : false, + 'description' => $response->metadata, + 'code' => $response, ]; } - SystemLogger::dispatch([ - 'server_response' => $response->getMessage(), 'data' => request()->all(), + SystemLogger::dispatch(['server_response' => $response, 'data' => request()->all(), ], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_STRIPE, $this->client); return [ 'transaction_reference' => null, - 'transaction_response' => json_encode($response->getData()), + 'transaction_response' => json_encode($response), 'success' => false, - 'description' => $response->getData()['error']['message'], - 'code' => $response->getData()['error']['code'], + 'description' => $response->failure_reason, + 'code' => 422, ]; } diff --git a/app/Services/Payment/RefundPayment.php b/app/Services/Payment/RefundPayment.php index 9edbc5da68b3..250b4229518b 100644 --- a/app/Services/Payment/RefundPayment.php +++ b/app/Services/Payment/RefundPayment.php @@ -72,18 +72,17 @@ class RefundPayment { if ($this->refund_data['gateway_refund'] !== false && $this->total_refund > 0) { if ($this->payment->company_gateway) { - - $response = $gateway->driver($this->payment->client)->refund($this->payment, $this->total_refund); - if ($response['success']) { + $response = $this->payment->company_gateway->driver($this->payment->client)->refund($this->payment, $this->total_refund); + + + if ($response['success'] == false) { throw new PaymentRefundFailed(); } $this->payment->refunded += $this->total_refund; - $this - ->createActivity($gateway) - ->updateCreditNoteBalance(); + $this->createActivity($this->payment); } } else { $this->payment->refunded += $this->total_refund; @@ -107,7 +106,7 @@ class RefundPayment $fields->user_id = $this->payment->user_id; $fields->company_id = $this->payment->company_id; $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); if (isset($this->refund_data['invoices'])) { diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 7f06753b9dc7..ea2eec4f6e60 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -3272,5 +3272,11 @@ return [ 'password_strength' => 'Password strength too weak', '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', ]; diff --git a/resources/views/portal/ninja2020/invoices/payment.blade.php b/resources/views/portal/ninja2020/invoices/payment.blade.php index 9cd24264dd4b..6a67f6176e5f 100644 --- a/resources/views/portal/ninja2020/invoices/payment.blade.php +++ b/resources/views/portal/ninja2020/invoices/payment.blade.php @@ -36,7 +36,7 @@
@foreach($payment_methods as $payment_method) - + {{ $payment_method['label'] }} @endforeach @@ -94,11 +94,11 @@
@if($invoice->po_number) - {{ $invoice->po_number }} + {{ $invoice->po_number }} @elseif($invoice->public_notes) - {{ $invoice->public_notes }} + {{ $invoice->public_notes }} @else - {{ $invoice->date}} + {{ $invoice->date}} @endif
@@ -108,9 +108,25 @@
{{ ctrans('texts.amount') }}
-
+
- + + @if(!$settings->client_portal_allow_under_payment && !$settings->client_portal_allow_over_payment) + {{ App\Utils\Number::formatMoney($invoice->amount, $invoice->client) }} + @else +
+ + {{ $invoice->client->currency()->code }} ({{ $invoice->client->currency()->symbol }}) +
+ @endif + + @if($settings->client_portal_allow_under_payment) + {{ ctrans('texts.minimum_payment') }}: {{ $settings->client_portal_under_payment_minimum }} + @endif
@endif @@ -122,10 +138,12 @@ + @include('portal.ninja2020.invoices.includes.terms') @include('portal.ninja2020.invoices.includes.signature') + @endsection @push('footer') - + @endpush \ No newline at end of file