diff --git a/autoload/front/Controllers/ShopBasketController.php b/autoload/front/Controllers/ShopBasketController.php index 78398aa..7f2405b 100644 --- a/autoload/front/Controllers/ShopBasketController.php +++ b/autoload/front/Controllers/ShopBasketController.php @@ -5,7 +5,6 @@ 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; // 30 minutes public static $title = [ 'mainView' => 'Koszyk' @@ -277,6 +276,19 @@ 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(); @@ -296,26 +308,23 @@ class ShopBasketController public function basketSave() { - $basket = \Shared\Helpers\Helpers::get_session( 'basket' ); + $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; - if ( ( !is_array( $basket ) || 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; - } - } - - $orderSubmitToken = (string)\Shared\Helpers\Helpers::get( 'order_submit_token', true ); if ( !$this->isValidOrderSubmitToken( $orderSubmitToken ) ) { - $this->logOrder( 'Token validation failed. formToken=' . ($orderSubmitToken ?: '(empty)') ); + if ( $existingOrderId > 0 ) + { + $existingOrderHash = $this->orderRepository->findHashById( $existingOrderId ); + if ( $existingOrderHash ) + { + header( 'Location: /zamowienie/' . $existingOrderHash ); + exit; + } + } + \Shared\Helpers\Helpers::error( \Shared\Helpers\Helpers::lang( 'zamowienie-zostalo-zlozone-komunikat-blad' ) ); - header( 'Location: /koszyk-podsumowanie' ); + header( 'Location: /koszyk' ); exit; } @@ -358,7 +367,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' ); exit; @@ -391,7 +400,6 @@ class ShopBasketController } else { - $this->logOrder( 'createFromBasket returned falsy order_id. client_id=' . ($client['id'] ?? 'guest') . ' email=' . \Shared\Helpers\Helpers::get( 'email', true ) ); \Shared\Helpers\Helpers::error( \Shared\Helpers\Helpers::lang( 'zamowienie-zostalo-zlozone-komunikat-blad' ) ); header( 'Location: /koszyk' ); exit; @@ -438,6 +446,79 @@ class ShopBasketController ] ); } + public function basketUpdateCustomFields() + { + $basket = \Shared\Helpers\Helpers::get_session( 'basket' ); + $product_code = \Shared\Helpers\Helpers::get( 'product_code' ); + + if ( !isset( $basket[ $product_code ] ) ) + { + echo json_encode( [ 'result' => 'error', 'message' => 'Pozycja nie istnieje w koszyku' ] ); + exit; + } + + $position = $basket[ $product_code ]; + $new_custom_fields = []; + $custom_fields_raw = \Shared\Helpers\Helpers::get( 'custom_field' ); + + if ( is_array( $custom_fields_raw ) ) + { + foreach ( $custom_fields_raw as $field_id => $value ) + { + $new_custom_fields[ (int)$field_id ] = $value; + } + } + + $productRepo = new \Domain\Product\ProductRepository( $GLOBALS['mdb'] ); + $missing_fields = []; + + foreach ( $new_custom_fields as $field_id => $value ) + { + $field_meta = $productRepo->findCustomFieldCached( $field_id ); + if ( $field_meta && (int)$field_meta['is_required'] === 1 && trim( $value ) === '' ) + { + $missing_fields[] = $field_meta['name']; + } + } + + if ( count( $missing_fields ) > 0 ) + { + echo json_encode( [ 'result' => 'error', 'message' => 'Wypełnij wymagane pola: ' . implode( ', ', $missing_fields ) ] ); + exit; + } + + $attributes_implode = ''; + if ( isset( $position['attributes'] ) && is_array( $position['attributes'] ) && count( $position['attributes'] ) > 0 ) + { + $attributes_implode = implode( '|', $position['attributes'] ); + } + + $message = isset( $position['message'] ) ? $position['message'] : ''; + $new_product_code = md5( $position['product-id'] . $attributes_implode . $message . json_encode( $new_custom_fields ) ); + + if ( $new_product_code === $product_code ) + { + $basket[ $product_code ]['custom_fields'] = $new_custom_fields; + } + elseif ( isset( $basket[ $new_product_code ] ) ) + { + $basket[ $new_product_code ]['quantity'] += $position['quantity']; + unset( $basket[ $product_code ] ); + } + else + { + $position['custom_fields'] = $new_custom_fields; + $basket[ $new_product_code ] = $position; + unset( $basket[ $product_code ] ); + } + + $basket = ( new \Domain\Promotion\PromotionRepository( $GLOBALS['mdb'] ) )->findPromotion( $basket ); + \Shared\Helpers\Helpers::set_session( 'basket', $basket ); + + echo json_encode( [ 'result' => 'ok' ] ); + exit; + } + private function jsonBasketResponse( $basket, $coupon, $lang_id, $basket_transport_method_id ) { global $settings; @@ -463,23 +544,8 @@ class ShopBasketController private function createOrderSubmitToken() { - $existingTokenData = isset( $_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] ) ? $_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] : null; - - if ( is_array( $existingTokenData ) && !empty( $existingTokenData['token'] ) && !empty( $existingTokenData['created_at'] ) ) - { - $age = time() - (int)$existingTokenData['created_at']; - if ( $age < self::ORDER_SUBMIT_TOKEN_TTL ) - { - \Shared\Helpers\Helpers::delete_session( self::ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY ); - return $existingTokenData['token']; - } - } - $token = $this->generateOrderSubmitToken(); - \Shared\Helpers\Helpers::set_session( self::ORDER_SUBMIT_TOKEN_SESSION_KEY, [ - 'token' => $token, - 'created_at' => time() - ] ); + \Shared\Helpers\Helpers::set_session( self::ORDER_SUBMIT_TOKEN_SESSION_KEY, $token ); \Shared\Helpers\Helpers::delete_session( self::ORDER_SUBMIT_LAST_ORDER_ID_SESSION_KEY ); return $token; @@ -502,26 +568,10 @@ class ShopBasketController if ( !$token ) return false; - $tokenData = isset( $_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] ) ? $_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] : null; - - if ( is_string( $tokenData ) ) - { - $sessionToken = $tokenData; - if ( !$sessionToken ) - return false; - - return function_exists( 'hash_equals' ) ? hash_equals( $sessionToken, $token ) : $sessionToken === $token; - } - - if ( !is_array( $tokenData ) || empty( $tokenData['token'] ) || empty( $tokenData['created_at'] ) ) + $sessionToken = isset( $_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] ) ? (string)$_SESSION[ self::ORDER_SUBMIT_TOKEN_SESSION_KEY ] : ''; + if ( !$sessionToken ) return false; - $age = time() - (int)$tokenData['created_at']; - if ( $age > self::ORDER_SUBMIT_TOKEN_TTL ) - return false; - - $sessionToken = (string)$tokenData['token']; - if ( function_exists( 'hash_equals' ) ) return hash_equals( $sessionToken, $token ); @@ -532,12 +582,4 @@ class ShopBasketController { \Shared\Helpers\Helpers::delete_session( self::ORDER_SUBMIT_TOKEN_SESSION_KEY ); } - - private function logOrder( $message ) - { - $logDir = $_SERVER['DOCUMENT_ROOT'] . '/logs'; - $logFile = $logDir . '/logs-order-' . date( 'Y-m-d' ) . '.log'; - $line = '[' . date( 'Y-m-d H:i:s' ) . '] ' . $message . PHP_EOL; - @file_put_contents( $logFile, $line, FILE_APPEND | LOCK_EX ); - } } diff --git a/templates/shop-basket/_partials/product-custom-fields.php b/templates/shop-basket/_partials/product-custom-fields.php index d0b651f..8d2c805 100644 --- a/templates/shop-basket/_partials/product-custom-fields.php +++ b/templates/shop-basket/_partials/product-custom-fields.php @@ -1,26 +1,52 @@ if ( $this -> custom_fields ) : ?> - foreach ( $this -> custom_fields as $key => $val ) : ?> - $custom_field = ( new \Domain\Product\ProductRepository( $GLOBALS['mdb'] ) )->findCustomFieldCached( $key ); ?> - $field_type = !empty( $custom_field['type'] ) ? $custom_field['type'] : 'text'; ?> +