Full migration of front\factory\ — entire directory removed (all 20 classes migrated). ProductRepository +20 frontend methods, PromotionRepository +5 applyType methods, TransportRepository +4 cached methods, PaymentMethodRepository +cached frontend methods. Fix: broken transports_list() in ajax.php replaced with forPaymentMethod(). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
953 lines
36 KiB
PHP
953 lines
36 KiB
PHP
<?php
|
|
namespace shop;
|
|
use shop\Shop;
|
|
use S;
|
|
class Product implements \ArrayAccess
|
|
{
|
|
public function __construct( int $product_id, $lang_id = null, $permutation_hash = null )
|
|
{
|
|
global $mdb;
|
|
|
|
if ( !$lang_id )
|
|
$lang_id = ( new \Domain\Languages\LanguagesRepository( $mdb ) )->defaultLanguage();
|
|
|
|
$result = $mdb -> get( 'pp_shop_products', '*', [ 'id' => $product_id ] );
|
|
if ( \Shared\Helpers\Helpers::is_array_fix( $result ) ) foreach ( $result as $key => $val )
|
|
$this -> $key = $val;
|
|
|
|
// kombinacja produktu
|
|
if ( $this -> parent_id )
|
|
{
|
|
// pobranie wartości z produktu głównego
|
|
if ( !$this -> price_netto or !$this -> price_brutto )
|
|
{
|
|
$result = $mdb -> get( 'pp_shop_products', [ 'price_netto', 'price_brutto', 'price_netto_promo', 'price_brutto_promo', 'vat', 'wp' ], [ 'id' => $this -> parent_id ] );
|
|
if ( \Shared\Helpers\Helpers::is_array_fix( $result ) ) foreach ( $result as $key => $val )
|
|
$this -> $key = $val;
|
|
}
|
|
|
|
$results = $mdb -> select( 'pp_shop_products_langs', '*', [ 'AND' => [ 'product_id' => $this -> parent_id, 'lang_id' => $lang_id ] ] );
|
|
if ( \Shared\Helpers\Helpers::is_array_fix( $results ) ) foreach ( $results as $row )
|
|
{
|
|
if ( $row[ 'copy_from' ] )
|
|
{
|
|
$results2 = $mdb -> select( 'pp_shop_products_langs', '*', [ 'AND' => [ 'product_id' => $this -> parent_id, 'lang_id' => $row[ 'copy_from' ] ] ] );
|
|
if ( is_array( $results2 ) )
|
|
foreach ( $results2 as $row2 )
|
|
$this -> language = $row2;
|
|
}
|
|
else
|
|
$this -> language = $row;
|
|
}
|
|
|
|
$this -> images = $mdb -> select( 'pp_shop_products_images', '*', [ 'product_id' => $this -> parent_id, 'ORDER' => [ 'o' => 'ASC', 'id' => 'ASC' ] ] );
|
|
$this -> files = $mdb -> select( 'pp_shop_products_files', '*', [ 'product_id' => $this -> parent_id] );
|
|
$this -> categories = $mdb -> select( 'pp_shop_products_categories', 'category_id', [ 'product_id' => $this -> parent_id ] );
|
|
|
|
$this -> products_related = $mdb -> select( 'pp_shop_products_related', 'product_related_id', [ 'product_id' => $this -> parent_id ] );
|
|
$this -> products_sets = $mdb -> select( 'pp_shop_product_sets_products', 'product_id', [ 'AND' => [ 'set_id' => $this -> set_id, 'product_id[!]' => $this -> parent_id ] ] );
|
|
}
|
|
else
|
|
{
|
|
$results = $mdb -> select( 'pp_shop_products_langs', '*', [ 'AND' => [ 'product_id' => $product_id, 'lang_id' => $lang_id ] ] );
|
|
if ( \Shared\Helpers\Helpers::is_array_fix( $results ) ) foreach ( $results as $row )
|
|
{
|
|
if ( $row[ 'copy_from' ] )
|
|
{
|
|
$results2 = $mdb -> select( 'pp_shop_products_langs', '*', [ 'AND' => [ 'product_id' => $product_id, 'lang_id' => $row[ 'copy_from' ] ] ] );
|
|
if ( is_array( $results2 ) )
|
|
foreach ( $results2 as $row2 )
|
|
$this -> language = $row2;
|
|
}
|
|
else
|
|
$this -> language = $row;
|
|
}
|
|
|
|
$this -> images = $mdb -> select( 'pp_shop_products_images', '*', [ 'product_id' => $product_id, 'ORDER' => [ 'o' => 'ASC', 'id' => 'ASC' ] ] );
|
|
$this -> files = $mdb -> select( 'pp_shop_products_files', '*', [ 'product_id' => $product_id ] );
|
|
$this -> categories = $mdb -> select( 'pp_shop_products_categories', 'category_id', [ 'product_id' => $product_id ] );
|
|
|
|
$this -> products_related = $mdb -> select( 'pp_shop_products_related', 'product_related_id', [ 'product_id' => $product_id ] );
|
|
$this -> products_sets = $mdb -> select( 'pp_shop_product_sets_products', 'product_id', [ 'AND' => [ 'set_id' => $this -> set_id, 'product_id[!]' => $product_id ] ] );
|
|
|
|
$results = $mdb -> select( 'pp_shop_products', 'id', [ 'parent_id' => $product_id ] );
|
|
if ( \Shared\Helpers\Helpers::is_array_fix( $results ) )
|
|
{
|
|
foreach ( $results as $row )
|
|
$product_combinations[] = \shop\Product::getFromCache( $row, $lang_id );
|
|
|
|
$this -> product_combinations = $product_combinations;
|
|
}
|
|
}
|
|
|
|
$producer = $mdb -> get( 'pp_shop_producer', '*', [ 'id' => (int) $this -> producer_id ] );
|
|
$producer_languages = $mdb -> get( 'pp_shop_producer_lang', '*', [ 'AND' => [ 'producer_id' => (int) $this -> producer_id, 'lang_id' => $lang_id ] ] );
|
|
$producer['description'] = $producer_languages['description'];
|
|
$producer['data'] = $producer_languages['data'];
|
|
$producer['meta_title'] = $producer_languages['meta_title'];
|
|
|
|
$this -> producer = $producer;
|
|
|
|
if ( $permutation_hash )
|
|
{
|
|
$permutation_price = $mdb -> get( 'pp_shop_products', [ 'price_netto', 'price_brutto', 'price_netto_promo', 'price_brutto_promo' ], [ 'AND' => [ 'permutation_hash' => $permutation_hash, 'parent_id' => $product_id ] ] );
|
|
if ( is_array( $permutation_price ) )
|
|
{
|
|
if ( $permutation_price[ 'price_netto' ] != null )
|
|
$this -> price_netto = $permutation_price[ 'price_netto' ];
|
|
|
|
if ( $permutation_price[ 'price_brutto' ] != null )
|
|
$this -> price_brutto = $permutation_price[ 'price_brutto' ];
|
|
|
|
if ( $permutation_price[ 'price_netto_promo' ] != null )
|
|
$this -> price_netto_promo = $permutation_price[ 'price_netto_promo' ];
|
|
|
|
if ( $permutation_price[ 'price_brutto_promo' ] != null )
|
|
$this -> price_brutto_promo = $permutation_price[ 'price_brutto_promo' ];
|
|
}
|
|
}
|
|
|
|
$this -> custom_fields = $mdb -> select( 'pp_shop_products_custom_fields', '*', [ 'id_product' => $product_id ] );
|
|
}
|
|
|
|
/**
|
|
* Retrieves a product object from cache or creates a new instance if not found.
|
|
*
|
|
* @param int $product_id The ID of the product.
|
|
* @param int $lang_id The ID of the language.
|
|
* @param string $permutation_hash The permutation hash of the product.
|
|
* @return \shop\Product The product object.
|
|
*/
|
|
public static function getFromCache($product_id, $lang_id, $permutation_hash = null)
|
|
{
|
|
// Check if Redis extension is loaded
|
|
if (class_exists('Redis'))
|
|
{
|
|
try
|
|
{
|
|
// Get the Redis connection instance
|
|
$redis = \Shared\Cache\RedisConnection::getInstance()->getConnection();
|
|
|
|
// Check if Redis connection is valid
|
|
if ( $redis )
|
|
{
|
|
// Try to retrieve the serialized product object from cache
|
|
$objectData = $redis->get("shop\product:$product_id:$lang_id:$permutation_hash");
|
|
|
|
if (!$objectData)
|
|
{
|
|
// Product not found in cache, create a new instance and store it in cache
|
|
$object = new self($product_id, $lang_id, $permutation_hash);
|
|
$redis->setex("shop\product:$product_id:$lang_id:$permutation_hash", 60 * 60 * 24, serialize($object));
|
|
}
|
|
else
|
|
{
|
|
// Product found in cache, unserialize it
|
|
$object = unserialize($objectData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Redis connection failed, create a new instance
|
|
$object = new self($product_id, $lang_id, $permutation_hash);
|
|
}
|
|
}
|
|
catch (\Exception $e)
|
|
{
|
|
// Log the exception if needed
|
|
$object = new self($product_id, $lang_id, $permutation_hash);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Redis extension not loaded, create a new instance
|
|
$object = new self($product_id, $lang_id, $permutation_hash);
|
|
}
|
|
|
|
return $object;
|
|
}
|
|
|
|
public function getDefaultCombinationPrices()
|
|
{
|
|
$permutation_hash = '';
|
|
|
|
$attributes = \shop\Product::get_product_attributes( $this -> product_combinations );
|
|
foreach ( $attributes as $attribute )
|
|
{
|
|
foreach ( $attribute['values'] as $value )
|
|
{
|
|
if ( $value['is_default'] )
|
|
{
|
|
if ( $permutation_hash )
|
|
$permutation_hash .= '|';
|
|
$permutation_hash .= $attribute['id'] . '-' . $value['id'];
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ( $this -> product_combinations as $product_combination )
|
|
{
|
|
if ( $product_combination -> permutation_hash == $permutation_hash )
|
|
{
|
|
$prices['price_netto'] = $product_combination -> price_netto;
|
|
$prices['price_brutto'] = $product_combination -> price_brutto;
|
|
$prices['price_netto_promo'] = $product_combination -> price_netto_promo;
|
|
$prices['price_brutto_promo'] = $product_combination -> price_brutto_promo;
|
|
}
|
|
}
|
|
|
|
return $prices;
|
|
}
|
|
|
|
public function generateSubtitleFromAttributes( $permutation_hash )
|
|
{
|
|
global $lang_id;
|
|
|
|
$subtitle = '';
|
|
|
|
$attributes = explode( '|', $permutation_hash );
|
|
foreach ( $attributes as $attribute )
|
|
{
|
|
$attribute = explode( '-', $attribute );
|
|
|
|
if ( $subtitle )
|
|
$subtitle .= ', ';
|
|
|
|
$subtitle .= \shop\ProductAttribute::getAttributeName( $attribute[0], $lang_id ) . ': ' . \shop\ProductAttribute::get_value_name( $attribute[1], $lang_id );
|
|
}
|
|
|
|
return $subtitle;
|
|
}
|
|
|
|
public function getProductDataBySelectedAttributes( $selected_attribute )
|
|
{
|
|
global $settings;
|
|
|
|
foreach ( $this -> product_combinations as $product_combination )
|
|
{
|
|
if ( $product_combination -> permutation_hash == $selected_attribute )
|
|
{
|
|
if ( $product_combination -> quantity !== null or $product_combination -> stock_0_buy )
|
|
{
|
|
$result['quantity'] = $product_combination -> quantity;
|
|
$result['stock_0_buy'] = $product_combination -> stock_0_buy;
|
|
$result['price_netto'] = Shop::shortPrice( $product_combination -> price_netto );
|
|
$result['price_brutto'] = Shop::shortPrice( $product_combination -> price_brutto );
|
|
$result['price_netto_promo'] = $product_combination -> price_netto_promo ? Shop::shortPrice( $product_combination -> price_netto_promo ) : null;
|
|
$result['price_brutto_promo'] = $product_combination -> price_brutto_promo ? Shop::shortPrice( $product_combination -> price_brutto_promo ) : null;
|
|
}
|
|
else
|
|
{
|
|
$result['quantity'] = $this -> quantity;
|
|
$result['stock_0_buy'] = $this -> stock_0_buy;
|
|
$result['price_netto'] = Shop::shortPrice( $this -> price_netto );
|
|
$result['price_brutto'] = Shop::shortPrice( $this -> price_brutto );
|
|
$result['price_netto_promo'] = $this -> price_netto_promo ? Shop::shortPrice( $this -> price_netto_promo ) : null;
|
|
$result['price_brutto_promo'] = $this -> price_brutto_promo ? Shop::shortPrice( $this -> price_brutto_promo ) : null;
|
|
}
|
|
}
|
|
}
|
|
$result['messages']['warehouse_message_zero'] = $this -> language['warehouse_message_zero'] ? $this -> language['warehouse_message_zero'] : $settings['warehouse_message_zero_pl'];
|
|
$result['messages']['warehouse_message_nonzero'] = $this -> language['warehouse_message_nonzero'] ? $this -> language['warehouse_message_nonzero'] : $settings['warehouse_message_nonzero_pl'];
|
|
$result['permutation_hash'] = $selected_attribute;
|
|
return $result;
|
|
}
|
|
|
|
// sprawdź czy produkt jest na promocji
|
|
static public function is_product_on_promotion( int $product_id )
|
|
{
|
|
global $mdb;
|
|
|
|
if ( $mdb -> get( 'pp_shop_products', 'price_netto_promo', [ 'id' => $product_id ] ) != null )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
// pobierz kod SKU
|
|
static public function get_product_sku( int $product_id )
|
|
{
|
|
global $mdb;
|
|
|
|
$result = $mdb -> get( 'pp_shop_products', [ 'parent_id', 'sku' ], [ 'id' => $product_id ] );
|
|
if ( $result['sku'] )
|
|
return $result['sku'];
|
|
else
|
|
return $mdb -> get( 'pp_shop_products', 'sku', [ 'id' => $result['parent_id'] ] );
|
|
}
|
|
|
|
// pobierz cenę produktu
|
|
// FASADA - wywołuje nową klasę Domain\Product\ProductRepository
|
|
static public function get_product_price( int $product_id )
|
|
{
|
|
global $mdb;
|
|
$repository = new \Domain\Product\ProductRepository($mdb);
|
|
return $repository->getPrice($product_id);
|
|
}
|
|
|
|
// pobierz nazwę produktu
|
|
// FASADA - wywołuje nową klasę Domain\Product\ProductRepository
|
|
static public function get_product_name( int $product_id, string $lang_id = null )
|
|
{
|
|
global $mdb;
|
|
|
|
if ( !$lang_id )
|
|
$lang_id = ( new \Domain\Languages\LanguagesRepository( $mdb ) )->defaultLanguage();
|
|
|
|
$repository = new \Domain\Product\ProductRepository($mdb);
|
|
return $repository->getName($product_id, $lang_id);
|
|
}
|
|
|
|
// pobierz i wyświetl produktu do zestawu po dodaniu do koszyka
|
|
static public function product_sets_when_add_to_basket( int $product_id )
|
|
{
|
|
global $mdb;
|
|
|
|
$cacheHandler = new \Shared\Cache\CacheHandler();
|
|
$cacheKey = "\shop\Product::product_sets_when_add_to_basket:$product_id";
|
|
|
|
$objectData = $cacheHandler -> get( $cacheKey );
|
|
|
|
if ( !$objectData )
|
|
{
|
|
if ( $product_id_tmp = $mdb -> get( 'pp_shop_products', 'parent_id', [ 'id' => $product_id ] ) )
|
|
$set_id = $mdb -> get( 'pp_shop_products', 'set_id', [ 'id' => $product_id_tmp ] );
|
|
else
|
|
$set_id = $mdb -> get( 'pp_shop_products', 'set_id', [ 'id' => $product_id ] );
|
|
|
|
$products = $mdb -> select( 'pp_shop_product_sets_products', 'product_id', [ 'set_id' => $set_id ] );
|
|
if ( !$products )
|
|
{
|
|
$products_intersection = $mdb -> select( 'pp_shop_orders_products_intersection', [ 'product_1_id', 'product_2_id' ], [ 'OR' => [ 'product_1_id' => $product_id, 'product_2_id' => $product_id ], 'ORDER' => [ 'count' => 'DESC' ], 'LIMIT' => 5 ] );
|
|
if ( !count( $products_intersection ) )
|
|
{
|
|
$product_id = $mdb -> get( 'pp_shop_products', 'parent_id', [ 'id' => $product_id ] );
|
|
$products_intersection = $mdb -> select( 'pp_shop_orders_products_intersection', [ 'product_1_id', 'product_2_id' ], [ 'OR' => [ 'product_1_id' => $product_id, 'product_2_id' => $product_id ], 'ORDER' => [ 'count' => 'DESC' ], 'LIMIT' => 5 ] );
|
|
}
|
|
|
|
foreach ( $products_intersection as $product_intersection )
|
|
{
|
|
if ( $product_intersection['product_1_id'] != $product_id )
|
|
$products[] = $product_intersection['product_1_id'];
|
|
else
|
|
$products[] = $product_intersection['product_2_id'];
|
|
}
|
|
array_unique( $products );
|
|
}
|
|
|
|
$cacheHandler -> set( $cacheKey, $products );
|
|
}
|
|
else
|
|
{
|
|
$products = unserialize( $objectData );
|
|
}
|
|
|
|
foreach ( $products as $product_id )
|
|
{
|
|
if ( !( new \Domain\Product\ProductRepository( $mdb ) )->isProductActiveCached( (int)$product_id ) )
|
|
$products = array_diff( $products, [ $product_id ] );
|
|
}
|
|
|
|
return \Shared\Tpl\Tpl::view( 'shop-basket/alert-product-sets', [
|
|
'products' => $products
|
|
] );
|
|
}
|
|
|
|
// dodaje 1 do licznika odwiedziń produktu
|
|
static public function add_visit( int $product_id )
|
|
{
|
|
global $mdb;
|
|
return $mdb -> update( 'pp_shop_products', [ 'visits[+]' => 1 ], [ 'id' => $product_id ] );
|
|
}
|
|
|
|
//FIX:ME - do poprawy nazwa
|
|
// pobierz zdjęcie główne
|
|
static public function getProductImg( int $product_id )
|
|
{
|
|
global $mdb;
|
|
|
|
$results = $mdb -> select( 'pp_shop_products_images', 'src', [ 'product_id' => $product_id, 'ORDER' => [ 'o' => 'ASC' ] ] );
|
|
if ( \Shared\Helpers\Helpers::is_array_fix( $results ) ) foreach ( $results as $row )
|
|
return $row;
|
|
}
|
|
|
|
//FIX:ME - do poprawy nazwa
|
|
// pobierz bezpośredni url produktu
|
|
static public function getProductUrl( int $product_id )
|
|
{
|
|
global $mdb;
|
|
|
|
$lang_id = ( new \Domain\Languages\LanguagesRepository( $mdb ) )->defaultLanguage();
|
|
|
|
$results = $mdb -> select( 'pp_shop_products_langs', '*', [ 'AND' => [ 'product_id' => $product_id, 'lang_id' => $lang_id ] ] );
|
|
if ( \Shared\Helpers\Helpers::is_array_fix( $results ) ) foreach ( $results as $row )
|
|
{
|
|
if ( $row[ 'copy_from' ] )
|
|
{
|
|
$results2 = $mdb -> select( 'pp_shop_products_langs', '*', [ 'AND' => [ 'product_id' => $product_id, 'lang_id' => $row[ 'copy_from' ] ] ] );
|
|
if ( is_array( $results2 ) )
|
|
foreach ( $results2 as $row2 )
|
|
$language = $row2;
|
|
}
|
|
else
|
|
$language = $row;
|
|
}
|
|
|
|
$language['seo_link'] ? $url = '/' . $language['seo_link'] : $url = '/p-' . $product_id . '-' . \Shared\Helpers\Helpers::seo( $language['name'] );
|
|
|
|
return $url;
|
|
}
|
|
|
|
// pobierz ilość wyników na podstawie wyszukiwanej nazwy
|
|
static public function searchProductsByNameCount( $query, $lang_id )
|
|
{
|
|
global $mdb;
|
|
|
|
$results = $mdb -> query( 'SELECT COUNT(0) AS c FROM ( '
|
|
. 'SELECT psp.id, '
|
|
. '( CASE '
|
|
. 'WHEN copy_from IS NULL THEN name '
|
|
. 'WHEN copy_from IS NOT NULL THEN ( '
|
|
. 'SELECT '
|
|
. 'name '
|
|
. 'FROM '
|
|
. 'pp_shop_products_langs '
|
|
. 'WHERE '
|
|
. 'lang_id = pspl.copy_from AND product_id = psp.id '
|
|
. ') '
|
|
. 'END ) AS name '
|
|
. 'FROM '
|
|
. 'pp_shop_products AS psp '
|
|
. 'INNER JOIN pp_shop_products_langs AS pspl ON pspl.product_id = psp.id '
|
|
. 'WHERE '
|
|
. 'status = 1 AND name LIKE :query AND lang_id = :lang_id '
|
|
. ') AS q1', [
|
|
':query' => '%' . $query . '%',
|
|
':lang_id' => $lang_id
|
|
] ) -> fetchAll( \PDO::FETCH_ASSOC );
|
|
return $results[0]['c'];
|
|
}
|
|
|
|
// pobierz id produktów na podstawie wyszukiwanej nazwy
|
|
static public function getProductsIdByName( string $query, string $lang_id, int $products_limit, int $from )
|
|
{
|
|
global $mdb;
|
|
|
|
$results = $mdb -> query( 'SELECT '
|
|
. 'psp.id, '
|
|
. '( CASE '
|
|
. 'WHEN copy_from IS NULL THEN name '
|
|
. 'WHEN copy_from IS NOT NULL THEN ( '
|
|
. 'SELECT '
|
|
. 'name '
|
|
. 'FROM '
|
|
. 'pp_shop_products_langs '
|
|
. 'WHERE '
|
|
. 'lang_id = pspl.copy_from AND product_id = psp.id '
|
|
. ') '
|
|
. 'END ) AS name '
|
|
. 'FROM '
|
|
. 'pp_shop_products AS psp '
|
|
. 'INNER JOIN pp_shop_products_langs AS pspl ON pspl.product_id = psp.id '
|
|
. 'WHERE '
|
|
. 'status = 1 AND name LIKE :query AND lang_id = :lang_id '
|
|
. 'ORDER BY '
|
|
. 'name ASC '
|
|
. 'LIMIT '
|
|
. $from . ',' . $products_limit, [
|
|
':query' => '%' . $query . '%',
|
|
':lang_id' => $lang_id
|
|
] ) -> fetchAll( \PDO::FETCH_ASSOC );
|
|
if ( is_array( $results ) and !empty( $results ) ) foreach ( $results as $row )
|
|
$output[] = $row['id'];
|
|
|
|
return $output;
|
|
}
|
|
|
|
static public function searchProductsByName( string $query, string $lang_id, int $bs = 0 )
|
|
{
|
|
$count = \shop\Product::searchProductsByNameCount( $query, $lang_id );
|
|
$ls = ceil( $count / 12 );
|
|
|
|
if ( $bs < 1 )
|
|
$bs = 1;
|
|
else if ( $bs > $ls )
|
|
$bs = $ls;
|
|
|
|
$from = 12 * ( $bs - 1 );
|
|
|
|
if ( $from < 0 )
|
|
$from = 0;
|
|
|
|
$results['products'] = \shop\Product::getProductsIdByName( $query, $lang_id, 12, $from );
|
|
$results['count'] = $count;
|
|
$results['ls'] = $ls;
|
|
|
|
return $results;
|
|
|
|
}
|
|
|
|
static public function searchProductByNameAjax( string $query, string $lang_id )
|
|
{
|
|
global $mdb;
|
|
return $mdb -> query(
|
|
'SELECT
|
|
product_id
|
|
FROM
|
|
pp_shop_products_langs AS pspl
|
|
INNER JOIN pp_shop_products AS psp ON psp.id = pspl.product_id
|
|
WHERE
|
|
status = 1 AND lang_id = :lang_id AND LOWER(name) LIKE :query
|
|
ORDER BY visits DESC
|
|
LIMIT 12', [
|
|
':query' => '%' . $query . '%',
|
|
':lang_id' => $lang_id
|
|
] ) -> fetchAll( \PDO::FETCH_ASSOC );
|
|
}
|
|
|
|
public function permutations()
|
|
{
|
|
if ( is_array( $this -> attributes ) ) foreach ( $this -> attributes as $attribute )
|
|
{
|
|
$attribute_obj = new \shop\ProductAttribute( $attribute['attribute_id'] );
|
|
|
|
if ( $attribute_obj['stock_influences'] )
|
|
$attributes_tmp[ $attribute[ 'attribute_id' ] ][] = $attribute[ 'value_id' ];
|
|
}
|
|
|
|
if ( is_array( $attributes_tmp ) )
|
|
return $this -> permutations = self::array_cartesian( $attributes_tmp );
|
|
}
|
|
|
|
/// sprawdź czy produkt można zamawiać przy stanie magazynowym zero
|
|
static public function is_stock_0_buy( int $product_id )
|
|
{
|
|
global $mdb;
|
|
|
|
// jeżeli jest to kombinacja produktu
|
|
if ( $parent_id = $mdb -> get( 'pp_shop_products', 'parent_id', [ 'id' => $product_id ] ) )
|
|
return $mdb -> get( 'pp_shop_products', 'stock_0_buy', [ 'id' => $parent_id ] );
|
|
else
|
|
return $mdb -> get( 'pp_shop_products', 'stock_0_buy', [ 'id' => $product_id ] );
|
|
}
|
|
|
|
// pobierz stan magazynowy i komunikaty dla kombinacji produktu
|
|
static public function get_product_permutation_quantity_options( int $product_id, $permutation )
|
|
{
|
|
global $mdb, $settings;
|
|
|
|
$cacheHandler = new \Shared\Cache\CacheHandler();
|
|
$cacheKey = "\shop\Product::get_product_permutation_quantity_options:v2:$product_id:$permutation";
|
|
|
|
$objectData = $cacheHandler -> get( $cacheKey );
|
|
|
|
if ( !$objectData )
|
|
{
|
|
if ( $mdb -> count( 'pp_shop_products', [ 'AND' => [ 'parent_id' => $product_id, 'permutation_hash' => $permutation ] ] ) )
|
|
{
|
|
$result['quantity'] = $mdb -> get( 'pp_shop_products', 'quantity', [ 'AND' => [ 'parent_id' => $product_id, 'permutation_hash' => $permutation ] ] );
|
|
$result['stock_0_buy'] = $mdb -> get( 'pp_shop_products', 'stock_0_buy', [ 'AND' => [ 'parent_id' => $product_id, 'permutation_hash' => $permutation ] ] );
|
|
|
|
if ( $result['quantity'] == null )
|
|
{
|
|
$result['quantity'] = $mdb -> get( 'pp_shop_products', 'quantity', [ 'id' => $product_id ] );
|
|
|
|
if ( $result['stock_0_buy'] == null )
|
|
$result['stock_0_buy'] = $mdb -> get( 'pp_shop_products', 'stock_0_buy', [ 'id' => $product_id] );
|
|
|
|
$result['messages'] = $mdb -> get( 'pp_shop_products_langs', [ 'warehouse_message_zero', 'warehouse_message_nonzero' ], [ 'AND' => [ 'product_id' => $product_id, 'lang_id' => 'pl' ] ] );
|
|
|
|
if ( !$result['messages']['warehouse_message_zero'] )
|
|
$result['messages']['warehouse_message_zero'] = $settings['warehouse_message_zero_pl'];
|
|
|
|
if ( !$result['messages']['warehouse_message_nonzero'] )
|
|
$result['messages']['warehouse_message_nonzero'] = $settings['warehouse_message_nonzero_pl'];
|
|
}
|
|
else
|
|
{
|
|
$result['messages'] = $mdb -> get( 'pp_shop_products_langs', [ 'warehouse_message_zero', 'warehouse_message_nonzero' ], [ 'AND' => [ 'product_id' => $product_id, 'lang_id' => 'pl' ] ] );
|
|
|
|
if ( !$result['messages']['warehouse_message_zero'] )
|
|
$result['messages']['warehouse_message_zero'] = $settings['warehouse_message_zero_pl'];
|
|
|
|
if ( !$result['messages']['warehouse_message_nonzero'] )
|
|
$result['messages']['warehouse_message_nonzero'] = $settings['warehouse_message_nonzero_pl'];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$result['quantity'] = $mdb -> get( 'pp_shop_products', 'quantity', [ 'id' => $product_id ] );
|
|
$result['stock_0_buy'] = $mdb -> get( 'pp_shop_products', 'stock_0_buy', [ 'id' => $product_id] );
|
|
$result['messages'] = $mdb -> get( 'pp_shop_products_langs', [ 'warehouse_message_zero', 'warehouse_message_nonzero' ], [ 'AND' => [ 'product_id' => $product_id, 'lang_id' => 'pl' ] ] );
|
|
|
|
if ( !$result['messages']['warehouse_message_zero'] )
|
|
$result['messages']['warehouse_message_zero'] = $settings['warehouse_message_zero_pl'];
|
|
|
|
if ( !$result['messages']['warehouse_message_nonzero'] )
|
|
$result['messages']['warehouse_message_nonzero'] = $settings['warehouse_message_nonzero_pl'];
|
|
}
|
|
|
|
$cacheHandler -> set( $cacheKey, $result );
|
|
}
|
|
else
|
|
{
|
|
return unserialize( $objectData );
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
// pobierz stan magazynowy produktu
|
|
// FASADA - wywołuje nową klasę Domain\Product\ProductRepository
|
|
static public function get_product_quantity( int $product_id )
|
|
{
|
|
global $mdb;
|
|
$repository = new \Domain\Product\ProductRepository($mdb);
|
|
return $repository->getQuantity($product_id);
|
|
}
|
|
|
|
public static function product_categories( int $product_id )
|
|
{
|
|
global $mdb;
|
|
return $mdb -> select( 'pp_shop_products_categories', 'category_id', [ 'product_id' => $product_id ] );
|
|
}
|
|
|
|
public static function calculate_basket_product_price( float $price_brutto_promo, float $price_brutto, $coupon, $basket_position )
|
|
{
|
|
// ? produkty przecenione
|
|
if ( $price_brutto_promo )
|
|
{
|
|
$price['price'] = $price_brutto;
|
|
$price['price_new'] = $price_brutto_promo;
|
|
|
|
// ? zastosuje kod rabatowy
|
|
if ( $coupon -> type && $coupon -> include_discounted_product )
|
|
{
|
|
// ? ograniczony do wybranych kategorii
|
|
if ( $coupon -> categories != null )
|
|
{
|
|
$coupon_categories = json_decode( $coupon -> categories );
|
|
$product_categories = \shop\Product::product_categories( (int)$basket_position['parent_id'] ? (int)$basket_position['parent_id'] : (int)$basket_position['product-id'] );
|
|
if ( is_array( $coupon_categories ) ) foreach ( $coupon_categories as $category_tmp )
|
|
{
|
|
if ( in_array( $category_tmp, $product_categories ) )
|
|
{
|
|
$price['price_new'] = \Shared\Helpers\Helpers::normalize_decimal( $price['price_new'] - $price['price_new'] * $coupon -> amount / 100 );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// ? nieograniczony kategoriami
|
|
else
|
|
$price['price_new'] = \Shared\Helpers\Helpers::normalize_decimal( $price['price_new'] - $price['price_new'] * $coupon -> amount / 100 );
|
|
|
|
// ? uwzględnij promocję jeżeli może łączyć się z rabatami i produktami przecenionymi
|
|
if ( $basket_position['discount_amount'] && $basket_position['discount_include_coupon'] && $basket_position['include_product_promo'] )
|
|
{
|
|
// ? najtańszy produkt w koszyku (z wybranych kategorii) za X zł
|
|
if ( $basket_position['discount_type'] == 3 )
|
|
$price['price_new'] = \Shared\Helpers\Helpers::normalize_decimal( $basket_position['discount_amount'] );
|
|
|
|
// ? rabat procentowy
|
|
if ( $basket_position['discount_type'] == 1 )
|
|
$price['price_new'] = \Shared\Helpers\Helpers::normalize_decimal($price['price_new'] - $price['price_new'] * $basket_position['discount_amount'] / 100 );
|
|
}
|
|
}
|
|
// ? brak kodu rabatowego
|
|
else
|
|
{
|
|
if ( $basket_position['discount_amount'] && $basket_position['include_product_promo'] )
|
|
{
|
|
// ? Najtańszy produkt w koszyku (z wybranych kategorii) za X zł
|
|
if ( $basket_position['discount_type'] == 3 )
|
|
$price['price_new'] = \Shared\Helpers\Helpers::normalize_decimal( $basket_position['discount_amount'] );
|
|
|
|
// ? rabat procentowy
|
|
if ( $basket_position['discount_type'] == 1 )
|
|
$price['price_new'] = \Shared\Helpers\Helpers::normalize_decimal($price['price_new'] - $price['price_new'] * $basket_position['discount_amount'] / 100 );
|
|
}
|
|
}
|
|
}
|
|
// ? produkt nieprzeceniony
|
|
else
|
|
{
|
|
$price['price'] = $price_brutto;
|
|
$price['price_new'] = $price_brutto;
|
|
|
|
// ? zastosuj kod rabatowy
|
|
if ( $coupon -> type )
|
|
{
|
|
// ? ograniczony do wybranych kategorii
|
|
if ( $coupon -> categories != null )
|
|
{
|
|
$coupon_categories = json_decode( $coupon -> categories );
|
|
$product_categories = \shop\Product::product_categories( $basket_position['parent_id'] ? $basket_position['parent_id'] : $basket_position['product-id'] );
|
|
if ( is_array( $coupon_categories ) ) foreach ( $coupon_categories as $category_tmp )
|
|
{
|
|
if ( in_array( $category_tmp, $product_categories ) )
|
|
{
|
|
$price['price_new'] = \Shared\Helpers\Helpers::normalize_decimal( $price['price_new'] - $price['price_new'] * $coupon -> amount / 100 );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// ? nieograniczony
|
|
else
|
|
$price['price_new'] = \Shared\Helpers\Helpers::normalize_decimal($price['price'] - $price['price'] * $coupon -> amount / 100 );
|
|
|
|
// ? uwzględnij promocję jeżeli może łączyć się z rabatami i produktami przecenionymi
|
|
if ( $basket_position['discount_amount'] && $basket_position['discount_include_coupon'] && $basket_position['include_product_promo'] )
|
|
{
|
|
// ? najtańszy produkt w koszyku (z wybranych kategorii) za X zł
|
|
if ( $basket_position['discount_type'] == 3 )
|
|
$price['price_new'] = \Shared\Helpers\Helpers::normalize_decimal( $basket_position['discount_amount'] );
|
|
|
|
// ? rabat procentowy
|
|
if ( $basket_position['discount_type'] == 1 )
|
|
$price['price_new'] = \Shared\Helpers\Helpers::normalize_decimal($price['price'] - $price['price'] * $basket_position['discount_amount'] / 100 );
|
|
}
|
|
}
|
|
// ? bez kodu rabatowego
|
|
else
|
|
{
|
|
if ( $basket_position['discount_amount'] )
|
|
{
|
|
// ? Najtańszy produkt w koszyku (z wybranych kategorii) za X zł
|
|
if ( $basket_position['discount_type'] == 3 )
|
|
$price['price_new'] = \Shared\Helpers\Helpers::normalize_decimal( $basket_position['discount_amount'] );
|
|
|
|
// ? rabat procentowy
|
|
if ( $basket_position['discount_type'] == 1 )
|
|
$price['price_new'] = \Shared\Helpers\Helpers::normalize_decimal($price['price'] - $price['price'] * $basket_position['discount_amount'] / 100 );
|
|
}
|
|
}
|
|
}
|
|
|
|
return $price;
|
|
}
|
|
|
|
// pobierz wiadomość zależną od stanu magazynowego
|
|
// id_product - id produktu
|
|
// attributes - wybrane atrybuty przez użytkownika
|
|
public static function getWarehouseMessage( int $id_product, $attributes, string $lang_id )
|
|
{
|
|
global $settings;
|
|
|
|
$permutation = self::getPermutation( $attributes );
|
|
|
|
$quantity = self::getPermutationQuantity( $id_product, $permutation );
|
|
|
|
if ( $quantity )
|
|
{
|
|
if ( $msg = ( new \Domain\Product\ProductRepository( $mdb ) )->getWarehouseMessageNonzero( (int)$id_product, $lang_id ) )
|
|
$result = [ 'msg' => $msg, 'quantity' => $quantity ];
|
|
else if ( $settings[ 'warehouse_message_nonzero_' . $lang_id ] )
|
|
$result = [ 'msg' => $settings[ 'warehouse_message_nonzero_' . $lang_id ], 'quantity' => $quantity ];
|
|
}
|
|
else
|
|
{
|
|
if ( $msg = ( new \Domain\Product\ProductRepository( $mdb ) )->getWarehouseMessageZero( (int)$id_product, $lang_id ) )
|
|
$result = [ 'msg' => $msg, 'quantity' => $quantity ];
|
|
else if ( $settings[ 'warehouse_message_zero_' . $lang_id ] )
|
|
$result = [ 'msg' => $settings[ 'warehouse_message_zero_' . $lang_id ], 'quantity' => $quantity ];
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
// pobranie id produktu wg wybranych parametrów
|
|
static public function get_product_id_by_attributes( int $parent_id, array $attributes )
|
|
{
|
|
global $mdb;
|
|
|
|
return $mdb -> get( 'pp_shop_products', 'id', [ 'AND' => [ 'parent_id' => $parent_id, 'permutation_hash' => implode( '|', $attributes ) ] ] );
|
|
}
|
|
|
|
// pobranie permutation_hash dla kombinacji produktu
|
|
static public function get_product_permutation_hash( int $product_id )
|
|
{
|
|
global $mdb;
|
|
return $mdb -> get( 'pp_shop_products', 'permutation_hash', [ 'id' => $product_id ] );
|
|
}
|
|
|
|
// pobranie listy atrybutów z wybranymi wartościami
|
|
static public function get_product_attributes( $products )
|
|
{
|
|
if ( !is_array( $products ) or !count( $products ) )
|
|
return false;
|
|
|
|
$attributes = array();
|
|
|
|
foreach ( $products as $product )
|
|
{
|
|
$permutations = explode( '|', $product['permutation_hash'] );
|
|
foreach ( $permutations as $permutation )
|
|
{
|
|
$attribute = explode( '-', $permutation );
|
|
|
|
$value['id'] = $attribute[1];
|
|
$value['is_default'] = \shop\ProductAttribute::is_value_default( $attribute[1] );
|
|
|
|
if ( array_search( $attribute[1], array_column( $attributes, 'id' ) ) === false )
|
|
$attributes[ $attribute[0] ][] = $value;
|
|
}
|
|
}
|
|
|
|
$attributes = \Shared\Helpers\Helpers::removeDuplicates( $attributes, 'id' );
|
|
|
|
foreach ( $attributes as $key => $val )
|
|
{
|
|
$row['id'] = $key;
|
|
$row['values'] = $val;
|
|
|
|
$attributes_sort[ \shop\ProductAttribute::get_attribute_order( $key ) ] = $row;
|
|
}
|
|
|
|
return $attributes_sort;
|
|
}
|
|
|
|
public static function array_cartesian( $input )
|
|
{
|
|
$result = array();
|
|
|
|
foreach ( $input as $key => $values )
|
|
{
|
|
if ( empty( $values ) )
|
|
continue;
|
|
|
|
if ( empty( $result ) )
|
|
{
|
|
foreach ( $values as $value )
|
|
{
|
|
$result[] = array( $key => $value );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$append = array();
|
|
|
|
foreach ( $result as &$product )
|
|
{
|
|
$product[$key] = array_shift( $values );
|
|
$copy = $product;
|
|
|
|
foreach ( $values as $item )
|
|
{
|
|
$copy[$key] = $item;
|
|
$append[] = $copy;
|
|
}
|
|
|
|
array_unshift( $values, $product[$key] );
|
|
}
|
|
|
|
$result = array_merge( $result, $append );
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
public function __get( $variable )
|
|
{
|
|
if ( is_array( $this -> data ) and array_key_exists( $variable, $this -> data ) )
|
|
return $this -> $variable;
|
|
}
|
|
|
|
public function __set( $variable, $value )
|
|
{
|
|
$this -> $variable = $value;
|
|
}
|
|
|
|
public function offsetExists( $offset )
|
|
{
|
|
return isset( $this -> $offset );
|
|
}
|
|
|
|
public function offsetGet( $offset )
|
|
{
|
|
return $this -> $offset;
|
|
}
|
|
|
|
public function offsetSet( $offset, $value )
|
|
{
|
|
$this -> $offset = $value;
|
|
}
|
|
|
|
public function offsetUnset( $offset )
|
|
{
|
|
unset( $this -> $offset );
|
|
}
|
|
|
|
// generate_sku_code
|
|
public static function generate_sku_code( int $product_id )
|
|
{
|
|
global $mdb;
|
|
// find product with sku like 'PP-000000'
|
|
$skus = $mdb -> select( 'pp_shop_products', 'sku', [ 'sku[~]' => 'PP-' ] );
|
|
if ( is_array( $skus ) )
|
|
{
|
|
foreach ( $skus as $sku )
|
|
$sku_codes[] = (int)substr( $sku, 3 );
|
|
}
|
|
|
|
// find max sku
|
|
if ( is_array( $sku_codes ) )
|
|
$sku = 'PP-' . str_pad( max( $sku_codes ) + 1, 6, '0', STR_PAD_LEFT );
|
|
else
|
|
$sku = 'PP-000001';
|
|
|
|
return $sku;
|
|
}
|
|
|
|
// product_xml_name_save
|
|
public static function product_xml_name_save( int $product_id, string $xml_name, string $lang_id )
|
|
{
|
|
global $mdb;
|
|
return $mdb -> update( 'pp_shop_products_langs', [ 'xml_name' => $xml_name ], [ 'AND' => [ 'product_id' => $product_id, 'lang_id' => $lang_id ] ] );
|
|
}
|
|
|
|
// product_custom_label_suggestions
|
|
public static function product_custom_label_suggestions( string $custom_label, string $label_type )
|
|
{
|
|
global $mdb;
|
|
|
|
$results = $mdb -> query( 'SELECT DISTINCT
|
|
' . $label_type . ' AS label
|
|
FROM
|
|
pp_shop_products
|
|
WHERE
|
|
' . $label_type . ' LIKE :custom_label
|
|
LIMIT 10', [ ':custom_label' => '%' . $custom_label . '%' ] ) -> fetchAll( \PDO::FETCH_ASSOC );
|
|
if ( is_array( $results ) )
|
|
{
|
|
foreach ( $results as $row )
|
|
$output[] = $row;
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
// product_custom_label_save
|
|
public static function product_custom_label_save( int $product_id, string $custom_label, string $label_type )
|
|
{
|
|
global $mdb;
|
|
return $mdb -> update( 'pp_shop_products', [ $label_type => $custom_label ], [ 'id' => $product_id ] );
|
|
}
|
|
public static function product_meta (int $product_id)
|
|
{
|
|
global $mdb;
|
|
return $mdb->select(
|
|
"pp_shop_products_categories (ppc)",
|
|
[
|
|
"[>]pp_shop_categories_langs (pcl)" => ["ppc.category_id" => "category_id"]
|
|
],
|
|
[
|
|
"pcl.title",
|
|
"pcl.seo_link"
|
|
],
|
|
[
|
|
"ppc.product_id" => $product_id
|
|
]
|
|
);
|
|
}
|
|
}
|