<?php
namespace Customize\Controller\Lp;
use Eccube\Common\EccubeConfig;
use Eccube\Controller\AbstractController;
use Eccube\Repository\ProductClassRepository;
use Eccube\Service\CartService;
use Plugin\AmazonPayV2_42\Repository\ConfigRepository;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class ProstateCareCtaController extends AbstractController
{
private const STARTER_PRODUCT_CLASS_ID = 43;
/**
* LP page
*/
#[Route('/lp/prostate-care', name: 'prostate-care', methods: ['GET'])]
public function index(
Request $request,
CartService $cartService,
ProductClassRepository $productClassRepository,
ConfigRepository $configRepository,
EccubeConfig $eccubeConfig
): Response {
$Carts = $cartService->getCarts();
// Ensure LP cart is always exactly: starter set x1
$ProductClass = $productClassRepository->find(self::STARTER_PRODUCT_CLASS_ID);
if (!$ProductClass) {
throw $this->createNotFoundException('Starter ProductClass not found: ' . self::STARTER_PRODUCT_CLASS_ID);
}
$hasStarter = false;
$hasOther = false;
foreach ($Carts as $Cart) {
foreach ($Cart->getCartItems() as $CartItem) {
$pc = $CartItem->getProductClass();
if ($pc && (int) $pc->getId() === self::STARTER_PRODUCT_CLASS_ID) {
$hasStarter = true;
} else {
$hasOther = true;
}
}
}
// If cart is empty OR has anything other than starter set, reset it to starter-only
if (!$hasStarter || $hasOther) {
if (method_exists($cartService, 'clear')) {
$cartService->clear(); // do NOT save an empty state
}
$cartService->addProduct($ProductClass, 1);
$session = $request->getSession();
$session->set('lp_flow', '1');
$session->set('lp_starter_added_at', time());
// optional: allow debug override once
if ($request->query->has('lp_cleanup_ttl')) {
$ttl = max(0, (int) $request->query->get('lp_cleanup_ttl'));
$session->set('lp_cleanup_ttl', $ttl);
}
// Strict-schema DB: ensure NOT NULL totals are not NULL (and consistent with x1)
$Carts2 = $cartService->getCarts();
foreach ($Carts2 as $C) {
$subtotal = (int) $ProductClass->getPrice02();
if (method_exists($C, 'getTotalQuantity') && $C->getTotalQuantity() === null && method_exists($C, 'setTotalQuantity')) {
$C->setTotalQuantity(1);
}
if (method_exists($C, 'getTotalPrice') && $C->getTotalPrice() === null && method_exists($C, 'setTotalPrice')) {
$C->setTotalPrice($subtotal);
}
if (method_exists($C, 'getDeliveryFeeTotal') && $C->getDeliveryFeeTotal() === null && method_exists($C, 'setDeliveryFeeTotal')) {
$C->setDeliveryFeeTotal(0);
}
foreach ([['getDiscount','setDiscount'], ['getCharge','setCharge'], ['getTax','setTax'], ['getPaymentTotal','setPaymentTotal']] as [$g, $s]) {
if (method_exists($C, $g) && method_exists($C, $s) && $C->$g() === null) {
$C->$s(0);
}
}
}
$cartService->save();
$session = $request->getSession();
$session->set('lp_starter_seeded', 1);
$session->set('lp_starter_seeded_at', time());
$session->set('lp_starter_pc_id', self::STARTER_PRODUCT_CLASS_ID);
// Optional: helps debugging
$session->set('lp_starter_seed_reason', (!$hasStarter ? 'no_starter' : 'has_other'));
$Carts = $cartService->getCarts(); // refresh for rendering below
}
$cart = !empty($Carts) ? reset($Carts) : null;
$starterInCart = false;
$cartKey = null;
foreach ($Carts as $Cart) {
foreach ($Cart->getCartItems() as $CartItem) {
$pc = $CartItem->getProductClass();
if ($pc && (int) $pc->getId() === self::STARTER_PRODUCT_CLASS_ID) {
$starterInCart = true;
$cartKey = $Cart->getCartKey();
break 2;
}
}
}
// Amazon Pay plugin config (used by @AmazonPayV2_42 twig includes)
$AmazonPayV2Config = $configRepository->get();
// Resolve API endpoints based on plugin env (prod vs sandbox)
$AmazonPayV2Api = [];
$ap = $eccubeConfig['amazon_pay_v2'] ?? null;
if (is_array($ap) && $AmazonPayV2Config && method_exists($AmazonPayV2Config, 'getEnv')) {
$envProd = $ap['env']['prod'] ?? 'prod';
$AmazonPayV2Api = ($AmazonPayV2Config->getEnv() === $envProd)
? ($ap['api']['prod'] ?? [])
: ($ap['api']['sandbox'] ?? []);
}
$AmazonMerchantId = null;
$AmazonPublicKeyId = null;
// Try common keys first (adjust if your eccubeConfig differs)
if (is_array($ap)) {
$AmazonMerchantId = $ap['merchant_id'] ?? $ap['merchantId'] ?? null;
$AmazonPublicKeyId = $ap['public_key_id'] ?? $ap['publicKeyId'] ?? null;
}
return $this->render('lp/prostate-care.twig', [
'Carts' => $Carts,
'cart' => [],
'AmazonPayV2Config' => $AmazonPayV2Config,
'AmazonPayV2Api' => $AmazonPayV2Api,
'AmazonMerchantId' => $AmazonMerchantId,
'AmazonPublicKeyId' => $AmazonPublicKeyId,
'starterInCart' => $starterInCart,
'cartKey' => $starterInCart ? $cartKey : null,
]);
}
#[Route('/lp/prostate-care/amazon-pay', name: 'lp_prostate_care_amazon_pay', methods: ['POST'])]
public function amazonPayStart(
Request $request,
CartService $cartService,
ProductClassRepository $productClassRepository
): Response {
if (!$this->isCsrfTokenValid('lp_prostate_care_amazon_pay', (string) $request->request->get('_token'))) {
throw $this->createAccessDeniedException('Invalid CSRF token.');
}
// Keep the medical/no-branding state through checkout pages
$request->getSession()->set('lp_flow', '1');
$ProductClass = $productClassRepository->find(self::STARTER_PRODUCT_CLASS_ID);
if (!$ProductClass) {
throw $this->createNotFoundException('Starter ProductClass not found: ' . self::STARTER_PRODUCT_CLASS_ID);
}
// Make sure the LP can ONLY buy the starter set
if (method_exists($cartService, 'clear')) {
$cartService->clear(); // do not save here
}
// Add exactly 1 unit
$cartService->addProduct($ProductClass, 1);
// Prevent your strict dtb_cart NOT NULL columns from blowing up:
// set only-if-null, and set totals consistent with having 1 item.
$Carts = $cartService->getCarts();
foreach ($Carts as $Cart) {
$subtotal = (int) $ProductClass->getPrice02();
if (method_exists($Cart, 'getTotalQuantity') && $Cart->getTotalQuantity() === null && method_exists($Cart, 'setTotalQuantity')) {
$Cart->setTotalQuantity(1);
}
if (method_exists($Cart, 'getTotalPrice') && $Cart->getTotalPrice() === null && method_exists($Cart, 'setTotalPrice')) {
$Cart->setTotalPrice($subtotal);
}
if (method_exists($Cart, 'getDeliveryFeeTotal') && $Cart->getDeliveryFeeTotal() === null && method_exists($Cart, 'setDeliveryFeeTotal')) {
$Cart->setDeliveryFeeTotal(0);
}
foreach ([['getDiscount','setDiscount'], ['getCharge','setCharge'], ['getTax','setTax'], ['getPaymentTotal','setPaymentTotal']] as [$g,$s]) {
if (method_exists($Cart, $g) && method_exists($Cart, $s) && $Cart->$g() === null) {
$Cart->$s(0);
}
}
}
$cartService->save();
// ✅ Single-click jump into Amazon Pay flow
return $this->redirectToRoute('prostate-care', ['autostart_amz' => 1], 303);
}
/**
* Normal checkout (no cart page)
*/
#[Route('/lp/prostate-care/buy', name: 'lp_prostate_care_buy', methods: ['POST'])]
public function buy(
Request $request,
CartService $cartService,
ProductClassRepository $productClassRepository
): Response {
if (!$this->isCsrfTokenValid('lp_prostate_care_buy', (string) $request->request->get('_token'))) {
throw $this->createAccessDeniedException('Invalid CSRF token.');
}
$session = $request->getSession();
$session->set('lp_flow', '1');
$session->set('lp_starter_added_at', time());
$ProductClass = $productClassRepository->find(self::STARTER_PRODUCT_CLASS_ID);
if (!$ProductClass) {
throw $this->createNotFoundException('Starter ProductClass not found: ' . self::STARTER_PRODUCT_CLASS_ID);
}
// Make cart exactly starter x1
if (method_exists($cartService, 'clear')) {
$cartService->clear(); // don't persist empty state; we'll add then save
}
// Ensure cart is initialized in the session
$cartService->getCarts();
// Add exactly 1 unit
$cartService->addProduct($ProductClass, 1);
// STRICT DB GUARD: ensure NOT NULL totals are not NULL before save()
$Carts = $cartService->getCarts();
foreach ($Carts as $Cart) {
$qty = 0;
$subtotal = 0;
foreach ($Cart->getCartItems() as $Item) {
$q = method_exists($Item, 'getQuantity') ? (int) $Item->getQuantity() : 0;
$qty += $q;
if (method_exists($Item, 'getTotalPrice') && $Item->getTotalPrice() !== null) {
$subtotal += (int) $Item->getTotalPrice();
} elseif ($Item->getProductClass() && method_exists($Item->getProductClass(), 'getPrice02')) {
$price = (int) $Item->getProductClass()->getPrice02();
$subtotal += $price * $q;
}
}
if ($qty < 1) $qty = 1;
if ($subtotal < 0) $subtotal = 0;
if (method_exists($Cart, 'getTotalQuantity') && $Cart->getTotalQuantity() === null && method_exists($Cart, 'setTotalQuantity')) {
$Cart->setTotalQuantity($qty);
}
if (method_exists($Cart, 'getTotalPrice') && $Cart->getTotalPrice() === null && method_exists($Cart, 'setTotalPrice')) {
$Cart->setTotalPrice($subtotal);
}
if (method_exists($Cart, 'getDeliveryFeeTotal') && $Cart->getDeliveryFeeTotal() === null && method_exists($Cart, 'setDeliveryFeeTotal')) {
$Cart->setDeliveryFeeTotal(0);
}
// If these are NOT NULL in your schema, don't leave them NULL.
// PaymentTotal being subtotal is the least-surprising "pre-shipping" state.
if (method_exists($Cart, 'getDiscount') && $Cart->getDiscount() === null && method_exists($Cart, 'setDiscount')) {
$Cart->setDiscount(0);
}
if (method_exists($Cart, 'getCharge') && $Cart->getCharge() === null && method_exists($Cart, 'setCharge')) {
$Cart->setCharge(0);
}
if (method_exists($Cart, 'getTax') && $Cart->getTax() === null && method_exists($Cart, 'setTax')) {
$Cart->setTax(0);
}
if (method_exists($Cart, 'getPaymentTotal') && $Cart->getPaymentTotal() === null && method_exists($Cart, 'setPaymentTotal')) {
$Cart->setPaymentTotal($subtotal);
}
}
$cartService->save();
// ✅ Go straight to guest checkout
return $this->redirectToRoute('shopping_nonmember', [], 303);
}
/**
* Prep endpoint: add starter set to cart, then redirect back to LP
*/
#[Route('/lp/prostate-care/amazon-ready', name: 'lp_prostate_care_amazon_ready', methods: ['POST'])]
public function amazonReady(
Request $request,
CartService $cartService,
ProductClassRepository $productClassRepository
): Response {
if (!$this->isCsrfTokenValid('lp_prostate_care_amazon_ready', (string) $request->request->get('_token'))) {
throw $this->createAccessDeniedException('Invalid CSRF token.');
}
$ProductClass = $productClassRepository->find(self::STARTER_PRODUCT_CLASS_ID);
if (!$ProductClass) {
throw $this->createNotFoundException('Starter ProductClass not found: ' . self::STARTER_PRODUCT_CLASS_ID);
}
// IMPORTANT:
// Don’t manually persist an “empty cart” state (that’s how you hit total_price null).
// Use CartService’s supported clear method if available.
// if (method_exists($cartService, 'clear')) {
// $cartService->clear();
// }
// $cartService->addProduct($ProductClass, 1);
// $cartService->save();
// 1) Force cart initialization (important on LP flows)
$cartService->getCarts();
// Add product
$cartService->addProduct($ProductClass, 1);
// Make strict-schema totals non-null before flush
$Carts = $cartService->getCarts();
foreach ($Carts as $Cart) {
$qty = 0;
$subtotal = 0;
if (method_exists($Cart, 'getCartItems')) {
foreach ($Cart->getCartItems() as $Item) {
$q = method_exists($Item, 'getQuantity') ? (int) $Item->getQuantity() : 0;
$qty += $q;
// Prefer item total if available, else compute from ProductClass price02
if (method_exists($Item, 'getTotalPrice') && $Item->getTotalPrice() !== null) {
$subtotal += (int) $Item->getTotalPrice();
} elseif (method_exists($Item, 'getProductClass') && $Item->getProductClass()
&& method_exists($Item->getProductClass(), 'getPrice02')) {
$price = (int) $Item->getProductClass()->getPrice02();
$subtotal += $price * $q;
}
}
}
// ✅ Do NOT allow 0 quantity if items exist
if ($qty < 1) { $qty = 1; }
if ($subtotal < 0) { $subtotal = 0; }
// Only set fields if currently NULL (don’t overwrite EC-CUBE values)
if (method_exists($Cart, 'getTotalQuantity') && $Cart->getTotalQuantity() === null
&& method_exists($Cart, 'setTotalQuantity')) {
$Cart->setTotalQuantity($qty);
}
if (method_exists($Cart, 'getTotalPrice') && $Cart->getTotalPrice() === null
&& method_exists($Cart, 'setTotalPrice')) {
$Cart->setTotalPrice($subtotal);
}
if (method_exists($Cart, 'getDeliveryFeeTotal') && $Cart->getDeliveryFeeTotal() === null
&& method_exists($Cart, 'setDeliveryFeeTotal')) {
$Cart->setDeliveryFeeTotal(0);
}
// If your schema has other NOT NULL totals, set them to 0 only if NULL
foreach ([
['getDiscount', 'setDiscount'],
['getCharge', 'setCharge'],
['getTax', 'setTax'],
['getPaymentTotal', 'setPaymentTotal'],
] as [$getter, $setter]) {
if (method_exists($Cart, $getter) && method_exists($Cart, $setter) && $Cart->$getter() === null) {
$Cart->$setter(0);
}
}
}
$cartService->save();
return $this->redirectToRoute('prostate-care', [], 303);
}
}