PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.16
Yatra – Travel Booking & Tour Operator Software v3.0.16
3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 All 84 releases
← All changes | app/Repositories/RecurringAvailabilityRepository.php +59 -6 3.0.4 → 3.0.16 View file →
@@ -79,8 +79,46 @@
79 79 return array_map([$this, 'hydrateRule'], $results ?: []);
80 80 }
81 81
82 82 /**
83 + * Find all rules matching ANY of the given trip IDs (batched
84 + * counterpart of {@see self::findByTripId()}). Used by callers like
85 + * {@see \Yatra\Repositories\DestinationRepository::computeStartingPriceForTripIds()}
86 + * that previously issued one query per trip and got N+1 amplification.
87 + *
88 + * Currently supports just the `status` filter — that's all the
89 + * batched callers need; ORDER and pagination are intentionally
90 + * dropped because the caller folds the rows in PHP.
91 + *
92 + * @param list<int> $tripIds
93 + */
94 + public function findByTripIds(array $tripIds, array $filters = []): array
95 + {
96 + $tripIds = array_values(array_unique(array_filter(array_map('intval', $tripIds), static fn (int $id): bool => $id > 0)));
97 + if ($tripIds === []) {
98 + return [];
99 + }
100 +
101 + $table = esc_sql($this->table);
102 + $placeholders = implode(',', array_fill(0, count($tripIds), '%d'));
103 + $where = ["trip_id IN ({$placeholders})"];
104 + $params = $tripIds;
105 +
106 + if (!empty($filters['status']) && $filters['status'] !== 'all') {
107 + $where[] = 'status = %s';
108 + $params[] = (string) $filters['status'];
109 + }
110 +
111 + $query = "SELECT * FROM `{$table}` WHERE " . implode(' AND ', $where);
112 +
113 + $results = $this->wpdb->get_results(
114 + $this->wpdb->prepare($query, ...$params)
115 + );
116 +
117 + return array_map([$this, 'hydrateRule'], $results ?: []);
118 + }
119 +
120 + /**
83 121 * Count rules by trip ID
84 122 */
85 123 public function countByTripId(int $tripId, array $filters = []): int
86 124 {
@@ -185,23 +223,38 @@
185 223 */
186 224 public function findActiveRulesForDate(int $tripId, string $date): array
187 225 {
188 226 $table = esc_sql($this->table);
189 -
227 +
228 + // Date-only compare: start_date/end_date are DATE columns, so a datetime
229 + // input would break the `end_date >= %s` boundary (DATE treated as midnight).
230 + if (preg_match('/^(\d{4}-\d{2}-\d{2})/', $date, $m)) {
231 + $date = $m[1];
232 + }
233 +
234 + // Callers (notably CapacityService) take the FIRST row as the winning
235 + // rule, so the ordering must be total — not just `priority DESC`.
236 + // `priority` is not exposed in the rule editor, so every rule carries the
237 + // same default and overlapping rules tied, leaving the winner to MySQL's
238 + // arbitrary row order. A trip with an older wide rule (e.g. 25 seats) plus
239 + // a newer, narrower one (e.g. 1 seat for a private group) could therefore
240 + // resolve to the wrong capacity and silently fall back to the trip default.
241 + // Break ties by most-recently-created, matching the ordering this same
242 + // repository already uses for rule listings.
190 243 $query = $this->wpdb->prepare(
191 - "SELECT * FROM `{$table}`
192 - WHERE trip_id = %d
244 + "SELECT * FROM `{$table}`
245 + WHERE trip_id = %d
193 246 AND status = 'active'
194 247 AND start_date <= %s
195 248 AND (end_date IS NULL OR end_date >= %s)
196 - ORDER BY priority DESC",
249 + ORDER BY priority DESC, created_at DESC, id DESC",
197 250 $tripId,
198 251 $date,
199 252 $date
200 253 );
201 -
254 +
202 255 $results = $this->wpdb->get_results($query);
203 -
256 +
204 257 return array_map([$this, 'hydrateRule'], $results ?: []);
205 258 }
206 259
207 260 /**