feat(payments): Mollie-Provider -- getrennte Zahlarten je Methode (Klarna, Kreditkarte, Apple Pay, Google Pay)

- core/payments/providers/mollie: Client (Bearer API-Key, Idempotency-Key), Provider nach dem
  PayPal-v2-Vertrag: start (POST /v2/payments mit method aus payment_methods.argument),
  onReturn/onCancel (Status per GET, Rueckkehr-URL traegt o=<orders.id>), onWebhook
  (id=tr_..., Wahrheit per GET), reconcile (paid/canceled/expired/failed, >24h abbrechen)
- Klarna: lines aus order_item (brutto je Stueck), Versand, Zahlartgebuehr, Gutschein, Rabatt,
  Rundungsausgleich; billing/shippingAddress mit E-Mail und Telefon (E.164)
- core/paymentmethods/molliepaymentmethod.class.php: Kassen-Adapter ohne Express
- install_mollie.sql: 16 Spalten in shipping_area (4 helperjoinkeys), Einstellungen Gruppe
  mollie, 4 Zahlarten (module mollie, argument = Methode), Freischaltung/Leichen als Kommentar
- Kasse neu: Mollie-Logos je Methode, Apple Pay nur auf faehigen Geraeten
- cli.php status: mehrere Zahlarten je Anbieter, Modus generisch
This commit is contained in:
Thomas Bartelt
2026-09-27 10:39:23 +02:00
parent d5a3727884
commit b8111a1e7f
6 changed files with 841 additions and 5 deletions
@@ -259,7 +259,7 @@
{foreach item=pMethod from=$payment_methods name=pMethodLoop}
{if ($pMethod->helperjoinkey != 'be' && $pMethod->helperjoinkey != 'r') || ($pMethod->helperjoinkey == 'be' && $customer->direct_debit_active == 1) || ($pMethod->helperjoinkey == 'r' && $customer->rechnung_active == 1)}
{if $pMethod->activeType > 0}
<label class="ck-opt ck-opt-pay ck-pay-{$pMethod->module|default:'std'}">
<label class="ck-opt ck-opt-pay ck-pay-{$pMethod->module|default:'std'}{if $pMethod->module == 'mollie'} ck-pay-{$pMethod->argument|escape}{/if}" data-method="{if $pMethod->module == 'mollie'}{$pMethod->argument|escape}{else}{$pMethod->module|escape}{/if}">
<input type="radio" name="payment_method" value="{$pMethod->id}" id="selection_{$pMethod->helperjoinkey}" {if (isset($personal_data.payment_method) && $personal_data.payment_method == $pMethod->id) || (!isset($personal_data.payment_method) && $smarty.foreach.pMethodLoop.first)}checked="checked"{/if} />
<span class="ck-opt-body">
<span class="ck-opt-name">{$pMethod->name}</span>
@@ -272,6 +272,8 @@
</span>
<span class="ck-opt-price">
{if $pMethod->module == 'paypal_v2' || $pMethod->module == 'paypal'}<img class="ck-paylogo" src="https://www.paypalobjects.com/webstatic/de_DE/i/de-pp-logo-100px.png" alt="PayPal" />{/if}
{* Mollie-Zahlarten (Klarna, Kreditkarte, Apple Pay, Google Pay): Logo je Methode von Mollie *}
{if $pMethod->module == 'mollie' && $pMethod->argument}<img class="ck-paylogo ck-paylogo-mollie" src="https://www.mollie.com/external/icons/payment-methods/{$pMethod->argument|escape:'url'}.svg" alt="{$pMethod->name|escape}" />{/if}
{if $pMethod->paymentAdd != 0}
{if $pMethod->accountType == '0'}+ {$pMethod->paymentAdd|number_format:"2":",":"."} &euro;
{elseif $pMethod->accountType == '1'}&minus; {$pMethod->paymentAdd|number_format:"2":",":"."} &euro;
@@ -460,6 +462,10 @@
.ck-opt-err { font-size: 12px; color: #b00020; }
.ck-opt-price { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; font-weight: 700; white-space: nowrap; }
.ck-paylogo { height: 18px; width: auto; }
.ck-paylogo-mollie { height: 24px; }
/* Apple Pay nur auf Geraeten, die es koennen (Safari/iOS); Skript unten blendet ein */
.ck-pay-applepay { display: none; }
.ck-pay-applepay.ck-pay-ok { display: flex; }
.ck-note summary { cursor: pointer; font-weight: 700; }
.ck-note textarea { margin-top: 8px; }
@@ -586,6 +592,15 @@ $(document).ready(function() {
// Lieferadresse: eigenes Formular ein-/ausblenden (Gast; eingeloggt macht es content_cash_desk.js)
$('#shipping_address_select').change(function() { $('.shipping_address_form_container').toggle($(this).val() != -1); });
$('.shipping_address_form_container').toggle($('#shipping_address_select').val() != -1);
// Apple Pay (Mollie) nur zeigen, wenn das Geraet es kann. War die versteckte Zahlart
// vorausgewaehlt, rueckt die erste sichtbare nach.
var applePayOk = false;
try { applePayOk = !!(window.ApplePaySession && window.ApplePaySession.canMakePayments()); } catch (e) {}
if (applePayOk) { $('.ck-pay-applepay').addClass('ck-pay-ok'); }
var $checked = $('.ck-opt-pay input[name=payment_method]:checked');
if ($checked.length && !$checked.closest('.ck-opt-pay').is(':visible')) {
$('.ck-opt-pay:visible input[name=payment_method]').first().attr('checked', 'checked');
}
});
</script>
{/literal}