mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2026-03-03 00:47:02 +00:00
Improvements for mollie in test mode
This commit is contained in:
@@ -288,11 +288,49 @@ class InvoiceFilters extends QueryFilters
|
||||
if ($sort_col[0] == 'client_id') {
|
||||
|
||||
|
||||
//2025-12-16: Better filtering for clients.
|
||||
return $this->builder->orderByRaw('client_id IS NULL')
|
||||
->orderBy(\App\Models\Client::select('name')
|
||||
->whereColumn('clients.id', 'invoices.client_id')
|
||||
->limit(1), $dir);
|
||||
// 2026-01-21: Original sort by client name that is not optimal when clients.name is empty.
|
||||
// return $this->builder->orderByRaw('client_id IS NULL')
|
||||
// ->orderBy(\App\Models\Client::select('name')
|
||||
// ->whereColumn('clients.id', 'recurring_invoices.client_id')
|
||||
// ->limit(1), $dir);
|
||||
|
||||
|
||||
/**
|
||||
* future options for order by raw if this is not performant:
|
||||
*
|
||||
COALESCE(
|
||||
NULLIF((SELECT name FROM clients WHERE clients.id = invoices.client_id LIMIT 1), ''),
|
||||
(SELECT email FROM client_contacts
|
||||
WHERE client_contacts.client_id = invoices.client_id
|
||||
AND client_contacts.email IS NOT NULL
|
||||
ORDER BY client_contacts.is_primary DESC, client_contacts.id ASC
|
||||
LIMIT 1),
|
||||
'No Contact Set'
|
||||
) " . $dir
|
||||
|
||||
*/
|
||||
|
||||
return $this->builder
|
||||
->orderByRaw("
|
||||
CASE
|
||||
WHEN CHAR_LENGTH((SELECT name FROM clients WHERE clients.id = invoices.client_id LIMIT 1)) > 1
|
||||
THEN (SELECT name FROM clients WHERE clients.id = invoices.client_id LIMIT 1)
|
||||
WHEN CHAR_LENGTH(CONCAT(
|
||||
COALESCE((SELECT first_name FROM client_contacts WHERE client_contacts.client_id = invoices.client_id AND client_contacts.email IS NOT NULL ORDER BY client_contacts.is_primary DESC, client_contacts.id ASC LIMIT 1), ''),
|
||||
COALESCE((SELECT last_name FROM client_contacts WHERE client_contacts.client_id = invoices.client_id AND client_contacts.email IS NOT NULL ORDER BY client_contacts.is_primary DESC, client_contacts.id ASC LIMIT 1), '')
|
||||
)) >= 1
|
||||
THEN TRIM(CONCAT(
|
||||
COALESCE((SELECT first_name FROM client_contacts WHERE client_contacts.client_id = invoices.client_id AND client_contacts.email IS NOT NULL ORDER BY client_contacts.is_primary DESC, client_contacts.id ASC LIMIT 1), ''),
|
||||
' ',
|
||||
COALESCE((SELECT last_name FROM client_contacts WHERE client_contacts.client_id = invoices.client_id AND client_contacts.email IS NOT NULL ORDER BY client_contacts.is_primary DESC, client_contacts.id ASC LIMIT 1), '')
|
||||
))
|
||||
WHEN CHAR_LENGTH((SELECT email FROM client_contacts WHERE client_contacts.client_id = invoices.client_id AND client_contacts.email IS NOT NULL ORDER BY client_contacts.is_primary DESC, client_contacts.id ASC LIMIT 1)) > 0
|
||||
THEN (SELECT email FROM client_contacts WHERE client_contacts.client_id = invoices.client_id AND client_contacts.email IS NOT NULL ORDER BY client_contacts.is_primary DESC, client_contacts.id ASC LIMIT 1)
|
||||
ELSE 'No Contact Set'
|
||||
END " . $dir
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
if ($sort_col[0] == 'project_id') {
|
||||
|
||||
@@ -142,14 +142,34 @@ class RecurringInvoiceFilters extends QueryFilters
|
||||
|
||||
if ($sort_col[0] == 'client_id') {
|
||||
|
||||
return $this->builder->orderByRaw('client_id IS NULL')
|
||||
->orderBy(\App\Models\Client::select('name')
|
||||
->whereColumn('clients.id', 'recurring_invoices.client_id')
|
||||
->limit(1), $dir);
|
||||
|
||||
// return $this->builder->orderByRaw('ISNULL(client_id), client_id '. $dir)
|
||||
// ->orderBy(\App\Models\Client::select('name')
|
||||
// ->whereColumn('clients.id', 'recurring_invoices.client_id'), $dir);
|
||||
return $this->builder
|
||||
->orderByRaw("
|
||||
CASE
|
||||
WHEN CHAR_LENGTH((SELECT name FROM clients WHERE clients.id = recurring_invoices.client_id LIMIT 1)) > 1
|
||||
THEN (SELECT name FROM clients WHERE clients.id = recurring_invoices.client_id LIMIT 1)
|
||||
WHEN CHAR_LENGTH(CONCAT(
|
||||
COALESCE((SELECT first_name FROM client_contacts WHERE client_contacts.client_id = recurring_invoices.client_id AND client_contacts.email IS NOT NULL ORDER BY client_contacts.is_primary DESC, client_contacts.id ASC LIMIT 1), ''),
|
||||
COALESCE((SELECT last_name FROM client_contacts WHERE client_contacts.client_id = recurring_invoices.client_id AND client_contacts.email IS NOT NULL ORDER BY client_contacts.is_primary DESC, client_contacts.id ASC LIMIT 1), '')
|
||||
)) >= 1
|
||||
THEN TRIM(CONCAT(
|
||||
COALESCE((SELECT first_name FROM client_contacts WHERE client_contacts.client_id = recurring_invoices.client_id AND client_contacts.email IS NOT NULL ORDER BY client_contacts.is_primary DESC, client_contacts.id ASC LIMIT 1), ''),
|
||||
' ',
|
||||
COALESCE((SELECT last_name FROM client_contacts WHERE client_contacts.client_id = recurring_invoices.client_id AND client_contacts.email IS NOT NULL ORDER BY client_contacts.is_primary DESC, client_contacts.id ASC LIMIT 1), '')
|
||||
))
|
||||
WHEN CHAR_LENGTH((SELECT email FROM client_contacts WHERE client_contacts.client_id = recurring_invoices.client_id AND client_contacts.email IS NOT NULL ORDER BY client_contacts.is_primary DESC, client_contacts.id ASC LIMIT 1)) > 0
|
||||
THEN (SELECT email FROM client_contacts WHERE client_contacts.client_id = recurring_invoices.client_id AND client_contacts.email IS NOT NULL ORDER BY client_contacts.is_primary DESC, client_contacts.id ASC LIMIT 1)
|
||||
ELSE 'No Contact Set'
|
||||
END " . $dir
|
||||
);
|
||||
|
||||
|
||||
|
||||
// return $this->builder->orderByRaw('client_id IS NULL')
|
||||
// ->orderBy(\App\Models\Client::select('name')
|
||||
// ->whereColumn('clients.id', 'recurring_invoices.client_id')
|
||||
// ->limit(1), $dir);
|
||||
|
||||
}
|
||||
|
||||
if ($sort_col[0] == 'number') {
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
|
||||
namespace App\PaymentDrivers\Mollie;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\Common\LivewireMethodInterface;
|
||||
use App\PaymentDrivers\MolliePaymentDriver;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\View\View;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\PaymentType;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use App\PaymentDrivers\MolliePaymentDriver;
|
||||
use App\PaymentDrivers\Common\LivewireMethodInterface;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
|
||||
class CreditCard implements LivewireMethodInterface
|
||||
{
|
||||
@@ -151,6 +151,7 @@ class CreditCard implements LivewireMethodInterface
|
||||
$payment = $this->mollie->gateway->payments->create($data);
|
||||
|
||||
if ($payment->status === 'paid') {
|
||||
|
||||
$this->mollie->logSuccessfulGatewayResponse(
|
||||
['response' => $payment, 'data' => $this->mollie->payment_hash->data],
|
||||
SystemLog::TYPE_MOLLIE
|
||||
@@ -177,6 +178,7 @@ class CreditCard implements LivewireMethodInterface
|
||||
|
||||
public function processSuccessfulPayment(\Mollie\Api\Resources\Payment $payment)
|
||||
{
|
||||
|
||||
$payment_hash = $this->mollie->payment_hash;
|
||||
|
||||
if (property_exists($payment_hash->data, 'shouldStoreToken') && $payment_hash->data->shouldStoreToken) {
|
||||
@@ -212,7 +214,7 @@ class CreditCard implements LivewireMethodInterface
|
||||
'payment_type' => PaymentType::CREDIT_CARD_OTHER,
|
||||
'transaction_reference' => $payment->id,
|
||||
];
|
||||
|
||||
|
||||
$payment_record = $this->mollie->createPayment($data, $payment->status === 'paid' ? Payment::STATUS_COMPLETED : Payment::STATUS_PENDING);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
|
||||
@@ -22,10 +22,12 @@ use App\Models\PaymentType;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Mollie\Api\MollieApiClient;
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\PaymentDrivers\BaseDriver;
|
||||
use App\PaymentDrivers\Mollie\KBC;
|
||||
use App\PaymentDrivers\Mollie\IDEAL;
|
||||
use App\Exceptions\PaymentOpenMollie;
|
||||
use Mollie\Api\Exceptions\ApiException;
|
||||
use App\PaymentDrivers\Mollie\Bancontact;
|
||||
use App\PaymentDrivers\Mollie\CreditCard;
|
||||
@@ -311,8 +313,6 @@ class MolliePaymentDriver extends BaseDriver
|
||||
'paid' => Payment::STATUS_COMPLETED,
|
||||
];
|
||||
|
||||
nlog($request->id);
|
||||
|
||||
try {
|
||||
$payment = $this->gateway->payments->get($request->id);
|
||||
$record = Payment::withTrashed()->where('transaction_reference', $request->id)->first();
|
||||
@@ -320,7 +320,28 @@ class MolliePaymentDriver extends BaseDriver
|
||||
if ($record) {
|
||||
$client = $record->client;
|
||||
$this->client = $client;
|
||||
} else {
|
||||
}
|
||||
elseif($payment->status == 'failed' && $payment->metadata->gateway_type_id === GatewayType::CREDIT_CARD){
|
||||
//no payment, and it failed? return early!
|
||||
$client = Client::withTrashed()->find($this->decodePrimaryKey($payment->metadata->client_id));
|
||||
|
||||
$message = [
|
||||
'server_response' => $payment,
|
||||
'data' => $request->all(),
|
||||
];
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$message,
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
$client,
|
||||
$client->company
|
||||
);
|
||||
|
||||
return response()->json([], 200);
|
||||
}
|
||||
else {
|
||||
$client = Client::withTrashed()->find($this->decodePrimaryKey($payment->metadata->client_id));
|
||||
$this->client = $client;
|
||||
// sometimes if the user is not returned to the site with a response from Mollie
|
||||
@@ -427,6 +448,15 @@ class MolliePaymentDriver extends BaseDriver
|
||||
|
||||
try {
|
||||
$payment = $this->gateway->payments->get($request->getPaymentId());
|
||||
// if($payment->status == 'open'){
|
||||
// nlog("open furfy");
|
||||
// return render('gateways.mollie.mollie_pending_payment_placeholder');
|
||||
// }
|
||||
// else
|
||||
|
||||
if($payment->status == 'failed'){
|
||||
return (new CreditCard($this))->processUnsuccessfulPayment(new PaymentFailed($payment->details->failureMessage, 400));
|
||||
}
|
||||
|
||||
return (new CreditCard($this))->processSuccessfulPayment($payment);
|
||||
} catch (\Mollie\Api\Exceptions\ApiException $e) {
|
||||
|
||||
@@ -5690,6 +5690,7 @@ $lang = array(
|
||||
'peppol_sending_failed' => 'E-Invoice sending failed!',
|
||||
'peppol_sending_success' => 'E-Invoice sent successfully!',
|
||||
'auto_generate' => 'Auto Generate',
|
||||
'mollie_payment_pending' => 'Your payment is pending. Please wait for it to be processed. We will email you when it is completed.',
|
||||
);
|
||||
|
||||
return $lang;
|
||||
|
||||
@@ -5688,6 +5688,7 @@ Développe automatiquement la section des notes dans le tableau de produits pour
|
||||
'purge_user_confirmation' => 'Attention ! Cette action réattribuera toutes les entités au propriétaire du compte et supprimera définitivement l\'utilisateur de l\'ensemble des entreprises et des comptes. Voulez-vous vraiment continuer ?',
|
||||
'peppol_sending_failed' => 'Problème technique de livraison. Réessai impossible.',
|
||||
'peppol_sending_success' => 'La facture électronique a été envoyée!',
|
||||
'auto_generate' => 'Auto générer',
|
||||
);
|
||||
|
||||
return $lang;
|
||||
|
||||
@@ -5689,6 +5689,7 @@ $lang = array(
|
||||
'purge_user_confirmation' => 'Cảnh báo! Thao tác này sẽ gán lại tất cả các thực thể đến chủ sở hữu tài khoản và Xóa vĩnh viễn Người dùng trên tất cả các công ty và tài khoản. Bạn có chắc chắn muốn đến tục không?',
|
||||
'peppol_sending_failed' => 'Sự cố giao hàng kỹ thuật. Không thể thử lại',
|
||||
'peppol_sending_success' => 'E- Hóa đơn gửi Thành công !',
|
||||
'auto_generate' => 'Tự động tạo',
|
||||
);
|
||||
|
||||
return $lang;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
@extends('portal.ninja2020.layout.clean')
|
||||
@section('meta_title', 'Mollie')
|
||||
|
||||
@section('body')
|
||||
<div class="grid lg:grid-cols-3">
|
||||
<div class="hidden lg:block col-span-1 bg-red-100 h-screen">
|
||||
<img src="{{ asset('images/client-portal-new-image.jpg') }}"
|
||||
class="w-full h-screen object-cover"
|
||||
alt="Background image">
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 h-screen flex">
|
||||
<div class="m-auto md:w-1/2 lg:w-1/4 flex flex-col items-center">
|
||||
<span class="flex items-center text-2xl">
|
||||
{{ ctrans('texts.mollie_payment_pending') }}
|
||||
</span>
|
||||
|
||||
<a class="button-link text-sm mt-2" href="{{ url(request()->getSchemeAndHttpHost() . '/client') }}">
|
||||
{{ ctrans('texts.back_to', ['url' => parse_url(request()->getHttpHost())['host'] ?? request()->getHttpHost()]) }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
|
||||
Reference in New Issue
Block a user