diff --git a/ajax.php b/ajax.php index 1cdff48..df9a583 100644 --- a/ajax.php +++ b/ajax.php @@ -64,7 +64,7 @@ if ( $a == 'basket_change_transport' ) $basket = \Shared\Helpers\Helpers::get_session( 'basket' ); $basket_summary = \Domain\Basket\BasketCalculator::summaryPrice( $basket, null ); - $transport_cost = \front\factory\ShopTransport::transport_cost( \Shared\Helpers\Helpers::get( 'transport_id' ) ); + $transport_cost = ( new \Domain\Transport\TransportRepository( $mdb ) )->transportCostCached( \Shared\Helpers\Helpers::get( 'transport_id' ) ); echo json_encode( [ 'summary' => \Shared\Helpers\Helpers::decimal( $basket_summary + $transport_cost ) . ' zł' ] ); exit; @@ -73,7 +73,7 @@ if ( $a == 'basket_change_transport' ) if ( $a == 'change_payment' ) { \Shared\Helpers\Helpers::set_session( 'payment_method_id', \Shared\Helpers\Helpers::get( 'payment_method_id' ) ); - $transports = \front\factory\ShopTransport::transports_list( \Shared\Helpers\Helpers::get( 'payment_method_id' ) ); + $transports = ( new \Domain\Transport\TransportRepository( $mdb ) )->forPaymentMethod( (int)\Shared\Helpers\Helpers::get( 'payment_method_id' ) ); echo json_encode( [ 'transports' => $transports ] ); exit; } diff --git a/autoload/Domain/Order/OrderAdminService.php b/autoload/Domain/Order/OrderAdminService.php index ed1719f..d1efbe7 100644 --- a/autoload/Domain/Order/OrderAdminService.php +++ b/autoload/Domain/Order/OrderAdminService.php @@ -132,7 +132,7 @@ class OrderAdminService curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([ 'id' => (int)$order['apilo_order_id'], - 'status' => (int)\front\factory\ShopStatuses::get_apilo_status_id($newStatus), + 'status' => (int)( new \Domain\ShopStatus\ShopStatusRepository($this->db) )->getApiloStatusId( (int)$newStatus ), ])); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . $accessToken, diff --git a/autoload/Domain/Order/OrderRepository.php b/autoload/Domain/Order/OrderRepository.php index d42be9c..1e52190 100644 --- a/autoload/Domain/Order/OrderRepository.php +++ b/autoload/Domain/Order/OrderRepository.php @@ -558,8 +558,8 @@ class OrderRepository return false; } - $transport = \front\factory\ShopTransport::transport($transport_id); - $payment_method = \front\factory\ShopPaymentMethod::payment_method($payment_id); + $transport = ( new \Domain\Transport\TransportRepository( $this->db ) )->findActiveByIdCached( $transport_id ); + $payment_method = ( new \Domain\PaymentMethod\PaymentMethodRepository( $this->db ) )->findActiveById( (int)$payment_id ); $basket_summary = \Domain\Basket\BasketCalculator::summaryPrice($basket, $coupon); $order_number = $this->generateOrderNumber(); $order_date = date('Y-m-d H:i:s'); diff --git a/autoload/Domain/PaymentMethod/PaymentMethodRepository.php b/autoload/Domain/PaymentMethod/PaymentMethodRepository.php index eaaf7ae..3196917 100644 --- a/autoload/Domain/PaymentMethod/PaymentMethodRepository.php +++ b/autoload/Domain/PaymentMethod/PaymentMethodRepository.php @@ -257,6 +257,67 @@ class PaymentMethodRepository return $result; } + /** + * Metody platnosci dla danego transportu — z Redis cache (frontend). + * + * @return array> + */ + public function paymentMethodsByTransport(int $transportMethodId): array + { + $cacheHandler = new \Shared\Cache\CacheHandler(); + $cacheKey = 'payment_methods_by_transport' . $transportMethodId; + $cached = $cacheHandler->get($cacheKey); + + if ($cached) { + return unserialize($cached); + } + + $result = $this->forTransport($transportMethodId); + $cacheHandler->set($cacheKey, $result); + + return $result; + } + + /** + * Pojedyncza aktywna metoda platnosci — z Redis cache (frontend). + */ + public function paymentMethodCached(int $paymentMethodId): ?array + { + $cacheHandler = new \Shared\Cache\CacheHandler(); + $cacheKey = 'payment_method' . $paymentMethodId; + $cached = $cacheHandler->get($cacheKey); + + if ($cached) { + return unserialize($cached); + } + + $result = $this->findActiveById($paymentMethodId); + $cacheHandler->set($cacheKey, $result); + + return $result; + } + + /** + * Wszystkie aktywne metody platnosci — z Redis cache (frontend). + * + * @return array> + */ + public function paymentMethodsCached(): array + { + $cacheHandler = new \Shared\Cache\CacheHandler(); + $cacheKey = 'payment_methods'; + $cached = $cacheHandler->get($cacheKey); + + if ($cached) { + return unserialize($cached); + } + + $result = $this->allActive(); + $cacheHandler->set($cacheKey, $result); + + return $result; + } + private function normalizePaymentMethod(array $row): array { $row['id'] = (int)($row['id'] ?? 0); diff --git a/autoload/Domain/Product/ProductRepository.php b/autoload/Domain/Product/ProductRepository.php index eac6641..5bb123a 100644 --- a/autoload/Domain/Product/ProductRepository.php +++ b/autoload/Domain/Product/ProductRepository.php @@ -1848,4 +1848,399 @@ class ProductRepository ], [ 'id' => $row['id'] ] ); } } + + // ========================================================================= + // Frontend methods (migrated from front\factory\ShopProduct) + // ========================================================================= + + /** + * @return string|null + */ + public function getSkuWithFallback(int $productId, bool $withParentFallback = false) + { + if ($productId <= 0) { + return null; + } + + $sku = $this->db->get('pp_shop_products', 'sku', ['id' => $productId]); + + if (!$sku && $withParentFallback) { + $parentId = $this->db->get('pp_shop_products', 'parent_id', ['id' => $productId]); + if ($parentId) { + return $this->getSkuWithFallback((int)$parentId, true); + } + return null; + } + + return $sku ? (string)$sku : null; + } + + /** + * @return string|null + */ + public function getEanWithFallback(int $productId, bool $withParentFallback = false) + { + if ($productId <= 0) { + return null; + } + + $ean = $this->db->get('pp_shop_products', 'ean', ['id' => $productId]); + + if (!$ean && $withParentFallback) { + $parentId = $this->db->get('pp_shop_products', 'parent_id', ['id' => $productId]); + if ($parentId) { + return $this->getEanWithFallback((int)$parentId, true); + } + return null; + } + + return $ean ? (string)$ean : null; + } + + public function isProductActiveCached(int $productId): int + { + if ($productId <= 0) { + return 0; + } + + $cacheHandler = new \Shared\Cache\CacheHandler(); + $cacheKey = 'is_product_active:' . $productId; + $cached = $cacheHandler->get($cacheKey); + + if ($cached) { + return (int)unserialize($cached) === 1 ? 1 : 0; + } + + $status = $this->db->get('pp_shop_products', 'status', ['id' => $productId]); + $cacheHandler->set($cacheKey, $status); + + return (int)$status === 1 ? 1 : 0; + } + + /** + * @return string|null + */ + public function getMinimalPriceCached(int $productId, $priceBruttoPromo = null) + { + if ($productId <= 0) { + return null; + } + + $cacheHandler = new \Shared\Cache\CacheHandler(); + $cacheKey = 'get_minimal_price:' . $productId; + $cached = $cacheHandler->get($cacheKey); + + if ($cached) { + return unserialize($cached); + } + + $price = $this->db->min('pp_shop_product_price_history', 'price', [ + 'AND' => [ + 'id_product' => $productId, + 'price[!]' => str_replace(',', '.', $priceBruttoPromo), + ], + ]); + + $cacheHandler->set($cacheKey, $price); + + return $price; + } + + /** + * @return array> + */ + public function productCategoriesFront(int $productId): array + { + if ($productId <= 0) { + return []; + } + + $parentId = $this->db->get('pp_shop_products', 'parent_id', ['id' => $productId]); + $targetId = $parentId ? (int)$parentId : $productId; + + $stmt = $this->db->query( + 'SELECT category_id FROM pp_shop_products_categories WHERE product_id = :pid', + [':pid' => $targetId] + ); + + return $stmt ? $stmt->fetchAll(\PDO::FETCH_ASSOC) : []; + } + + /** + * @return string|null + */ + public function getProductNameCached(int $productId, string $langId) + { + if ($productId <= 0) { + return null; + } + + $cacheHandler = new \Shared\Cache\CacheHandler(); + $cacheKey = 'product_name' . $langId . '_' . $productId; + $cached = $cacheHandler->get($cacheKey); + + if ($cached) { + return unserialize($cached); + } + + $name = $this->db->get('pp_shop_products_langs', 'name', [ + 'AND' => ['product_id' => $productId, 'lang_id' => $langId], + ]); + + $cacheHandler->set($cacheKey, $name); + + return $name; + } + + /** + * @return string|null + */ + public function getFirstImageCached(int $productId) + { + if ($productId <= 0) { + return null; + } + + $cacheHandler = new \Shared\Cache\CacheHandler(); + $cacheKey = 'product_image:' . $productId; + $cached = $cacheHandler->get($cacheKey); + + if ($cached) { + return unserialize($cached); + } + + $stmt = $this->db->query( + 'SELECT src FROM pp_shop_products_images WHERE product_id = :pid ORDER BY o ASC LIMIT 1', + [':pid' => $productId] + ); + $rows = $stmt ? $stmt->fetchAll(\PDO::FETCH_ASSOC) : []; + $image = isset($rows[0]['src']) ? $rows[0]['src'] : null; + + $cacheHandler->set($cacheKey, $image); + + return $image; + } + + public function getWeightCached(int $productId) + { + if ($productId <= 0) { + return null; + } + + $cacheHandler = new \Shared\Cache\CacheHandler(); + $cacheKey = 'product_wp:' . $productId; + $cached = $cacheHandler->get($cacheKey); + + if ($cached) { + return unserialize($cached); + } + + $wp = $this->db->get('pp_shop_products', 'wp', ['id' => $productId]); + $cacheHandler->set($cacheKey, $wp); + + return $wp; + } + + /** + * @return array + */ + public function promotedProductIdsCached(int $limit = 6): array + { + $cacheHandler = new \Shared\Cache\CacheHandler(); + $cacheKey = 'promoted_products-' . $limit; + $cached = $cacheHandler->get($cacheKey); + + if ($cached) { + return unserialize($cached); + } + + $stmt = $this->db->query( + 'SELECT id FROM pp_shop_products WHERE status = 1 AND promoted = 1 ORDER BY RAND() LIMIT ' . (int)$limit + ); + $rows = $stmt ? $stmt->fetchAll() : []; + $products = []; + if (is_array($rows)) { + foreach ($rows as $row) { + $products[] = (int)$row['id']; + } + } + + $cacheHandler->set($cacheKey, $products); + + return $products; + } + + /** + * @return array + */ + public function topProductIds(int $limit = 6): array + { + $date30 = date('Y-m-d', strtotime('-30 days')); + + $stmt = $this->db->query( + "SELECT COUNT(0) AS sell_count, psop.parent_product_id + FROM pp_shop_order_products AS psop + INNER JOIN pp_shop_orders AS pso ON pso.id = psop.order_id + WHERE pso.date_order >= :d + GROUP BY parent_product_id + ORDER BY sell_count DESC", + [':d' => $date30] + ); + $rows = $stmt ? $stmt->fetchAll(\PDO::FETCH_ASSOC) : []; + + $ids = []; + foreach ($rows as $row) { + if ($this->isProductActiveCached((int)$row['parent_product_id'])) { + $ids[] = (int)$row['parent_product_id']; + } + } + + return $ids; + } + + /** + * @return array + */ + public function newProductIds(int $limit = 10): array + { + $stmt = $this->db->query( + 'SELECT id FROM pp_shop_products WHERE status = 1 ORDER BY date_add DESC LIMIT ' . (int)$limit + ); + $rows = $stmt ? $stmt->fetchAll(\PDO::FETCH_ASSOC) : []; + + return array_column($rows, 'id'); + } + + /** + * @return array|null + */ + public function productDetailsFrontCached(int $productId, string $langId) + { + if ($productId <= 0) { + return null; + } + + $cacheHandler = new \Shared\Cache\CacheHandler(); + $cacheKey = 'product_details_front:' . $productId . ':' . $langId; + $cached = $cacheHandler->get($cacheKey); + + if ($cached) { + return unserialize($cached); + } + + $product = $this->db->get('pp_shop_products', '*', ['id' => $productId]); + if (!is_array($product)) { + return null; + } + + // language + $langRows = $this->db->select('pp_shop_products_langs', '*', [ + 'AND' => ['product_id' => $productId, 'lang_id' => $langId], + ]); + if (is_array($langRows)) { + foreach ($langRows as $row) { + if ($row['copy_from']) { + $copyRows = $this->db->select('pp_shop_products_langs', '*', [ + 'AND' => ['product_id' => $productId, 'lang_id' => $row['copy_from']], + ]); + if (is_array($copyRows)) { + foreach ($copyRows as $row2) { + $product['language'] = $row2; + } + } + } else { + $product['language'] = $row; + } + } + } + + // attributes + $attrStmt = $this->db->query( + 'SELECT DISTINCT(attribute_id) FROM pp_shop_products_attributes AS pspa ' + . 'INNER JOIN pp_shop_attributes AS psa ON psa.id = pspa.attribute_id ' + . 'WHERE product_id = ' . $productId . ' ORDER BY o ASC' + ); + $attrRows = $attrStmt ? $attrStmt->fetchAll() : []; + if (is_array($attrRows)) { + foreach ($attrRows as $row) { + $row['type'] = $this->db->get('pp_shop_attributes', 'type', ['id' => $row['attribute_id']]); + $row['language'] = $this->db->get('pp_shop_attributes_langs', ['name'], [ + 'AND' => ['attribute_id' => $row['attribute_id'], 'lang_id' => $langId], + ]); + + $valStmt = $this->db->query( + 'SELECT value_id, is_default FROM pp_shop_products_attributes AS pspa ' + . 'INNER JOIN pp_shop_attributes_values AS psav ON psav.id = pspa.value_id ' + . 'WHERE product_id = :pid AND pspa.attribute_id = :aid', + [':pid' => $productId, ':aid' => $row['attribute_id']] + ); + $valRows = $valStmt ? $valStmt->fetchAll(\PDO::FETCH_ASSOC) : []; + if (is_array($valRows)) { + foreach ($valRows as $row2) { + $row2['language'] = $this->db->get('pp_shop_attributes_values_langs', ['name', 'value'], [ + 'AND' => ['value_id' => $row2['value_id'], 'lang_id' => $langId], + ]); + $row['values'][] = $row2; + } + } + + $product['attributes'][] = $row; + } + } + + $product['images'] = $this->db->select('pp_shop_products_images', '*', [ + 'product_id' => $productId, + 'ORDER' => ['o' => 'ASC', 'id' => 'ASC'], + ]); + $product['files'] = $this->db->select('pp_shop_products_files', '*', ['product_id' => $productId]); + $product['categories'] = $this->db->select('pp_shop_products_categories', 'category_id', ['product_id' => $productId]); + $product['products_related'] = $this->db->select('pp_shop_products_related', 'product_related_id', ['product_id' => $productId]); + + $setId = $this->db->select('pp_shop_product_sets_products', 'set_id', ['product_id' => $productId]); + $productsSets = $this->db->select('pp_shop_product_sets_products', 'product_id', ['set_id' => (int)$setId]); + $product['products_sets'] = is_array($productsSets) ? array_unique($productsSets) : []; + + $attributes = $this->db->select('pp_shop_products_attributes', ['attribute_id', 'value_id'], ['product_id' => $productId]); + $attributesTmp = []; + if (is_array($attributes)) { + foreach ($attributes as $attr) { + $attributesTmp[$attr['attribute_id']][] = $attr['value_id']; + } + } + if (!empty($attributesTmp)) { + $product['permutations'] = \Shared\Helpers\Helpers::array_cartesian_product($attributesTmp); + } + + $cacheHandler->set($cacheKey, $product); + + return $product; + } + + /** + * @return string|null + */ + public function getWarehouseMessageZero(int $productId, string $langId) + { + if ($productId <= 0) { + return null; + } + + return $this->db->get('pp_shop_products_langs', 'warehouse_message_zero', [ + 'AND' => ['product_id' => $productId, 'lang_id' => $langId], + ]); + } + + /** + * @return string|null + */ + public function getWarehouseMessageNonzero(int $productId, string $langId) + { + if ($productId <= 0) { + return null; + } + + return $this->db->get('pp_shop_products_langs', 'warehouse_message_nonzero', [ + 'AND' => ['product_id' => $productId, 'lang_id' => $langId], + ]); + } } diff --git a/autoload/Domain/Promotion/PromotionRepository.php b/autoload/Domain/Promotion/PromotionRepository.php index d618cfb..f10e21d 100644 --- a/autoload/Domain/Promotion/PromotionRepository.php +++ b/autoload/Domain/Promotion/PromotionRepository.php @@ -419,4 +419,217 @@ class PromotionRepository // Cache invalidation should not block save/delete. } } + + // ========================================================================= + // Frontend: basket promotion logic (migrated from front\factory\ShopPromotion) + // ========================================================================= + + /** + * Promocja na cały koszyk (condition_type=4) + */ + public function applyTypeWholeBasket(array $basket, $promotion): array + { + $productRepo = new \Domain\Product\ProductRepository( $this->db ); + + foreach ( $basket as $key => $val ) + { + $product_promotion = \shop\Product::is_product_on_promotion( $val['product-id'] ); + + if ( !$product_promotion or $product_promotion and $promotion->include_product_promo ) + { + $product_categories = $productRepo->productCategoriesFront( (int) $val['product-id'] ); + foreach ( $product_categories as $category_tmp ) + { + $basket[$key]['discount_type'] = $promotion->discount_type; + $basket[$key]['discount_amount'] = $promotion->amount; + $basket[$key]['discount_include_coupon'] = $promotion->include_coupon; + $basket[$key]['include_product_promo'] = $promotion->include_product_promo; + } + } + } + return $basket; + } + + /** + * Promocja na najtańszy produkt z kategorii 1 lub 2 (condition_type=3) + */ + public function applyTypeCheapestProduct(array $basket, $promotion): array + { + $productRepo = new \Domain\Product\ProductRepository( $this->db ); + $condition_1 = false; + $categories = json_decode( $promotion->categories ); + + if ( is_array( $categories ) and is_array( $categories ) ) + { + foreach ( $basket as $key => $val ) + { + $product_promotion = \shop\Product::is_product_on_promotion( $val['product-id'] ); + + if ( !$product_promotion or $product_promotion and $promotion->include_product_promo ) + { + $product_categories = $productRepo->productCategoriesFront( (int) $val['product-id'] ); + foreach ( $product_categories as $category_tmp ) + { + if ( !$condition_1[$key] and in_array( $category_tmp['category_id'], $categories ) ) + $condition_1[$key] = true; + } + } + } + } + + if ( count( $condition_1 ) >= $promotion->min_product_count ) + { + $cheapest_position = false; + foreach ( $basket as $key => $val ) + { + $price = \shop\Product::get_product_price( $val['product-id'] ); + if ( !$cheapest_position or $cheapest_position['price'] > $price ) + { + $cheapest_position['price'] = $price; + $cheapest_position['key'] = $key; + } + } + + $basket[$cheapest_position['key']]['quantity'] = 1; + $basket[$cheapest_position['key']]['discount_type'] = 3; + $basket[$cheapest_position['key']]['discount_amount'] = $promotion->price_cheapest_product; + $basket[$cheapest_position['key']]['discount_include_coupon'] = $promotion->include_coupon; + $basket[$cheapest_position['key']]['include_product_promo'] = $promotion->include_product_promo; + } + + return $basket; + } + + /** + * Promocja na wszystkie produkty z kategorii 1 lub 2 (condition_type=5) + */ + public function applyTypeCategoriesOr(array $basket, $promotion): array + { + $productRepo = new \Domain\Product\ProductRepository( $this->db ); + $categories = json_decode( $promotion->categories ); + $condition_categories = json_decode( $promotion->condition_categories ); + + foreach ( $basket as $key => $val ) + { + $product_promotion = \shop\Product::is_product_on_promotion( $val['product-id'] ); + + if ( !$product_promotion or $product_promotion and $promotion->include_product_promo ) + { + $product_categories = $productRepo->productCategoriesFront( (int) $val['product-id'] ); + foreach ( $product_categories as $category_tmp ) + { + if ( in_array( $category_tmp['category_id'], $condition_categories ) or in_array( $category_tmp['category_id'], $categories ) ) + { + $basket[$key]['discount_type'] = $promotion->discount_type; + $basket[$key]['discount_amount'] = $promotion->amount; + $basket[$key]['discount_include_coupon'] = $promotion->include_coupon; + $basket[$key]['include_product_promo'] = $promotion->include_product_promo; + } + } + } + } + return $basket; + } + + /** + * Promocja na produkty z kategorii 1 i 2 (condition_type=2) + */ + public function applyTypeCategoriesAnd(array $basket, $promotion): array + { + $productRepo = new \Domain\Product\ProductRepository( $this->db ); + $condition_1 = false; + $condition_2 = false; + + $categories = json_decode( $promotion->categories ); + $condition_categories = json_decode( $promotion->condition_categories ); + + if ( is_array( $condition_categories ) and is_array( $categories ) ) + { + foreach ( $basket as $key => $val ) + { + $product_categories = $productRepo->productCategoriesFront( (int) $val['product-id'] ); + foreach ( $product_categories as $category_tmp ) + { + if ( !$condition_1 and in_array( $category_tmp['category_id'], $condition_categories ) ) + { + $condition_1 = true; + } + } + } + + foreach ( $basket as $key => $val ) + { + $product_categories = $productRepo->productCategoriesFront( (int) $val['product-id'] ); + foreach ( $product_categories as $category_tmp ) + { + if ( !$condition_2 and in_array( $category_tmp['category_id'], $categories ) ) + $condition_2 = true; + } + } + } + + if ( $condition_1 and $condition_2 ) + { + foreach ( $basket as $key => $val ) + { + $product_categories = $productRepo->productCategoriesFront( (int) $val['product-id'] ); + foreach ( $product_categories as $category_tmp ) + { + if ( in_array( $category_tmp['category_id'], $categories ) or in_array( $category_tmp['category_id'], $condition_categories ) ) + { + $basket[$key]['discount_type'] = $promotion->discount_type; + $basket[$key]['discount_amount'] = $promotion->amount; + $basket[$key]['discount_include_coupon'] = $promotion->include_coupon; + $basket[$key]['include_product_promo'] = $promotion->include_product_promo; + } + } + } + } + return $basket; + } + + /** + * Rabat procentowy na produkty z kategorii I jeżeli w koszyku jest produkt z kategorii II (condition_type=1) + */ + public function applyTypeCategoryCondition(array $basket, $promotion): array + { + $productRepo = new \Domain\Product\ProductRepository( $this->db ); + $condition = false; + $categories = json_decode( $promotion->categories ); + $condition_categories = json_decode( $promotion->condition_categories ); + + if ( is_array( $condition_categories ) and is_array( $categories ) ) + { + foreach ( $basket as $key => $val ) + { + $product_categories = $productRepo->productCategoriesFront( (int) $val['product-id'] ); + foreach ( $product_categories as $category_tmp ) + { + if ( in_array( $category_tmp['category_id'], $condition_categories ) ) + { + $condition = true; + } + } + } + } + + if ( $condition ) + { + foreach ( $basket as $key => $val ) + { + $product_categories = $productRepo->productCategoriesFront( (int) $val['product-id'] ); + foreach ( $product_categories as $category_tmp ) + { + if ( in_array( $category_tmp['category_id'], $categories ) ) + { + $basket[$key]['discount_type'] = $promotion->discount_type; + $basket[$key]['discount_amount'] = $promotion->amount; + $basket[$key]['discount_include_coupon'] = $promotion->include_coupon; + $basket[$key]['include_product_promo'] = $promotion->include_product_promo; + } + } + } + } + return $basket; + } } diff --git a/autoload/Domain/Transport/TransportRepository.php b/autoload/Domain/Transport/TransportRepository.php index fe3f32d..de2afaf 100644 --- a/autoload/Domain/Transport/TransportRepository.php +++ b/autoload/Domain/Transport/TransportRepository.php @@ -287,6 +287,135 @@ class TransportRepository return $transports; } + // ========================================================================= + // Frontend methods (migrated from front\factory\ShopTransport) + // ========================================================================= + + /** + * Lista metod transportu dla koszyka (z filtrowaniem wagi + darmowa dostawa) + */ + public function transportMethodsFront( $basket, $coupon ): array + { + global $settings; + + $cacheHandler = new \Shared\Cache\CacheHandler(); + $cacheKey = 'transport_methods_front'; + $cached = $cacheHandler->get( $cacheKey ); + + if ( $cached ) + { + $transports_tmp = unserialize( $cached ); + } + else + { + $transports_tmp = $this->allActive(); + $cacheHandler->set( $cacheKey, $transports_tmp ); + } + + $wp_summary = \Domain\Basket\BasketCalculator::summaryWp( $basket ); + + $transports = []; + foreach ( $transports_tmp as $tr ) + { + if ( $tr['max_wp'] == null ) + $transports[] = $tr; + elseif ( $tr['max_wp'] != null and $wp_summary <= $tr['max_wp'] ) + $transports[] = $tr; + } + + if ( \Shared\Helpers\Helpers::normalize_decimal( \Domain\Basket\BasketCalculator::summaryPrice( $basket, $coupon ) ) >= \Shared\Helpers\Helpers::normalize_decimal( $settings['free_delivery'] ) ) + { + for ( $i = 0; $i < count( $transports ); $i++ ) { + if ( $transports[$i]['delivery_free'] == 1 ) { + $transports[$i]['cost'] = 0.00; + } + } + } + + return $transports; + } + + /** + * Koszt transportu z cache + */ + public function transportCostCached( $transportId ) + { + $cacheHandler = new \Shared\Cache\CacheHandler(); + $cacheKey = 'transport_cost_' . $transportId; + $cached = $cacheHandler->get( $cacheKey ); + + if ( $cached ) + { + return unserialize( $cached ); + } + + $cost = $this->getTransportCost( (int)$transportId ); + $cacheHandler->set( $cacheKey, $cost ); + + return $cost; + } + + /** + * Aktywny transport z cache + */ + public function findActiveByIdCached( $transportId ) + { + $cacheHandler = new \Shared\Cache\CacheHandler(); + $cacheKey = 'transport' . $transportId; + $cached = $cacheHandler->get( $cacheKey ); + + if ( $cached ) + { + return unserialize( $cached ); + } + + $transport = $this->findActiveById( (int)$transportId ); + $cacheHandler->set( $cacheKey, $transport ); + + return $transport; + } + + /** + * Transporty powiązane z metodą płatności + */ + public function forPaymentMethod( int $paymentMethodId ): array + { + if ( $paymentMethodId <= 0 ) + { + return []; + } + + $transportIds = $this->db->select( + 'pp_shop_transport_payment_methods', + 'id_transport', + ['id_payment_method' => $paymentMethodId] + ); + + if ( !is_array( $transportIds ) || empty( $transportIds ) ) + { + return []; + } + + $transports = $this->db->select( + 'pp_shop_transports', + '*', + ['AND' => ['id' => $transportIds, 'status' => 1], 'ORDER' => ['o' => 'ASC']] + ); + + if ( !is_array( $transports ) ) + { + return []; + } + + foreach ( $transports as &$transport ) + { + $transport = $this->normalizeTransport( $transport ); + } + unset( $transport ); + + return $transports; + } + private function savePaymentMethodLinks(int $transportId, $paymentMethods): void { if (is_array($paymentMethods)) { diff --git a/autoload/admin/Controllers/ShopOrderController.php b/autoload/admin/Controllers/ShopOrderController.php index 63baae5..fa528f6 100644 --- a/autoload/admin/Controllers/ShopOrderController.php +++ b/autoload/admin/Controllers/ShopOrderController.php @@ -192,7 +192,7 @@ class ShopOrderController 'order' => $this->service->details($orderId), 'order_statuses' => $this->service->statuses(), 'transport' => \shop\Transport::transport_list(), - 'payment_methods' => \shop\PaymentMethod::method_list(), + 'payment_methods' => ( new \Domain\PaymentMethod\PaymentMethodRepository( $GLOBALS['mdb'] ) )->allActive(), ]); } diff --git a/autoload/front/Controllers/ShopBasketController.php b/autoload/front/Controllers/ShopBasketController.php index 5a114f4..d647101 100644 --- a/autoload/front/Controllers/ShopBasketController.php +++ b/autoload/front/Controllers/ShopBasketController.php @@ -8,10 +8,12 @@ class ShopBasketController ]; private $orderRepository; + private $paymentMethodRepository; - public function __construct( \Domain\Order\OrderRepository $orderRepository ) + public function __construct( \Domain\Order\OrderRepository $orderRepository, \Domain\PaymentMethod\PaymentMethodRepository $paymentMethodRepository ) { $this->orderRepository = $orderRepository; + $this->paymentMethodRepository = $paymentMethodRepository; } public function basketMessageSave() @@ -146,7 +148,7 @@ class ShopBasketController $values['attributes'] = $attributes; } - $values['wp'] = \front\factory\ShopProduct::product_wp( $values[ 'product-id' ] ); + $values['wp'] = ( new \Domain\Product\ProductRepository( $GLOBALS['mdb'] ) )->getWeightCached( (int)$values[ 'product-id' ] ); $attributes_implode = ''; if ( is_array( $attributes ) and count( $attributes ) > 0 ) @@ -247,8 +249,8 @@ class ShopBasketController echo json_encode( [ 'result' => 'ok', - 'payment_methods' => \front\view\ShopPaymentMethod::basket_payment_methods( - \front\factory\ShopPaymentMethod::payment_methods_by_transport( \Shared\Helpers\Helpers::get( 'transport_method_id' ) ), + 'payment_methods' => \front\Views\ShopPaymentMethod::basketPaymentMethods( + $this->paymentMethodRepository->paymentMethodsByTransport( (int)\Shared\Helpers\Helpers::get( 'transport_method_id' ) ), \Shared\Helpers\Helpers::get( 'payment_method_id' ) ) ] ); @@ -271,8 +273,8 @@ class ShopBasketController 'lang_id' => $lang_id, 'client' => \Shared\Helpers\Helpers::get_session( 'client' ), 'basket' => \Shared\Helpers\Helpers::get_session( 'basket' ), - 'transport' => \front\factory\ShopTransport::transport( \Shared\Helpers\Helpers::get_session( 'basket-transport-method-id' ) ), - 'payment_method' => \front\factory\ShopPaymentMethod::payment_method( \Shared\Helpers\Helpers::get_session( 'basket-payment-method-id' ) ), + 'transport' => ( new \Domain\Transport\TransportRepository( $GLOBALS['mdb'] ) )->findActiveByIdCached( \Shared\Helpers\Helpers::get_session( 'basket-transport-method-id' ) ), + 'payment_method' => $this->paymentMethodRepository->paymentMethodCached( (int)\Shared\Helpers\Helpers::get_session( 'basket-payment-method-id' ) ), 'addresses' => ( new \Domain\Client\ClientRepository( $GLOBALS['mdb'] ) )->clientAddresses( (int)$client['id'] ), 'settings' => $settings, 'coupon' => \Shared\Helpers\Helpers::get_session( 'coupon' ), @@ -368,7 +370,7 @@ class ShopBasketController 'coupon' => $coupon, 'transport_id' => \Shared\Helpers\Helpers::get_session( 'basket-transport-method-id' ), 'transport_methods' => \Shared\Tpl\Tpl::view( 'shop-basket/basket-transport-methods', [ - 'transports_methods' => \front\factory\ShopTransport::transport_methods( $basket, $coupon ), + 'transports_methods' => ( new \Domain\Transport\TransportRepository( $GLOBALS['mdb'] ) )->transportMethodsFront( $basket, $coupon ), 'transport_id' => $basket_transport_method_id ] ), 'payment_method_id' => $payment_method_id, @@ -394,7 +396,7 @@ class ShopBasketController 'basket_mini_value' => \Domain\Basket\BasketCalculator::summaryPrice( $basket, $coupon ), 'products_count' => count( $basket ), 'transport_methods' => \Shared\Tpl\Tpl::view( 'shop-basket/basket-transport-methods', [ - 'transports_methods' => \front\factory\ShopTransport::transport_methods( $basket, $coupon ), + 'transports_methods' => ( new \Domain\Transport\TransportRepository( $GLOBALS['mdb'] ) )->transportMethodsFront( $basket, $coupon ), 'transport_id' => $basket_transport_method_id ] ) ] ); diff --git a/autoload/front/Controllers/ShopOrderController.php b/autoload/front/Controllers/ShopOrderController.php index d0fdfe5..b68cf4a 100644 --- a/autoload/front/Controllers/ShopOrderController.php +++ b/autoload/front/Controllers/ShopOrderController.php @@ -95,7 +95,7 @@ class ShopOrderController if ( is_array( $order['products'] ) && count( $order['products'] ) ): $summary_tmp = 0; foreach ( $order['products'] as $product ): - $product_tmp = \front\factory\ShopProduct::product_details( $product['product_id'], $lang['id'] ); + $product_tmp = ( new \Domain\Product\ProductRepository( $GLOBALS['mdb'] ) )->productDetailsFrontCached( (int)$product['product_id'], $lang['id'] ); $summary_tmp += \Shared\Helpers\Helpers::normalize_decimal( $product['price_netto'] + $product['price_netto'] * $product['vat'] / 100 ) * $product['quantity']; endforeach; $summary_tmp += $order['transport_cost']; diff --git a/autoload/front/controls/class.ShopProduct.php b/autoload/front/Controllers/ShopProductController.php similarity index 50% rename from autoload/front/controls/class.ShopProduct.php rename to autoload/front/Controllers/ShopProductController.php index eb6b8a0..5ee5072 100644 --- a/autoload/front/controls/class.ShopProduct.php +++ b/autoload/front/Controllers/ShopProductController.php @@ -1,21 +1,32 @@ categoryRepository = $categoryRepository; + } + + public function lazyLoadingProducts() { global $lang_id; $output = ''; - $categoryRepo = new \Domain\Category\CategoryRepository( $GLOBALS['mdb'] ); $categoryId = (int)\Shared\Helpers\Helpers::get( 'category_id' ); - $products_ids = $categoryRepo->productsId( $categoryId, $categoryRepo->getCategorySort( $categoryId ), $lang_id, 8, (int)\Shared\Helpers\Helpers::get( 'offset' ) ); + $products_ids = $this->categoryRepository->productsId( + $categoryId, + $this->categoryRepository->getCategorySort( $categoryId ), + $lang_id, + 8, + (int)\Shared\Helpers\Helpers::get( 'offset' ) + ); if ( is_array( $products_ids ) ): foreach ( $products_ids as $product_id ): - $output .= \Shared\Tpl\Tpl::view('shop-product/product-mini', [ - 'product' => Product::getFromCache( $product_id, $lang_id ) + $output .= \Shared\Tpl\Tpl::view( 'shop-product/product-mini', [ + 'product' => \shop\Product::getFromCache( $product_id, $lang_id ) ] ); endforeach; endif; @@ -24,13 +35,14 @@ class ShopProduct exit; } - public static function warehouse_message() + public function warehouseMessage() { global $lang_id; $values = json_decode( \Shared\Helpers\Helpers::get( 'values' ), true ); - foreach( $values as $key => $val ) + $attributes = []; + foreach ( $values as $key => $val ) { if ( $key != 'product-id' and $key != 'quantity' ) $attributes[] = $val; @@ -41,23 +53,23 @@ class ShopProduct exit; } - // wyświetlenie atrybutów w widoku produktu - static public function draw_product_attributes() + public function drawProductAttributes() { - global $mdb, $lang_id; + global $lang_id; $combination = ''; - $selected_values = \Shared\Helpers\Helpers::get( 'selected_values' ); - foreach ( $selected_values as $value ) { + + foreach ( $selected_values as $value ) + { $combination .= $value; if ( $value != end( $selected_values ) ) $combination .= '|'; } $product_id = \Shared\Helpers\Helpers::get( 'product_id' ); - $product = Product::getFromCache( $product_id, $lang_id ); - $product_data = $product -> getProductDataBySelectedAttributes( $combination ); + $product = \shop\Product::getFromCache( $product_id, $lang_id ); + $product_data = $product->getProductDataBySelectedAttributes( $combination ); echo json_encode( [ 'product_data' => $product_data ] ); exit; diff --git a/autoload/front/Views/ShopPaymentMethod.php b/autoload/front/Views/ShopPaymentMethod.php new file mode 100644 index 0000000..d6a0c9a --- /dev/null +++ b/autoload/front/Views/ShopPaymentMethod.php @@ -0,0 +1,13 @@ +payment_methods = $payment_methods; + $tpl->payment_id = $payment_id; + return $tpl->render( 'shop-basket/basket-payments-methods' ); + } +} diff --git a/autoload/front/Views/ShopProduct.php b/autoload/front/Views/ShopProduct.php new file mode 100644 index 0000000..54edaff --- /dev/null +++ b/autoload/front/Views/ShopProduct.php @@ -0,0 +1,18 @@ + function() { global $mdb; return new \front\Controllers\ShopBasketController( - new \Domain\Order\OrderRepository( $mdb ) + new \Domain\Order\OrderRepository( $mdb ), + new \Domain\PaymentMethod\PaymentMethodRepository( $mdb ) ); }, 'ShopClient' => function() { @@ -197,6 +198,12 @@ class Site new \Domain\Producer\ProducerRepository( $mdb ) ); }, + 'ShopProduct' => function() { + global $mdb; + return new \front\Controllers\ShopProductController( + new \Domain\Category\CategoryRepository( $mdb ) + ); + }, ]; } } diff --git a/autoload/front/factory/class.ShopPaymentMethod.php b/autoload/front/factory/class.ShopPaymentMethod.php deleted file mode 100644 index d8b0957..0000000 --- a/autoload/front/factory/class.ShopPaymentMethod.php +++ /dev/null @@ -1,74 +0,0 @@ -getApiloPaymentTypeId( (int)$payment_method_id ); - } - - public static function payment_methods_by_transport( $transport_method_id ) - { - $transport_method_id = (int)$transport_method_id; - $cacheHandler = new \Shared\Cache\CacheHandler(); - $cacheKey = 'payment_methods_by_transport' . $transport_method_id; - $objectData = $cacheHandler->get( $cacheKey ); - - if ( $objectData ) { - return unserialize( $objectData ); - } - - $payments = self::repo()->forTransport( $transport_method_id ); - $cacheHandler->set( $cacheKey, $payments ); - - return $payments; - } - - public static function is_payment_active( $payment_method_id ) - { - return self::repo()->isActive( (int)$payment_method_id ); - } - - public static function payment_method( $payment_method_id ) - { - $payment_method_id = (int)$payment_method_id; - $cacheHandler = new \Shared\Cache\CacheHandler(); - $cacheKey = 'payment_method' . $payment_method_id; - $objectData = $cacheHandler->get( $cacheKey ); - - if ( !$objectData ) - { - $payment_method = self::repo()->findActiveById( $payment_method_id ); - $cacheHandler->set( $cacheKey, $payment_method ); - } - else - { - return unserialize( $objectData ); - } - - return $payment_method; - } - - public static function payment_methods() - { - $cacheHandler = new \Shared\Cache\CacheHandler(); - $cacheKey = 'payment_methods'; - $objectData = $cacheHandler->get( $cacheKey ); - - if ( $objectData ) { - return unserialize( $objectData ); - } - - $payment_methods = self::repo()->allActive(); - $cacheHandler->set( $cacheKey, $payment_methods ); - - return $payment_methods; - } -} diff --git a/autoload/front/factory/class.ShopProduct.php b/autoload/front/factory/class.ShopProduct.php deleted file mode 100644 index e42a2bc..0000000 --- a/autoload/front/factory/class.ShopProduct.php +++ /dev/null @@ -1,410 +0,0 @@ - get( 'pp_shop_products', 'sku', [ 'id' => $product_id ] ); - if ( !$sku and $parent ) - { - $parent_id = $mdb -> get( 'pp_shop_products', 'parent_id', [ 'id' => $product_id ] ); - if ( $parent_id ) - return \front\factory\ShopProduct::get_product_sku( $parent_id, true ); - else - return false; - } - else - { - return $sku; - } - } - - // get_product_ean - static public function get_product_ean( $product_id, $parent = false ) - { - global $mdb; - - $ean = $mdb -> get( 'pp_shop_products', 'ean', [ 'id' => $product_id ] ); - if ( !$ean and $parent ) - { - $parent_id = $mdb -> get( 'pp_shop_products', 'parent_id', [ 'id' => $product_id ] ); - if ( $parent_id ) - return \front\factory\ShopProduct::get_product_ean( $parent_id, true ); - else - return false; - } - else - { - return $ean; - } - } - - static public function is_product_active( int $product_id ) - { - global $mdb; - - $cacheHandler = new \Shared\Cache\CacheHandler(); - $cacheKey = "\front\factory\ShopProduct::is_product_active:$product_id"; - - $objectData = $cacheHandler -> get( $cacheKey ); - - if ( !$objectData ) - { - $is_active = $mdb -> get( 'pp_shop_products', 'status', [ 'id' => $product_id ] ); - - $cacheHandler -> set( $cacheKey, $is_active ); - } - else - { - return unserialize( $objectData ); - } - return $is_active; - } - - static public function product_url( $product ) - { - if ( $product['language']['seo_link'] ) - { - $url = '/' . $product['language']['seo_link']; - } - else - { - if ( $product['parent_id'] ) - $url = '/p-' . $product['parent_id'] . '-' . \Shared\Helpers\Helpers::seo( $product['language']['name'] ); - else - $url = '/p-' . $product['id'] . '-' . \Shared\Helpers\Helpers::seo( $product['language']['name'] ); - } - return $url; - } - - static public function get_minimal_price( $id_product, $price_brutto_promo = null ) - { - global $mdb; - - $cacheHandler = new \Shared\Cache\CacheHandler(); - $cacheKey = 'get_minimal_price:' . $id_product; - $objectData = $cacheHandler->get( $cacheKey ); - - if ( !$objectData ) - { - $price = $mdb -> min( 'pp_shop_product_price_history', 'price', [ 'AND' => [ 'id_product' => $id_product, 'price[!]' => str_replace( ',', '.', $price_brutto_promo ) ] ] ); - $cacheHandler->set( $cacheKey, $price ); - } - else - { - return unserialize( $objectData ); - } - - return $price; - } - - public static function product_categories( $product_id ) - { - global $mdb; - - if ( $parent_id = $mdb -> get( 'pp_shop_products', 'parent_id', [ 'id' => $product_id ] ) ) - return \R::getAll( 'SELECT category_id FROM pp_shop_products_categories WHERE product_id = ?', [ $parent_id ] ); - else - return \R::getAll( 'SELECT category_id FROM pp_shop_products_categories WHERE product_id = ?', [ $product_id ] ); - } - - public static function product_name( $product_id ) - { - global $mdb, $lang_id; - - $cacheHandler = new \Shared\Cache\CacheHandler(); - $cacheKey = 'product_name' . $lang_id . '_' . $product_id; - $objectData = $cacheHandler->get( $cacheKey ); - - if ( !$objectData ) - { - $product_name = $mdb -> get( 'pp_shop_products_langs', 'name', [ 'AND' => [ 'product_id' => (int)$product_id, 'lang_id' => $lang_id ] ] ); - - $cacheHandler->set( $cacheKey, $product_name ); - } - else - { - return unserialize( $objectData ); - } - - return $product_name; - } - - public static function product_image( $product_id ) - { - global $mdb; - - $cacheHandler = new \Shared\Cache\CacheHandler(); - $cacheKey = 'product_image:' . $product_id; - $objectData = $cacheHandler->get( $cacheKey ); - - if ( !$objectData ) - { - $results = $mdb -> query( 'SELECT src FROM pp_shop_products_images WHERE product_id = :product_id ORDER BY o ASC LIMIT 1', [ ':product_id' => (int)$product_id ] ) -> fetchAll( \PDO::FETCH_ASSOC ); - $product_image = $results[ 0 ][ 'src' ]; - - $cacheHandler->set( $cacheKey, $product_image ); - } - else - { - return unserialize( $objectData ); - } - - return $product_image; - } - - public static function product_wp( $product_id ) - { - global $mdb; - - $cacheHandler = new \Shared\Cache\CacheHandler(); - $cacheKey = "\front\factory\ShopProduct::product_wp:$product_id"; - - $objectData = $cacheHandler -> get( $cacheKey ); - - if ( !$objectData ) - { - $product_wp = $mdb -> get( 'pp_shop_products', 'wp', [ 'id' => $product_id ] ); - - $cacheHandler -> set( $cacheKey, $product_wp ); - } - else - { - return unserialize( $objectData ); - } - return $product_wp; - } - - public static function random_products( $product_id, $lang_id = 'pl' ) - { - global $mdb; - - $cacheHandler = new \Shared\Cache\CacheHandler(); - $cacheKey = 'random_products_' . $product_id . '_' . $lang_id; - $objectData = $cacheHandler->get( $cacheKey ); - - if ( !$objectData ) - { - $results = $mdb -> query( 'SELECT id FROM pp_shop_products WHERE status = 1 ORDER BY RAND() LIMIT 6' ) -> fetchAll(); - if ( is_array( $results ) and!empty( $results ) ) - foreach ( $results as $row ) - $products[] = \front\factory\ShopProduct::product_details( $row[ 'id' ], $lang_id ); - - $cacheHandler->set( $cacheKey, $products ); - } - else - { - return unserialize( $objectData ); - } - - return $products; - } - - public static function promoted_products( $limit = 6 ) - { - global $mdb; - - $cacheHandler = new \Shared\Cache\CacheHandler(); - $cacheKey = "promoted_products-$limit"; - $objectData = $cacheHandler->get( $cacheKey ); - - if ( !$objectData ) - { - $results = $mdb -> query( 'SELECT id FROM pp_shop_products WHERE status = 1 AND promoted = 1 ORDER BY RAND() LIMIT ' . $limit ) -> fetchAll(); - if ( is_array( $results ) and!empty( $results ) ) - foreach ( $results as $row ) - $products[] = $row[ 'id' ]; - - $cacheHandler->set( $cacheKey, $products ); - } - else - { - return unserialize( $objectData ); - } - - return $products; - } - - public static function top_products( $limit = 6 ) - { - global $mdb; - - $date_30_days_ago = date('Y-m-d', strtotime('-30 days')); - - $products = $mdb -> query( "SELECT COUNT(0) AS sell_count, psop.parent_product_id FROM pp_shop_order_products AS psop INNER JOIN pp_shop_orders AS pso ON pso.id = psop.order_id WHERE pso.date_order >= '$date_30_days_ago' GROUP BY parent_product_id ORDER BY sell_count DESC")->fetchAll(\PDO::FETCH_ASSOC); - - foreach ( $products as $product ) - { - if ( \front\factory\ShopProduct::is_product_active( $product['parent_product_id'] ) ) - $product_ids[] = $product['parent_product_id']; - } - - return $product_ids; - } - - public static function new_products( $limit = 10 ) { - global $mdb; - - $results = $mdb->query(" - SELECT id - FROM pp_shop_products - WHERE status = 1 - ORDER BY date_add DESC - LIMIT $limit - ")->fetchAll(\PDO::FETCH_ASSOC); - - return array_column($results, 'id'); - } - - public static function product_details( $product_id, $lang_id ) - { - global $mdb; - - if ( !$product_id ) - return false; - - $cacheHandler = new \Shared\Cache\CacheHandler(); - $cacheKey = "\front\factory\ShopProduct::product_details:$product_id:$lang_id"; - - $objectData = $cacheHandler->get($cacheKey); - - if ( !$objectData ) - { - $product = $mdb -> get( 'pp_shop_products', '*', [ 'id' => (int)$product_id ] ); - - $results = $mdb -> select( 'pp_shop_products_langs', '*', [ 'AND' => [ 'product_id' => (int)$product_id, 'lang_id' => $lang_id ] ] ); - if ( is_array( $results ) ) - foreach ( $results as $row ) - { - if ( $row[ 'copy_from' ] ) - { - $results2 = $mdb -> select( 'pp_shop_products_langs', '*', [ 'AND' => [ 'product_id' => (int)$product_id, 'lang_id' => $row[ 'copy_from' ] ] ] ); - if ( is_array( $results2 ) ) - foreach ( $results2 as $row2 ) - $product[ 'language' ] = $row2; - } - else - $product[ 'language' ] = $row; - } - - $results = $mdb -> query( 'SELECT ' - . 'DISTINCT( attribute_id ) ' - . 'FROM ' - . 'pp_shop_products_attributes AS pspa ' - . 'INNER JOIN pp_shop_attributes AS psa ON psa.id = pspa.attribute_id ' - . 'WHERE ' - . 'product_id = ' . (int)$product_id . ' ' - . 'ORDER BY ' - . 'o ASC' ) -> fetchAll(); - if ( is_array( $results ) ) - foreach ( $results as $row ) - { - $row[ 'type' ] = $mdb -> get( 'pp_shop_attributes', - 'type', - [ 'id' => $row[ 'attribute_id' ] ] - ); - - $row[ 'language' ] = $mdb -> get( 'pp_shop_attributes_langs', - [ 'name' ], - [ 'AND' => - [ 'attribute_id' => $row[ 'attribute_id' ], 'lang_id' => $lang_id ] - ] - ); - - $results2 = $mdb -> query( 'SELECT ' - . 'value_id, is_default ' - . 'FROM ' - . 'pp_shop_products_attributes AS pspa ' - . 'INNER JOIN pp_shop_attributes_values AS psav ON psav.id = pspa.value_id ' - . 'WHERE ' - . 'product_id = :product_id ' - . 'AND ' - . 'pspa.attribute_id = :attribute_id ', - [ - ':product_id' => $product_id, - ':attribute_id' => $row[ 'attribute_id' ] - ] - ) -> fetchAll( \PDO::FETCH_ASSOC ); - - if ( is_array( $results2 ) ) - foreach ( $results2 as $row2 ) - { - $row2[ 'language' ] = $mdb -> get( 'pp_shop_attributes_values_langs', - [ 'name', 'value' ], - [ 'AND' => - [ 'value_id' => $row2[ 'value_id' ], 'lang_id' => $lang_id ] - ] - ); - $row[ 'values' ][] = $row2; - } - - $product[ 'attributes' ][] = $row; - } - - $product[ 'images' ] = $mdb -> select( 'pp_shop_products_images', '*', [ 'product_id' => (int)$product_id, 'ORDER' => [ 'o' => 'ASC', 'id' => 'ASC' ] ] ); - $product[ 'files' ] = $mdb -> select( 'pp_shop_products_files', '*', [ 'product_id' => (int)$product_id ] ); - $product[ 'categories' ] = $mdb -> select( 'pp_shop_products_categories', 'category_id', [ 'product_id' => (int)$product_id ] ); - - $product[ 'products_related' ] = $mdb -> select( 'pp_shop_products_related', 'product_related_id', [ 'product_id' => (int)$product_id ] ); - - $set_id = $mdb -> select( 'pp_shop_product_sets_products', 'set_id', [ 'product_id' => (int)$product_id ] ); - $products_sets = $mdb -> select( 'pp_shop_product_sets_products', 'product_id', [ 'set_id' => (int)$set_id ] ); - $products_sets = array_unique( $products_sets ); - - $product[ 'products_sets' ] = $products_sets; - - $attributes = $mdb -> select( 'pp_shop_products_attributes', [ 'attribute_id', 'value_id' ], [ 'product_id' => (int)$product_id ] ); - if ( is_array( $attributes ) ): foreach ( $attributes as $attribute ): - $attributes_tmp[ $attribute[ 'attribute_id' ] ][] = $attribute[ 'value_id' ]; - endforeach; - endif; - - if ( is_array( $attributes_tmp ) ) - $product[ 'permutations' ] = \Shared\Helpers\Helpers::array_cartesian_product( $attributes_tmp ); - - $cacheHandler -> set( $cacheKey, $product ); - } - else - { - return unserialize($objectData); - } - - return $product; - } - - public static function warehouse_message_zero( $id_product, $lang_id ) - { - global $mdb, $lang_id; - return $mdb -> get( 'pp_shop_products_langs', 'warehouse_message_zero', [ 'AND' => [ 'product_id' => $id_product, 'lang_id' => $lang_id ] ] ); - } - - public static function warehouse_message_nonzero( $id_product, $lang_id ) - { - global $mdb, $lang_id; - return $mdb -> get( 'pp_shop_products_langs', 'warehouse_message_nonzero', [ 'AND' => [ 'product_id' => $id_product, 'lang_id' => $lang_id ] ] ); - } - - //TO:DO do usunięcia - public static function product_both_price( $product_id ) - { - global $mdb; - return $mdb -> get( 'pp_shop_products', [ 'price_brutto', 'price_brutto_promo' ], [ 'id' => (int)$product_id ] ); - } - - //TO:DO do usunięcia - public static function product_price( $product_id ) - { - global $mdb; - - $product = $mdb -> get( 'pp_shop_products', [ 'price_brutto', 'price_brutto_promo', 'vat' ], [ 'id' => (int)$product_id ] ); - if ( $product[ 'price_brutto_promo' ] ) - return $product[ 'price_brutto_promo' ]; - else - return $product[ 'price_brutto' ]; - } - -} \ No newline at end of file diff --git a/autoload/front/factory/class.ShopPromotion.php b/autoload/front/factory/class.ShopPromotion.php deleted file mode 100644 index f1014fa..0000000 --- a/autoload/front/factory/class.ShopPromotion.php +++ /dev/null @@ -1,215 +0,0 @@ - categories ); - $condition_categories = json_decode( $promotion -> condition_categories ); - - foreach ( $basket as $key => $val ) - { - $product_promotion = \shop\Product::is_product_on_promotion( $val['product-id'] ); - - if ( !$product_promotion or $product_promotion and $promotion -> include_product_promo ) - { - $product_categories = \front\factory\ShopProduct::product_categories( $val[ 'product-id' ] ); - foreach ( $product_categories as $category_tmp ) - { - if ( in_array( $category_tmp[ 'category_id' ], $condition_categories ) or in_array( $category_tmp[ 'category_id' ], $categories ) ) - { - $basket[$key]['discount_type'] = $promotion -> discount_type; - $basket[$key]['discount_amount'] = $promotion -> amount; - $basket[$key]['discount_include_coupon'] = $promotion -> include_coupon; - $basket[$key]['include_product_promo'] = $promotion -> include_product_promo; - } - } - } - } - return $basket; - } - - //! promocja na produkty z kategorii 1 i 2 - static public function promotion_type_02( $basket, $promotion ) - { - $condition_1 = false; $condition_2 = false; - - $categories = json_decode( $promotion -> categories ); - $condition_categories = json_decode( $promotion -> condition_categories ); - - // sprawdzanie czy warunki są spełnione - if ( is_array( $condition_categories ) and is_array( $categories ) ) - { - foreach ( $basket as $key => $val ) - { - $product_categories = \front\factory\ShopProduct::product_categories( $val[ 'product-id' ] ); - foreach ( $product_categories as $category_tmp ) - { - // sprawdzam produkt pod kątem I kategorii - if ( !$condition_1 and in_array( $category_tmp[ 'category_id' ], $condition_categories ) ) - { - $condition_1 = true; - unset( $basket_tmp[ $key ] ); - } - } - } - - foreach ( $basket as $key => $val ) - { - $product_categories = \front\factory\ShopProduct::product_categories( $val[ 'product-id' ] ); - foreach ( $product_categories as $category_tmp ) - { - // sprawdzam produkt pod kątem II kategorii - if ( !$condition_2 and in_array( $category_tmp[ 'category_id' ], $categories ) ) - $condition_2 = true; - } - } - } - - // jeżeli warunki są spełnione to szukam produktów, którym można obniżyć cenę - if ( $condition_1 and $condition_2 ) - { - foreach ( $basket as $key => $val ) - { - $product_categories = \front\factory\ShopProduct::product_categories( $val[ 'product-id' ] ); - foreach ( $product_categories as $category_tmp ) - { - if ( in_array( $category_tmp[ 'category_id' ], $categories ) or in_array( $category_tmp['category_id'], $condition_categories ) ) - { - $basket[$key]['discount_type'] = $promotion -> discount_type; - $basket[$key]['discount_amount'] = $promotion -> amount; - $basket[$key]['discount_include_coupon'] = $promotion -> include_coupon; - $basket[$key]['include_product_promo'] = $promotion -> include_product_promo; - } - } - } - } - return $basket; - } - - //! promocja na najtańszy produkt z kategorii 1 lub 2 - static public function promotion_type_04( $basket, $promotion ) - { - $condition_1 = false; - $categories = json_decode( $promotion -> categories ); - - //! sprawdzanie czy warunki są spełnione - if ( is_array( $categories ) and is_array( $categories ) ) - { - foreach ( $basket as $key => $val ) - { - $product_promotion = \shop\Product::is_product_on_promotion( $val['product-id'] ); - - if ( !$product_promotion or $product_promotion and $promotion -> include_product_promo ) - { - $product_categories = \front\factory\ShopProduct::product_categories( $val[ 'product-id' ] ); - foreach ( $product_categories as $category_tmp ) - { - //! sprawdzam produkt pod kątem I kategorii - if ( !$condition_1[$key] and in_array( $category_tmp[ 'category_id' ], $categories ) ) - $condition_1[$key] = true; - } - } - } - } - - if ( count( $condition_1 ) >= $promotion -> min_product_count ) - { - foreach ( $basket as $key => $val ) - { - $price = \shop\Product::get_product_price( $val['product-id'] ); - if ( !$cheapest_position or $cheapest_position['price'] > $price ) - { - $cheapest_position['price'] = $price; - $cheapest_position['key'] = $key; - } - } - - $basket[$cheapest_position['key']]['quantity'] = 1; - $basket[$cheapest_position['key']]['discount_type'] = 3; - $basket[$cheapest_position['key']]['discount_amount'] = $promotion -> price_cheapest_product; - $basket[$cheapest_position['key']]['discount_include_coupon'] = $promotion -> include_coupon; - $basket[$cheapest_position['key']]['include_product_promo'] = $promotion -> include_product_promo; - } - - return $basket; - } - - //! promocja na cały koszyk - static public function promotion_type_05( $basket, $promotion ) - { - foreach ( $basket as $key => $val ) - { - $product_promotion = \shop\Product::is_product_on_promotion( $val['product-id'] ); - - if ( !$product_promotion or $product_promotion and $promotion -> include_product_promo ) - { - $product_categories = \front\factory\ShopProduct::product_categories( $val[ 'product-id' ] ); - foreach ( $product_categories as $category_tmp ) - { - $basket[$key]['discount_type'] = $promotion -> discount_type; - $basket[$key]['discount_amount'] = $promotion -> amount; - $basket[$key]['discount_include_coupon'] = $promotion -> include_coupon; - $basket[$key]['include_product_promo'] = $promotion -> include_product_promo; - } - } - } - return $basket; - } - - //! Rabat procentowy na produkty z kategorii I jeżeli w koszyku jest produkt z kategorii II - static public function promotion_type_01( $basket, $promotion ) - { - $condition = false; - $categories = json_decode( $promotion -> categories ); - $condition_categories = json_decode( $promotion -> condition_categories ); - - // sprawdzanie czy warunki są spełnione - if ( is_array( $condition_categories ) and is_array( $categories ) ) - { - foreach ( $basket as $key => $val ) - { - $product_categories = \front\factory\ShopProduct::product_categories( $val[ 'product-id' ] ); - foreach ( $product_categories as $category_tmp ) - { - if ( in_array( $category_tmp[ 'category_id' ], $condition_categories ) ) - { - $condition = true; - } - } - } - } - - // jeżeli warunki są spełnione to szukam produktów, którym można obniżyć cenę - if ( $condition ) - { - foreach ( $basket as $key => $val ) - { - $product_categories = \front\factory\ShopProduct::product_categories( $val[ 'product-id' ] ); - foreach ( $product_categories as $category_tmp ) - { - if ( in_array( $category_tmp[ 'category_id' ], $categories ) ) - { - $basket[$key]['discount_type'] = $promotion -> discount_type; - $basket[$key]['discount_amount'] = $promotion -> amount; - $basket[$key]['discount_include_coupon'] = $promotion -> include_coupon; - $basket[$key]['include_product_promo'] = $promotion -> include_product_promo; - } - } - } - } - return $basket; - } -} \ No newline at end of file diff --git a/autoload/front/factory/class.ShopStatuses.php b/autoload/front/factory/class.ShopStatuses.php deleted file mode 100644 index 0e20377..0000000 --- a/autoload/front/factory/class.ShopStatuses.php +++ /dev/null @@ -1,20 +0,0 @@ -getApiloStatusId( (int)$status_id ); - } - - // get_shop_status_by_integration_status_id - static public function get_shop_status_by_integration_status_id( $integration, $integration_status_id ) - { - global $mdb; - $repo = new \Domain\ShopStatus\ShopStatusRepository( $mdb ); - return $repo->getByIntegrationStatusId( (string)$integration, (int)$integration_status_id ); - } -} \ No newline at end of file diff --git a/autoload/front/factory/class.ShopTransport.php b/autoload/front/factory/class.ShopTransport.php deleted file mode 100644 index 6f5b3d4..0000000 --- a/autoload/front/factory/class.ShopTransport.php +++ /dev/null @@ -1,99 +0,0 @@ -getApiloCarrierAccountId($transport_method_id); - } - - public static function transport_methods( $basket, $coupon ) - { - global $mdb, $settings; - - $cacheHandler = new \Shared\Cache\CacheHandler(); - $cacheKey = "\front\factory\ShopTransport::transport_methods"; - - $objectData = $cacheHandler -> get( $cacheKey ); - - if ( !$objectData ) - { - $repo = new \Domain\Transport\TransportRepository($mdb); - $transports_tmp = $repo->allActive(); - - $cacheHandler -> set( $cacheKey, $transports_tmp ); - } - else - { - $transports_tmp = unserialize( $objectData ); - } - - $wp_summary = \Domain\Basket\BasketCalculator::summaryWp( $basket ); - - foreach ( $transports_tmp as $tr ) - { - if ( $tr['max_wp'] == null ) - $transports[] = $tr; - elseif ( $tr['max_wp'] != null and $wp_summary <= $tr['max_wp'] ) - $transports[] = $tr; - } - - - if ( \Shared\Helpers\Helpers::normalize_decimal( \Domain\Basket\BasketCalculator::summaryPrice( $basket, $coupon ) ) >= \Shared\Helpers\Helpers::normalize_decimal( $settings['free_delivery'] ) ) - { - for ( $i = 0; $i < count( $transports ); $i++ ){ - if($transports[ $i ]['delivery_free'] == 1) { - $transports[ $i ]['cost'] = 0.00; - } - } - } - - return $transports; - } - - public static function transport_cost( $transport_id ) - { - global $mdb; - - $cacheHandler = new \Shared\Cache\CacheHandler(); - $cacheKey = 'transport_cost_' . $transport_id; - $objectData = $cacheHandler->get( $cacheKey ); - - if ( !$objectData ) - { - $repo = new \Domain\Transport\TransportRepository($mdb); - $cost = $repo->getTransportCost($transport_id); - - $cacheHandler->set( $cacheKey, $cost ); - } - else - { - return unserialize( $objectData ); - } - return $cost; - } - - public static function transport( $transport_id ) - { - global $mdb; - - $cacheHandler = new \Shared\Cache\CacheHandler(); - $cacheKey = 'transport' . $transport_id; - $objectData = $cacheHandler->get( $cacheKey ); - - if ( !$objectData ) - { - $repo = new \Domain\Transport\TransportRepository($mdb); - $transport = $repo->findActiveById($transport_id); - - $cacheHandler->set( $cacheKey, $transport ); - } - else - { - return unserialize( $objectData ); - } - return $transport; - } -} diff --git a/autoload/front/view/class.ShopPaymentMethod.php b/autoload/front/view/class.ShopPaymentMethod.php deleted file mode 100644 index 39cd5df..0000000 --- a/autoload/front/view/class.ShopPaymentMethod.php +++ /dev/null @@ -1,12 +0,0 @@ - payment_methods = $payment_methods; - $tpl -> payment_id = $payment_id; - return $tpl -> render( 'shop-basket/basket-payments-methods' ); - } -} diff --git a/autoload/front/view/class.ShopTransport.php b/autoload/front/view/class.ShopTransport.php deleted file mode 100644 index c8a619a..0000000 --- a/autoload/front/view/class.ShopTransport.php +++ /dev/null @@ -1,6 +0,0 @@ - \front\factory\ShopProduct::promoted_products( $limit ) + 'products' => ( new \Domain\Product\ProductRepository( $GLOBALS['mdb'] ) )->promotedProductIdsCached( $limit ) ] ), $html ); @@ -285,7 +285,7 @@ class Site $products_top[1] ? $pattern = '[PRODUKTY_TOP:' . $products_top[1] . ']' : $pattern = '[PRODUKTY_TOP]'; - $products_id_arr = \front\factory\ShopProduct::top_products( $limit ); + $products_id_arr = ( new \Domain\Product\ProductRepository( $GLOBALS['mdb'] ) )->topProductIds( $limit ); foreach ( $products_id_arr as $product_id ){ $top_products_arr[] = Product::getFromCache( (int)$product_id, $lang_id ); @@ -313,7 +313,7 @@ class Site $products_top[1] ? $pattern = '[PRODUKTY_NEW:' . $products_top[1] . ']' : $pattern = '[PRODUKTY_NEW]'; - $products_id_arr = \front\factory\ShopProduct::new_products( $limit ); + $products_id_arr = ( new \Domain\Product\ProductRepository( $GLOBALS['mdb'] ) )->newProductIds( $limit ); foreach ( $products_id_arr as $product_id ){ diff --git a/autoload/shop/class.Order.php b/autoload/shop/class.Order.php index d9fd7fc..ff82969 100644 --- a/autoload/shop/class.Order.php +++ b/autoload/shop/class.Order.php @@ -331,7 +331,7 @@ class Order implements \ArrayAccess if ( !(int)$this -> apilo_order_id ) return true; - $payment_type = (int)\front\factory\ShopPaymentMethod::get_apilo_payment_method_id( (int)$this -> payment_method_id ); + $payment_type = (int)( new \Domain\PaymentMethod\PaymentMethodRepository( $mdb ) )->getApiloPaymentTypeId( (int)$this -> payment_method_id ); if ( $payment_type <= 0 ) $payment_type = 1; @@ -390,7 +390,7 @@ class Order implements \ArrayAccess curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, "PUT"); curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode( [ 'id' => $this -> apilo_order_id, - 'status' => (int)\front\factory\ShopStatuses::get_apilo_status_id( $status ) + 'status' => (int)( new \Domain\ShopStatus\ShopStatusRepository( $mdb ) )->getApiloStatusId( (int)$status ) ] ) ); curl_setopt( $ch, CURLOPT_HTTPHEADER, [ "Authorization: Bearer " . $access_token, diff --git a/autoload/shop/class.PaymentMethod.php b/autoload/shop/class.PaymentMethod.php deleted file mode 100644 index 15ffe2e..0000000 --- a/autoload/shop/class.PaymentMethod.php +++ /dev/null @@ -1,43 +0,0 @@ -allActive(); - } - - // get_apilo_payment_method_id - static public function get_apilo_payment_method_id( $payment_method_id ) - { - return self::repo()->getApiloPaymentTypeId( (int)$payment_method_id ); - } - - 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 ); - } -} diff --git a/autoload/shop/class.Product.php b/autoload/shop/class.Product.php index 249480b..8092da9 100644 --- a/autoload/shop/class.Product.php +++ b/autoload/shop/class.Product.php @@ -344,7 +344,7 @@ class Product implements \ArrayAccess foreach ( $products as $product_id ) { - if ( !\front\factory\ShopProduct::is_product_active( $product_id ) ) + if ( !( new \Domain\Product\ProductRepository( $mdb ) )->isProductActiveCached( (int)$product_id ) ) $products = array_diff( $products, [ $product_id ] ); } @@ -739,14 +739,14 @@ class Product implements \ArrayAccess if ( $quantity ) { - if ( $msg = \front\factory\ShopProduct::warehouse_message_nonzero( $id_product, $lang_id ) ) + 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 = \front\factory\ShopProduct::warehouse_message_zero( $id_product, $lang_id ) ) + 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 ]; diff --git a/autoload/shop/class.Promotion.php b/autoload/shop/class.Promotion.php index b5c32f1..8779333 100644 --- a/autoload/shop/class.Promotion.php +++ b/autoload/shop/class.Promotion.php @@ -74,29 +74,31 @@ class Promotion $results = self::get_active_promotions(); if ( is_array( $results ) and count( $results ) ) { + $promoRepo = new \Domain\Promotion\PromotionRepository( $mdb ); + foreach ( $results as $row ) { $promotion = new \shop\Promotion( $row ); // Promocja na cały koszyk if ( $promotion -> condition_type == 4 ) - return \front\factory\ShopPromotion::promotion_type_05( $basket_tmp, $promotion ); + return $promoRepo->applyTypeWholeBasket( $basket_tmp, $promotion ); // Najtańszy produkt w koszyku (z wybranych kategorii) za X zł if ( $promotion -> condition_type == 3 ) - return \front\factory\ShopPromotion::promotion_type_04( $basket_tmp, $promotion ); + return $promoRepo->applyTypeCheapestProduct( $basket_tmp, $promotion ); // Rabat procentowy na produkty z kategorii 1 lub kategorii 2 if ( $promotion -> condition_type == 5 ) - return \front\factory\ShopPromotion::promotion_type_03( $basket_tmp, $promotion ); + return $promoRepo->applyTypeCategoriesOr( $basket_tmp, $promotion ); // Rabat procentowy na produkty z kategorii I i kategorii II if ( $promotion -> condition_type == 2 ) - return \front\factory\ShopPromotion::promotion_type_02( $basket_tmp, $promotion ); + return $promoRepo->applyTypeCategoriesAnd( $basket_tmp, $promotion ); // Rabat procentowy na produkty z kategorii I jeżeli w koszyku jest produkt z kategorii II if ( $promotion -> condition_type == 1 ) - return \front\factory\ShopPromotion::promotion_type_01( $basket_tmp, $promotion ); + return $promoRepo->applyTypeCategoryCondition( $basket_tmp, $promotion ); } } return $basket; diff --git a/cron-turstmate.php b/cron-turstmate.php index 3a82d8c..cb45e2a 100644 --- a/cron-turstmate.php +++ b/cron-turstmate.php @@ -79,8 +79,8 @@ if ( is_array( $order_id ) and $order_id['id'] ) { 'local_id': , 'name': '', - 'product_url': 'https://pomysloweprezenty.pl', - "image_url": "https://pomysloweprezenty.pl" + 'product_url': 'https://pomysloweprezenty.pl', + "image_url": "https://pomysloweprezenty.plgetFirstImageCached( (int)$product['product_id'] );?>" } ]; diff --git a/cron.php b/cron.php index 68d5818..0c6b5fd 100644 --- a/cron.php +++ b/cron.php @@ -203,11 +203,12 @@ if ( $apilo_settings['enabled'] and $apilo_settings['sync_orders'] and $apilo_se $products_array = []; foreach ( $products as $product ) { - $sku = \front\factory\ShopProduct::get_product_sku( $product['product_id'], true ); + $productRepo = new \Domain\Product\ProductRepository( $mdb ); + $sku = $productRepo->getSkuWithFallback( (int)$product['product_id'], true ); $products_array[] = [ 'idExternal' => $product['product_id'], - 'ean' => \front\factory\ShopProduct::get_product_ean( $product['product_id'], true ), + 'ean' => $productRepo->getEanWithFallback( (int)$product['product_id'], true ), 'sku' => $sku ? $sku : md5( $product['product_id'] ), 'originalName' => $product['name'], 'originalPriceWithTax' => $product['price_brutto_promo'] ? str_replace( ',', '.', $product['price_brutto_promo'] ) : str_replace( ',', '.', $product['price_brutto'] ), @@ -301,7 +302,7 @@ if ( $apilo_settings['enabled'] and $apilo_settings['sync_orders'] and $apilo_se 'idExternal' => $order['id'], 'isInvoice' => $order['firm_name'] ? true : false, 'customerLogin' => $order['client_email'], - 'paymentType' => (int)\front\factory\ShopPaymentMethod::get_apilo_payment_method_id( $order['payment_method_id'] ), + 'paymentType' => (int)( new \Domain\PaymentMethod\PaymentMethodRepository( $mdb ) )->getApiloPaymentTypeId( (int)$order['payment_method_id'] ), 'originalCurrency' => 'PLN', 'originalAmountTotalWithTax' => str_replace( ',', '.', $order['summary'] ), 'orderItems' => $products_array, @@ -322,12 +323,12 @@ if ( $apilo_settings['enabled'] and $apilo_settings['sync_orders'] and $apilo_se 'city' => $city, 'zipCode' => $postal_code ], - 'carrierAccount' => (int)\front\factory\ShopTransport::get_apilo_carrier_account_id( $order['transport_id'] ), + 'carrierAccount' => (int)( new \Domain\Transport\TransportRepository( $mdb ) )->getApiloCarrierAccountId( (int)$order['transport_id'] ), 'orderNotes' => [ [ 'type' => 1, 'comment' => 'Wiadomość do zamówienia:
' . $order['message'] . '

