repository->findActiveByEvent('order.status_aged'); if ($rules === []) { return 0; } $totalTriggered = 0; foreach ($rules as $rule) { try { $totalTriggered += $this->processRule($rule); } catch (Throwable) { // Blad jednej reguly nie blokuje kolejnych } } return $totalTriggered; } /** * @param array $rule */ private function processRule(array $rule): int { $conditions = is_array($rule['conditions'] ?? null) ? $rule['conditions'] : []; $statusCodes = $this->extractStatusCodes($conditions); $days = $this->extractDays($conditions); if ($statusCodes === [] || $days < 1) { return 0; } $orders = $this->findAgedOrders($statusCodes, $days); $triggered = 0; foreach ($orders as $order) { $orderId = (int) ($order['id'] ?? 0); if ($orderId <= 0) { continue; } try { $currentStatus = strtolower(trim((string) ($order['external_status_id'] ?? ''))); $lastChanged = (string) ($order['last_changed'] ?? ''); $actualDays = $lastChanged !== '' ? $this->daysSince($lastChanged) : $days; $this->automation->trigger('order.status_aged', $orderId, [ 'current_status' => $currentStatus, 'days_in_status' => $actualDays, 'status_changed_at' => $lastChanged, ]); $triggered++; } catch (Throwable) { // Blad jednego zamowienia nie blokuje kolejnych } } return $triggered; } /** * @param list> $conditions * @return list */ private function extractStatusCodes(array $conditions): array { foreach ($conditions as $condition) { $type = (string) ($condition['condition_type'] ?? ''); $value = is_array($condition['condition_value'] ?? null) ? $condition['condition_value'] : []; if ($type === 'order_status') { $codes = is_array($value['order_status_codes'] ?? null) ? $value['order_status_codes'] : []; return array_values(array_filter( array_map(static fn (mixed $c): string => strtolower(trim((string) $c)), $codes), static fn (string $c): bool => $c !== '' )); } } return []; } /** * @param list> $conditions */ private function extractDays(array $conditions): int { foreach ($conditions as $condition) { $type = (string) ($condition['condition_type'] ?? ''); $value = is_array($condition['condition_value'] ?? null) ? $condition['condition_value'] : []; if ($type === 'days_in_status') { return max(0, (int) ($value['days'] ?? 0)); } } return 0; } /** * @param list $statusCodes * @return list> */ private function findAgedOrders(array $statusCodes, int $days): array { if ($statusCodes === [] || $days < 1) { return []; } $placeholders = implode(', ', array_fill(0, count($statusCodes), '?')); $sql = "SELECT o.id, o.external_status_id, MAX(h.changed_at) AS last_changed FROM orders o INNER JOIN order_status_history h ON h.order_id = o.id AND LOWER(h.to_status_id) = LOWER(o.external_status_id) WHERE LOWER(COALESCE(o.external_status_id, '')) IN ({$placeholders}) GROUP BY o.id, o.external_status_id HAVING MAX(h.changed_at) <= DATE_SUB(NOW(), INTERVAL ? DAY) LIMIT " . self::MAX_ORDERS_PER_RULE; try { $stmt = $this->db->prepare($sql); $params = $statusCodes; $params[] = $days; $stmt->execute($params); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); return is_array($rows) ? $rows : []; } catch (Throwable) { return []; } } private function daysSince(string $datetime): int { $timestamp = strtotime($datetime); if ($timestamp === false) { return 0; } $diff = time() - $timestamp; return max(0, (int) floor($diff / 86400)); } }