db = $db; } public function listForAdmin( array $filters = [], string $sortColumn = 'name', string $sortDir = 'ASC', int $page = 1, int $perPage = 15 ): array { $allowedSortColumns = [ 'id' => 'st.id', 'name' => 'st.name', 'status' => 'st.status', 'cost' => 'st.cost', 'max_wp' => 'st.max_wp', 'default' => 'st.default', 'o' => 'st.o', ]; $sortSql = $allowedSortColumns[$sortColumn] ?? 'st.name'; $sortDir = strtoupper(trim($sortDir)) === 'DESC' ? 'DESC' : 'ASC'; $page = max(1, $page); $perPage = min(self::MAX_PER_PAGE, max(1, $perPage)); $offset = ($page - 1) * $perPage; $where = ['1 = 1']; $params = []; $name = trim((string)($filters['name'] ?? '')); if ($name !== '') { if (strlen($name) > 255) { $name = substr($name, 0, 255); } $where[] = 'st.name LIKE :name'; $params[':name'] = '%' . $name . '%'; } $status = trim((string)($filters['status'] ?? '')); if ($status === '0' || $status === '1') { $where[] = 'st.status = :status'; $params[':status'] = (int)$status; } $whereSql = implode(' AND ', $where); $sqlCount = " SELECT COUNT(0) FROM pp_shop_transports AS st WHERE {$whereSql} "; $stmtCount = $this->db->query($sqlCount, $params); $countRows = $stmtCount ? $stmtCount->fetchAll() : []; $total = isset($countRows[0][0]) ? (int)$countRows[0][0] : 0; $sql = " SELECT st.id, st.name, st.name_visible, st.description, st.status, st.cost, st.max_wp, st.default, st.apilo_carrier_account_id, st.delivery_free, st.o FROM pp_shop_transports AS st WHERE {$whereSql} ORDER BY {$sortSql} {$sortDir}, st.id ASC LIMIT {$perPage} OFFSET {$offset} "; $stmt = $this->db->query($sql, $params); $items = $stmt ? $stmt->fetchAll() : []; if (!is_array($items)) { $items = []; } foreach ($items as &$item) { $item = $this->normalizeTransport($item); } unset($item); return [ 'items' => $items, 'total' => $total, ]; } public function find(int $transportId): ?array { if ($transportId <= 0) { return null; } $transport = $this->db->get('pp_shop_transports', '*', ['id' => $transportId]); if (!is_array($transport)) { return null; } $transport = $this->normalizeTransport($transport); $paymentMethods = $this->db->select( 'pp_shop_transport_payment_methods', 'id_payment_method', ['id_transport' => $transportId] ); $transport['payment_methods'] = is_array($paymentMethods) ? $paymentMethods : []; return $transport; } public function save(array $data): ?int { $transportId = isset($data['id']) ? (int)$data['id'] : 0; $name = trim((string)($data['name'] ?? '')); $nameVisible = trim((string)($data['name_visible'] ?? '')); $description = trim((string)($data['description'] ?? '')); $status = $this->toSwitchValue($data['status'] ?? 0); $cost = isset($data['cost']) ? (float)$data['cost'] : 0.0; $maxWp = isset($data['max_wp']) && $data['max_wp'] !== '' ? (int)$data['max_wp'] : null; $default = $this->toSwitchValue($data['default'] ?? 0); $apiloCarrierAccountId = isset($data['apilo_carrier_account_id']) && $data['apilo_carrier_account_id'] !== '' ? (int)$data['apilo_carrier_account_id'] : null; $deliveryFree = $this->toSwitchValue($data['delivery_free'] ?? 0); $paymentMethods = $data['payment_methods'] ?? []; if ($default === 1) { $this->db->update('pp_shop_transports', ['default' => 0]); } $transportData = [ 'name' => $name, 'name_visible' => $nameVisible, 'description' => $description, 'status' => $status, 'default' => $default, 'cost' => $cost, 'max_wp' => $maxWp, 'apilo_carrier_account_id' => $apiloCarrierAccountId, 'delivery_free' => $deliveryFree, ]; if (!$transportId) { $this->db->insert('pp_shop_transports', $transportData); $id = $this->db->id(); if ($id) { $this->savePaymentMethodLinks((int)$id, $paymentMethods); return (int)$id; } return null; } else { $this->db->update('pp_shop_transports', $transportData, ['id' => $transportId]); $this->db->delete('pp_shop_transport_payment_methods', ['id_transport' => $transportId]); $this->savePaymentMethodLinks($transportId, $paymentMethods); return $transportId; } } public function allActive(): array { $transports = $this->db->select( 'pp_shop_transports', '*', [ 'status' => 1, 'ORDER' => ['o' => 'ASC'], ] ); if (!is_array($transports)) { return []; } foreach ($transports as &$transport) { $transport = $this->normalizeTransport($transport); } unset($transport); return $transports; } public function findActiveById(int $transportId): ?array { if ($transportId <= 0) { return null; } $transport = $this->db->get( 'pp_shop_transports', '*', ['AND' => ['id' => $transportId, 'status' => 1]] ); if (!$transport) { return null; } return $this->normalizeTransport($transport); } public function getApiloCarrierAccountId(int $transportId): ?int { if ($transportId <= 0) { return null; } $result = $this->db->get( 'pp_shop_transports', 'apilo_carrier_account_id', ['id' => $transportId] ); return $result !== null ? (int)$result : null; } public function getTransportCost(int $transportId): ?float { if ($transportId <= 0) { return null; } $result = $this->db->get( 'pp_shop_transports', 'cost', ['AND' => ['id' => $transportId, 'status' => 1]] ); return $result !== null ? (float)$result : null; } public function lowestTransportPrice(int $wp): ?float { $result = $this->db->get( 'pp_shop_transports', 'cost', [ 'AND' => [ 'status' => 1, 'id' => [2, 4, 6, 8, 9], 'max_wp[>=]' => $wp ], 'ORDER' => ['cost' => 'ASC'] ] ); return $result !== null ? (float)$result : null; } public function allForAdmin(): array { $transports = $this->db->select( 'pp_shop_transports', '*', ['ORDER' => ['o' => 'ASC']] ); if (!is_array($transports)) { return []; } foreach ($transports as &$transport) { $transport = $this->normalizeTransport($transport); } unset($transport); 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; } $products_summary = (float)\Domain\Basket\BasketCalculator::summaryPrice( $basket, $coupon ); if ( \Shared\Helpers\Helpers::normalize_decimal( $products_summary ) >= \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; } } } // Ukryj transporty, dla których nie ma żadnej dostępnej formy płatności $paymentMethodRepo = new \Domain\PaymentMethod\PaymentMethodRepository( $this->db ); $filtered = []; foreach ( $transports as $tr ) { $paymentMethods = $paymentMethodRepo->paymentMethodsByTransport( $tr['id'] ); $order_total = $products_summary + (float)$tr['cost']; $has_available_pm = false; foreach ( $paymentMethods as $pm ) { $min = isset( $pm['min_order_amount'] ) ? (float)$pm['min_order_amount'] : null; $max = isset( $pm['max_order_amount'] ) ? (float)$pm['max_order_amount'] : null; $available = true; if ( $min !== null && $min > 0 && $order_total < $min ) $available = false; if ( $max !== null && $max > 0 && $order_total > $max ) $available = false; if ( $available ) { $has_available_pm = true; break; } } if ( $has_available_pm ) { $filtered[] = $tr; } } return $filtered; } /** * 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)) { foreach ($paymentMethods as $paymentMethodId) { $this->db->insert('pp_shop_transport_payment_methods', [ 'id_payment_method' => (int)$paymentMethodId, 'id_transport' => $transportId, ]); } } elseif ($paymentMethods) { $this->db->insert('pp_shop_transport_payment_methods', [ 'id_payment_method' => (int)$paymentMethods, 'id_transport' => $transportId, ]); } } private function normalizeTransport(array $transport): array { $transport['id'] = isset($transport['id']) ? (int)$transport['id'] : 0; $transport['status'] = $this->toSwitchValue($transport['status'] ?? 0); $transport['default'] = $this->toSwitchValue($transport['default'] ?? 0); $transport['delivery_free'] = $this->toSwitchValue($transport['delivery_free'] ?? 0); $transport['cost'] = isset($transport['cost']) ? (float)$transport['cost'] : 0.0; $transport['max_wp'] = isset($transport['max_wp']) && $transport['max_wp'] !== null ? (int)$transport['max_wp'] : null; $transport['apilo_carrier_account_id'] = isset($transport['apilo_carrier_account_id']) && $transport['apilo_carrier_account_id'] !== null ? (int)$transport['apilo_carrier_account_id'] : null; $transport['o'] = isset($transport['o']) ? (int)$transport['o'] : 0; return $transport; } private function toSwitchValue($value): int { if (is_bool($value)) { return $value ? 1 : 0; } if (is_numeric($value)) { return ((int)$value) === 1 ? 1 : 0; } if (is_string($value)) { $normalized = strtolower(trim($value)); return in_array($normalized, ['1', 'on', 'true', 'yes'], true) ? 1 : 0; } return 0; } }