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>
62 lines
1.6 KiB
PHP
62 lines
1.6 KiB
PHP
<?php
|
||
|
||
namespace App\Services;
|
||
|
||
use App\Models\Product;
|
||
|
||
class ProductOrderContext
|
||
{
|
||
/**
|
||
* @return list<string>
|
||
*/
|
||
public static function allowedShowOnIds(bool $isAbo, string $shippingIsFor): array
|
||
{
|
||
if ($shippingIsFor === 'me' || $shippingIsFor === 'abo-me') {
|
||
return $isAbo ? ['12', '13'] : ['2'];
|
||
}
|
||
|
||
return $isAbo ? ['12', '13'] : ['3'];
|
||
}
|
||
|
||
/**
|
||
* Sortiment für Einmalprodukte (Abo-Zusatzartikel, nur nächste/erste Lieferung):
|
||
* normales Bestellsortiment – identisch zum Einmalprodukte-Feature laufender Abos.
|
||
*
|
||
* @return list<string>
|
||
*/
|
||
public static function oneTimeShowOnIds(): array
|
||
{
|
||
return ['3'];
|
||
}
|
||
|
||
/**
|
||
* @param list<string> $allowedIds
|
||
*/
|
||
public static function productMatchesShowOn(Product $product, array $allowedIds): bool
|
||
{
|
||
$showOn = $product->show_on;
|
||
if (! is_array($showOn)) {
|
||
return false;
|
||
}
|
||
|
||
foreach ($allowedIds as $id) {
|
||
foreach ($showOn as $value) {
|
||
if ((string) $value === (string) $id) {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
public static function isProductAllowedInContext(Product $product, bool $isAbo, string $shippingIsFor): bool
|
||
{
|
||
return self::productMatchesShowOn($product, self::allowedShowOnIds($isAbo, $shippingIsFor));
|
||
}
|
||
|
||
public static function isProductAllowedInCustomerWebshop(Product $product): bool
|
||
{
|
||
return self::isProductAllowedInContext($product, false, 'ot-customer');
|
||
}
|
||
}
|