Abo: Einmalprodukte bereits bei der Abo-Anlage + es/fr-Sprachsync

Einmalprodukte (Normalsortiment, show_on 3) können jetzt schon beim
Abo-Abschluss hinzugefügt werden – im Portal-Wizard (Abschnitt im
Upgrade-Schritt) und in allen drei Sales-Center-Abo-Strecken (eigene
Produktliste). Variante A: Zeilen laufen als Cart-Option abo_addon mit
durch den Checkout, werden sofort bezahlt und mit der Erstlieferung
verschickt (Rechnung/Lieferschein gruppieren automatisch).

- Checkout persistiert is_abo_addon (CheckoutRepository, PaymentHelper)
- createAboItems/ensureUserAboItemsFromLatestOrder überspringen Addons
  (sonst würden Einmalprodukte dauerhaft wiederkehren); amount ohne
  Addon-Anteil; aboHasBaseProduct ignoriert Addon-Zeilen
- CreateAboReplacementOrder propagiert is_abo_addon in Ersatzbestellungen
- iq-shopping-cart.js: zweite Datatable + abo_addon-Flag-Weitergabe
- i18n: neue abo.onetime_create_*-Keys (de/en/es/fr); zusätzlich es/fr
  komplett synchronisiert (abo-Kartenblock, navigation, payment,
  weborder inkl. Entfernung PAYONE-Altlasten, withdrawal.php neu)
- Tests: AboCreateOneTimeItemsTest, AboCreateOneTimeCartTest,
  AboPortalCreateOneTimeTest (17 neue, 122 Tests gesamt grün)

Plan: dev/2026-07-21-abo-einmalprodukte-anlage/

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin 2026-07-21 14:36:40 +00:00
parent 1e7ae92d0c
commit cdb121fde0
32 changed files with 1479 additions and 52 deletions

View file

