Conversation
Co-authored-by: nielsdrost7 <47660417+nielsdrost7@users.noreply.github.com>
Co-authored-by: nielsdrost7 <47660417+nielsdrost7@users.noreply.github.com>
Co-authored-by: nielsdrost7 <47660417+nielsdrost7@users.noreply.github.com>
The Mollie payment gateway implementation is complete! All components are in place and working: ✅ MollieLib library (Omnipay integration) The implementation follows the existing Stripe/PayPal pattern with encrypted API key storage, merchant response logging, and comprehensive error handling. Admins can enable it via Settings → Online Payments by adding their Mollie API key. Users will then be able to select Mollie as a payment option and access various European payment methods (iDEAL, Bancontact, PayPal, Apple/Google Pay, etc.). |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@application/libraries/gateways/MollieLib.php`:
- Around line 17-27: The constructor (__construct) of MollieLib should validate
that 'api_key' exists and is non-empty in the $params array before assigning it
to $this->api_key and calling $this->gateway->setApiKey; update the __construct
to check isset($params['api_key']) and that it's not empty, and if missing
either throw a clear InvalidArgumentException or log an error via
log_message('error', ...) and abort initialization so Omnipay::create('Mollie')
/ setApiKey are not called with a missing key; reference the __construct method,
$params, $this->api_key, and $this->gateway->setApiKey when implementing the
change.
In `@application/modules/guest/controllers/gateways/Mollie.php`:
- Around line 105-110: The callback currently assumes the invoice lookup
($this->mdl_invoices->where(...)->get()->row()) returned a record and
immediately uses $invoice; add a null check after retrieving $invoice in the
Mollie callback (same pattern used in mollie_create_payment) to handle a missing
invoice: if $invoice is null, log an error (or set an error flash/message),
return an appropriate HTTP response or redirect, and stop further processing so
subsequent code (which accesses $invoice properties) cannot trigger a fatal
error; refer to $this->mdl_invoices, the $invoice variable, and the payment
success check ($payment->isSuccessful()) when adding this guard.
- Around line 37-43: The lookup of $invoice via
$this->mdl_invoices->where(...)->get()->row() can return null; add a null-check
before accessing $invoice->invoice_balance in Mollie.php so you don't
dereference null. If $invoice is null, set an appropriate session error (e.g.,
alert_error or a 404 message) and redirect (similar to existing redirect to
guest/view/invoice) or call show_404(); otherwise proceed with the existing
payable check. Update the block that references $invoice (the result of
mdl_invoices->where(...)->get()->row()) to handle the missing-invoice case
first.
- Around line 88-94: The code reads a single session key
'mollie_transaction_ref' which gets overwritten by concurrent tabs; update the
logic in Mollie.php to store/retrieve transaction refs keyed by the invoice
identifier (e.g. session array under 'mollie_transaction_ref' keyed by
$invoice_url_key) or accept the transaction ref via a Mollie return query
parameter (invoice_url_key or transaction_ref) and use that to look up the
correct transaction; update both the place that sets the session value (replace
$this->session->set_userdata('mollie_transaction_ref', ...) with storing into an
array keyed by $invoice_url_key) and the callback/retrieval code (replace
$this->session->userdata('mollie_transaction_ref') with reading the keyed array
or reading the query param) and ensure any cleanup removes only the specific
keyed entry rather than the entire session key.
🧹 Nitpick comments (1)
application/modules/guest/views/gateways/mollie.php (1)
10-13: Consider escaping the URL key for JavaScript context.The
$invoice_url_keyis output directly into JavaScript. While invoice URL keys are typically generated internally and should be safe, usinghtmlspecialchars()orjson_encode()provides defense-in-depth against potential XSS if the key ever contains unexpected characters.Proposed fix
<script> // Redirect to Mollie payment creation endpoint - window.location.href = '<?php echo site_url('guest/gateways/mollie/mollie_create_payment/' . $invoice_url_key); ?>'; + window.location.href = <?php echo json_encode(site_url('guest/gateways/mollie/mollie_create_payment/' . $invoice_url_key)); ?>; </script>
| $invoice = $this->mdl_invoices->where('ip_invoices.invoice_url_key', $invoice_url_key)->get()->row(); | ||
|
|
||
| // Check if the invoice is payable | ||
| if ($invoice->invoice_balance <= 0) { | ||
| $this->session->set_userdata('alert_error', lang('invoice_already_paid')); | ||
| redirect(site_url('guest/view/invoice/' . $invoice->invoice_url_key)); | ||
| } |
There was a problem hiding this comment.
Missing null check for invoice lookup.
If the invoice doesn't exist (e.g., invalid invoice_url_key), $invoice will be null, causing a fatal error on line 40 when accessing $invoice->invoice_balance.
Proposed fix
$invoice = $this->mdl_invoices->where('ip_invoices.invoice_url_key', $invoice_url_key)->get()->row();
+if (!$invoice) {
+ $this->session->set_flashdata('alert_error', lang('invoice_not_found'));
+ redirect(site_url('guest/view/invoice/' . $invoice_url_key));
+}
+
// Check if the invoice is payable
if ($invoice->invoice_balance <= 0) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| $invoice = $this->mdl_invoices->where('ip_invoices.invoice_url_key', $invoice_url_key)->get()->row(); | |
| // Check if the invoice is payable | |
| if ($invoice->invoice_balance <= 0) { | |
| $this->session->set_userdata('alert_error', lang('invoice_already_paid')); | |
| redirect(site_url('guest/view/invoice/' . $invoice->invoice_url_key)); | |
| } | |
| $invoice = $this->mdl_invoices->where('ip_invoices.invoice_url_key', $invoice_url_key)->get()->row(); | |
| if (!$invoice) { | |
| $this->session->set_flashdata('alert_error', lang('invoice_not_found')); | |
| redirect(site_url('guest/view/invoice/' . $invoice_url_key)); | |
| } | |
| // Check if the invoice is payable | |
| if ($invoice->invoice_balance <= 0) { | |
| $this->session->set_userdata('alert_error', lang('invoice_already_paid')); | |
| redirect(site_url('guest/view/invoice/' . $invoice->invoice_url_key)); | |
| } |
🤖 Prompt for AI Agents
In `@application/modules/guest/controllers/gateways/Mollie.php` around lines 37 -
43, The lookup of $invoice via $this->mdl_invoices->where(...)->get()->row() can
return null; add a null-check before accessing $invoice->invoice_balance in
Mollie.php so you don't dereference null. If $invoice is null, set an
appropriate session error (e.g., alert_error or a 404 message) and redirect
(similar to existing redirect to guest/view/invoice) or call show_404();
otherwise proceed with the existing payable check. Update the block that
references $invoice (the result of mdl_invoices->where(...)->get()->row()) to
handle the missing-invoice case first.
| try { | ||
| // Get transaction reference from session | ||
| $transaction_ref = $this->session->userdata('mollie_transaction_ref'); | ||
|
|
||
| if ( ! $transaction_ref) { | ||
| throw new Exception('No transaction reference found'); | ||
| } |
There was a problem hiding this comment.
Session-based transaction reference may cause issues with multiple tabs.
If a user opens multiple invoices for payment in different tabs, the mollie_transaction_ref session value will be overwritten, causing incorrect transaction lookups. Consider using a session array keyed by invoice_url_key, or pass the reference via query parameter from Mollie's return URL.
Suggested approach using invoice-keyed session
-// Save the transaction reference in session for callback
-$this->session->set_userdata('mollie_transaction_ref', $mollie_response['reference']);
+// Save the transaction reference in session for callback (keyed by invoice)
+$mollie_refs = $this->session->userdata('mollie_transaction_refs') ?: [];
+$mollie_refs[$invoice_url_key] = $mollie_response['reference'];
+$this->session->set_userdata('mollie_transaction_refs', $mollie_refs);And in callback:
-$transaction_ref = $this->session->userdata('mollie_transaction_ref');
+$mollie_refs = $this->session->userdata('mollie_transaction_refs') ?: [];
+$transaction_ref = $mollie_refs[$invoice_url_key] ?? null;🤖 Prompt for AI Agents
In `@application/modules/guest/controllers/gateways/Mollie.php` around lines 88 -
94, The code reads a single session key 'mollie_transaction_ref' which gets
overwritten by concurrent tabs; update the logic in Mollie.php to store/retrieve
transaction refs keyed by the invoice identifier (e.g. session array under
'mollie_transaction_ref' keyed by $invoice_url_key) or accept the transaction
ref via a Mollie return query parameter (invoice_url_key or transaction_ref) and
use that to look up the correct transaction; update both the place that sets the
session value (replace $this->session->set_userdata('mollie_transaction_ref',
...) with storing into an array keyed by $invoice_url_key) and the
callback/retrieval code (replace
$this->session->userdata('mollie_transaction_ref') with reading the keyed array
or reading the query param) and ensure any cleanup removes only the specific
keyed entry rather than the entire session key.
There was a problem hiding this comment.
Pull request overview
This pull request implements Mollie payment gateway integration for InvoicePlane, enabling European payment methods (iDEAL, Bancontact, PayPal, Apple Pay, Google Pay, etc.) through the Omnipay-based Mollie API wrapper.
Changes:
- Added Mollie payment gateway support via Omnipay library (omnipay/mollie ^5.5)
- Implemented MollieLib library wrapper for payment creation and status retrieval
- Created Mollie controller with payment creation and callback handling
- Enabled Mollie configuration in payment gateways with encrypted API key storage
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| composer.json | Added omnipay/mollie ^5.5 dependency |
| composer.lock | Updated dependencies including omnipay/mollie, omnipay/common, and supporting libraries |
| application/config/payment_gateways.php | Enabled Mollie gateway configuration with password-type API key field |
| application/libraries/gateways/MollieLib.php | Created Omnipay wrapper for Mollie API with payment creation and retrieval methods |
| application/modules/guest/controllers/gateways/Mollie.php | Implemented payment flow controller with creation endpoint and callback handler |
| application/modules/guest/views/gateways/mollie.php | Added redirect view to initiate payment creation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| } catch (Exception $e) { | ||
| log_message('error', 'Mollie library payment creation exception: ' . $e->getMessage()); | ||
|
|
||
| return [ | ||
| 'status' => false, | ||
| 'message' => $e->getMessage(), | ||
| ]; | ||
| } |
There was a problem hiding this comment.
The library catches generic Exception but Omnipay can throw more specific exceptions. The Omnipay library may throw exceptions like InvalidRequestException or InvalidResponseException. Consider catching these specific exception types to provide more meaningful error messages, or at least ensure that the exception message is properly logged and returned to the caller for better debugging.
There was a problem hiding this comment.
Now catches specific Omnipay exceptions (InvalidRequestException, InvalidResponseException) before the generic Exception, providing more meaningful error messages for debugging. Commit: 11cfdf8
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
|
@copilot apply changes based on the comments in this thread In
In
|
… session security Co-authored-by: nielsdrost7 <47660417+nielsdrost7@users.noreply.github.com>
Co-authored-by: nielsdrost7 <47660417+nielsdrost7@users.noreply.github.com>
…mpatibility Co-authored-by: nielsdrost7 <47660417+nielsdrost7@users.noreply.github.com>
…erence Co-authored-by: nielsdrost7 <47660417+nielsdrost7@users.noreply.github.com>
All requested changes have been implemented: MollieLib.php:
Mollie.php:
Commit: cef17ef |
d314f64 to
5b927da
Compare
Add Mollie Payment Gateway Support
Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.
Summary by CodeRabbit
New Features
Security
✏️ Tip: You can customize this high-level summary in your review settings.