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:
parent
1e7ae92d0c
commit
cdb121fde0
32 changed files with 1479 additions and 52 deletions
|
|
@ -1,6 +1,8 @@
|
|||
|
||||
var IqShoppingCart = {
|
||||
table: "#datatables-order-list",
|
||||
// Zweite Produktliste (Abo-Anlage): Einmalprodukte, deren Cart-Zeilen die Option abo_addon tragen
|
||||
table_onetime: "#datatables-onetime-list",
|
||||
btn_add: '.add-product-basket',
|
||||
btn_remove: '.remove-product-basket',
|
||||
card_holder: '#holder_html_view_card',
|
||||
|
|
@ -39,17 +41,25 @@ var IqShoppingCart = {
|
|||
},
|
||||
reInit: function (){
|
||||
var _self = this;
|
||||
$(_self.table).find(_self.btn_add).on('click', function(){
|
||||
_self.add_product($(this))
|
||||
});
|
||||
[_self.table, _self.table_onetime].forEach(function(tableSel){
|
||||
$(tableSel).find(_self.btn_add).off('click').on('click', function(){
|
||||
_self.add_product($(this), tableSel)
|
||||
});
|
||||
|
||||
$(_self.table).find(_self.btn_remove).on('click', function(){
|
||||
_self.remove_product($(this))
|
||||
});
|
||||
$(_self.table).find(_self.table_input).off('change').on('change', function(){
|
||||
_self.update_input_table($(this));
|
||||
$(tableSel).find(_self.btn_remove).off('click').on('click', function(){
|
||||
_self.remove_product($(this), tableSel)
|
||||
});
|
||||
$(tableSel).find(_self.table_input).off('change').on('change', function(){
|
||||
_self.update_input_table($(this), tableSel);
|
||||
});
|
||||
});
|
||||
},
|
||||
isAddonElement: function (_obj){
|
||||
return _obj.data('abo-addon') == 1;
|
||||
},
|
||||
qtyInputName: function (product_id, isAddon){
|
||||
return (isAddon ? 'onetime_qty_' : 'product_qty_') + product_id;
|
||||
},
|
||||
showInit: function (){
|
||||
var _self = this;
|
||||
$(_self.btn_clear).on('click', function (){
|
||||
|
|
@ -67,7 +77,7 @@ var IqShoppingCart = {
|
|||
});
|
||||
$(_self.remove_item).on('click', function(event){
|
||||
event.preventDefault();
|
||||
_self.update_cart_database($(this).data('product-id'), 0);
|
||||
_self.update_cart_database($(this).data('product-id'), 0, _self.isAddonElement($(this)));
|
||||
});
|
||||
if(_self.is_for === 'me' || _self.is_for === 'abo-me'){
|
||||
$('input[name^="'+_self.comp_products+'"]').on('change', function(){
|
||||
|
|
@ -82,19 +92,19 @@ var IqShoppingCart = {
|
|||
_self.performRequest({shipping_country_id: id, shipping_is_for: is_for, action: 'updateShippingCountry'})
|
||||
.done(_self.refreshItemsAndView);
|
||||
},
|
||||
update_input_table: function (_obj){
|
||||
update_input_table: function (_obj, tableSel){
|
||||
var _self = this;
|
||||
var qty = parseInt(_obj.val());
|
||||
qty = _self.checkNumber(qty);
|
||||
_obj.val(qty);
|
||||
_self.update_cart(_obj.data('product-id'), qty);
|
||||
_self.update_cart(_obj.data('product-id'), qty, _self.isAddonElement(_obj));
|
||||
},
|
||||
update_input_cart: function (_obj){
|
||||
var _self = this;
|
||||
var qty = parseInt(_obj.val());
|
||||
qty = _self.checkNumber(qty);
|
||||
_obj.val(qty);
|
||||
_self.update_cart_database(_obj.data('product-id'), qty);
|
||||
_self.update_cart_database(_obj.data('product-id'), qty, _self.isAddonElement(_obj));
|
||||
},
|
||||
/**
|
||||
* Plus-/Minus-Buttons im Warenkorb: Menge nicht optimistisch erhöhen, sondern
|
||||
|
|
@ -104,41 +114,46 @@ var IqShoppingCart = {
|
|||
change_cart_qty: function (_obj, delta){
|
||||
var _self = this;
|
||||
var productId = _obj.data('product-id');
|
||||
var input = $(_self.card_holder).find('.cart-input-event-onchange[data-product-id="'+productId+'"]');
|
||||
var isAddon = _self.isAddonElement(_obj);
|
||||
var input = $(_self.card_holder).find('.cart-input-event-onchange[data-product-id="'+productId+'"]').filter(function(){
|
||||
return IqShoppingCart.isAddonElement($(this)) === isAddon;
|
||||
});
|
||||
var qty = _self.checkNumber(parseInt(input.val(), 10) + delta);
|
||||
_self.update_cart_database(productId, qty);
|
||||
_self.update_cart_database(productId, qty, isAddon);
|
||||
},
|
||||
update_comp_product: function (_obj){
|
||||
var _self = this;
|
||||
_self.performRequest({comp_product_id: _obj.val(), comp_num: _obj.data('comp_num'), count_comp_products: $('input[name="'+_self.count_comp_products+'"]').val(), action: 'updateCompProduct'})
|
||||
.done(_self.refreshItemsAndView);
|
||||
},
|
||||
add_product: function (_obj){
|
||||
add_product: function (_obj, tableSel){
|
||||
var _self = this;
|
||||
var input = $(_self.table).find('input[name="product_qty_'+_obj.data('product-id')+'"]');
|
||||
var isAddon = _self.isAddonElement(_obj);
|
||||
var input = $(tableSel || _self.table).find('input[name="'+_self.qtyInputName(_obj.data('product-id'), isAddon)+'"]');
|
||||
var qty = parseInt(input.val()) + 1;
|
||||
qty = _self.checkNumber(qty);
|
||||
input.val(qty);
|
||||
_self.update_cart(_obj.data('product-id'), qty);
|
||||
_self.update_cart(_obj.data('product-id'), qty, isAddon);
|
||||
},
|
||||
remove_product: function (_obj){
|
||||
remove_product: function (_obj, tableSel){
|
||||
var _self = this;
|
||||
var input = $(_self.table).find('input[name="product_qty_'+_obj.data('product-id')+'"]');
|
||||
var isAddon = _self.isAddonElement(_obj);
|
||||
var input = $(tableSel || _self.table).find('input[name="'+_self.qtyInputName(_obj.data('product-id'), isAddon)+'"]');
|
||||
var qty = parseInt(input.val()) - 1;
|
||||
if(qty < 0){
|
||||
qty = 0;
|
||||
}
|
||||
input.val(qty);
|
||||
_self.update_cart(_obj.data('product-id'), qty);
|
||||
_self.update_cart(_obj.data('product-id'), qty, isAddon);
|
||||
},
|
||||
update_cart_database: function (product_id, qty){
|
||||
update_cart_database: function (product_id, qty, isAddon){
|
||||
var _self = this;
|
||||
_self.performRequest({product_id: product_id, qty: qty, action: 'updateCart'})
|
||||
_self.performRequest({product_id: product_id, qty: qty, abo_addon: isAddon ? 1 : 0, action: 'updateCart'})
|
||||
.done(_self.refreshDatabaseAndView);
|
||||
},
|
||||
update_cart: function (product_id, qty){
|
||||
update_cart: function (product_id, qty, isAddon){
|
||||
var _self = this;
|
||||
_self.performRequest({product_id: product_id, qty: qty, action: 'updateCart'})
|
||||
_self.performRequest({product_id: product_id, qty: qty, abo_addon: isAddon ? 1 : 0, action: 'updateCart'})
|
||||
.done(_self.refreshItemsAndView);
|
||||
},
|
||||
/**
|
||||
|
|
@ -225,7 +240,9 @@ var IqShoppingCart = {
|
|||
$(_self.card_holder).html(data.html_card);
|
||||
$(_self.comp_holder).html(data.html_comp);
|
||||
|
||||
var input = $(_self.table).find('input[name="product_qty_'+data.data.product_id+'"]');
|
||||
var isAddon = data.data && data.data.abo_addon == 1;
|
||||
var tableSel = isAddon ? _self.table_onetime : _self.table;
|
||||
var input = $(tableSel).find('input[name="'+_self.qtyInputName(data.data.product_id, isAddon)+'"]');
|
||||
input.val(data.data.qty);
|
||||
_self.showInit();
|
||||
_self.updateAboIntervalWarning();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue