From 0f968aac14bea6e271b2195d018cc83229e83575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CVeLiTi=E2=80=9D?= <“info@veliti.nl”> Date: Sun, 21 Dec 2025 14:44:37 +0100 Subject: [PATCH 1/2] Add Mollie API integration and webhook for software upgrade payments - Introduced the `CaBundle.php` class for managing CA certificates. - Updated `installed.json` and `installed.php` to include the new `composer/ca-bundle` dependency. - Added `platform_check.php` to enforce PHP version requirements. - Created `initialize.php` for initializing the Mollie API client with the API key. - Implemented `webhook_mollie.php` to handle webhook callbacks for software upgrade payments, including transaction status updates and invoice generation. - Integrated DomPDF for generating invoices and sending them via email. --- api/v2/get/payment.php | 88 + api/v2/post/payment.php | 280 ++ assets/functions.php | 256 +- assets/mollie/.DS_Store | Bin 0 -> 6148 bytes assets/mollie/LICENSE | 8 + assets/mollie/README.md | 231 ++ assets/mollie/composer.json | 84 + assets/mollie/src/.DS_Store | Bin 0 -> 6148 bytes assets/mollie/src/CompatibilityChecker.php | 47 + .../mollie/src/Endpoints/BalanceEndpoint.php | 74 + .../src/Endpoints/BalanceReportEndpoint.php | 57 + .../Endpoints/BalanceTransactionEndpoint.php | 73 + .../src/Endpoints/ChargebackEndpoint.php | 46 + .../mollie/src/Endpoints/ClientEndpoint.php | 63 + .../src/Endpoints/ClientLinkEndpoint.php | 36 + .../Endpoints/CollectionEndpointAbstract.php | 41 + .../mollie/src/Endpoints/CustomerEndpoint.php | 111 + .../Endpoints/CustomerPaymentsEndpoint.php | 88 + .../mollie/src/Endpoints/EndpointAbstract.php | 163 + .../mollie/src/Endpoints/InvoiceEndpoint.php | 73 + .../mollie/src/Endpoints/MandateEndpoint.php | 134 + .../mollie/src/Endpoints/MethodEndpoint.php | 88 + .../src/Endpoints/OnboardingEndpoint.php | 74 + assets/mollie/src/Endpoints/OrderEndpoint.php | 119 + .../src/Endpoints/OrderLineEndpoint.php | 115 + .../src/Endpoints/OrderPaymentEndpoint.php | 67 + .../src/Endpoints/OrderRefundEndpoint.php | 63 + .../src/Endpoints/OrganizationEndpoint.php | 58 + .../Endpoints/OrganizationPartnerEndpoint.php | 49 + .../src/Endpoints/PaymentCaptureEndpoint.php | 109 + .../Endpoints/PaymentChargebackEndpoint.php | 80 + .../mollie/src/Endpoints/PaymentEndpoint.php | 152 + .../src/Endpoints/PaymentLinkEndpoint.php | 79 + .../src/Endpoints/PaymentRefundEndpoint.php | 109 + .../src/Endpoints/PaymentRouteEndpoint.php | 60 + .../src/Endpoints/PermissionEndpoint.php | 60 + .../mollie/src/Endpoints/ProfileEndpoint.php | 130 + .../src/Endpoints/ProfileMethodEndpoint.php | 116 + .../mollie/src/Endpoints/RefundEndpoint.php | 46 + .../Endpoints/SettlementPaymentEndpoint.php | 40 + .../src/Endpoints/SettlementsEndpoint.php | 80 + .../mollie/src/Endpoints/ShipmentEndpoint.php | 145 + .../src/Endpoints/SubscriptionEndpoint.php | 187 + .../mollie/src/Endpoints/TerminalEndpoint.php | 65 + .../mollie/src/Endpoints/WalletEndpoint.php | 33 + assets/mollie/src/Exceptions/ApiException.php | 194 + .../CurlConnectTimeoutException.php | 7 + ...dapterDoesNotSupportDebuggingException.php | 7 + .../src/Exceptions/IncompatiblePlatform.php | 12 + .../UnrecognizedClientException.php | 7 + .../src/HttpAdapter/CurlMollieHttpAdapter.php | 190 + .../Guzzle6And7MollieHttpAdapter.php | 169 + .../Guzzle6And7RetryMiddlewareFactory.php | 67 + .../MollieHttpAdapterInterface.php | 25 + .../HttpAdapter/MollieHttpAdapterPicker.php | 55 + .../MollieHttpAdapterPickerInterface.php | 13 + .../DefaultIdempotencyKeyGenerator.php | 36 + .../FakeIdempotencyKeyGenerator.php | 18 + .../IdempotencyKeyGeneratorContract.php | 8 + assets/mollie/src/MollieApiClient.php | 623 +++ assets/mollie/src/Resources/Balance.php | 101 + .../src/Resources/BalanceCollection.php | 21 + assets/mollie/src/Resources/BalanceReport.php | 72 + .../src/Resources/BalanceTransaction.php | 74 + .../BalanceTransactionCollection.php | 22 + .../mollie/src/Resources/BaseCollection.php | 31 + assets/mollie/src/Resources/BaseResource.php | 28 + assets/mollie/src/Resources/Capture.php | 62 + .../src/Resources/CaptureCollection.php | 21 + assets/mollie/src/Resources/Chargeback.php | 67 + .../src/Resources/ChargebackCollection.php | 21 + assets/mollie/src/Resources/Client.php | 32 + .../mollie/src/Resources/ClientCollection.php | 21 + assets/mollie/src/Resources/ClientLink.php | 38 + .../mollie/src/Resources/CurrentProfile.php | 32 + .../mollie/src/Resources/CursorCollection.php | 80 + assets/mollie/src/Resources/Customer.php | 216 ++ .../src/Resources/CustomerCollection.php | 21 + assets/mollie/src/Resources/Invoice.php | 94 + .../src/Resources/InvoiceCollection.php | 21 + assets/mollie/src/Resources/Issuer.php | 32 + .../mollie/src/Resources/IssuerCollection.php | 14 + assets/mollie/src/Resources/Mandate.php | 89 + .../src/Resources/MandateCollection.php | 36 + assets/mollie/src/Resources/Method.php | 82 + .../mollie/src/Resources/MethodCollection.php | 14 + assets/mollie/src/Resources/MethodPrice.php | 26 + .../src/Resources/MethodPriceCollection.php | 14 + assets/mollie/src/Resources/Onboarding.php | 56 + assets/mollie/src/Resources/Order.php | 485 +++ .../mollie/src/Resources/OrderCollection.php | 21 + assets/mollie/src/Resources/OrderLine.php | 358 ++ .../src/Resources/OrderLineCollection.php | 30 + assets/mollie/src/Resources/Organization.php | 62 + .../src/Resources/OrganizationCollection.php | 21 + assets/mollie/src/Resources/Partner.php | 45 + assets/mollie/src/Resources/Payment.php | 672 ++++ .../src/Resources/PaymentCollection.php | 21 + assets/mollie/src/Resources/PaymentLink.php | 112 + .../src/Resources/PaymentLinkCollection.php | 21 + assets/mollie/src/Resources/Permission.php | 24 + .../src/Resources/PermissionCollection.php | 14 + assets/mollie/src/Resources/Profile.php | 180 + .../src/Resources/ProfileCollection.php | 21 + assets/mollie/src/Resources/Refund.php | 153 + .../mollie/src/Resources/RefundCollection.php | 21 + .../mollie/src/Resources/ResourceFactory.php | 61 + assets/mollie/src/Resources/Route.php | 32 + .../mollie/src/Resources/RouteCollection.php | 21 + assets/mollie/src/Resources/Settlement.php | 154 + .../src/Resources/SettlementCollection.php | 21 + assets/mollie/src/Resources/Shipment.php | 104 + .../src/Resources/ShipmentCollection.php | 14 + assets/mollie/src/Resources/Subscription.php | 180 + .../src/Resources/SubscriptionCollection.php | 21 + assets/mollie/src/Resources/Terminal.php | 138 + .../src/Resources/TerminalCollection.php | 21 + assets/mollie/src/Types/ApprovalPrompt.php | 13 + .../src/Types/BalanceTransferFrequency.php | 18 + assets/mollie/src/Types/InvoiceStatus.php | 19 + assets/mollie/src/Types/MandateMethod.php | 24 + assets/mollie/src/Types/MandateStatus.php | 10 + assets/mollie/src/Types/OnboardingStatus.php | 19 + assets/mollie/src/Types/OrderLineStatus.php | 36 + assets/mollie/src/Types/OrderLineType.php | 14 + .../Types/OrderLineUpdateOperationType.php | 11 + assets/mollie/src/Types/OrderStatus.php | 44 + assets/mollie/src/Types/PaymentMethod.php | 113 + .../mollie/src/Types/PaymentMethodStatus.php | 46 + assets/mollie/src/Types/PaymentStatus.php | 40 + assets/mollie/src/Types/ProfileStatus.php | 19 + assets/mollie/src/Types/RefundStatus.php | 31 + assets/mollie/src/Types/SequenceType.php | 15 + assets/mollie/src/Types/SettlementStatus.php | 23 + .../mollie/src/Types/SubscriptionStatus.php | 14 + assets/mollie/src/Types/TerminalStatus.php | 19 + assets/mollie/vendor/autoload.php | 31 + assets/mollie/vendor/composer-autoload.php | 25 + assets/mollie/vendor/composer/ClassLoader.php | 579 +++ .../vendor/composer/InstalledVersions.php | 313 ++ assets/mollie/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 139 + .../vendor/composer/autoload_namespaces.php | 9 + .../mollie/vendor/composer/autoload_psr4.php | 11 + .../mollie/vendor/composer/autoload_real.php | 39 + .../vendor/composer/autoload_static.php | 173 + .../mollie/vendor/composer/ca-bundle/LICENSE | 19 + .../vendor/composer/ca-bundle/README.md | 85 + .../vendor/composer/ca-bundle/composer.json | 54 + .../vendor/composer/ca-bundle/res/cacert.pem | 3363 +++++++++++++++++ .../composer/ca-bundle/src/CaBundle.php | 361 ++ assets/mollie/vendor/composer/installed.json | 85 + assets/mollie/vendor/composer/installed.php | 5 + .../mollie/vendor/composer/platform_check.php | 26 + assets/mollie/vendor/scoper-autoload.php.bak | 31 + assets/softwaretool.js | 97 +- initialize.php | 18 + softwaretool.php | 22 +- webhook_mollie.php | 210 + 159 files changed, 16197 insertions(+), 21 deletions(-) create mode 100644 api/v2/get/payment.php create mode 100644 api/v2/post/payment.php create mode 100644 assets/mollie/.DS_Store create mode 100644 assets/mollie/LICENSE create mode 100644 assets/mollie/README.md create mode 100644 assets/mollie/composer.json create mode 100644 assets/mollie/src/.DS_Store create mode 100644 assets/mollie/src/CompatibilityChecker.php create mode 100644 assets/mollie/src/Endpoints/BalanceEndpoint.php create mode 100644 assets/mollie/src/Endpoints/BalanceReportEndpoint.php create mode 100644 assets/mollie/src/Endpoints/BalanceTransactionEndpoint.php create mode 100644 assets/mollie/src/Endpoints/ChargebackEndpoint.php create mode 100644 assets/mollie/src/Endpoints/ClientEndpoint.php create mode 100644 assets/mollie/src/Endpoints/ClientLinkEndpoint.php create mode 100644 assets/mollie/src/Endpoints/CollectionEndpointAbstract.php create mode 100644 assets/mollie/src/Endpoints/CustomerEndpoint.php create mode 100644 assets/mollie/src/Endpoints/CustomerPaymentsEndpoint.php create mode 100644 assets/mollie/src/Endpoints/EndpointAbstract.php create mode 100644 assets/mollie/src/Endpoints/InvoiceEndpoint.php create mode 100644 assets/mollie/src/Endpoints/MandateEndpoint.php create mode 100644 assets/mollie/src/Endpoints/MethodEndpoint.php create mode 100644 assets/mollie/src/Endpoints/OnboardingEndpoint.php create mode 100644 assets/mollie/src/Endpoints/OrderEndpoint.php create mode 100644 assets/mollie/src/Endpoints/OrderLineEndpoint.php create mode 100644 assets/mollie/src/Endpoints/OrderPaymentEndpoint.php create mode 100644 assets/mollie/src/Endpoints/OrderRefundEndpoint.php create mode 100644 assets/mollie/src/Endpoints/OrganizationEndpoint.php create mode 100644 assets/mollie/src/Endpoints/OrganizationPartnerEndpoint.php create mode 100644 assets/mollie/src/Endpoints/PaymentCaptureEndpoint.php create mode 100644 assets/mollie/src/Endpoints/PaymentChargebackEndpoint.php create mode 100644 assets/mollie/src/Endpoints/PaymentEndpoint.php create mode 100644 assets/mollie/src/Endpoints/PaymentLinkEndpoint.php create mode 100644 assets/mollie/src/Endpoints/PaymentRefundEndpoint.php create mode 100644 assets/mollie/src/Endpoints/PaymentRouteEndpoint.php create mode 100644 assets/mollie/src/Endpoints/PermissionEndpoint.php create mode 100644 assets/mollie/src/Endpoints/ProfileEndpoint.php create mode 100644 assets/mollie/src/Endpoints/ProfileMethodEndpoint.php create mode 100644 assets/mollie/src/Endpoints/RefundEndpoint.php create mode 100644 assets/mollie/src/Endpoints/SettlementPaymentEndpoint.php create mode 100644 assets/mollie/src/Endpoints/SettlementsEndpoint.php create mode 100644 assets/mollie/src/Endpoints/ShipmentEndpoint.php create mode 100644 assets/mollie/src/Endpoints/SubscriptionEndpoint.php create mode 100644 assets/mollie/src/Endpoints/TerminalEndpoint.php create mode 100644 assets/mollie/src/Endpoints/WalletEndpoint.php create mode 100644 assets/mollie/src/Exceptions/ApiException.php create mode 100644 assets/mollie/src/Exceptions/CurlConnectTimeoutException.php create mode 100644 assets/mollie/src/Exceptions/HttpAdapterDoesNotSupportDebuggingException.php create mode 100644 assets/mollie/src/Exceptions/IncompatiblePlatform.php create mode 100644 assets/mollie/src/Exceptions/UnrecognizedClientException.php create mode 100644 assets/mollie/src/HttpAdapter/CurlMollieHttpAdapter.php create mode 100644 assets/mollie/src/HttpAdapter/Guzzle6And7MollieHttpAdapter.php create mode 100644 assets/mollie/src/HttpAdapter/Guzzle6And7RetryMiddlewareFactory.php create mode 100644 assets/mollie/src/HttpAdapter/MollieHttpAdapterInterface.php create mode 100644 assets/mollie/src/HttpAdapter/MollieHttpAdapterPicker.php create mode 100644 assets/mollie/src/HttpAdapter/MollieHttpAdapterPickerInterface.php create mode 100644 assets/mollie/src/Idempotency/DefaultIdempotencyKeyGenerator.php create mode 100644 assets/mollie/src/Idempotency/FakeIdempotencyKeyGenerator.php create mode 100644 assets/mollie/src/Idempotency/IdempotencyKeyGeneratorContract.php create mode 100644 assets/mollie/src/MollieApiClient.php create mode 100644 assets/mollie/src/Resources/Balance.php create mode 100644 assets/mollie/src/Resources/BalanceCollection.php create mode 100644 assets/mollie/src/Resources/BalanceReport.php create mode 100644 assets/mollie/src/Resources/BalanceTransaction.php create mode 100644 assets/mollie/src/Resources/BalanceTransactionCollection.php create mode 100644 assets/mollie/src/Resources/BaseCollection.php create mode 100644 assets/mollie/src/Resources/BaseResource.php create mode 100644 assets/mollie/src/Resources/Capture.php create mode 100644 assets/mollie/src/Resources/CaptureCollection.php create mode 100644 assets/mollie/src/Resources/Chargeback.php create mode 100644 assets/mollie/src/Resources/ChargebackCollection.php create mode 100644 assets/mollie/src/Resources/Client.php create mode 100644 assets/mollie/src/Resources/ClientCollection.php create mode 100644 assets/mollie/src/Resources/ClientLink.php create mode 100644 assets/mollie/src/Resources/CurrentProfile.php create mode 100644 assets/mollie/src/Resources/CursorCollection.php create mode 100644 assets/mollie/src/Resources/Customer.php create mode 100644 assets/mollie/src/Resources/CustomerCollection.php create mode 100644 assets/mollie/src/Resources/Invoice.php create mode 100644 assets/mollie/src/Resources/InvoiceCollection.php create mode 100644 assets/mollie/src/Resources/Issuer.php create mode 100644 assets/mollie/src/Resources/IssuerCollection.php create mode 100644 assets/mollie/src/Resources/Mandate.php create mode 100644 assets/mollie/src/Resources/MandateCollection.php create mode 100644 assets/mollie/src/Resources/Method.php create mode 100644 assets/mollie/src/Resources/MethodCollection.php create mode 100644 assets/mollie/src/Resources/MethodPrice.php create mode 100644 assets/mollie/src/Resources/MethodPriceCollection.php create mode 100644 assets/mollie/src/Resources/Onboarding.php create mode 100644 assets/mollie/src/Resources/Order.php create mode 100644 assets/mollie/src/Resources/OrderCollection.php create mode 100644 assets/mollie/src/Resources/OrderLine.php create mode 100644 assets/mollie/src/Resources/OrderLineCollection.php create mode 100644 assets/mollie/src/Resources/Organization.php create mode 100644 assets/mollie/src/Resources/OrganizationCollection.php create mode 100644 assets/mollie/src/Resources/Partner.php create mode 100644 assets/mollie/src/Resources/Payment.php create mode 100644 assets/mollie/src/Resources/PaymentCollection.php create mode 100644 assets/mollie/src/Resources/PaymentLink.php create mode 100644 assets/mollie/src/Resources/PaymentLinkCollection.php create mode 100644 assets/mollie/src/Resources/Permission.php create mode 100644 assets/mollie/src/Resources/PermissionCollection.php create mode 100644 assets/mollie/src/Resources/Profile.php create mode 100644 assets/mollie/src/Resources/ProfileCollection.php create mode 100644 assets/mollie/src/Resources/Refund.php create mode 100644 assets/mollie/src/Resources/RefundCollection.php create mode 100644 assets/mollie/src/Resources/ResourceFactory.php create mode 100644 assets/mollie/src/Resources/Route.php create mode 100644 assets/mollie/src/Resources/RouteCollection.php create mode 100644 assets/mollie/src/Resources/Settlement.php create mode 100644 assets/mollie/src/Resources/SettlementCollection.php create mode 100644 assets/mollie/src/Resources/Shipment.php create mode 100644 assets/mollie/src/Resources/ShipmentCollection.php create mode 100644 assets/mollie/src/Resources/Subscription.php create mode 100644 assets/mollie/src/Resources/SubscriptionCollection.php create mode 100644 assets/mollie/src/Resources/Terminal.php create mode 100644 assets/mollie/src/Resources/TerminalCollection.php create mode 100644 assets/mollie/src/Types/ApprovalPrompt.php create mode 100644 assets/mollie/src/Types/BalanceTransferFrequency.php create mode 100644 assets/mollie/src/Types/InvoiceStatus.php create mode 100644 assets/mollie/src/Types/MandateMethod.php create mode 100644 assets/mollie/src/Types/MandateStatus.php create mode 100644 assets/mollie/src/Types/OnboardingStatus.php create mode 100644 assets/mollie/src/Types/OrderLineStatus.php create mode 100644 assets/mollie/src/Types/OrderLineType.php create mode 100644 assets/mollie/src/Types/OrderLineUpdateOperationType.php create mode 100644 assets/mollie/src/Types/OrderStatus.php create mode 100644 assets/mollie/src/Types/PaymentMethod.php create mode 100644 assets/mollie/src/Types/PaymentMethodStatus.php create mode 100644 assets/mollie/src/Types/PaymentStatus.php create mode 100644 assets/mollie/src/Types/ProfileStatus.php create mode 100644 assets/mollie/src/Types/RefundStatus.php create mode 100644 assets/mollie/src/Types/SequenceType.php create mode 100644 assets/mollie/src/Types/SettlementStatus.php create mode 100644 assets/mollie/src/Types/SubscriptionStatus.php create mode 100644 assets/mollie/src/Types/TerminalStatus.php create mode 100644 assets/mollie/vendor/autoload.php create mode 100644 assets/mollie/vendor/composer-autoload.php create mode 100644 assets/mollie/vendor/composer/ClassLoader.php create mode 100644 assets/mollie/vendor/composer/InstalledVersions.php create mode 100644 assets/mollie/vendor/composer/LICENSE create mode 100644 assets/mollie/vendor/composer/autoload_classmap.php create mode 100644 assets/mollie/vendor/composer/autoload_namespaces.php create mode 100644 assets/mollie/vendor/composer/autoload_psr4.php create mode 100644 assets/mollie/vendor/composer/autoload_real.php create mode 100644 assets/mollie/vendor/composer/autoload_static.php create mode 100644 assets/mollie/vendor/composer/ca-bundle/LICENSE create mode 100644 assets/mollie/vendor/composer/ca-bundle/README.md create mode 100644 assets/mollie/vendor/composer/ca-bundle/composer.json create mode 100644 assets/mollie/vendor/composer/ca-bundle/res/cacert.pem create mode 100644 assets/mollie/vendor/composer/ca-bundle/src/CaBundle.php create mode 100644 assets/mollie/vendor/composer/installed.json create mode 100644 assets/mollie/vendor/composer/installed.php create mode 100644 assets/mollie/vendor/composer/platform_check.php create mode 100644 assets/mollie/vendor/scoper-autoload.php.bak create mode 100644 initialize.php create mode 100644 webhook_mollie.php diff --git a/api/v2/get/payment.php b/api/v2/get/payment.php new file mode 100644 index 0000000..132e34d --- /dev/null +++ b/api/v2/get/payment.php @@ -0,0 +1,88 @@ + 'Missing required parameter: payment_id'], JSON_UNESCAPED_UNICODE); + exit; +} + +$payment_id = $criterias['payment_id']; + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +// STEP 1: Fetch transaction +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +$sql = 'SELECT * FROM transactions WHERE txn_id = ?'; +$stmt = $pdo->prepare($sql); +$stmt->execute([$payment_id]); +$transaction = $stmt->fetch(PDO::FETCH_ASSOC); + +if (!$transaction) { + http_response_code(404); + echo json_encode(['error' => 'Payment not found'], JSON_UNESCAPED_UNICODE); + exit; +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +// STEP 2: Fetch transaction item +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +$sql = 'SELECT * FROM transactions_items WHERE txn_id = ? LIMIT 1'; +$stmt = $pdo->prepare($sql); +$stmt->execute([$payment_id]); +$item = $stmt->fetch(PDO::FETCH_ASSOC); + +if (!$item) { + http_response_code(404); + echo json_encode(['error' => 'Payment item not found'], JSON_UNESCAPED_UNICODE); + exit; +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +// STEP 3: Parse item_options JSON +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +$item_options = []; +if (!empty($item['item_options'])) { + $item_options = json_decode($item['item_options'], true); +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +// STEP 4: Return payment details +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +$messages = json_encode([ + 'payment_id' => $transaction['txn_id'], + 'payment_status' => $transaction['payment_status'], + 'payment_amount' => $transaction['payment_amount'], + 'currency' => 'EUR', // Default currency + 'serial_number' => $item_options['serial_number'] ?? null, + 'equipment_id' => $item_options['equipment_id'] ?? null, + 'hw_version' => $item_options['hw_version'] ?? null, + 'version_id' => $item['item_id'], + 'payer_email' => $transaction['payer_email'], + 'customer_name' => trim(($transaction['first_name'] ?? '') . ' ' . ($transaction['last_name'] ?? '')), + 'created' => $transaction['created'] +], JSON_UNESCAPED_UNICODE); + +echo $messages; + +?> diff --git a/api/v2/post/payment.php b/api/v2/post/payment.php new file mode 100644 index 0000000..1087f40 --- /dev/null +++ b/api/v2/post/payment.php @@ -0,0 +1,280 @@ + 'Missing required fields: serial_number, version_id'], JSON_UNESCAPED_UNICODE); + exit; +} + +$serial_number = $post_content['serial_number']; +$version_id = $post_content['version_id']; +$user_data = $post_content['user_data'] ?? []; + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +// STEP 1: Get equipment data from serial_number +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +$sql = 'SELECT rowID, sw_version, sw_version_license, hw_version FROM equipment WHERE serialnumber = ?'; +$stmt = $pdo->prepare($sql); +$stmt->execute([$serial_number]); +$equipment = $stmt->fetch(PDO::FETCH_ASSOC); + +if (!$equipment) { + http_response_code(404); + echo json_encode(['error' => 'Device not found with serial number: ' . $serial_number], JSON_UNESCAPED_UNICODE); + exit; +} + +$equipment_id = $equipment['rowID']; +$current_sw_version = trim(strtolower(ltrim($equipment['sw_version'], '0'))); +$sw_version_license = $equipment['sw_version_license'] ?? null; +$hw_version = $equipment['hw_version'] ?? ''; + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +// STEP 2: Get version data from version_id +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +$sql = 'SELECT v.rowID as version_id, v.version, v.name, v.description, v.hw_version, p.productcode + FROM products_software_versions v + JOIN products_software p ON v.product_software_id = p.rowID + WHERE v.rowID = ? AND v.is_active = 1'; +$stmt = $pdo->prepare($sql); +$stmt->execute([$version_id]); +$version = $stmt->fetch(PDO::FETCH_ASSOC); + +if (!$version) { + http_response_code(404); + echo json_encode(['error' => 'Software version not found or inactive'], JSON_UNESCAPED_UNICODE); + exit; +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +// STEP 3: Calculate price SERVER-SIDE (same logic as software_update.php) +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +$final_price = '0.00'; +$final_currency = ''; + +// Check if version has upgrade paths defined +$sql = 'SELECT COUNT(*) as path_count FROM products_software_upgrade_paths WHERE to_version_id = ? AND is_active = 1'; +$stmt = $pdo->prepare($sql); +$stmt->execute([$version_id]); +$path_count_result = $stmt->fetch(PDO::FETCH_ASSOC); +$has_upgrade_paths = ($path_count_result['path_count'] > 0); + +if (!$has_upgrade_paths) { + // No upgrade paths defined = FREE (lines 240-242 in software_update.php) + $final_price = '0.00'; +} else { + // Check for valid upgrade path FROM current version + $sql = 'SELECT pup.price, pup.currency + FROM products_software_upgrade_paths pup + JOIN products_software_versions from_ver ON pup.from_version_id = from_ver.rowID + WHERE pup.to_version_id = ? + AND LOWER(TRIM(LEADING "0" FROM from_ver.version)) = ? + AND pup.is_active = 1'; + $stmt = $pdo->prepare($sql); + $stmt->execute([$version_id, $current_sw_version]); + $upgrade_path = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($upgrade_path) { + $final_price = $upgrade_path['price'] ?? '0.00'; + $final_currency = $upgrade_path['currency'] ?? 'EUR'; + } else { + // No upgrade path FROM current version + http_response_code(400); + echo json_encode(['error' => 'No valid upgrade path from current version'], JSON_UNESCAPED_UNICODE); + exit; + } +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +// STEP 4: Check license validity (lines 280-311 in software_update.php) +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +if ($final_price > 0 && $sw_version_license) { + $sql = 'SELECT status, start_at, expires_at + FROM products_software_licenses + WHERE license_key = ? AND equipment_id = ?'; + $stmt = $pdo->prepare($sql); + $stmt->execute([$sw_version_license, $equipment_id]); + $license = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($license && $license['status'] == 1) { + $now = date('Y-m-d H:i:s'); + $start_at = $license['start_at']; + $expires_at = $license['expires_at']; + + // Check if license is within valid date range + if ((!$start_at || $start_at <= $now) && (!$expires_at || $expires_at >= $now)) { + $final_price = '0.00'; + } + } +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +// STEP 5: Verify price > 0 (free upgrades shouldn't reach payment API) +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +if ($final_price <= 0) { + http_response_code(400); + echo json_encode(['error' => 'This upgrade is free. No payment required.'], JSON_UNESCAPED_UNICODE); + exit; +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +// STEP 6: DEBUG MODE - Simulate payment without Mollie +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +if (debug) { + // Generate fake payment ID + $fake_payment_id = 'DEBUG_' . uniqid() . '_' . time(); + $checkout_url = 'https://'.$_SERVER['SERVER_NAME'].'/softwaretool.php?payment_return=1&payment_id=' . $fake_payment_id; + + // Store transaction in DB + $sql = 'INSERT INTO transactions (txn_id, payment_amount, payment_status, payer_email, first_name, last_name, + address_street, address_city, address_state, address_zip, address_country, account_id, payment_method, created) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; + $stmt = $pdo->prepare($sql); + $stmt->execute([ + $fake_payment_id, + $final_price, + 0, // 0 = pending + $user_data['email'] ?? '', + $user_data['first_name'] ?? '', + $user_data['last_name'] ?? '', + $user_data['address_street'] ?? '', + $user_data['address_city'] ?? '', + $user_data['address_state'] ?? '', + $user_data['address_zip'] ?? '', + $user_data['address_country'] ?? '', + $serial_number, + 0, // payment method + date('Y-m-d H:i:s') + ]); + + // Store transaction item with serial_number in item_options + $item_options = json_encode([ + 'serial_number' => $serial_number, + 'equipment_id' => $equipment_id, + 'hw_version' => $hw_version + ], JSON_UNESCAPED_UNICODE); + + $sql = 'INSERT INTO transactions_items (txn_id, item_id, item_price, item_quantity, item_options, created) + VALUES (?, ?, ?, ?, ?, ?)'; + $stmt = $pdo->prepare($sql); + $stmt->execute([ + $fake_payment_id, + $version_id, + $final_price, + 1, + $item_options, + date('Y-m-d H:i:s') + ]); + + // Return fake checkout URL + $messages = json_encode([ + 'checkout_url' => $checkout_url, + 'payment_id' => $fake_payment_id, + 'debug_mode' => true + ], JSON_UNESCAPED_UNICODE); + echo $messages; + exit; +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +// STEP 7: Call Mollie API to create payment +//+++++++++++++++++++++++++++++++++++++++++++++++++++++ +try { + // Initialize Mollie + require dirname(__FILE__, 3).'/initialize.php'; + + // Format price for Mollie (must be string with 2 decimals) + $formatted_price = number_format((float)$final_price, 2, '.', ''); + + // Create payment with Mollie + $payment = $mollie->payments->create([ + 'amount' => [ + 'currency' => $final_currency ?: 'EUR', + 'value' => $formatted_price + ], + 'description' => 'Software upgrade to ' . $version['name'] . ' (v' . $version['version'] . ')', + 'redirectUrl' => 'https://'.$_SERVER['SERVER_NAME'].'/softwaretool.php?payment_return=1&payment_id={id}', + 'webhookUrl' => 'https://'.$_SERVER['SERVER_NAME'].'/webhook_mollie.php', + 'metadata' => [ + 'order_id' => $payment->id // Store payment ID in metadata + ] + ]); + + $mollie_payment_id = $payment->id; + $checkout_url = $payment->getCheckoutUrl(); + + //+++++++++++++++++++++++++++++++++++++++++++++++++++++ + // STEP 8: Store transaction in DB + //+++++++++++++++++++++++++++++++++++++++++++++++++++++ + $sql = 'INSERT INTO transactions (txn_id, payment_amount, payment_status, payer_email, first_name, last_name, + address_street, address_city, address_state, address_zip, address_country, account_id, payment_method, created) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; + $stmt = $pdo->prepare($sql); + $stmt->execute([ + $mollie_payment_id, + $final_price, + 0, // 0 = pending + $user_data['email'] ?? '', + $user_data['first_name'] ?? '', + $user_data['last_name'] ?? '', + $user_data['address_street'] ?? '', + $user_data['address_city'] ?? '', + $user_data['address_state'] ?? '', + $user_data['address_zip'] ?? '', + $user_data['address_country'] ?? '', + $serial_number, + 0, // payment method + date('Y-m-d H:i:s') + ]); + + //+++++++++++++++++++++++++++++++++++++++++++++++++++++ + // STEP 9: Store transaction item with serial_number in item_options + //+++++++++++++++++++++++++++++++++++++++++++++++++++++ + $item_options = json_encode([ + 'serial_number' => $serial_number, + 'equipment_id' => $equipment_id, + 'hw_version' => $hw_version + ], JSON_UNESCAPED_UNICODE); + + $sql = 'INSERT INTO transactions_items (txn_id, item_id, item_price, item_quantity, item_options, created) + VALUES (?, ?, ?, ?, ?, ?)'; + $stmt = $pdo->prepare($sql); + $stmt->execute([ + $mollie_payment_id, + $version_id, + $final_price, + 1, + $item_options, + date('Y-m-d H:i:s') + ]); + + //+++++++++++++++++++++++++++++++++++++++++++++++++++++ + // STEP 10: Return checkout URL and payment ID + //+++++++++++++++++++++++++++++++++++++++++++++++++++++ + $messages = json_encode([ + 'checkout_url' => $checkout_url, + 'payment_id' => $mollie_payment_id + ], JSON_UNESCAPED_UNICODE); + echo $messages; + +} catch (Exception $e) { + http_response_code(500); + echo json_encode(['error' => 'Payment creation failed: ' . $e->getMessage()], JSON_UNESCAPED_UNICODE); + exit; +} + +?> diff --git a/assets/functions.php b/assets/functions.php index 69c7486..a02c05f 100644 --- a/assets/functions.php +++ b/assets/functions.php @@ -5280,7 +5280,7 @@ function translateDeviceHardwareVersion($device_hw_version) { /** * Translates hardware version from database to match device format if needed * This can be used for display or API responses - * + * * @param string $db_hw_version - Hardware version from database * @return string - Hardware version (currently returns same as input) */ @@ -5288,4 +5288,258 @@ function translateDbHardwareVersion($db_hw_version) { // For now, we keep the standardized format from DB // This function exists for future reverse translation if needed return $db_hw_version; +} + +/** + * Generates a unique license key for software upgrades + * Format: XXXX-XXXX-XXXX-XXXX (16 uppercase alphanumeric characters) + * + * @return string - Unique license key + */ +function generateUniqueLicenseKey() { + include dirname(__FILE__,2).'/settings/settings_redirector.php'; + + $pdo = dbConnect($dbname); + $max_attempts = 10; + $attempt = 0; + + do { + // Generate 16 random bytes and convert to uppercase hex + $random_bytes = random_bytes(8); // 8 bytes = 16 hex characters + $hex = strtoupper(bin2hex($random_bytes)); + + // Format as XXXX-XXXX-XXXX-XXXX + $license_key = substr($hex, 0, 4) . '-' . + substr($hex, 4, 4) . '-' . + substr($hex, 8, 4) . '-' . + substr($hex, 12, 4); + + // Check if this key already exists + $sql = 'SELECT COUNT(*) as count FROM products_software_licenses WHERE license_key = ?'; + $stmt = $pdo->prepare($sql); + $stmt->execute([$license_key]); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($result['count'] == 0) { + return $license_key; + } + + $attempt++; + } while ($attempt < $max_attempts); + + // Fallback: append timestamp if collision persists (extremely unlikely) + return $license_key . '-' . time(); +} + +/** + * Generates HTML invoice for software upgrade payments + * Based on existing invoice template but customized for software licenses + * + * @param array $invoice_data - Invoice data from /v2/invoice API (includes customer, transaction, items) + * @param string $order_id - Transaction ID (txn_id) + * @param string $language - Invoice language code (e.g., 'US', 'NL') + * @return array - [$html_content, $customer_email, $order_id] + */ +function generateSoftwareInvoice($invoice_data, $order_id, $language = 'US') { + include dirname(__FILE__,2).'/settings/settings_redirector.php'; + + // Extract customer data + $customer = $invoice_data['customer'] ?? []; + $customer_email = $customer['email'] ?? $invoice_data['payer_email'] ?? ''; + $customer_name = trim(($customer['first_name'] ?? '') . ' ' . ($customer['last_name'] ?? '')); + $customer_address = $customer['address_street'] ?? ''; + $customer_city = $customer['address_city'] ?? ''; + $customer_state = $customer['address_state'] ?? ''; + $customer_zip = $customer['address_zip'] ?? ''; + $customer_country = $customer['address_country'] ?? ''; + + // Extract transaction data + $payment_amount = $invoice_data['payment_amount'] ?? 0; + $tax_amount = $invoice_data['tax_amount'] ?? 0; + $shipping_amount = $invoice_data['shipping_amount'] ?? 0; + $discount_amount = $invoice_data['discount_amount'] ?? 0; + $currency = 'EUR'; // Default currency + $invoice_date = $invoice_data['invoice_created'] ?? date('Y-m-d H:i:s'); + + // Extract item data (software upgrade details) + $items = []; + $serial_number = ''; + $software_version = ''; + $license_key = ''; + + if (isset($invoice_data['item_id'])) { + // Single item format from API + $item_options = !empty($invoice_data['item_options']) ? json_decode($invoice_data['item_options'], true) : []; + $serial_number = $item_options['serial_number'] ?? 'N/A'; + $software_version = $invoice_data['productname'] ?? 'Software Upgrade'; + + // Get license key from database + $pdo = dbConnect($dbname); + $sql = 'SELECT license_key FROM products_software_licenses WHERE transaction_id = ? LIMIT 1'; + $stmt = $pdo->prepare($sql); + $stmt->execute([$order_id]); + $license_result = $stmt->fetch(PDO::FETCH_ASSOC); + $license_key = $license_result['license_key'] ?? 'Pending'; + + $items[] = [ + 'name' => $software_version, + 'quantity' => $invoice_data['item_quantity'] ?? 1, + 'price' => $invoice_data['item_price'] ?? $payment_amount, + 'serial_number' => $serial_number, + 'license_key' => $license_key + ]; + } + + // Load language translations + $translations = []; + $translation_file = dirname(__FILE__,2).'/settings/translations/translations_'.$language.'.php'; + if (file_exists($translation_file)) { + include $translation_file; + } else { + // Fallback to US English + include dirname(__FILE__,2).'/settings/translations/translations_US.php'; + } + + // Invoice labels (with fallbacks) + $lbl_invoice = $translations['invoice'] ?? 'Invoice'; + $lbl_invoice_number = $translations['invoice_number'] ?? 'Invoice Number'; + $lbl_invoice_date = $translations['invoice_date'] ?? 'Invoice Date'; + $lbl_customer = $translations['customer'] ?? 'Customer'; + $lbl_product = $translations['product'] ?? 'Product'; + $lbl_quantity = $translations['quantity'] ?? 'Quantity'; + $lbl_price = $translations['price'] ?? 'Price'; + $lbl_subtotal = $translations['subtotal'] ?? 'Subtotal'; + $lbl_tax = $translations['tax'] ?? 'Tax'; + $lbl_shipping = $translations['shipping'] ?? 'Shipping'; + $lbl_discount = $translations['discount'] ?? 'Discount'; + $lbl_total = $translations['total'] ?? 'Total'; + $lbl_device_serial = $translations['device_serial'] ?? 'Device Serial Number'; + $lbl_license_key = $translations['license_key'] ?? 'License Key'; + $lbl_license_expiry = $translations['license_expiry'] ?? 'License Expiry'; + + // Build HTML invoice + $html = ' + +
+ + + + +| ' . htmlspecialchars($lbl_product) . ' | +' . htmlspecialchars($lbl_quantity) . ' | +' . htmlspecialchars($lbl_price) . ' | +
|---|---|---|
| ' . htmlspecialchars($item['name']) . ' | +' . htmlspecialchars($item['quantity']) . ' | +' . number_format($item['price'], 2) . ' ' . htmlspecialchars($currency) . ' | +
| ' . htmlspecialchars($lbl_subtotal) . ': | +' . number_format($subtotal, 2) . ' ' . htmlspecialchars($currency) . ' | +|
| ' . htmlspecialchars($lbl_tax) . ': | +' . number_format($tax_amount, 2) . ' ' . htmlspecialchars($currency) . ' | +|
| ' . htmlspecialchars($lbl_shipping) . ': | +' . number_format($shipping_amount, 2) . ' ' . htmlspecialchars($currency) . ' | +|
| ' . htmlspecialchars($lbl_discount) . ': | +-' . number_format($discount_amount, 2) . ' ' . htmlspecialchars($currency) . ' | +|
| ' . htmlspecialchars($lbl_total) . ': | +' . number_format($payment_amount, 2) . ' ' . htmlspecialchars($currency) . ' | +|
+
+
+
+Accepting [iDEAL](https://www.mollie.com/payments/ideal/), [Apple Pay](https://www.mollie.com/payments/apple-pay), [Bancontact](https://www.mollie.com/payments/bancontact/), [SOFORT Banking](https://www.mollie.com/payments/sofort/), [Creditcard](https://www.mollie.com/payments/credit-card/), [SEPA Bank transfer](https://www.mollie.com/payments/bank-transfer/), [SEPA Direct debit](https://www.mollie.com/payments/direct-debit/), [PayPal](https://www.mollie.com/payments/paypal/), [Belfius Direct Net](https://www.mollie.com/payments/belfius/), [KBC/CBC](https://www.mollie.com/payments/kbc-cbc/), [paysafecard](https://www.mollie.com/payments/paysafecard/), [ING Home'Pay](https://www.mollie.com/payments/ing-homepay/), [Giropay](https://www.mollie.com/payments/giropay/), [EPS](https://www.mollie.com/payments/eps/), [Przelewy24](https://www.mollie.com/payments/przelewy24/), [Postepay](https://www.mollie.com/en/payments/postepay), [In3](https://www.mollie.com/payments/in3/), [Klarna](https://www.mollie.com/payments/klarna-pay-later/) ([Pay now](https://www.mollie.com/payments/klarna-pay-now/), [Pay later](https://www.mollie.com/payments/klarna-pay-later/), [Slice it](https://www.mollie.com/payments/klarna-slice-it/), [Pay in 3](https://www.mollie.com/payments/klarna-pay-in-3/)), [Giftcard](https://www.mollie.com/payments/gift-cards/) and [Voucher](https://www.mollie.com/en/payments/meal-eco-gift-vouchers) online payments without fixed monthly costs or any punishing registration procedures. Just use the Mollie API to receive payments directly on your website or easily refund transactions to your customers.
+
+[](https://github.com/mollie/mollie-api-php/actions)
+[](https://packagist.org/packages/mollie/mollie-api-php)
+[](https://packagist.org/packages/mollie/mollie-api-php)
+
+## Requirements ##
+To use the Mollie API client, the following things are required:
+
++ Get yourself a free [Mollie account](https://www.mollie.com/signup). No sign up costs.
++ Now you're ready to use the Mollie API client in test mode.
++ Follow [a few steps](https://www.mollie.com/dashboard/?modal=onboarding) to enable payment methods in live mode, and let us handle the rest.
++ PHP >= 7.0
++ Up-to-date OpenSSL (or other SSL/TLS toolkit)
+
+For leveraging [Mollie Connect](https://docs.mollie.com/oauth/overview) (advanced use cases only), we recommend also installing our [OAuth2 client](https://github.com/mollie/oauth2-mollie-php).
+
+## Composer Installation ##
+
+By far the easiest way to install the Mollie API client is to require it with [Composer](http://getcomposer.org/doc/00-intro.md).
+
+ $ composer require mollie/mollie-api-php:^2.0
+
+ {
+ "require": {
+ "mollie/mollie-api-php": "^2.0"
+ }
+ }
+
+The version of the API client corresponds to the version of the API it implements. Check the [notes on migration](https://docs.mollie.com/migrating-v1-to-v2) to see what changes you need to make if you want to start using a newer API version.
+
+
+## Manual Installation ##
+If you're not familiar with using composer we've added a ZIP file to the releases containing the API client and all the packages normally installed by composer.
+Download the ``mollie-api-php.zip`` from the [releases page](https://github.com/mollie/mollie-api-php/releases).
+
+Include the ``vendor/autoload.php`` as shown in [Initialize example](https://github.com/mollie/mollie-api-php/blob/master/examples/initialize.php).
+
+## How to receive payments ##
+
+To successfully receive a payment, these steps should be implemented:
+
+1. Use the Mollie API client to create a payment with the requested amount, currency, description and optionally, a payment method. It is important to specify a unique redirect URL where the customer is supposed to return to after the payment is completed.
+
+2. Immediately after the payment is completed, our platform will send an asynchronous request to the configured webhook to allow the payment details to be retrieved, so you know when exactly to start processing the customer's order.
+
+3. The customer returns, and should be satisfied to see that the order was paid and is now being processed.
+
+Find our full documentation online on [docs.mollie.com](https://docs.mollie.com).
+
+## Getting started ##
+
+Initializing the Mollie API client, and setting your API key.
+
+```php
+$mollie = new \Mollie\Api\MollieApiClient();
+$mollie->setApiKey("test_dHar4XY7LxsDOtmnkVtjNVWXLSlXsM");
+```
+
+Creating a new payment.
+
+```php
+$payment = $mollie->payments->create([
+ "amount" => [
+ "currency" => "EUR",
+ "value" => "10.00"
+ ],
+ "description" => "My first API payment",
+ "redirectUrl" => "https://webshop.example.org/order/12345/",
+ "webhookUrl" => "https://webshop.example.org/mollie-webhook/",
+]);
+```
+_After creation, the payment id is available in the `$payment->id` property. You should store this id with your order._
+
+After storing the payment id you can send the customer to the checkout using the `$payment->getCheckoutUrl()`.
+
+```php
+header("Location: " . $payment->getCheckoutUrl(), true, 303);
+```
+_This header location should always be a GET, thus we enforce 303 http response code_
+
+For a payment create example, see [Example - New Payment](https://github.com/mollie/mollie-api-php/blob/master/examples/payments/create-payment.php).
+
+## Retrieving payments ##
+We can use the `$payment->id` to retrieve a payment and check if the payment `isPaid`.
+
+```php
+$payment = $mollie->payments->get($payment->id);
+
+if ($payment->isPaid())
+{
+ echo "Payment received.";
+}
+```
+
+Or retrieve a collection of payments.
+
+```php
+$payments = $mollie->payments->page();
+```
+
+For an extensive example of listing payments with the details and status, see [Example - List Payments](https://github.com/mollie/mollie-api-php/blob/master/examples/payments/list-payments.php).
+
+## Payment webhook ##
+
+When the status of a payment changes the `webhookUrl` we specified in the creation of the payment will be called.
+There we can use the `id` from our POST parameters to check te status and act upon that, see [Example - Webhook](https://github.com/mollie/mollie-api-php/blob/master/examples/payments/webhook.php).
+
+
+## Multicurrency ##
+Since 2.0 it is now possible to create non-EUR payments for your customers.
+A full list of available currencies can be found [in our documentation](https://docs.mollie.com/guides/multicurrency).
+
+```php
+$payment = $mollie->payments->create([
+ "amount" => [
+ "currency" => "USD",
+ "value" => "10.00"
+ ],
+ "description" => "Order #12345",
+ "redirectUrl" => "https://webshop.example.org/order/12345/",
+ "webhookUrl" => "https://webshop.example.org/mollie-webhook/",
+]);
+```
+_After creation, the `settlementAmount` will contain the EUR amount that will be settled on your account._
+
+
+### Fully integrated iDEAL payments ###
+
+If you want to fully integrate iDEAL payments in your web site, some additional steps are required. First, you need to
+retrieve the list of issuers (banks) that support iDEAL and have your customer pick the issuer he/she wants to use for
+the payment.
+
+Retrieve the iDEAL method and include the issuers
+
+```php
+$method = $mollie->methods->get(\Mollie\Api\Types\PaymentMethod::IDEAL, ["include" => "issuers"]);
+```
+
+_`$method->issuers` will be a list of objects. Use the property `$id` of this object in the
+ API call, and the property `$name` for displaying the issuer to your customer. For a more in-depth example, see [Example - iDEAL payment](https://github.com/mollie/mollie-api-php/blob/master/examples/payments/create-ideal-payment.php)._
+
+Create a payment with the selected issuer:
+
+```php
+$payment = $mollie->payments->create([
+ "amount" => [
+ "currency" => "EUR",
+ "value" => "10.00"
+ ],
+ "description" => "My first API payment",
+ "redirectUrl" => "https://webshop.example.org/order/12345/",
+ "webhookUrl" => "https://webshop.example.org/mollie-webhook/",
+ "method" => \Mollie\Api\Types\PaymentMethod::IDEAL,
+ "issuer" => $selectedIssuerId, // e.g. "ideal_INGBNL2A"
+]);
+```
+
+_The `_links` property of the `$payment` object will contain an object `checkout` with a `href` property, which is a URL that points directly to the online banking environment of the selected issuer.
+A short way of retrieving this URL can be achieved by using the `$payment->getCheckoutUrl()`._
+
+### Refunding payments ###
+
+The API also supports refunding payments. Note that there is no confirmation and that all refunds are immediate and
+definitive. refunds are supported for all methods except for paysafecard and gift cards.
+
+```php
+$payment = $mollie->payments->get($payment->id);
+
+// Refund € 2 of this payment
+$refund = $payment->refund([
+ "amount" => [
+ "currency" => "EUR",
+ "value" => "2.00"
+ ]
+]);
+```
+
+For a working example, see [Example - Refund payment](https://github.com/mollie/mollie-api-php/blob/master/examples/payments/refund-payment.php).
+
+## Enabling debug mode
+
+When debugging it can be convenient to have the submitted request available on the `ApiException`.
+
+In order to prevent leaking sensitive request data into your local application logs, debugging is disabled by default.
+
+To enable debugging and inspect the request:
+
+```php
+/** @var $mollie \Mollie\Api\MollieApiClient */
+$mollie->enableDebugging();
+
+try {
+ $mollie->payments->get('tr_12345678');
+} catch (\Mollie\Api\Exceptions\ApiException $exception) {
+ $request = $exception->getRequest();
+}
+```
+
+If you're logging the `ApiException`, the request will also be logged. Make sure to not retain any sensitive data in
+these logs and clean up after debugging.
+
+To disable debugging again:
+
+```php
+/** @var $mollie \Mollie\Api\MollieApiClient */
+$mollie->disableDebugging();
+```
+
+Note that debugging is only available when using the default Guzzle http adapter (`Guzzle6And7MollieHttpAdapter`).
+
+## API documentation ##
+If you wish to learn more about our API, please visit the [Mollie Developer Portal](https://www.mollie.com/developers). API Documentation is available in English.
+
+## Want to help us make our API client even better? ##
+
+Want to help us make our API client even better? We take [pull requests](https://github.com/mollie/mollie-api-php/pulls?utf8=%E2%9C%93&q=is%3Apr), sure. But how would you like to contribute to a technology oriented organization? Mollie is hiring developers and system engineers. [Check out our vacancies](https://jobs.mollie.com/) or [get in touch](mailto:personeel@mollie.com).
+
+## License ##
+[BSD (Berkeley Software Distribution) License](https://opensource.org/licenses/bsd-license.php).
+Copyright (c) 2013-2018, Mollie B.V.
+
+## Support ##
+Contact: [www.mollie.com](https://www.mollie.com) — info@mollie.com — +31 20 820 20 70
diff --git a/assets/mollie/composer.json b/assets/mollie/composer.json
new file mode 100644
index 0000000..8b4dd00
--- /dev/null
+++ b/assets/mollie/composer.json
@@ -0,0 +1,84 @@
+{
+ "name": "mollie\/mollie-api-php",
+ "description": "Mollie API client library for PHP. Mollie is a European Payment Service provider and offers international payment methods such as Mastercard, VISA, American Express and PayPal, and local payment methods such as iDEAL, Bancontact, SOFORT Banking, SEPA direct debit, Belfius Direct Net, KBC Payment Button and various gift cards such as Podiumcadeaukaart and fashioncheque.",
+ "keywords": [
+ "mollie",
+ "payment",
+ "service",
+ "ideal",
+ "creditcard",
+ "apple pay",
+ "mistercash",
+ "bancontact",
+ "sofort",
+ "sofortbanking",
+ "sepa",
+ "paypal",
+ "paysafecard",
+ "podiumcadeaukaart",
+ "przelewy24",
+ "banktransfer",
+ "direct debit",
+ "belfius",
+ "belfius direct net",
+ "refunds",
+ "api",
+ "payments",
+ "gateway",
+ "subscriptions",
+ "recurring",
+ "charges",
+ "kbc",
+ "cbc",
+ "gift cards",
+ "intersolve",
+ "fashioncheque",
+ "inghomepay",
+ "klarna",
+ "paylater",
+ "sliceit"
+ ],
+ "homepage": "https:\/\/www.mollie.com\/en\/developers",
+ "license": "BSD-2-Clause",
+ "authors": [
+ {
+ "name": "Mollie B.V.",
+ "email": "info@mollie.com"
+ }
+ ],
+ "require": {
+ "php": "^7.2|^8.0",
+ "ext-curl": "*",
+ "ext-json": "*",
+ "ext-openssl": "*",
+ "composer\/ca-bundle": "^1.2"
+ },
+ "require-dev": {
+ "eloquent\/liberator": "^2.0||^3.0",
+ "friendsofphp\/php-cs-fixer": "^3.0",
+ "guzzlehttp\/guzzle": "^6.3",
+ "phpstan\/phpstan": "^1.4",
+ "phpunit\/phpunit": "^8.5 || ^9.5"
+ },
+ "suggest": {
+ "mollie\/oauth2-mollie-php": "Use OAuth to authenticate with the Mollie API. This is needed for some endpoints. Visit https:\/\/docs.mollie.com\/ for more information."
+ },
+ "config": {
+ "sort-packages": true
+ },
+ "autoload": {
+ "psr-4": {
+ "Mollie\\Api\\": "src\/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "_PhpScoperf7c63b60b99d\\Tests\\": "tests\/",
+ "_PhpScoperf7c63b60b99d\\Tests\\Mollie\\Api\\": "tests\/Mollie\/API\/"
+ }
+ },
+ "scripts": {
+ "test": ".\/vendor\/bin\/phpunit tests",
+ "format": ".\/vendor\/bin\/php-cs-fixer fix --allow-risky=yes"
+ }
+}
\ No newline at end of file
diff --git a/assets/mollie/src/.DS_Store b/assets/mollie/src/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..c6ec5837655044ebf2159e546cc74c086deb766e
GIT binary patch
literal 6148
zcmeHKyH3L}6umB?>SO5!Z21JbFfpW6EAiMUA5i)bAT>$V2Wq!`0umb^!iJdm4t|Am
zuPumGTVg^8`AYV2?Q@-zlfYour payment has been processed. Please reconnect your device to apply the software upgrade.
+Payment ID: '.htmlspecialchars($payment_return).'
+