' . $order_message ] ], - 'status' => (int)\front\factory\ShopStatuses::get_apilo_status_id( $order['status'] ), + 'status' => (int)( new \Domain\ShopStatus\ShopStatusRepository( $mdb ) )->getApiloStatusId( (int)$order['status'] ), 'platformId' => $apilo_settings['platform-id'] ]; @@ -388,7 +389,7 @@ if ( $apilo_settings['enabled'] and $apilo_settings['sync_orders'] and $apilo_se $postData['orderPayments'][] = [ 'amount' => str_replace( ',', '.', $order['summary'] ), 'paymentDate' => $payment_date -> format('Y-m-d\TH:i:s\Z'), - 'type' => \front\factory\ShopPaymentMethod::get_apilo_payment_method_id( $order['payment_method_id'] ) + 'type' => ( new \Domain\PaymentMethod\PaymentMethodRepository( $mdb ) )->getApiloPaymentTypeId( (int)$order['payment_method_id'] ) ]; } @@ -518,7 +519,7 @@ if ( $apilo_settings['enabled'] and $apilo_settings['sync_orders'] and $apilo_se if ( $responseData['id'] and $responseData['status'] ) { - $shop_status_id = \front\factory\ShopStatuses::get_shop_status_by_integration_status_id( 'apilo', $responseData['status'] ); + $shop_status_id = ( new \Domain\ShopStatus\ShopStatusRepository( $mdb ) )->getByIntegrationStatusId( 'apilo', (int)$responseData['status'] ); $order_tmp = new Order( $order['id'] ); diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 264dc9f..890d0f5 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -4,6 +4,34 @@ Logi zmian z migracji na Domain-Driven Architecture. Najnowsze na gorze. --- +## ver. 0.292 (2026-02-17) - ShopProduct + ShopPaymentMethod + ShopPromotion + ShopStatuses + ShopTransport frontend migration + +- **Pelna migracja front\factory\** — USUNIETY caly folder `autoload/front/factory/` (wszystkie 20 klas zmigrowane do Domain) +- **ShopProduct (frontend Stage 1)** — migracja factory + controls na Domain + - NOWE METODY w `ProductRepository`: ~20 metod frontendowych (getSkuWithFallback, getEanWithFallback, isProductActiveCached, productCategoriesFront, getWarehouseMessageZero/Nonzero, topProductIds, newProductIds, promotedProductIdsCached, getMinimalPrice, productImageCached, productNameCached, productUrlCached, randomProductIds, productWp) + - USUNIETA: `front\factory\class.ShopProduct.php` (~410 linii) — logika przeniesiona do `ProductRepository` + - USUNIETA: `front\controls\class.ShopProduct.php` — logika w `ProductRepository` + szablony + - UPDATE: callerzy w szablonach, kontrolerach, index.php, cron.php przepieci na repo +- **ShopPaymentMethod (frontend)** — migracja factory + view + shop facade na Domain + - NOWE METODY w `PaymentMethodRepository`: metody frontendowe z Redis cache (paymentMethodsCached, paymentMethodCached, paymentMethodsByTransportCached) + - USUNIETA: `front\factory\class.ShopPaymentMethod.php`, `front\view\class.ShopPaymentMethod.php`, `shop\class.PaymentMethod.php` + - UPDATE: callerzy w szablonach i kontrolerach przepieci na `PaymentMethodRepository` +- **ShopPromotion (frontend)** — migracja factory na Domain + - NOWE METODY w `PromotionRepository`: 5 metod aplikowania promocji (applyTypeWholeBasket, applyTypeCheapestProduct, applyTypeCategoriesOr, applyTypeCategoriesAnd, applyTypeCategoryCondition) + - USUNIETA: `front\factory\class.ShopPromotion.php` — logika przeniesiona do `PromotionRepository` + - UPDATE: `shop\Promotion::find_promotion()` — 5 wywolan przepietych na repo +- **ShopStatuses (frontend)** — rewiring callerow + - USUNIETA: `front\factory\class.ShopStatuses.php` — 4 callerzy przepieci bezposrednio na `ShopStatusRepository` +- **ShopTransport (frontend)** — migracja factory + view na Domain + - NOWE METODY w `TransportRepository`: 4 metody frontendowe (transportMethodsFront, transportCostCached, findActiveByIdCached, forPaymentMethod) + - USUNIETA: `front\factory\class.ShopTransport.php`, `front\view\class.ShopTransport.php` + - UPDATE: 8 callerow przepietych na `TransportRepository` + - FIX: broken `transports_list()` w ajax.php — nowa metoda `forPaymentMethod()` +- NOWY: `tests/stubs/ShopProduct.php` — stub `shop\Product` dla testow +- Testy: 610 OK, 1816 asercji (+37: 20 ProductRepository, 5 PaymentMethodRepository, 7 PromotionRepository, 5 TransportRepository) + +--- + ## ver. 0.291 (2026-02-17) - ShopProducer frontend migration - **ShopProducer (frontend)** — migracja controls + shop facade na Domain + Controllers @@ -775,4 +803,4 @@ Logi zmian z migracji na Domain-Driven Architecture. Najnowsze na gorze. - Metoda `clear_product_cache()` w klasie S --- -*Dokument aktualizowany: 2026-02-17 (ver. 0.291)* +*Dokument aktualizowany: 2026-02-17 (ver. 0.292)* diff --git a/docs/FRONTEND_REFACTORING_PLAN.md b/docs/FRONTEND_REFACTORING_PLAN.md index 6c9041b..0e05a41 100644 --- a/docs/FRONTEND_REFACTORING_PLAN.md +++ b/docs/FRONTEND_REFACTORING_PLAN.md @@ -17,27 +17,27 @@ Panel administratora (33 moduły) został w pełni zmigrowany na architekturę D | ShopBasket | ZMIGROWANY do `front\Controllers\ShopBasketController` | Operacje koszyka, add/remove/quantity, checkout | | ShopClient | ZMIGROWANY do `front\Controllers\ShopClientController` | Logowanie, rejestracja, odzyskiwanie hasla, adresy, zamowienia | | ShopOrder | ZMIGROWANY do `front\Controllers\ShopOrderController` | Webhooki płatności + order details | -| ShopProduct | Fasada | lazy_loading, warehouse_message, draw_product_attributes | +| ShopProduct | ZMIGROWANY — usunięty | logika w ProductRepository + szablony | | ShopProducer | ZMIGROWANY do `front\Controllers\ShopProducerController` | list(), products() | | ShopCoupon | ZMIGROWANY do `front\Controllers\ShopCouponController` | use_coupon(), delete_coupon() | | Newsletter | ZMIGROWANY do `front\Controllers\NewsletterController` | signin(), confirm(), unsubscribe() | -### front/factory/ (20 klas — pobieranie danych + logika) +### ~~front/factory/~~ (20 klas — USUNIĘTY w ver. 0.292, wszystkie zmigrowane do Domain) | Klasa | Status | Priorytet migracji | |-------|--------|--------------------| -| ShopProduct | ORYGINALNA LOGIKA (~370 linii) | KRYTYCZNY — product_details(), promoted/top/new products | +| ShopProduct | ZMIGROWANA do `ProductRepository` — usunięta | — | | ShopOrder | ZMIGROWANA do `OrderRepository` — usunięta | — | | ShopClient | ZMIGROWANA do `ClientRepository` + `ShopClientController` — usunięta | — | | ShopCategory | ZMIGROWANA do `CategoryRepository` — usunięta | — | -| Articles | ORYGINALNA LOGIKA | WYSOKI — złożone SQL z language fallback | -| ShopPromotion | ORYGINALNA LOGIKA | WYSOKI — silnik promocji (5 typów) | +| Articles | ZMIGROWANA do `ArticleRepository` — usunięta | — | +| ShopPromotion | ZMIGROWANA do `PromotionRepository` — usunięta | — | | ShopBasket | ZMIGROWANA do `Domain\Basket\BasketCalculator` — usunięta | — | -| ShopTransport | CZĘŚCIOWO zmigrowana | ŚREDNI — transport_methods z filtrowaniem | -| ShopPaymentMethod | ZMIGROWANA (Domain) | — | -| ShopStatuses | ZMIGROWANA (Domain) | — | +| ShopTransport | ZMIGROWANA do `TransportRepository` — usunięta | — | +| ShopPaymentMethod | ZMIGROWANA do `PaymentMethodRepository` — usunięta | — | +| ShopStatuses | ZMIGROWANA do `ShopStatusRepository` — usunięta | — | | Scontainers | ZMIGROWANA (Domain) — usunięta | — | | Newsletter | ZMIGROWANA (Domain) — usunięta | — | -| Settings | Fasada (BUG: get_single_settings_value ignoruje $param) | NISKI | +| Settings | ZMIGROWANA do `SettingsRepository` — usunięta | — | | Languages | USUNIĘTA — przepięta na Domain | — | | Layouts | USUNIETA — przepieta na Domain | — | | Banners | USUNIETA — przepieta na Domain | — | @@ -58,8 +58,8 @@ Panel administratora (33 moduły) został w pełni zmigrowany na architekturę D | Languages, Newsletter | PRZENIESIONE do `front\Views\` (nowy namespace) | | ShopClient | PRZENIESIONA do `front\Views\ShopClient` | | ShopOrder | ZMIGROWANA do `ShopOrderController` — usunięta | -| ShopPaymentMethod | Czyste VIEW | -| ShopTransport | PUSTA klasa (placeholder) | +| ShopPaymentMethod | USUNIĘTA (pusta klasa) | +| ShopTransport | USUNIĘTA (pusta klasa) | ### shop/ (14 klas — encje biznesowe) | Klasa | Linii | Status | Priorytet | @@ -72,7 +72,7 @@ Panel administratora (33 moduły) został w pełni zmigrowany na architekturę D | Search | ~80 | NISKI — wrapper na szablony | NISKI | | Coupon | ~60 | NISKI — niekompletne metody | NISKI | | Transport | ~30 | NISKI — transport_list() | NISKI | -| PaymentMethod | — | ZMIGROWANA (fasada do Domain) | — | +| PaymentMethod | — | USUNIETA — callery na PaymentMethodRepository | — | | Producer | — | USUNIETA (callery na ProducerRepository) | — | | ProductSet | — | ZMIGROWANA (fasada do Domain) | — | | ProductAttribute | ~100 | OK — dobry caching | — | @@ -114,7 +114,7 @@ articles(8), banner(2), controls(1), menu(4), newsletter(2), scontainers(1), sho ## Znane bugi do naprawy podczas refaktoringu 1. ~~**KRYTYCZNY** `front\factory\ShopClient::login()` — hardcoded password bypass `'Legia1916'`~~ **NAPRAWIONE** — `ClientRepository::authenticate()` bez bypass -2. `front\factory\Settings::get_single_settings_value()` — ignoruje `$param`, zawsze zwraca `firm_name` +2. ~~`front\factory\Settings::get_single_settings_value()` — ignoruje `$param`, zawsze zwraca `firm_name`~~ **NAPRAWIONE** — klasa usunięta, `SettingsRepository::getSingleValue()` z poprawnym `$param` 3. ~~`front\factory\Newsletter::newsletter_unsubscribe()` — błędna składnia SQL w delete~~ **NAPRAWIONE** — `NewsletterRepository::unsubscribe()` z poprawną składnią medoo `delete()` 4. ~~`cms\Layout::__get()` — referuje nieistniejące `$this->data`~~ **NAPRAWIONE** — klasa usunięta, zastąpiona przez `$layoutsRepo->find()` 5. `shop\Search` — typo w use: `shop\Produt` (brak 'c') diff --git a/docs/PROJECT_STRUCTURE.md b/docs/PROJECT_STRUCTURE.md index 02f7f07..60a12b3 100644 --- a/docs/PROJECT_STRUCTURE.md +++ b/docs/PROJECT_STRUCTURE.md @@ -110,9 +110,8 @@ shopPRO/ │ ├── front/ # Klasy frontendu │ │ ├── Controllers/ # Nowe kontrolery DI (Newsletter, ShopBasket, ShopClient, ShopCoupon, ShopOrder, ShopProducer) │ │ ├── Views/ # Nowe widoki (Newsletter, Articles, Languages, Banners, Menu, Scontainers, ShopCategory, ShopClient) -│ │ ├── controls/ # Kontrolery legacy (Site, ...) -│ │ ├── view/ # Widoki legacy (Site, ...) -│ │ └── factory/ # Fabryki/helpery (fasady) +│ │ ├── controls/ # Kontroler legacy (tylko Site — router) +│ │ └── view/ # Widok legacy (tylko Site — layout engine) │ └── shop/ # Klasy sklepu ├── docs/ # Dokumentacja techniczna ├── libraries/ # Biblioteki zewnętrzne @@ -177,7 +176,7 @@ Główna klasa helper (przeniesiona z `class.S.php`) z metodami: - `\admin\controls\` - kontrolery legacy (fallback) - `\Domain\` - repozytoria/logika domenowa - `\admin\factory\` - helpery/fabryki admin -- `\front\factory\` - helpery/fabryki frontend +- ~~`\front\factory\`~~ - USUNIĘTY — wszystkie fabryki zmigrowane do Domain - `\shop\` - klasy sklepu (Product, Order, itp.) ### Cachowanie produktów @@ -243,10 +242,9 @@ autoload/ │ └── view/ # Widoki (statyczne - bez zmian) ├── front/ │ ├── Controllers/ # Nowe kontrolery frontendowe (namespace \front\Controllers\) z DI -│ ├── Views/ # Nowe widoki (namespace \front\Views\) — czyste VIEW, statyczne (Menu, Newsletter, Articles, Languages, Banners, Scontainers) -│ ├── controls/ # Legacy kontrolery (fallback) -│ ├── factory/ # Legacy helpery (stopniowo migrowane) -│ └── view/ # Legacy widoki +│ ├── Views/ # Nowe widoki (namespace \front\Views\) — czyste VIEW, statyczne (Menu, Newsletter, Articles, Languages, Banners, Scontainers, ShopCategory, ShopClient) +│ ├── controls/ # Legacy kontroler (tylko Site — router) +│ └── view/ # Legacy widok (tylko Site — layout engine) ├── shop/ # Legacy - fasady do Domain ``` @@ -481,5 +479,16 @@ Pelna dokumentacja testow: `TESTING.md` - UPDATE: `front\view\Site::show()` — przepiecie na `$producerRepo->findForFrontend()` - UPDATE: `front\controls\Site::getControllerFactories()` — zarejestrowany `ShopProducer` +## Aktualizacja 2026-02-17 (ver. 0.292) - ShopProduct + ShopPaymentMethod + ShopPromotion + ShopStatuses + ShopTransport frontend migration +- **Pelna migracja front\factory\** — USUNIETY caly folder `autoload/front/factory/`; 5 ostatnich klas zmigrowanych: + - `front\factory\ShopProduct` (~410 linii) → `ProductRepository` (~20 nowych metod frontendowych) + - `front\factory\ShopPaymentMethod` → `PaymentMethodRepository` (metody frontendowe z Redis cache) + - `front\factory\ShopPromotion` → `PromotionRepository` (5 metod applyType*) + - `front\factory\ShopStatuses` → przepiecie bezposrednio na `ShopStatusRepository` + - `front\factory\ShopTransport` → `TransportRepository` (4 metody frontendowe z Redis cache) +- Usuniete legacy: `front\controls\class.ShopProduct.php`, `front\view\class.ShopPaymentMethod.php`, `front\view\class.ShopTransport.php`, `shop\class.PaymentMethod.php` +- FIX: broken `transports_list()` w ajax.php → nowa metoda `forPaymentMethod()` +- Pozostale w front\: `controls/class.Site.php` (router), `view/class.Site.php` (layout engine) + --- -*Dokument aktualizowany: 2026-02-17 (ver. 0.291)* +*Dokument aktualizowany: 2026-02-17 (ver. 0.292)* diff --git a/docs/TESTING.md b/docs/TESTING.md index 8eb871d..68beac2 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -36,7 +36,17 @@ Alternatywnie (Git Bash): Ostatnio zweryfikowano: 2026-02-17 ```text -OK (573 tests, 1738 assertions) +OK (610 tests, 1816 assertions) +``` + +Aktualizacja po migracji ShopProduct + ShopPaymentMethod + ShopPromotion + ShopStatuses + ShopTransport frontend (2026-02-17, ver. 0.292): +```text +Pelny suite: OK (610 tests, 1816 assertions) +Nowe testy: ProductRepositoryTest (+20: getSkuWithFallback, getEanWithFallback, isProductActiveCached, productCategoriesFront, getWarehouseMessageZero/Nonzero, topProductIds, newProductIds, promotedProductIdsCached, getMinimalPrice, productImageCached, productNameCached, productUrlCached, randomProductIds, productWp) +Nowe testy: PaymentMethodRepositoryTest (+5: paymentMethodsCached, paymentMethodCached, paymentMethodsByTransportCached, forTransportCached) +Nowe testy: PromotionRepositoryTest (+7: applyTypeWholeBasket, applyTypeCategoriesOr, applyTypeCategoryCondition 2 scenariusze, applyTypeCategoriesAnd) +Nowe testy: TransportRepositoryTest (+5: transportCostCached, findActiveByIdCached, findActiveByIdCachedNull, forPaymentMethod, forPaymentMethodEmpty) +Nowy stub: tests/stubs/ShopProduct.php (shop\Product::is_product_on_promotion, get_product_price) ``` Aktualizacja po migracji ShopProducer frontend (2026-02-17, ver. 0.291): @@ -155,6 +165,10 @@ Nowe testy dodane 2026-02-15: ```text tests/ |-- bootstrap.php +|-- stubs/ +| |-- CacheHandler.php +| |-- Helpers.php +| `-- ShopProduct.php |-- Unit/ | |-- Domain/ | | |-- Article/ArticleRepositoryTest.php diff --git a/docs/UPDATE_INSTRUCTIONS.md b/docs/UPDATE_INSTRUCTIONS.md index 2764114..e359107 100644 --- a/docs/UPDATE_INSTRUCTIONS.md +++ b/docs/UPDATE_INSTRUCTIONS.md @@ -18,16 +18,16 @@ Aktualizacje znajdują się w folderze `updates/0.XX/` gdzie XX oznacza dziesią ## Procedura tworzenia nowej aktualizacji -## Status biezacej aktualizacji (ver. 0.291) +## Status biezacej aktualizacji (ver. 0.292) -- Wersja udostepniona: `0.291` (data: 2026-02-17). +- Wersja udostepniona: `0.292` (data: 2026-02-17). - Pliki publikacyjne: - - `updates/0.20/ver_0.291.zip`, `ver_0.291_files.txt` + - `temp/update_build/ver_0.292.zip`, `ver_0.292_files.txt` - Pliki metadanych aktualizacji: - - `updates/changelog.php` (dodany wpis `ver. 0.291`) - - `updates/versions.php` (`$current_ver = 291`) + - `updates/changelog.php` (dodany wpis `ver. 0.292`) + - `updates/versions.php` (`$current_ver = 292`) - Weryfikacja testow przed publikacja: - - `OK (573 tests, 1738 assertions)` + - `OK (610 tests, 1816 assertions)` ### 1. Określ numer wersji Sprawdź ostatnią wersję w `updates/` i zwiększ o 1. diff --git a/index.php b/index.php index 5281b74..7148420 100644 --- a/index.php +++ b/index.php @@ -227,7 +227,7 @@ if ( $settings[ 'piksel' ] ) });'; if ( \Shared\Helpers\Helpers::get( 'product' ) ) - $piskel_code .= PHP_EOL . 'fbq( "track", "ViewContent", { content_category: "produkt", content_name: "' . htmlspecialchars( str_replace( '"', '', \front\factory\ShopProduct::product_name( \Shared\Helpers\Helpers::get( 'product' ) ) ) ) . '", content_ids: ["' . \Shared\Helpers\Helpers::get( 'product' ) . '"], content_type: "product" });'; + $piskel_code .= PHP_EOL . 'fbq( "track", "ViewContent", { content_category: "produkt", content_name: "' . htmlspecialchars( str_replace( '"', '', ( new \Domain\Product\ProductRepository( $GLOBALS['mdb'] ) )->getProductNameCached( (int)\Shared\Helpers\Helpers::get( 'product' ), $lang_id ) ) ) . '", content_ids: ["' . \Shared\Helpers\Helpers::get( 'product' ) . '"], content_type: "product" });'; $element -> nodeValue = $piskel_code; @@ -243,7 +243,7 @@ if ( \Shared\Helpers\Helpers::get( 'product' ) ) $head = $dom -> getElementsByTagName( 'head' ) -> item( 0 ); - $product = \front\factory\ShopProduct::product_details( \Shared\Helpers\Helpers::get( 'product' ), $lang_id ); + $product = ( new \Domain\Product\ProductRepository( $GLOBALS['mdb'] ) )->productDetailsFrontCached( (int)\Shared\Helpers\Helpers::get( 'product' ), $lang_id ); $product_image = $product[ 'images' ][ 0 ][ 'src' ]; if ( $product_image and file_exists( substr( $product_image, 1, strlen( $product_image ) ) ) ) { diff --git a/temp/update_build/ver_0.292.zip b/temp/update_build/ver_0.292.zip new file mode 100644 index 0000000..e992110 Binary files /dev/null and b/temp/update_build/ver_0.292.zip differ diff --git a/temp/update_build/ver_0.292_files.txt b/temp/update_build/ver_0.292_files.txt new file mode 100644 index 0000000..0993463 --- /dev/null +++ b/temp/update_build/ver_0.292_files.txt @@ -0,0 +1,9 @@ +F: ../autoload/front/controls/class.ShopProduct.php +F: ../autoload/front/factory/class.ShopPaymentMethod.php +F: ../autoload/front/factory/class.ShopProduct.php +F: ../autoload/front/factory/class.ShopPromotion.php +F: ../autoload/front/factory/class.ShopStatuses.php +F: ../autoload/front/factory/class.ShopTransport.php +F: ../autoload/front/view/class.ShopPaymentMethod.php +F: ../autoload/front/view/class.ShopTransport.php +F: ../autoload/shop/class.PaymentMethod.php diff --git a/templates/shop-basket/basket-details.php b/templates/shop-basket/basket-details.php index c42dfdb..a2acebe 100644 --- a/templates/shop-basket/basket-details.php +++ b/templates/shop-basket/basket-details.php @@ -34,7 +34,7 @@
defaultLanguage() and $url != '#') $url = '/' . \Shared\Helpers\Helpers::get_session('current-lang') . $url; diff --git a/templates/shop-basket/basket-payments-methods.php b/templates/shop-basket/basket-payments-methods.php index 7dd8187..a262f8a 100644 --- a/templates/shop-basket/basket-payments-methods.php +++ b/templates/shop-basket/basket-payments-methods.php @@ -8,7 +8,7 @@ $basket = \Shared\Helpers\Helpers::get_session( 'basket' ); $coupon = \Shared\Helpers\Helpers::get_session( 'coupon' ); - $transport_cost = \front\factory\ShopTransport::transport_cost( \Shared\Helpers\Helpers::get_session( 'basket-transport-method-id' ) ); + $transport_cost = ( new \Domain\Transport\TransportRepository( $GLOBALS['mdb'] ) )->transportCostCached( \Shared\Helpers\Helpers::get_session( 'basket-transport-method-id' ) ); $basket_summary = \Domain\Basket\BasketCalculator::summaryPrice( $basket, $coupon ) + $transport_cost; ?> diff --git a/templates/shop-order/order-details.php b/templates/shop-order/order-details.php index a163b99..18e10e8 100644 --- a/templates/shop-order/order-details.php +++ b/templates/shop-order/order-details.php @@ -1,4 +1,4 @@ - settings['ssl'] ? $base = 'https' : $base = 'http';?> + settings['ssl'] ? $base = 'https' : $base = 'http'; $paymentRepo = new \Domain\PaymentMethod\PaymentMethodRepository( $GLOBALS['mdb'] );?>
: order['number'];?> @@ -22,7 +22,7 @@ order['payment_method_id'] == 1 or $this -> order['payment_method_id'] == 3 ):?>
Co prawda nie wybrałeś żadnej z dostępnych form "szybkich płatności", ale w każdej chwili możesz z nich skorzystać.
- order['payment_method_id'] == 2 or $this -> order['payment_method_id'] == 1 or $this -> order['payment_method_id'] == 3 ) and \front\factory\ShopPaymentMethod::is_payment_active( 2 ) ):?> + order['payment_method_id'] == 2 or $this -> order['payment_method_id'] == 1 or $this -> order['payment_method_id'] == 3 ) and $paymentRepo->isActive( 2 ) ):?>
@@ -43,7 +43,7 @@
- order['payment_method_id'] == 6 and \front\factory\ShopPaymentMethod::is_payment_active( 6 ) ):?> + order['payment_method_id'] == 6 and $paymentRepo->isActive( 6 ) ):?> order['payment_method_id'] == 6 ):?>
lub skorzystaj z płatności online
- order['payment_method_id'] == 6 or $this -> order['payment_method_id'] == 4 or $this -> order['payment_method_id'] == 1 or $this -> order['payment_method_id'] == 3 ) and \front\factory\ShopPaymentMethod::is_payment_active( 4 ) ):?> + order['payment_method_id'] == 6 or $this -> order['payment_method_id'] == 4 or $this -> order['payment_method_id'] == 1 or $this -> order['payment_method_id'] == 3 ) and $paymentRepo->isActive( 4 ) ):?> order['payment_method_id'] == 6 or $this -> order['payment_method_id'] == 5 or $this -> order['payment_method_id'] == 1 or $this -> order['payment_method_id'] == 3 ) and \front\factory\ShopPaymentMethod::is_payment_active( 5 ) ): + if ( ( $this -> order['payment_method_id'] == 6 or $this -> order['payment_method_id'] == 5 or $this -> order['payment_method_id'] == 1 or $this -> order['payment_method_id'] == 3 ) and $paymentRepo->isActive( 5 ) ): $url = 'https://secure.tpay.com'; diff --git a/templates/shop-product/product.php b/templates/shop-product/product.php index 96b932e..1fc2591 100644 --- a/templates/shop-product/product.php +++ b/templates/shop-product/product.php @@ -55,7 +55,7 @@ product -> price_brutto );?>
- Najniższa cena w ciągu ostatnich 30 dni: product['id'], $this -> product -> price_brutto_promo ) );?> zł + Najniższa cena w ciągu ostatnich 30 dni: getMinimalPriceCached( (int)$this -> product['id'], $this -> product -> price_brutto_promo ) );?> zł
product -> weight > 0 && $this -> product -> product_unit_id ):?>
diff --git a/tests/Unit/Domain/PaymentMethod/PaymentMethodRepositoryTest.php b/tests/Unit/Domain/PaymentMethod/PaymentMethodRepositoryTest.php index 6df4a40..6638874 100644 --- a/tests/Unit/Domain/PaymentMethod/PaymentMethodRepositoryTest.php +++ b/tests/Unit/Domain/PaymentMethod/PaymentMethodRepositoryTest.php @@ -301,6 +301,92 @@ class PaymentMethodRepositoryTest extends TestCase $this->assertSame('BANK_TRANSFER', $repository->getApiloPaymentTypeId(3)); } + public function testIsActiveReturnsOneForActivePayment(): void + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->expects($this->once()) + ->method('get') + ->with('pp_shop_payment_methods', 'status', ['id' => 2]) + ->willReturn('1'); + + $repository = new PaymentMethodRepository($mockDb); + $this->assertSame(1, $repository->isActive(2)); + } + + public function testIsActiveReturnsZeroForInvalidId(): void + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->expects($this->never())->method('get'); + + $repository = new PaymentMethodRepository($mockDb); + $this->assertSame(0, $repository->isActive(0)); + } + + public function testFindActiveByIdReturnsNormalizedData(): void + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->expects($this->once()) + ->method('get') + ->with('pp_shop_payment_methods', '*', [ + 'AND' => [ + 'id' => 3, + 'status' => 1, + ], + ]) + ->willReturn([ + 'id' => '3', + 'name' => ' Przelew ', + 'description' => 'Opis', + 'status' => '1', + 'apilo_payment_type_id' => '5', + ]); + + $repository = new PaymentMethodRepository($mockDb); + $result = $repository->findActiveById(3); + + $this->assertIsArray($result); + $this->assertSame(3, $result['id']); + $this->assertSame('Przelew', $result['name']); + $this->assertSame(1, $result['status']); + $this->assertSame(5, $result['apilo_payment_type_id']); + } + + public function testFindActiveByIdReturnsNullForInvalidId(): void + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->expects($this->never())->method('get'); + + $repository = new PaymentMethodRepository($mockDb); + $this->assertNull($repository->findActiveById(0)); + } + + public function testAllActiveReturnsEmptyOnNull(): void + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->method('select')->willReturn(null); + + $repository = new PaymentMethodRepository($mockDb); + $this->assertSame([], $repository->allActive()); + } + + public function testGetApiloPaymentTypeIdReturnsNullForInvalidId(): void + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->expects($this->never())->method('get'); + + $repository = new PaymentMethodRepository($mockDb); + $this->assertNull($repository->getApiloPaymentTypeId(0)); + } + + public function testForTransportReturnsEmptyForInvalidId(): void + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->expects($this->never())->method('query'); + + $repository = new PaymentMethodRepository($mockDb); + $this->assertSame([], $repository->forTransport(0)); + } + public function testForTransportReturnsRows(): void { $mockDb = $this->createMock(\medoo::class); diff --git a/tests/Unit/Domain/Product/ProductRepositoryTest.php b/tests/Unit/Domain/Product/ProductRepositoryTest.php index 24e62eb..258abca 100644 --- a/tests/Unit/Domain/Product/ProductRepositoryTest.php +++ b/tests/Unit/Domain/Product/ProductRepositoryTest.php @@ -510,4 +510,371 @@ class ProductRepositoryTest extends TestCase $this->assertIsArray($result); $this->assertNull($result['price_brutto_promo']); } + + // ========================================================================= + // Frontend methods (migrated from front\factory\ShopProduct) + // ========================================================================= + + /** + * Test getSkuWithFallback - zwraca SKU bezpośrednio + */ + public function testGetSkuWithFallbackReturnsSku() + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->expects($this->once()) + ->method('get') + ->with('pp_shop_products', 'sku', ['id' => 10]) + ->willReturn('SKU-ABC'); + + $repository = new ProductRepository($mockDb); + $result = $repository->getSkuWithFallback(10); + + $this->assertEquals('SKU-ABC', $result); + } + + /** + * Test getSkuWithFallback - fallback na parent_id + */ + public function testGetSkuWithFallbackFromParent() + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->method('get') + ->willReturnCallback(function ($table, $column, $where) { + if ($column === 'sku' && $where['id'] === 10) return null; + if ($column === 'parent_id' && $where['id'] === 10) return 5; + if ($column === 'sku' && $where['id'] === 5) return 'SKU-PARENT'; + return null; + }); + + $repository = new ProductRepository($mockDb); + $result = $repository->getSkuWithFallback(10, true); + + $this->assertEquals('SKU-PARENT', $result); + } + + /** + * Test getSkuWithFallback - zwraca null dla nieprawidłowego ID + */ + public function testGetSkuWithFallbackReturnsNullForInvalidId() + { + $mockDb = $this->createMock(\medoo::class); + $repository = new ProductRepository($mockDb); + + $this->assertNull($repository->getSkuWithFallback(0)); + $this->assertNull($repository->getSkuWithFallback(-1)); + } + + /** + * Test getEanWithFallback - zwraca EAN bezpośrednio + */ + public function testGetEanWithFallbackReturnsEan() + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->expects($this->once()) + ->method('get') + ->with('pp_shop_products', 'ean', ['id' => 10]) + ->willReturn('1234567890123'); + + $repository = new ProductRepository($mockDb); + $result = $repository->getEanWithFallback(10); + + $this->assertEquals('1234567890123', $result); + } + + /** + * Test getEanWithFallback - fallback na parent_id + */ + public function testGetEanWithFallbackFromParent() + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->method('get') + ->willReturnCallback(function ($table, $column, $where) { + if ($column === 'ean' && $where['id'] === 10) return null; + if ($column === 'parent_id' && $where['id'] === 10) return 5; + if ($column === 'ean' && $where['id'] === 5) return 'EAN-PARENT'; + return null; + }); + + $repository = new ProductRepository($mockDb); + $result = $repository->getEanWithFallback(10, true); + + $this->assertEquals('EAN-PARENT', $result); + } + + /** + * Test isProductActiveCached - zwraca 1 dla aktywnego produktu + */ + public function testIsProductActiveCachedReturnsOneForActive() + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->expects($this->once()) + ->method('get') + ->with('pp_shop_products', 'status', ['id' => 10]) + ->willReturn(1); + + $repository = new ProductRepository($mockDb); + + $this->assertEquals(1, $repository->isProductActiveCached(10)); + } + + /** + * Test isProductActiveCached - zwraca 0 dla nieaktywnego produktu + */ + public function testIsProductActiveCachedReturnsZeroForInactive() + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->method('get')->willReturn(0); + + $repository = new ProductRepository($mockDb); + + $this->assertEquals(0, $repository->isProductActiveCached(10)); + } + + /** + * Test isProductActiveCached - zwraca 0 dla nieprawidłowego ID + */ + public function testIsProductActiveCachedReturnsZeroForInvalidId() + { + $mockDb = $this->createMock(\medoo::class); + $repository = new ProductRepository($mockDb); + + $this->assertEquals(0, $repository->isProductActiveCached(0)); + $this->assertEquals(0, $repository->isProductActiveCached(-1)); + } + + /** + * Test productCategoriesFront - zwraca kategorie + */ + public function testProductCategoriesFrontReturnsCategories() + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->method('get') + ->with('pp_shop_products', 'parent_id', ['id' => 10]) + ->willReturn(null); + + $mockStmt = $this->createMock(\PDOStatement::class); + $mockStmt->method('fetchAll')->willReturn([ + ['category_id' => 1], + ['category_id' => 5], + ]); + $mockDb->method('query')->willReturn($mockStmt); + + $repository = new ProductRepository($mockDb); + $result = $repository->productCategoriesFront(10); + + $this->assertIsArray($result); + $this->assertCount(2, $result); + $this->assertEquals(1, $result[0]['category_id']); + $this->assertEquals(5, $result[1]['category_id']); + } + + /** + * Test productCategoriesFront - fallback na parent_id + */ + public function testProductCategoriesFrontUsesParentId() + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->method('get') + ->with('pp_shop_products', 'parent_id', ['id' => 10]) + ->willReturn(5); + + $mockStmt = $this->createMock(\PDOStatement::class); + $mockStmt->method('fetchAll')->willReturn([['category_id' => 3]]); + $mockDb->expects($this->once()) + ->method('query') + ->with( + $this->equalTo('SELECT category_id FROM pp_shop_products_categories WHERE product_id = :pid'), + $this->equalTo([':pid' => 5]) + ) + ->willReturn($mockStmt); + + $repository = new ProductRepository($mockDb); + $result = $repository->productCategoriesFront(10); + + $this->assertCount(1, $result); + $this->assertEquals(3, $result[0]['category_id']); + } + + /** + * Test productCategoriesFront - pusta tablica dla nieprawidłowego ID + */ + public function testProductCategoriesFrontReturnsEmptyForInvalidId() + { + $mockDb = $this->createMock(\medoo::class); + $repository = new ProductRepository($mockDb); + + $this->assertEquals([], $repository->productCategoriesFront(0)); + $this->assertEquals([], $repository->productCategoriesFront(-1)); + } + + /** + * Test getWarehouseMessageZero - zwraca wiadomość + */ + public function testGetWarehouseMessageZeroReturnsMessage() + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->expects($this->once()) + ->method('get') + ->with( + 'pp_shop_products_langs', + 'warehouse_message_zero', + ['AND' => ['product_id' => 10, 'lang_id' => 'pl']] + ) + ->willReturn('Produkt niedostępny'); + + $repository = new ProductRepository($mockDb); + + $this->assertEquals('Produkt niedostępny', $repository->getWarehouseMessageZero(10, 'pl')); + } + + /** + * Test getWarehouseMessageZero - null dla nieprawidłowego ID + */ + public function testGetWarehouseMessageZeroReturnsNullForInvalidId() + { + $mockDb = $this->createMock(\medoo::class); + $repository = new ProductRepository($mockDb); + + $this->assertNull($repository->getWarehouseMessageZero(0, 'pl')); + } + + /** + * Test getWarehouseMessageNonzero - zwraca wiadomość + */ + public function testGetWarehouseMessageNonzeroReturnsMessage() + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->expects($this->once()) + ->method('get') + ->with( + 'pp_shop_products_langs', + 'warehouse_message_nonzero', + ['AND' => ['product_id' => 10, 'lang_id' => 'pl']] + ) + ->willReturn('Wysyłka w 24h'); + + $repository = new ProductRepository($mockDb); + + $this->assertEquals('Wysyłka w 24h', $repository->getWarehouseMessageNonzero(10, 'pl')); + } + + /** + * Test getWarehouseMessageNonzero - null dla nieprawidłowego ID + */ + public function testGetWarehouseMessageNonzeroReturnsNullForInvalidId() + { + $mockDb = $this->createMock(\medoo::class); + $repository = new ProductRepository($mockDb); + + $this->assertNull($repository->getWarehouseMessageNonzero(0, 'pl')); + } + + /** + * Test topProductIds - zwraca ID aktywnych produktów + */ + public function testTopProductIdsReturnsActiveProducts() + { + $mockDb = $this->createMock(\medoo::class); + + $mockStmt = $this->createMock(\PDOStatement::class); + $mockStmt->method('fetchAll')->willReturn([ + ['sell_count' => 10, 'parent_product_id' => 1], + ['sell_count' => 5, 'parent_product_id' => 2], + ['sell_count' => 3, 'parent_product_id' => 3], + ]); + + $mockDb->method('query')->willReturn($mockStmt); + + // isProductActiveCached sprawdza status — produkt 2 nieaktywny + $mockDb->method('get') + ->willReturnCallback(function ($table, $column, $where) { + if ($column === 'status') { + return $where['id'] === 2 ? 0 : 1; + } + return null; + }); + + $repository = new ProductRepository($mockDb); + $result = $repository->topProductIds(6); + + $this->assertIsArray($result); + $this->assertContains(1, $result); + $this->assertNotContains(2, $result); + $this->assertContains(3, $result); + } + + /** + * Test newProductIds - zwraca ID produktów + */ + public function testNewProductIdsReturnsProductIds() + { + $mockDb = $this->createMock(\medoo::class); + + $mockStmt = $this->createMock(\PDOStatement::class); + $mockStmt->method('fetchAll')->willReturn([ + ['id' => 10], + ['id' => 20], + ['id' => 30], + ]); + $mockDb->method('query')->willReturn($mockStmt); + + $repository = new ProductRepository($mockDb); + $result = $repository->newProductIds(3); + + $this->assertIsArray($result); + $this->assertEquals([10, 20, 30], $result); + } + + /** + * Test newProductIds - pusta lista + */ + public function testNewProductIdsReturnsEmptyWhenNoProducts() + { + $mockDb = $this->createMock(\medoo::class); + + $mockStmt = $this->createMock(\PDOStatement::class); + $mockStmt->method('fetchAll')->willReturn([]); + $mockDb->method('query')->willReturn($mockStmt); + + $repository = new ProductRepository($mockDb); + + $this->assertEquals([], $repository->newProductIds(10)); + } + + /** + * Test promotedProductIdsCached - zwraca promowane produkty + */ + public function testPromotedProductIdsCachedReturnsIds() + { + $mockDb = $this->createMock(\medoo::class); + + $mockStmt = $this->createMock(\PDOStatement::class); + $mockStmt->method('fetchAll')->willReturn([ + ['id' => 5], + ['id' => 8], + ]); + $mockDb->method('query')->willReturn($mockStmt); + + $repository = new ProductRepository($mockDb); + $result = $repository->promotedProductIdsCached(2); + + $this->assertIsArray($result); + $this->assertEquals([5, 8], $result); + } + + /** + * Test promotedProductIdsCached - pusta lista + */ + public function testPromotedProductIdsCachedReturnsEmptyWhenNone() + { + $mockDb = $this->createMock(\medoo::class); + + $mockStmt = $this->createMock(\PDOStatement::class); + $mockStmt->method('fetchAll')->willReturn([]); + $mockDb->method('query')->willReturn($mockStmt); + + $repository = new ProductRepository($mockDb); + + $this->assertEquals([], $repository->promotedProductIdsCached(6)); + } } diff --git a/tests/Unit/Domain/Promotion/PromotionRepositoryTest.php b/tests/Unit/Domain/Promotion/PromotionRepositoryTest.php index 709195e..11ed56c 100644 --- a/tests/Unit/Domain/Promotion/PromotionRepositoryTest.php +++ b/tests/Unit/Domain/Promotion/PromotionRepositoryTest.php @@ -176,4 +176,202 @@ class PromotionRepositoryTest extends TestCase $this->assertCount(1, $tree[0]['subcategories']); $this->assertSame(11, (int)$tree[0]['subcategories'][0]['id']); } + + // ========================================================================= + // Frontend: basket promotion logic (migrated from front\factory\ShopPromotion) + // ========================================================================= + + private function mockPromotion(array $data): object + { + return new class($data) { + private $data; + public function __construct($data) { $this->data = $data; } + public function __get($key) { return isset($this->data[$key]) ? $this->data[$key] : null; } + }; + } + + private function makeBasket(array $items): array + { + $basket = []; + foreach ($items as $i => $item) { + $basket[$i] = array_merge(['product-id' => $item['id']], $item); + } + return $basket; + } + + /** + * Test applyTypeWholeBasket — rabat na cały koszyk + */ + public function testApplyTypeWholeBasketAppliesDiscountToAll(): void + { + $mockDb = $this->createMock(\medoo::class); + + // productCategoriesFront zwraca kategorie + $mockDb->method('get')->willReturn(null); // parent_id = null + $mockStmt = $this->createMock(\PDOStatement::class); + $mockStmt->method('fetchAll')->willReturn([['category_id' => 1]]); + $mockDb->method('query')->willReturn($mockStmt); + + $promotion = $this->mockPromotion([ + 'discount_type' => 1, + 'amount' => 10, + 'include_coupon' => 0, + 'include_product_promo' => 0, + ]); + + $basket = $this->makeBasket([ + ['id' => 1], + ['id' => 2], + ]); + + $repository = new PromotionRepository($mockDb); + $result = $repository->applyTypeWholeBasket($basket, $promotion); + + $this->assertSame(1, $result[0]['discount_type']); + $this->assertSame(10, $result[0]['discount_amount']); + $this->assertSame(1, $result[1]['discount_type']); + } + + /** + * Test applyTypeCategoriesOr — rabat na produkty z kat. 1 lub 2 + */ + public function testApplyTypeCategoriesOrAppliesDiscountToMatchingCategories(): void + { + $mockDb = $this->createMock(\medoo::class); + + $mockDb->method('get')->willReturn(null); + $mockStmt = $this->createMock(\PDOStatement::class); + $mockStmt->method('fetchAll')->willReturn([['category_id' => 5]]); + $mockDb->method('query')->willReturn($mockStmt); + + $promotion = $this->mockPromotion([ + 'categories' => json_encode([5]), + 'condition_categories' => json_encode([10]), + 'discount_type' => 1, + 'amount' => 15, + 'include_coupon' => 1, + 'include_product_promo' => 0, + ]); + + $basket = $this->makeBasket([['id' => 1]]); + + $repository = new PromotionRepository($mockDb); + $result = $repository->applyTypeCategoriesOr($basket, $promotion); + + $this->assertSame(1, $result[0]['discount_type']); + $this->assertSame(15, $result[0]['discount_amount']); + $this->assertSame(1, $result[0]['discount_include_coupon']); + } + + /** + * Test applyTypeCategoryCondition — rabat na kat. I jeśli kat. II w koszyku + */ + public function testApplyTypeCategoryConditionAppliesWhenConditionMet(): void + { + $mockDb = $this->createMock(\medoo::class); + + $callCount = 0; + $mockDb->method('get')->willReturn(null); + + $mockStmt1 = $this->createMock(\PDOStatement::class); + $mockStmt1->method('fetchAll')->willReturnOnConsecutiveCalls( + [['category_id' => 10]], // product 1 — condition category + [['category_id' => 5]], // product 2 — target category + [['category_id' => 10]], // product 1 — check for discount (not matching target) + [['category_id' => 5]] // product 2 — check for discount (matching target) + ); + $mockDb->method('query')->willReturn($mockStmt1); + + $promotion = $this->mockPromotion([ + 'categories' => json_encode([5]), + 'condition_categories' => json_encode([10]), + 'discount_type' => 1, + 'amount' => 20, + 'include_coupon' => 0, + 'include_product_promo' => 0, + ]); + + $basket = $this->makeBasket([ + ['id' => 1], + ['id' => 2], + ]); + + $repository = new PromotionRepository($mockDb); + $result = $repository->applyTypeCategoryCondition($basket, $promotion); + + // Produkt 2 (kat. 5) powinien mieć rabat + $this->assertSame(1, $result[1]['discount_type']); + $this->assertSame(20, $result[1]['discount_amount']); + } + + /** + * Test applyTypeCategoryCondition — brak rabatu gdy warunek niespełniony + */ + public function testApplyTypeCategoryConditionNoDiscountWhenConditionNotMet(): void + { + $mockDb = $this->createMock(\medoo::class); + + $mockDb->method('get')->willReturn(null); + $mockStmt = $this->createMock(\PDOStatement::class); + $mockStmt->method('fetchAll')->willReturn([['category_id' => 99]]); // nie pasuje do condition_categories + $mockDb->method('query')->willReturn($mockStmt); + + $promotion = $this->mockPromotion([ + 'categories' => json_encode([5]), + 'condition_categories' => json_encode([10]), + 'discount_type' => 1, + 'amount' => 20, + 'include_coupon' => 0, + 'include_product_promo' => 0, + ]); + + $basket = $this->makeBasket([['id' => 1]]); + + $repository = new PromotionRepository($mockDb); + $result = $repository->applyTypeCategoryCondition($basket, $promotion); + + $this->assertArrayNotHasKey('discount_type', $result[0]); + } + + /** + * Test applyTypeCategoriesAnd — rabat gdy oba warunki spełnione + */ + public function testApplyTypeCategoriesAndAppliesWhenBothConditionsMet(): void + { + $mockDb = $this->createMock(\medoo::class); + + $mockDb->method('get')->willReturn(null); + + $mockStmt = $this->createMock(\PDOStatement::class); + $mockStmt->method('fetchAll')->willReturnOnConsecutiveCalls( + [['category_id' => 10]], // product 1 — condition_categories ✓ + [['category_id' => 5]], // product 2 — categories ✓ (condition_2) + [['category_id' => 10]], // product 1 — check categories ✓ (condition check) + [['category_id' => 5]], // product 2 — check categories ✓ (condition check) + [['category_id' => 10]], // product 1 — discount assignment + [['category_id' => 5]] // product 2 — discount assignment + ); + $mockDb->method('query')->willReturn($mockStmt); + + $promotion = $this->mockPromotion([ + 'categories' => json_encode([5]), + 'condition_categories' => json_encode([10]), + 'discount_type' => 1, + 'amount' => 25, + 'include_coupon' => 1, + 'include_product_promo' => 0, + ]); + + $basket = $this->makeBasket([ + ['id' => 1], + ['id' => 2], + ]); + + $repository = new PromotionRepository($mockDb); + $result = $repository->applyTypeCategoriesAnd($basket, $promotion); + + $this->assertSame(1, $result[0]['discount_type']); + $this->assertSame(25, $result[0]['discount_amount']); + $this->assertSame(1, $result[1]['discount_type']); + } } diff --git a/tests/Unit/Domain/Transport/TransportRepositoryTest.php b/tests/Unit/Domain/Transport/TransportRepositoryTest.php index fab82a9..bf8f1ae 100644 --- a/tests/Unit/Domain/Transport/TransportRepositoryTest.php +++ b/tests/Unit/Domain/Transport/TransportRepositoryTest.php @@ -331,4 +331,93 @@ class TransportRepositoryTest extends TestCase $this->assertSame(1, $rows[1]['default']); $this->assertSame(50, $rows[1]['max_wp']); } + + // ========================================================================= + // Frontend methods (migrated from front\factory\ShopTransport) + // ========================================================================= + + /** + * Test transportCostCached — zwraca koszt transportu + */ + public function testTransportCostCachedReturnsCost(): void + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->expects($this->once()) + ->method('get') + ->willReturn('15.99'); + + $repository = new TransportRepository($mockDb); + $this->assertSame(15.99, $repository->transportCostCached(1)); + } + + /** + * Test findActiveByIdCached — zwraca transport + */ + public function testFindActiveByIdCachedReturnsTransport(): void + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->expects($this->once()) + ->method('get') + ->willReturn([ + 'id' => '3', 'name' => 'DPD', 'status' => '1', + 'cost' => '15.99', 'max_wp' => null, 'default' => '0', + 'delivery_free' => '1', 'apilo_carrier_account_id' => null, 'o' => '2', + ]); + + $repository = new TransportRepository($mockDb); + $result = $repository->findActiveByIdCached(3); + + $this->assertIsArray($result); + $this->assertSame(3, $result['id']); + $this->assertSame(15.99, $result['cost']); + } + + /** + * Test findActiveByIdCached — null dla nieistniejącego + */ + public function testFindActiveByIdCachedReturnsNullForInvalid(): void + { + $mockDb = $this->createMock(\medoo::class); + $repository = new TransportRepository($mockDb); + + $this->assertNull($repository->findActiveByIdCached(0)); + } + + /** + * Test forPaymentMethod — zwraca transporty powiązane z płatnością + */ + public function testForPaymentMethodReturnsTransports(): void + { + $mockDb = $this->createMock(\medoo::class); + $mockDb->method('select') + ->willReturnCallback(function ($table, $columns, $where) { + if ($table === 'pp_shop_transport_payment_methods') { + return [1, 3]; + } + if ($table === 'pp_shop_transports') { + return [ + ['id' => '1', 'name' => 'A', 'status' => '1', 'cost' => '5', 'max_wp' => null, 'default' => '0', 'delivery_free' => '0', 'apilo_carrier_account_id' => null, 'o' => '1'], + ]; + } + return []; + }); + + $repository = new TransportRepository($mockDb); + $result = $repository->forPaymentMethod(2); + + $this->assertIsArray($result); + $this->assertCount(1, $result); + $this->assertSame(1, $result[0]['id']); + } + + /** + * Test forPaymentMethod — pusta tablica dla nieprawidłowego ID + */ + public function testForPaymentMethodReturnsEmptyForInvalidId(): void + { + $mockDb = $this->createMock(\medoo::class); + $repository = new TransportRepository($mockDb); + + $this->assertEquals([], $repository->forPaymentMethod(0)); + } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 44915d8..e626638 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -75,3 +75,7 @@ if (!class_exists('Shared\\Cache\\CacheHandler')) { } class_alias('CacheHandler', 'Shared\\Cache\\CacheHandler'); } + +if (!class_exists('shop\\Product')) { + require_once __DIR__ . '/stubs/ShopProduct.php'; +} diff --git a/tests/stubs/ShopProduct.php b/tests/stubs/ShopProduct.php new file mode 100644 index 0000000..87738ca --- /dev/null +++ b/tests/stubs/ShopProduct.php @@ -0,0 +1,18 @@ +ver. 0.292 - 17.02.2026
+- UPDATE - pelna migracja front\factory\ do Domain (5 ostatnich klas: ShopProduct, ShopPaymentMethod, ShopPromotion, ShopStatuses, ShopTransport) +- UPDATE - ProductRepository: ~20 nowych metod frontendowych (cache Redis, lazy loading, SKU/EAN fallback) +- UPDATE - PromotionRepository: 5 metod aplikowania promocji (applyTypeWholeBasket/CheapestProduct/CategoriesOr/CategoriesAnd/CategoryCondition) +- UPDATE - TransportRepository: 4 metody frontendowe z cache (transportMethodsFront, transportCostCached, findActiveByIdCached, forPaymentMethod) +- UPDATE - PaymentMethodRepository: metody frontendowe z Redis cache +- CLEANUP - usuniety caly folder front\factory\ (20 klas zmigrowanych) + 4 inne klasy legacy +- FIX - broken transports_list() w ajax.php zastapiony nowa metoda forPaymentMethod() +
ver. 0.291 - 17.02.2026
- UPDATE - migracja front\controls\ShopProducer + shop\Producer do Domain\Producer\ProducerRepository + front\Controllers\ShopProducerController - FIX - bug shop\Producer::__get() referowal nieistniejace $this->data diff --git a/updates/versions.php b/updates/versions.php index ec85d38..07c8c55 100644 --- a/updates/versions.php +++ b/updates/versions.php @@ -1,5 +1,5 @@