@ -120,6 +120,10 @@ return [
'abo_subtotal' => 'Subtotal productos de suscripción',
'abo_next_delivery_total' => 'Importe total de la próxima entrega',
'onetime_empty' => 'Aún no se han añadido productos únicos.',
'onetime_product' => 'Producto único',
'onetime_create_hl' => 'Añadir productos únicos al primer envío',
'onetime_create_info' => 'Estos productos se envían solo con la primera entrega de la suscripción y se pagan junto con el pedido de suscripción. No forman parte de la suscripción recurrente y no se cobrarán de nuevo en futuras entregas.',
'onetime_badge_first_delivery' => 'Único (solo primer envío)',
'onetime_badge' => 'Único',
'combined_summary_hl' => 'Total de la próxima entrega',
'create_abo' => 'Crear suscripción',
@ -249,4 +253,47 @@ return [
'admin_delete_confirm_copy' => 'La suscripción se eliminará (deleted_at) y ya no aparecerá en el resumen. Continúe solo si realmente lo desea.',
'admin_delete_confirm_button' => 'Eliminar suscripción ahora',
'admin_delete_success' => 'La suscripción se ha eliminado.',
// Kreditkarte / Zahlart aktualisieren (Abo)
'update_card_title' => 'Actualizar tarjeta de crédito',
'card_change_history' => 'Historial de cambios',
'current_card' => 'Tarjeta actual',
'card_update_intro' => 'Guarde una nueva tarjeta de crédito para esta suscripción. Puede realizarse una autorización de verificación de 0,01 EUR que no se cobra. El próximo cargo se realizará con la nueva tarjeta.',
'card_security_notice' => 'Sus datos de tarjeta no se almacenan aquí. Se transmiten cifrados por SSL directamente a nuestro proveedor de pagos PAYONE solo para su verificación.',
'card_holder_required' => 'Introduzca el nombre del titular de la tarjeta.',
'card_number_invalid' => 'Introduzca un número de tarjeta de crédito válido.',
'card_expiry_invalid' => 'Introduzca una fecha de caducidad válida.',
'card_cvc_invalid' => 'Introduzca un código de seguridad (CVC) válido.',
'card_type_invalid' => 'Seleccione un tipo de tarjeta válido (Visa o Mastercard).',
'card_update_success' => 'Su tarjeta de crédito se ha actualizado. El próximo cargo se realizará con la nueva tarjeta.',
'card_update_failed' => 'No se pudo actualizar la tarjeta de crédito. Inténtelo de nuevo.',
'card_update_not_allowed' => 'La tarjeta de crédito no se puede actualizar para esta suscripción.',
'card_update_link_button' => 'Enviar enlace de actualización al cliente',
'card_update_link_sent' => 'El enlace de actualización se ha enviado al cliente.',
'card_update_link_invalid' => 'Este enlace no es válido o ha caducado.',
'card_update_link_not_allowed' => 'No se puede enviar un enlace de actualización para esta suscripción.',
'card_update_link_mail_subject' => 'Actualice la tarjeta de crédito de su suscripción',
'card_update_link_mail_intro' => 'Actualice la tarjeta de crédito de su suscripción a través del siguiente enlace seguro. Sus datos de tarjeta se transmiten cifrados por SSL únicamente a nuestro proveedor de pagos PAYONE.',
'card_update_link_mail_button' => 'Actualizar tarjeta de crédito',
'card_update_link_mail_hint' => 'Si el botón no funciona, copie este enlace en su navegador:',
'card_update_done_success_title' => 'Tarjeta de crédito actualizada',
'card_update_done_success_copy' => 'Gracias. El próximo cargo se realizará con su nueva tarjeta.',
'card_update_done_failed_title' => 'Actualización fallida',
'card_update_done_failed_copy' => 'No se pudo actualizar la tarjeta de crédito. Solicite un nuevo enlace si es necesario.',
'card_update_portal_hint' => 'También encontrará esta suscripción en su portal de clientes. Allí puede iniciar sesión y gestionar usted mismo su método de pago y su suscripción en cualquier momento.',
'card_update_to_portal' => 'Ir al portal de clientes',
'payment_method' => 'Método de pago',
'current_payment_method' => 'Método de pago actual',
'update_payment_method' => 'Actualizar método de pago',
'payment_method_change_title' => 'Cambiar método de pago',
'payment_method_change_intro' => 'Elija un nuevo método de pago para esta suscripción en la página de pago segura, por ejemplo si su tarjeta ha caducado o desea pagar de otra forma en el futuro.',
'payment_method_change_no_charge' => 'No se cobrará nada: el nuevo método de pago se aplica a partir del próximo pago de la suscripción.',
'payment_method_change_button' => 'Elegir nuevo método de pago',
'payment_method_change_success' => 'Su método de pago se ha actualizado. El próximo pago se realizará con el nuevo método.',
'payment_method_change_failed' => 'No se pudo cambiar el método de pago. Inténtelo de nuevo.',
'payment_method_change_done_title' => 'Método de pago actualizado',
'payment_method_change_done_failed_copy' => 'No se pudo cambiar el método de pago. Solicite un nuevo enlace si es necesario.',
'payment_method_change_link_mail_subject' => 'Actualice el método de pago de su suscripción',
'payment_method_change_link_mail_intro' => 'Actualice el método de pago de su suscripción a través del siguiente enlace seguro. Elegirá su nuevo método de pago directamente en la página segura de nuestro proveedor de pagos Stripe; no se cobrará nada.',
'payment_method_change_link_mail_button' => 'Actualizar método de pago',
];

View file

@ -89,4 +89,8 @@ return [
'team_customers' => 'Clientes del Equipo',
'payment_monitor' => 'Monitor de Pagos',
'payment_monitor_management' => 'Monitor de Pagos (Dir.)',
'my_statistics' => 'Mi estadística',
'team_statistics' => 'Estadística del equipo',
'withdrawals' => 'Desistimientos',
];

View file

@ -196,4 +196,20 @@ return [
'packstation_alert_footer' => 'El NÚMERO de Packstation tiene 3 dígitos (100-999, en el letrero amarillo). El número de correo DHL tiene 6-10 dígitos y va en el campo separado arriba.',
'' => '',
'unknown' => 'desconocido',
'prepayment_payone' => 'Pago por adelantado (PAYONE)',
'prepayment_no_clearing_data' => 'Los datos bancarios aún no están disponibles: el pago todavía no se ha registrado correctamente en el proveedor de pagos.',
'checkout_maintenance_title' => 'Dificultades técnicas',
'checkout_maintenance' => 'Actualmente no es posible realizar pedidos debido a dificultades técnicas. Volveremos en breve; inténtelo de nuevo más tarde.',
'abo_payments_frozen_title' => 'Pagos de suscripción temporalmente no disponibles',
'abo_payments_frozen' => 'Los pagos de suscripción no son posibles en este momento. Estamos trabajando intensamente en una solución técnica; inténtelo de nuevo más tarde. Sus suscripciones y pedidos no se perderán.',
'stripe_online' => 'Pago en línea',
'stripe_online_short' => 'Pago en línea (Stripe)',
'stripe_online_copy' => 'Será redirigido a la página de pago segura, donde podrá elegir su método de pago.',
'stripe_online_methods' => 'Tarjeta de crédito, PayPal, Apple Pay, Google Pay, Klarna, Amazon Pay y muchos más',
'stripe_order_label' => 'Pedido :reference',
'stripe_unavailable' => 'El pago en línea no está disponible en este momento. Inténtelo de nuevo en un momento.',
'stripe_abo_hint' => 'Su método de pago se guarda de forma segura en nuestro proveedor de pagos Stripe y se utiliza para los próximos cobros de la suscripción.',
'stripe_abo_payment_method_missing' => 'No hay ningún método de pago válido guardado para esta suscripción. Actualice su método de pago.',
'stripe_abo_authentication_required' => 'Su banco requiere una confirmación del pago. Complete el pago desde su página de suscripción.',
];

View file

@ -21,14 +21,10 @@ return [
'only_missing_free_shipping_costs_from' => 'Ya sólo te queda :value € para tu envío gratis.',
'payment_method_creditcard' => 'tarjeta de crédito',
'payment_method_creditcard_copy' => 'El importe se deducirá de su tarjeta de crédito tan pronto como se envíe el pedido. El proceso de la tarjeta de crédito se procesa a través de nuestro proveedor de servicios de pago PAYONE.',
'payment_method_direct' => 'transferencia bancaria instantánea',
'payment_method_direct_copy' => 'Después de una verificación exitosa, será redirigido a la página de pago seguro de PAYONE para que las transferencias SOFORT continúen con el pago. Después del pago exitoso, no cierre el navegador hasta que haya sido redirigido nuevamente a la tienda.',
'payment_method_paypal' => 'pago con Paypal',
'payment_method_paypal_copy' => 'Después de una verificación exitosa, será redirigido a la página de pago seguro de Paypal para continuar con el pago. Después del pago exitoso, no cierre el navegador hasta que haya sido redirigido nuevamente a la tienda.',
'payment_method_prepayment' => 'pago por adelantado',
'payment_method_prepayment_copy' => 'Una vez que hayas enviado el pedido, recibirás un correo electrónico con los datos bancarios para realizar el pago. Una vez recibido el importe, se enviarán sus productos.',
'payment_method_sepa' => 'débito directo SEPA',
'payment_method_sepa_copy' => 'Se le cobrará a su cuenta por este pedido después de enviarlo. El débito directo SEPA se procesa a través de nuestro proveedor de servicios de pago PAYONE.',
'payment_methods' => 'métodos de pago',
'plus_shipping_cost' => 'más envío y manipulación',
'price_net' => 'precios netos',
@ -42,4 +38,22 @@ return [
'to_product' => 'al producto',
'to_shopping_cart' => 'a la canasta de productos',
'' => '',
'payment_methods_intro' => 'Los pagos en línea se procesan de forma segura a través de nuestro proveedor de pagos Stripe. En el checkout será redirigido a la página de pago, donde podrá elegir su método de pago preferido.',
'payment_method_applepay' => 'Apple Pay',
'payment_method_applepay_copy' => 'Pague en pocos segundos con su dispositivo Apple, sin introducir los datos de la tarjeta; disponible en Safari y en iPhone y iPad.',
'payment_method_googlepay' => 'Google Pay',
'payment_method_googlepay_copy' => 'Pague de forma rápida y segura con los datos de pago de su cuenta de Google, p. ej. en Chrome o en su dispositivo Android.',
'payment_method_klarna' => 'Klarna',
'payment_method_klarna_copy' => 'Pague cómodamente a través de Klarna. Verá qué opciones de Klarna están disponibles para usted directamente en la página de pago.',
'payment_method_amazonpay' => 'Amazon Pay',
'payment_method_amazonpay_copy' => 'Pague con los datos de pago y dirección de su cuenta de Amazon, sin necesidad de un nuevo registro.',
'payment_method_link' => 'Link (Stripe)',
'payment_method_link_copy' => 'Con Link guarda sus datos de pago una sola vez y de forma segura en Stripe y después paga con un clic en todas las tiendas compatibles con Link.',
'payment_method_bancontact' => 'Bancontact',
'payment_method_bancontact_copy' => 'El método de pago más popular en Bélgica: se paga directamente a través de su cuenta bancaria belga.',
'payment_method_eps' => 'EPS',
'payment_method_eps_copy' => 'La transferencia en línea para clientes con cuenta bancaria austriaca: se paga directamente a través de su banca en línea.',
'payment_method_more' => 'Otros métodos de pago',
'payment_method_more_copy' => 'Según el país y el dispositivo, en la página de pago encontrará otros métodos de pago, p. ej. BLIK, MB WAY, Pix, Satispay, Samsung Pay, Kakao Pay, Naver Pay o PAYCO.',
];

View file

@ -0,0 +1,63 @@
<?php
return [
// Buttons / Navigation
'button_label' => 'Revocar contrato',
'nav_title' => 'Desistimiento',
// Identifikationsformular
'page_title' => 'Revocar contrato',
'intro' => 'Aquí puede revocar fácilmente su pedido realizado en línea. Primero, identifique su pedido.',
'identify_hl' => 'Identificar pedido',
'order_number' => 'Número de pedido',
'order_number_placeholder' => 'p. ej. 12345',
'order_number_help' => 'Encontrará el número de pedido en su confirmación de pedido.',
'email' => 'Dirección de correo electrónico del pedido',
'email_placeholder' => 'su@email.es',
'find_order' => 'Buscar pedido',
// Bestellung gefunden / Auswahl
'order_found_hl' => 'Su pedido',
'order_date' => 'Fecha del pedido',
'choose_scope_hl' => '¿Qué desea revocar?',
'scope_full' => 'Desistimiento completo (todo el pedido)',
'scope_partial' => 'Desistimiento parcial (artículos individuales)',
'select_items_hl' => 'Seleccionar artículos',
'product' => 'Artículo',
'quantity' => 'Cantidad',
'withdraw_quantity' => 'Cantidad a revocar',
'reason' => 'Motivo (opcional)',
'reason_placeholder' => 'No está obligado a indicar un motivo. Si lo desea, puede comunicárnoslo aquí.',
'submit' => 'Enviar desistimiento de forma vinculante',
'back' => 'Atrás',
'legal_note' => 'Con el envío declara el desistimiento de su contrato frente a mivita care gmbh, Leinfeld 2, 87755 Kirchhaslach (Alemania). Recibirá de inmediato una confirmación de recepción por correo electrónico con fecha y hora.',
// Fehler
'not_found' => 'No hemos podido encontrar ningún pedido que coincida con estos datos. Compruebe el número de pedido y la dirección de correo electrónico.',
'no_items_selected' => 'Seleccione al menos un artículo para el desistimiento parcial.',
// Erfolg / Eingangsbestätigung
'success_hl' => 'Hemos recibido su desistimiento',
'success_intro' => 'Muchas gracias. Hemos recibido su desistimiento y lo tramitaremos lo antes posible.',
'clock' => 'h',
'success_received_at' => 'Recepción de su desistimiento',
'success_reference' => 'Número de referencia',
'success_email_sent' => 'Además, hemos enviado una confirmación de recepción a :email.',
'success_full' => 'Ha revocado el pedido completo.',
'success_partial' => 'Ha revocado artículos individuales de su pedido.',
// E-Mail
'mail_subject' => 'Confirmación de recepción de su desistimiento',
'mail_hello' => 'Hola',
'mail_intro' => 'confirmamos la recepción de su desistimiento del siguiente pedido. Su desistimiento nos llegó en el momento indicado:',
'mail_received_at' => 'Recibido el',
'mail_order_number' => 'Número de pedido',
'mail_reference' => 'Número de referencia',
'mail_scope' => 'Alcance del desistimiento',
'mail_items_hl' => 'Artículos revocados',
'mail_outro' => 'Nos encargaremos de la tramitación y nos pondremos en contacto con usted si es necesario.',
'mail_greetings' => 'Un cordial saludo',
'mail_sender' => 'Su equipo de mivita.care',
];