<?php
 class ref_product { private $_currency_code; private $_language_codes; private $_customer_id; private $_data = []; function __construct($product_id, $language_code=null, $currency_code=null, $customer_id=null) { if (empty($language_code)) $language_code = language::$selected['code']; if (empty($currency_code)) $currency_code = currency::$selected['code']; if (empty($customer_id)) $customer_id = customer::$data['id']; $this->_data['id'] = (int)$product_id; $this->_language_codes = array_unique([ $language_code, settings::get('default_language_code'), settings::get('store_language_code'), ]); $this->_currency_code = $currency_code; $this->_customer_id = $customer_id; } public function &__get($name) { if (array_key_exists($name, $this->_data)) { return $this->_data[$name]; } $this->_data[$name] = null; $this->_load($name); return $this->_data[$name]; } public function &__isset($name) { return $this->__get($name); } public function __set($name, $value) { throw new Error('Setting data is prohibited ('.$name.')'); } private function _load($field) { switch($field) { case 'also_purchased_products': $this->_data['also_purchased_products'] = []; $query = database::query( "select oi.product_id, sum(oi.quantity) as total_quantity from ". DB_TABLE_PREFIX ."orders_items oi
              left join ". DB_TABLE_PREFIX ."products p on (p.id = oi.product_id)
              where p.status
              and (oi.product_id != 0 and oi.product_id != ". (int)$this->_data['id'] .")
              and order_id in (
                select distinct order_id as id from ". DB_TABLE_PREFIX ."orders_items
                where product_id = ". (int)$this->_data['id'] ."
              )
              group by oi.product_id
              order by total_quantity desc;" ); while ($row = database::fetch($query)) { $this->_data['also_purchased_products'][$row['product_id']] = reference::product($row['product_id'], $this->_language_codes[0]); } break; case 'attributes': $this->_data['attributes'] = []; $product_attributes_query = database::query( "select pa.*, ag.code, agi.name as group_name, avi.name as value_name, pa.custom_value from ". DB_TABLE_PREFIX ."products_attributes pa
            left join ". DB_TABLE_PREFIX ."attribute_groups ag on (ag.id = pa.group_id)
            left join ". DB_TABLE_PREFIX ."attribute_groups_info agi on (agi.group_id = pa.group_id and agi.language_code = '". database::input($this->_language_codes[0]) ."')
            left join ". DB_TABLE_PREFIX ."attribute_values_info avi on (avi.value_id = pa.value_id and avi.language_code = '". database::input($this->_language_codes[0]) ."')
            where product_id = ". (int)$this->_data['id'] ."
            order by group_name, value_name, custom_value;" ); while ($attribute = database::fetch($product_attributes_query)) { $this->_data['attributes'][$attribute['group_id'].'-'.$attribute['value_id']] = $attribute; } break; case 'name': case 'short_description': case 'description': case 'technical_data': case 'head_title': case 'meta_description': $this->_data['name'] = ''; $this->_data['short_description'] = ''; $this->_data['description'] = ''; $this->_data['technical_data'] = ''; $this->_data['head_title'] = ''; $this->_data['meta_description'] = ''; $query = database::query( "select * from ". DB_TABLE_PREFIX ."products_info
            where product_id = ". (int)$this->_data['id'] ."
            and language_code in ('". implode("', '", database::input($this->_language_codes)) ."')
            order by field(language_code, '". implode("', '", database::input($this->_language_codes)) ."');" ); while ($row = database::fetch($query)) { foreach ($row as $key => $value) { if (in_array($key, ['id', 'product_id', 'language_code'])) continue; if (empty($this->_data[$key])) $this->_data[$key] = $value; } } break; case 'campaign': $this->_data['campaign'] = []; $campaigns_query = database::query( "select *, min(if(`". database::input(currency::$selected['code']) ."`, `". database::input(currency::$selected['code']) ."` * ". (float)currency::$selected['value'] .", `". database::input(settings::get('store_currency_code')) ."`)) as price
            from ". DB_TABLE_PREFIX ."products_campaigns
            where product_id = ". (int)$this->_data['id'] ."
            and (start_date is null or start_date <= '". date('Y-m-d H:i:s') ."')
            and (end_date is null or year(end_date) < '1971' or end_date >= '". date('Y-m-d H:i:s') ."');" ); while ($campaign = database::fetch($campaigns_query)) { if ($campaign['price'] < $this->price) { if (!isset($this->_data['campaign']['price']) || $campaign['price'] < $this->_data['campaign']['price']) { $this->_data['campaign'] = $campaign; } } } break; case 'categories': $this->_data['categories'] = []; $products_to_categories_query = database::query( "select * from ". DB_TABLE_PREFIX ."products_to_categories
            where product_id = ". (int)$this->_data['id'] .";" ); while ($product_to_category = database::fetch($products_to_categories_query)) { $categories_info_query = database::query( "select * from ". DB_TABLE_PREFIX ."categories_info
              where category_id = ". (int)$product_to_category['category_id'] ."
              and language_code in ('". implode("', '", database::input($this->_language_codes)) ."')
              order by field(language_code, '". implode("', '", database::input($this->_language_codes)) ."');" ); while ($row = database::fetch($categories_info_query)) { foreach ($row as $key => $value) { if (in_array($key, ['id', 'category_id', 'language_code'])) continue; if (empty($this->_data['categories'][$product_to_category['category_id']])) $this->_data['categories'][$product_to_category['category_id']] = $value; } } } break; case 'default_category': $this->_data['default_category'] = 0; if (empty($this->default_category_id)) return; $this->_data['default_category'] = reference::category($this->default_category_id, $this->_language_codes[0]); break; case 'delivery_status': $this->_data['delivery_status'] = []; $query = database::query( "select * from ". DB_TABLE_PREFIX ."delivery_statuses_info
            where delivery_status_id = ". (int)$this->_data['delivery_status_id'] ."
            and language_code in ('". implode("', '", database::input($this->_language_codes)) ."')
            order by field(language_code, '". implode("', '", database::input($this->_language_codes)) ."');" ); while ($row = database::fetch($query)) { foreach ($row as $key => $value) { if (in_array($key, ['id', 'delivery_status_id', 'language_code'])) continue; if (empty($this->_data['delivery_status'][$key])) $this->_data['delivery_status'][$key] = $value; } } break; case 'final_price': $this->_data['final_price'] = $this->price; if (isset($this->campaign['price']) && $this->campaign['price'] > 0 && $this->campaign['price'] < $this->_data['final_price']) { $this->_data['final_price'] = $this->campaign['price']; } break; case 'images': $this->_data['images'] = []; $query = database::query( "select * from ". DB_TABLE_PREFIX ."products_images
            where product_id = ". (int)$this->_data['id'] ."
            order by priority asc, id asc;" ); while ($row = database::fetch($query)) { $this->_data['images'][$row['id']] = $row['filename']; } break; case 'manufacturer': $this->_data['manufacturer'] = []; if (empty($this->_data['manufacturer_id'])) return; $this->_data['manufacturer'] = reference::manufacturer($this->manufacturer_id, $this->_language_codes[0]); break; case 'options': $this->_data['options'] = []; $products_options_query = database::query( "select * from ". DB_TABLE_PREFIX ."products_options
            where product_id = ". (int)$this->_data['id'] ."
            order by priority;" ); while ($option = database::fetch($products_options_query)) { $attribute_group_info_query = database::query( "select * from ". DB_TABLE_PREFIX ."attribute_groups_info pcgi
              where group_id = ". (int)$option['group_id'] ."
              and language_code in ('". implode("', '", database::input($this->_language_codes)) ."')
              order by field(language_code, '". implode("', '", database::input($this->_language_codes)) ."');" ); while ($attribute_group_info = database::fetch($attribute_group_info_query)) { foreach ($attribute_group_info as $k => $v) { if (in_array($k, ['id', 'group_id', 'language_code'])) continue; if (empty($option[$k])) $option[$k] = $v; } } $option['values'] = []; $option_values_query = database::query( "select * from ". DB_TABLE_PREFIX ."products_options_values
              where product_id = ". (int)$this->_data['id'] ."
              and group_id = ". (int)$option['group_id'] ."
              order by priority;" ); while ($value = database::fetch($option_values_query)) { if (!empty($value['value_id'])) { $attribute_values_info_query = database::query( "select * from ". DB_TABLE_PREFIX ."attribute_values_info pcvi
                  where value_id = ". (int)$value['value_id'] ."
                  and language_code in ('". implode("', '", database::input($this->_language_codes)) ."')
                  order by field(language_code, '". implode("', '", database::input($this->_language_codes)) ."');" ); while ($attribute_value_info = database::fetch($attribute_values_info_query)) { foreach ($attribute_value_info as $k => $v) { if (in_array($k, ['id', 'value_id', 'language_code'])) continue; if (empty($value[$k])) $value[$k] = $v; } } } else { $value['name'] = $value['custom_value']; } $value['price_adjust'] = 0; if ((!empty($value[$this->_currency_code]) && (float)$value[$this->_currency_code] != 0) || (!empty($value[settings::get('store_currency_code')]) && (float)$value[settings::get('store_currency_code')] != 0)) { switch ($value['price_operator']) { case '+': if ((float)$value[$this->_currency_code] != 0) { $value['price_adjust'] = currency::convert($value[$this->_currency_code], $this->_currency_code, settings::get('store_currency_code')); } else if ($value[settings::get('store_currency_code')]) { $value['price_adjust'] = (float)$value[settings::get('store_currency_code')]; } break; case '%': if ((float)$value[$this->_currency_code] != 0) { $value['price_adjust'] = $this->price * currency::convert((float)$value[$this->_currency_code], $this->_currency_code, settings::get('store_currency_code')) / 100; } else if ($value[settings::get('store_currency_code')]) { $value['price_adjust'] = $this->price * (float)$value[settings::get('store_currency_code')] / 100; } break; case '*': if ((float)$value[$this->_currency_code] != 0) { $value['price_adjust'] = $this->price * currency::convert($value[$this->_currency_code], $this->_currency_code, settings::get('store_currency_code')); } else if ($value[settings::get('store_currency_code')]) { $value['price_adjust'] = $this->price * $value[settings::get('store_currency_code')]; } break; case '=': if ((float)$value[$this->_currency_code] != 0) { $value['price_adjust'] = currency::convert($value[$this->_currency_code], $this->_currency_code, settings::get('store_currency_code')) - $this->price; } else if ($value[settings::get('store_currency_code')]) { $value['price_adjust'] = $value[settings::get('store_currency_code')] - $this->price; } break; default: trigger_error('Unknown price operator for option', E_USER_WARNING); break; } } if ($value['price_adjust'] && !empty($this->campaign['price'])) { $value['price_adjust'] = $value['price_adjust'] * $this->campaign['price'] / $this->price; } if (!empty($value['value_id'])) { $option['values'][$value['value_id']] = $value; } else { $option['values'][uniqid()] = $value; } } if ($option['sort'] == 'alphabetically') { uasort($option['values'], function($a, $b){ if ($a['name'] == $b['name']) return 0; return ($a['name'] < $b['name']) ? -1 : 1; }); break; } $this->_data['options'][$option['group_id']] = $option; } break; case 'options_stock': $this->_data['options_stock'] = []; $query = database::query( "select * from ". DB_TABLE_PREFIX ."products_options_stock
            where product_id = ". (int)$this->_data['id'] ."
            order by priority asc;" ); while ($row = database::fetch($query)) { if (empty($row['tax_class_id'])) { $row['tax_class_id'] = $this->tax_class_id; } if (empty($row['sku'])) { $row['sku'] = $this->sku; } if (empty($row['weight']) || (float)$row['weight'] == 0) { $row['weight'] = $this->weight; $row['weight_class'] = $this->weight_class; } if (empty($row['dim_x'])) { $row['dim_x'] = $this->dim_x; $row['dim_y'] = $this->dim_y; $row['dim_z'] = $this->dim_z; $row['dim_class'] = $this->dim_class; } $row['quantity_available'] = null; $reserved_items_query = database::query( "select sum(quantity) as total_reserved from ". DB_TABLE_PREFIX ."orders_items oi
              left join ". DB_TABLE_PREFIX ."orders o on (o.id = oi.order_id)
              where oi.product_id = ". (int)$this->_data['id'] ."
              and oi.option_stock_combination = '". database::input($row['combination']) ."'
              and o.order_status_id in (
                select id from ". DB_TABLE_PREFIX ."order_statuses
                where stock_action = 'reserve'
              );" ); $row['reserved_quantity'] = database::fetch($reserved_items_query, 'total_reserved'); $row['quantity_available'] = $row['quantity'] - $row['reserved_quantity']; $row['name'] = []; foreach (explode(',', $row['combination']) as $combination) { list($group_id, $value_id) = explode('-', $combination); if (preg_match('#^0:"?(.*?)"?$#', $value_id, $matches)) { foreach (array_keys(language::$languages) as $language_code) { $row['name'][$language_code] = $matches[1]; } } else { $options_values_query = database::query( "select * from ". DB_TABLE_PREFIX ."products_options_values pov
                  left join ". DB_TABLE_PREFIX ."attribute_values_info avi on (avi.value_id = pov.value_id)
                  where pov.value_id = ". (int)$value_id ."
                  and avi.language_code in ('". implode("', '", database::input($this->_language_codes)) ."')
                  order by field(avi.language_code, '". implode("', '", database::input($this->_language_codes)) ."');" ); while ($option_value_info = database::fetch($options_values_query)) { foreach ($option_value_info as $key => $value) { if (in_array($key, ['id', 'value_id', 'language_code'])) continue; if (!is_array(empty($row[$key][$option_value_info['value_id']]))) continue; if (empty($row[$key][$option_value_info['value_id']])) { $row[$key][$option_value_info['value_id']] = $value; } } } } } $row['name'] = implode(',', $row['name']); $this->_data['options_stock'][$row['id']] = $row; } break; case 'parents': $this->_data['parents'] = []; $query = database::query( "select category_id from ". DB_TABLE_PREFIX ."products_to_categories
            where product_id = ". (int)$this->_data['id'] .";" ); while ($row = database::fetch($query)) { $this->_data['parents'][$row['category_id']] = reference::category($row['category_id'], $this->_language_codes[0]); } break; case 'price': $this->_data['price'] = 0; $products_prices_query = database::query( "select * from ". DB_TABLE_PREFIX ."products_prices
            where product_id = ". (int)$this->_data['id'] ."
            limit 1;" ); if ($product_price = database::fetch($products_prices_query)) { if (!empty($product_price[$this->_currency_code]) && (float)$product_price[$this->_currency_code] != 0) { $this->_data['price'] = currency::convert($product_price[$this->_currency_code], $this->_currency_code, settings::get('store_currency_code')); } else { $this->_data['price'] = $product_price[settings::get('store_currency_code')]; } } break; case 'quantity_available': case 'quantity_reserved': $this->_data['quantity_available'] = null; $reserved_items_query = database::query( "select sum(quantity) as total_reserved from ". DB_TABLE_PREFIX ."orders_items oi
            left join ". DB_TABLE_PREFIX ."orders o on (o.id = oi.order_id)
            where oi.product_id = ". (int)$this->_data['id'] ."
            and o.order_status_id in (
              select id from ". DB_TABLE_PREFIX ."order_statuses
              where stock_action = 'reserve'
            );" ); $this->_data['quantity_reserved'] = database::fetch($reserved_items_query, 'total_reserved'); $this->_data['quantity_available'] = $this->quantity - $this->_data['quantity_reserved']; break; case 'quantity_unit': $quantity_unit_query = database::query( "select id, decimals, separate from ". DB_TABLE_PREFIX ."quantity_units
            where id = ". (int)$this->quantity_unit_id ."
            limit 1;" ); if (!$this->_data['quantity_unit'] = database::fetch($quantity_unit_query)) return; $query = database::query( "select * from ". DB_TABLE_PREFIX ."quantity_units_info
            where quantity_unit_id = ". (int)$this->quantity_unit_id ."
            and language_code in ('". implode("', '", database::input($this->_language_codes)) ."')
            order by field(language_code, '". implode("', '", database::input($this->_language_codes)) ."');" ); while ($row = database::fetch($query)) { foreach ($row as $key => $value) { if (in_array($key, ['id', 'quantity_unit_id', 'language_code'])) continue; if (empty($this->_data['quantity_unit'][$key])) $this->_data['quantity_unit'][$key] = $value; } } break; case 'supplier': $this->_data['supplier'] = null; if (!empty($this->supplier_id)) { $this->_data['supplier'] = reference::supplier($this->supplier_id); } break; case 'sold_out_status': $this->_data['sold_out_status'] = []; $query = database::query( "select id, orderable from ". DB_TABLE_PREFIX ."sold_out_statuses
            where id = ". (int)$this->sold_out_status_id ."
            limit 1;" ); if (!$this->_data['sold_out_status'] = database::fetch($query)) return; $query = database::query( "select * from ". DB_TABLE_PREFIX ."sold_out_statuses_info
            where sold_out_status_id = ". (int)$this->_data['sold_out_status_id'] ."
            and language_code in ('". implode("', '", database::input($this->_language_codes)) ."')
            order by field(language_code, '". implode("', '", database::input($this->_language_codes)) ."');" ); while ($row = database::fetch($query)) { foreach ($row as $key => $value) { if (in_array($key, ['id', 'sold_out_status_id', 'language_code'])) continue; if (empty($this->_data['sold_out_status'][$key])) $this->_data['sold_out_status'][$key] = $value; } } break; case 'tax': $this->_data['tax'] = tax::get_tax($this->final_price, $this->tax_class_id); break; default: $query = database::query( "select * from ". DB_TABLE_PREFIX ."products
            where id = ". (int)$this->_data['id'] ."
            limit 1;" ); if (!$row = database::fetch($query)) return; foreach ($row as $key => $value) $this->_data[$key] = $value; $this->_data['keywords'] = preg_split('#\s*,\s*#', $this->_data['keywords'], -1, PREG_SPLIT_NO_EMPTY); break; } } public function adjust_stock($combination, $quantity) { trigger_error('catalog_stock_adjust() is deprecated. Use $ent_product->adjust_quantity()', E_USER_DEPRECATED); $product = new ent_product($this->_data['id']); return $product->adjust_quantity($quantity, $combination); } } 