db = $db; } /** * @return array{items: array>, total: int} */ public function listForAdmin( array $filters, string $sortColumn = 'date_order', string $sortDir = 'DESC', int $page = 1, int $perPage = 15 ): array { $allowedSortColumns = [ 'id' => 'q1.id', 'number' => 'q1.number', 'date_order' => 'q1.date_order', 'status' => 'q1.status', 'summary' => 'q1.summary', 'client' => 'q1.client', 'order_email' => 'q1.order_email', 'client_phone' => 'q1.client_phone', 'transport' => 'q1.transport', 'payment_method' => 'q1.payment_method', 'total_orders' => 'shop_order.total_orders', 'paid' => 'q1.paid', ]; $sortSql = $allowedSortColumns[$sortColumn] ?? 'q1.date_order'; $sortDir = strtoupper(trim($sortDir)) === 'ASC' ? 'ASC' : 'DESC'; $page = max(1, $page); $perPage = min(self::MAX_PER_PAGE, max(1, $perPage)); $offset = ($page - 1) * $perPage; $where = []; $params = []; $number = $this->normalizeTextFilter($filters['number'] ?? ''); if ($number !== '') { $where[] = 'q1.number LIKE :number'; $params[':number'] = '%' . $number . '%'; } $dateFrom = $this->normalizeDateFilter($filters['date_from'] ?? ''); if ($dateFrom !== null) { $where[] = 'q1.date_order >= :date_from'; $params[':date_from'] = $dateFrom . ' 00:00:00'; } $dateTo = $this->normalizeDateFilter($filters['date_to'] ?? ''); if ($dateTo !== null) { $where[] = 'q1.date_order <= :date_to'; $params[':date_to'] = $dateTo . ' 23:59:59'; } $status = trim((string)($filters['status'] ?? '')); if ($status !== '' && is_numeric($status)) { $where[] = 'q1.status = :status'; $params[':status'] = (int)$status; } $client = $this->normalizeTextFilter($filters['client'] ?? ''); if ($client !== '') { $where[] = 'q1.client LIKE :client'; $params[':client'] = '%' . $client . '%'; } $address = $this->normalizeTextFilter($filters['address'] ?? ''); if ($address !== '') { $where[] = 'q1.address LIKE :address'; $params[':address'] = '%' . $address . '%'; } $email = $this->normalizeTextFilter($filters['order_email'] ?? ''); if ($email !== '') { $where[] = 'q1.order_email LIKE :order_email'; $params[':order_email'] = '%' . $email . '%'; } $phone = $this->normalizeTextFilter($filters['client_phone'] ?? ''); if ($phone !== '') { $where[] = 'q1.client_phone LIKE :client_phone'; $params[':client_phone'] = '%' . $phone . '%'; } $transport = $this->normalizeTextFilter($filters['transport'] ?? ''); if ($transport !== '') { $where[] = 'q1.transport LIKE :transport'; $params[':transport'] = '%' . $transport . '%'; } $payment = $this->normalizeTextFilter($filters['payment_method'] ?? ''); if ($payment !== '') { $where[] = 'q1.payment_method LIKE :payment_method'; $params[':payment_method'] = '%' . $payment . '%'; } $whereSql = ''; if (!empty($where)) { $whereSql = ' WHERE ' . implode(' AND ', $where); } $baseSql = " FROM ( SELECT id, number, date_order, CONCAT(client_name, ' ', client_surname) AS client, client_email AS order_email, CONCAT(client_street, ', ', client_postal_code, ' ', client_city) AS address, status, client_phone, transport, payment_method, summary, paid FROM pp_shop_orders AS pso ) AS q1 LEFT JOIN ( SELECT client_email, COUNT(*) AS total_orders FROM pp_shop_orders WHERE client_name IS NOT NULL AND client_surname IS NOT NULL AND client_email IS NOT NULL GROUP BY client_email ) AS shop_order ON q1.order_email = shop_order.client_email "; $sqlCount = 'SELECT COUNT(0) ' . $baseSql . $whereSql; $stmtCount = $this->db->query($sqlCount, $params); $countRows = $stmtCount ? $stmtCount->fetchAll() : []; $total = 0; if (is_array($countRows) && isset($countRows[0]) && is_array($countRows[0])) { $firstRow = $countRows[0]; $firstValue = reset($firstRow); $total = $firstValue !== false ? (int)$firstValue : 0; } $sql = ' SELECT q1.*, COALESCE(shop_order.total_orders, 0) AS total_orders ' . $baseSql . $whereSql . ' ORDER BY ' . $sortSql . ' ' . $sortDir . ', q1.id DESC' . ' LIMIT ' . $perPage . ' OFFSET ' . $offset; $stmt = $this->db->query($sql, $params); if (!$stmt) { return [ 'items' => [], 'total' => $total, ]; } $items = $stmt ? $stmt->fetchAll() : []; if (!is_array($items)) { $items = []; } foreach ($items as &$item) { $item['id'] = (int)($item['id'] ?? 0); $item['status'] = (int)($item['status'] ?? 0); $item['paid'] = (int)($item['paid'] ?? 0); $item['summary'] = (float)($item['summary'] ?? 0); $item['total_orders'] = (int)($item['total_orders'] ?? 0); $item['number'] = (string)($item['number'] ?? ''); $item['date_order'] = (string)($item['date_order'] ?? ''); $item['client'] = trim((string)($item['client'] ?? '')); $item['order_email'] = (string)($item['order_email'] ?? ''); $item['address'] = trim((string)($item['address'] ?? '')); $item['client_phone'] = (string)($item['client_phone'] ?? ''); $item['transport'] = (string)($item['transport'] ?? ''); $item['payment_method'] = (string)($item['payment_method'] ?? ''); } unset($item); return [ 'items' => $items, 'total' => $total, ]; } public function findForAdmin(int $orderId): array { if ($orderId <= 0) { return []; } $order = $this->db->get('pp_shop_orders', '*', ['id' => $orderId]); if (!is_array($order)) { return []; } $order['id'] = (int)($order['id'] ?? 0); $order['status'] = (int)($order['status'] ?? 0); $order['paid'] = (int)($order['paid'] ?? 0); $order['summary'] = (float)($order['summary'] ?? 0); $order['transport_cost'] = (float)($order['transport_cost'] ?? 0); $order['products'] = $this->orderProducts($orderId); $order['statuses'] = $this->orderStatusHistory($orderId); return $order; } public function orderProducts(int $orderId): array { if ($orderId <= 0) { return []; } $rows = $this->db->select('pp_shop_order_products', '*', [ 'order_id' => $orderId, ]); return is_array($rows) ? $rows : []; } public function orderStatusHistory(int $orderId): array { if ($orderId <= 0) { return []; } $rows = $this->db->select('pp_shop_order_statuses', '*', [ 'order_id' => $orderId, 'ORDER' => ['id' => 'DESC'], ]); return is_array($rows) ? $rows : []; } public function orderStatuses(): array { $rows = $this->db->select('pp_shop_statuses', ['id', 'status'], [ 'ORDER' => ['o' => 'ASC'], ]); if (!is_array($rows)) { return []; } $result = []; foreach ($rows as $row) { $id = (int)($row['id'] ?? 0); if ($id < 0) { continue; } $result[$id] = (string)($row['status'] ?? ''); } return $result; } public function nextOrderId(int $orderId): ?int { if ($orderId <= 0) { return null; } $next = $this->db->get('pp_shop_orders', 'id', [ 'id[>]' => $orderId, 'ORDER' => ['id' => 'ASC'], 'LIMIT' => 1, ]); if (!$next) { return null; } return (int)$next; } public function prevOrderId(int $orderId): ?int { if ($orderId <= 0) { return null; } $prev = $this->db->get('pp_shop_orders', 'id', [ 'id[<]' => $orderId, 'ORDER' => ['id' => 'DESC'], 'LIMIT' => 1, ]); if (!$prev) { return null; } return (int)$prev; } public function saveNotes(int $orderId, string $notes): bool { if ($orderId <= 0) { return false; } $this->db->update('pp_shop_orders', ['notes' => $notes], ['id' => $orderId]); return true; } public function saveOrderByAdmin( int $orderId, string $clientName, string $clientSurname, string $clientStreet, string $clientPostalCode, string $clientCity, string $clientEmail, string $firmName, string $firmStreet, string $firmPostalCode, string $firmCity, string $firmNip, int $transportId, string $inpostPaczkomat, int $paymentMethodId ): bool { if ($orderId <= 0) { return false; } $transportName = $this->db->get('pp_shop_transports', 'name_visible', ['id' => $transportId]); $transportCost = $this->db->get('pp_shop_transports', 'cost', ['id' => $transportId]); $transportDescription = $this->db->get('pp_shop_transports', 'description', ['id' => $transportId]); $paymentMethodName = $this->db->get('pp_shop_payment_methods', 'name', ['id' => $paymentMethodId]); $this->db->update('pp_shop_orders', [ 'client_name' => $clientName, 'client_surname' => $clientSurname, 'client_street' => $clientStreet, 'client_postal_code' => $clientPostalCode, 'client_city' => $clientCity, 'client_email' => $clientEmail, 'firm_name' => $this->nullableString($firmName), 'firm_street' => $this->nullableString($firmStreet), 'firm_postal_code' => $this->nullableString($firmPostalCode), 'firm_city' => $this->nullableString($firmCity), 'firm_nip' => $this->nullableString($firmNip), 'transport_id' => $transportId, 'transport' => $transportName ?: null, 'transport_cost' => $transportCost !== null ? $transportCost : 0, 'transport_description' => $transportDescription ?: null, 'inpost_paczkomat' => $inpostPaczkomat, 'payment_method_id' => $paymentMethodId, 'payment_method' => $paymentMethodName ?: null, ], [ 'id' => $orderId, ]); $this->db->update('pp_shop_orders', [ 'summary' => $this->calculateOrderSummaryByAdmin($orderId), ], [ 'id' => $orderId, ]); return true; } public function calculateOrderSummaryByAdmin(int $orderId): float { if ($orderId <= 0) { return 0.0; } $rows = $this->db->select('pp_shop_order_products', [ 'price_brutto', 'price_brutto_promo', 'quantity', ], [ 'order_id' => $orderId, ]); $summary = 0.0; if (is_array($rows)) { foreach ($rows as $row) { $quantity = (float)($row['quantity'] ?? 0); $pricePromo = (float)($row['price_brutto_promo'] ?? 0); $price = (float)($row['price_brutto'] ?? 0); if ($pricePromo > 0) { $summary += $pricePromo * $quantity; } else { $summary += $price * $quantity; } } } $transportCost = (float)$this->db->get('pp_shop_orders', 'transport_cost', ['id' => $orderId]); return (float)$summary + $transportCost; } public function toggleTrustmateSend(int $orderId): ?int { if ($orderId <= 0) { return null; } $order = $this->db->get('pp_shop_orders', ['trustmate_send'], ['id' => $orderId]); if (!is_array($order)) { return null; } $newValue = ((int)($order['trustmate_send'] ?? 0) === 1) ? 0 : 1; $this->db->update('pp_shop_orders', ['trustmate_send' => $newValue], ['id' => $orderId]); return $newValue; } public function deleteOrder(int $orderId): bool { if ($orderId <= 0) { return false; } $this->db->delete('pp_shop_orders', ['id' => $orderId]); return true; } private function nullableString(string $value): ?string { $value = trim($value); return $value === '' ? null : $value; } private function normalizeTextFilter($value): string { $value = trim((string)$value); if ($value === '') { return ''; } if (strlen($value) > 255) { return substr($value, 0, 255); } return $value; } private function normalizeDateFilter($value): ?string { $value = trim((string)$value); if ($value === '') { return null; } if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) { return null; } return $value; } }