diff --git a/autoload/front/Controllers/ShopBasketController.php b/autoload/front/Controllers/ShopBasketController.php index 7f2405b..e26e7fa 100644 --- a/autoload/front/Controllers/ShopBasketController.php +++ b/autoload/front/Controllers/ShopBasketController.php @@ -5,6 +5,7 @@ class ShopBasketController { private const ORDER_SUBMIT_TOKEN_SESSION_KEY = 'order-submit-token'; private const ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY = 'order-submit-last-order-id'; + private const ORDER_SUBMIT_TOKEN_TTL = 1800; public static $title = [ 'mainView' => 'Koszyk' @@ -276,19 +277,6 @@ class ShopBasketController exit; } - $existingOrderId = isset( $_SESSION[ self::ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY ] ) - ? (int)$_SESSION[ self::ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY ] - : 0; - if ( $existingOrderId > 0 ) - { - $existingOrderHash = $this->orderRepository->findHashById( $existingOrderId ); - if ( $existingOrderHash ) - { - header( 'Location: /zamowienie/' . $existingOrderHash ); - exit; - } - } - $client = \Shared\Helpers\Helpers::get_session( 'client' ); $orderSubmitToken = $this->createOrderSubmitToken(); @@ -311,20 +299,23 @@ class ShopBasketController $orderSubmitToken = (string)\Shared\Helpers\Helpers::get( 'order_submit_token', true ); $existingOrderId = isset( $_SESSION[ self::ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY ] ) ? (int)$_SESSION[ self::ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY ] : 0; + $basket = \Shared\Helpers\Helpers::get_session( 'basket' ); + if ( empty( $basket ) && $existingOrderId > 0 ) + { + $existingOrderHash = $this->orderRepository->findHashById( $existingOrderId ); + if ( $existingOrderHash ) + { + $this->logOrder( 'Double-submit detected, redirecting to existing order id=' . $existingOrderId ); + header( 'Location: /zamowienie/' . $existingOrderHash ); + exit; + } + } + if ( !$this->isValidOrderSubmitToken( $orderSubmitToken ) ) { - if ( $existingOrderId > 0 ) - { - $existingOrderHash = $this->orderRepository->findHashById( $existingOrderId ); - if ( $existingOrderHash ) - { - header( 'Location: /zamowienie/' . $existingOrderHash ); - exit; - } - } - + $this->logOrder( 'Token validation failed. formToken=' . $orderSubmitToken . ' existingOrderId=' . $existingOrderId ); \Shared\Helpers\Helpers::error( \Shared\Helpers\Helpers::lang( 'zamowienie-zostalo-zlozone-komunikat-blad' ) ); - header( 'Location: /koszyk' ); + header( 'Location: /koszyk-podsumowanie' ); exit; } @@ -367,6 +358,7 @@ class ShopBasketController } catch ( \Exception $e ) { + $this->logOrder( 'createFromBasket exception: ' . $e->getMessage() ); error_log( '[basketSave] createFromBasket exception: ' . $e->getMessage() ); \Shared\Helpers\Helpers::error( \Shared\Helpers\Helpers::lang( 'zamowienie-zostalo-zlozone-komunikat-blad' ) ); header( 'Location: /koszyk' ); @@ -400,6 +392,7 @@ class ShopBasketController } else { + $this->logOrder( 'createFromBasket returned falsy order_id. client_id=' . ( $client['id'] ?? '?' ) . ' email=' . ( \Shared\Helpers\Helpers::get( 'email', true ) ?: '?' ) ); \Shared\Helpers\Helpers::error( \Shared\Helpers\Helpers::lang( 'zamowienie-zostalo-zlozone-komunikat-blad' ) ); header( 'Location: /koszyk' ); exit; @@ -544,8 +537,23 @@ class ShopBasketController private function createOrderSubmitToken() { + $sessionData = isset( $_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] ) + ? $_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] + : null; + + if ( is_array( $sessionData ) && isset( $sessionData['token'], $sessionData['created_at'] ) ) + { + if ( ( time() - $sessionData['created_at'] ) < self::ORDER_SUBMIT_TOKEN_TTL ) + { + return $sessionData['token']; + } + } + $token = $this->generateOrderSubmitToken(); - \Shared\Helpers\Helpers::set_session( self::ORDER_SUBMIT_TOKEN_SESSION_KEY, $token ); + \Shared\Helpers\Helpers::set_session( self::ORDER_SUBMIT_TOKEN_SESSION_KEY, [ + 'token' => $token, + 'created_at' => time() + ] ); \Shared\Helpers\Helpers::delete_session( self::ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY ); return $token; @@ -568,10 +576,29 @@ class ShopBasketController if ( !$token ) return false; - $sessionToken = isset( $_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] ) ? (string)$_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] : ''; - if ( !$sessionToken ) + $sessionData = isset( $_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] ) + ? $_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] + : null; + + if ( !$sessionData ) return false; + // Backward compatibility: stary format (plain string) + if ( is_string( $sessionData ) ) + { + $sessionToken = $sessionData; + } + elseif ( is_array( $sessionData ) && isset( $sessionData['token'], $sessionData['created_at'] ) ) + { + if ( ( time() - $sessionData['created_at'] ) >= self::ORDER_SUBMIT_TOKEN_TTL ) + return false; + $sessionToken = $sessionData['token']; + } + else + { + return false; + } + if ( function_exists( 'hash_equals' ) ) return hash_equals( $sessionToken, $token ); @@ -582,4 +609,11 @@ class ShopBasketController { \Shared\Helpers\Helpers::delete_session( self::ORDER_SUBMIT_TOKEN_SESSION_KEY ); } + + private function logOrder( $message ) + { + $logFile = __DIR__ . '/../../../logs/logs-order-' . date( 'Y-m-d' ) . '.log'; + $line = '[' . date( 'Y-m-d H:i:s' ) . '] ' . $message . "\n"; + @file_put_contents( $logFile, $line, FILE_APPEND ); + } } diff --git a/templates/shop-basket/basket.php b/templates/shop-basket/basket.php index 479b2e3..a7f7db5 100644 --- a/templates/shop-basket/basket.php +++ b/templates/shop-basket/basket.php @@ -1,4 +1,46 @@ + basket ) && count( $this -> basket ) ): + $view_cart_items = ''; + $view_cart_value = 0; + + foreach ( $this -> basket as $position ): + $vc_product = (new \Domain\Product\ProductRepository($GLOBALS['mdb']))->findCached( (int)$position['product-id'], (new \Domain\Languages\LanguagesRepository($GLOBALS['mdb']))->defaultLanguage() ); + + if ( !$vc_product ) + continue; + + $vc_price = (float)$vc_product['price_brutto_promo'] > 0 && (float)$vc_product['price_brutto_promo'] < (float)$vc_product['price_brutto'] + ? (float)$vc_product['price_brutto_promo'] + : (float)$vc_product['price_brutto']; + + $vc_qty = (int)$position['quantity']; + $view_cart_value += $vc_price * $vc_qty; + + if ( $view_cart_items ) + $view_cart_items .= ','; + + $view_cart_items .= '{'; + $view_cart_items .= 'item_id: "' . $vc_product['id'] . '",'; + $view_cart_items .= 'item_name: "' . str_replace( '"', '', $vc_product['language']['name'] ) . '",'; + $view_cart_items .= 'price: ' . \Shared\Helpers\Helpers::normalize_decimal( $vc_price ) . ','; + $view_cart_items .= 'quantity: ' . $vc_qty . ','; + $view_cart_items .= 'google_business_vertical: "retail"'; + $view_cart_items .= '}'; + endforeach; +?> + +
basket_details; ?> diff --git a/templates/shop-basket/summary-view.php b/templates/shop-basket/summary-view.php index 78acbe5..26e373d 100644 --- a/templates/shop-basket/summary-view.php +++ b/templates/shop-basket/summary-view.php @@ -73,10 +73,11 @@ $begin_checkout_items .= ','; $begin_checkout_items .= '{'; - $begin_checkout_items .= '"id": "' . $product['id'] . '",'; - $begin_checkout_items .= '"name": "' . $product['language']['name'] . '",'; + $begin_checkout_items .= '"item_id": "' . $product['id'] . '",'; + $begin_checkout_items .= '"item_name": "' . str_replace( '"', '', $product['language']['name'] ) . '",'; $begin_checkout_items .= '"price": ' . \Shared\Helpers\Helpers::normalize_decimal( $price_product['price_new'] ) . ','; - $begin_checkout_items .= '"quantity": ' . $position['quantity']; + $begin_checkout_items .= '"quantity": ' . (int)$position['quantity'] . ','; + $begin_checkout_items .= '"google_business_vertical": "retail"'; $begin_checkout_items .= '}'; ?> diff --git a/templates/shop-order/order-details.php b/templates/shop-order/order-details.php index d32eef6..fb09f05 100644 --- a/templates/shop-order/order-details.php +++ b/templates/shop-order/order-details.php @@ -169,17 +169,17 @@ event: "purchase", ecommerce: { transaction_id: " order['id'];?>", - value: 25.42, currency: "PLN", value: order['summary'], 2 ) ) - str_replace( ',', '.', round( $this -> order['transport_cost'], 2 ) );?>, shipping: order['transport_cost'] );?>, items: [ order['products'] as $product ):?> { - 'id': , - 'name': '', - 'quantity': , - 'price': 0 && (float)$product['price_brutto_promo'] < (float)$product['price_brutto']) ? (float)$product['price_brutto_promo'] : (float)$product['price_brutto'];?> + item_id: "", + item_name: "", + quantity: , + price: 0 && (float)$product['price_brutto_promo'] < (float)$product['price_brutto']) ? \Shared\Helpers\Helpers::normalize_decimal( $product['price_brutto_promo'] ) : \Shared\Helpers\Helpers::normalize_decimal( $product['price_brutto'] );?>, + google_business_vertical: "retail" } order['products'] ) ) echo ',';?> ] diff --git a/templates/shop-product/product.php b/templates/shop-product/product.php index 3d0ce7c..7cb7468 100644 --- a/templates/shop-product/product.php +++ b/templates/shop-product/product.php @@ -275,12 +275,15 @@ dataLayer.push({ event: "view_item", ecommerce: { + currency: "PLN", + value: product['price_brutto_promo'] ): echo \Shared\Helpers\Helpers::normalize_decimal( $this -> product['price_brutto_promo'] ); else: echo \Shared\Helpers\Helpers::normalize_decimal( $this -> product['price_brutto'] ); endif;?>, items: [ { item_id: " product['id'];?>", item_name: " product['language']['name'] );?>", - price: ' product['price_brutto_promo'] ): echo \Shared\Helpers\Helpers::normalize_decimal( $this -> product['price_brutto_promo'] ); else: echo \Shared\Helpers\Helpers::normalize_decimal( $this -> product['price_brutto'] ); endif;?>', - quantity: 1 + price: product['price_brutto_promo'] ): echo \Shared\Helpers\Helpers::normalize_decimal( $this -> product['price_brutto_promo'] ); else: echo \Shared\Helpers\Helpers::normalize_decimal( $this -> product['price_brutto'] ); endif;?>, + quantity: 1, + google_business_vertical: "retail" } ] } @@ -617,7 +620,8 @@ item_id: " product['id'];?>", item_name: " product['language']['name'] );?>", price: product['price_brutto_promo'] ): echo \Shared\Helpers\Helpers::normalize_decimal( $this -> product['price_brutto_promo'] ); else: echo \Shared\Helpers\Helpers::normalize_decimal( $this -> product['price_brutto'] ); endif;?>, - quantity: quantity + quantity: parseInt(quantity), + google_business_vertical: "retail" } ] } diff --git a/templates_user/shop-basket/basket.php b/templates_user/shop-basket/basket.php index 4bbd75a..f68eecd 100644 --- a/templates_user/shop-basket/basket.php +++ b/templates_user/shop-basket/basket.php @@ -35,6 +35,7 @@
settings['google_tag_manager_id'] && is_array( $this -> basket ) && count( $this -> basket ) ):?> \ No newline at end of file + diff --git a/templates_user/shop-order/order-details.php b/templates_user/shop-order/order-details.php index 09fed35..06b23d9 100644 --- a/templates_user/shop-order/order-details.php +++ b/templates_user/shop-order/order-details.php @@ -163,6 +163,7 @@ settings['google_tag_manager_id'] ):?> + dataLayer.push({ ecommerce: null }); dataLayer.push({ event: "purchase", ecommerce: { @@ -174,9 +175,9 @@ order['products'] as $product ):?> { item_id: "", - item_name: '', + item_name: "", quantity: , - price: 0 ? \Shared\Helpers\Helpers::normalize_decimal( $product['price_brutto_promo'] ) : \Shared\Helpers\Helpers::normalize_decimal( $product['price_brutto'] );?>, + price: 0 && (float)$product['price_brutto_promo'] < (float)$product['price_brutto']) ? \Shared\Helpers\Helpers::normalize_decimal( $product['price_brutto_promo'] ) : \Shared\Helpers\Helpers::normalize_decimal( $product['price_brutto'] );?>, google_business_vertical: 'retail' } order['products'] ) ) echo ',';?> @@ -194,7 +195,7 @@ } }); - + }); - \ No newline at end of file + diff --git a/templates_user/shop-product/product.php b/templates_user/shop-product/product.php index 0ecc00b..b0c359a 100644 --- a/templates_user/shop-product/product.php +++ b/templates_user/shop-product/product.php @@ -244,6 +244,7 @@ \ No newline at end of file +