PluginProbe
Yatra – Travel Booking & Tour Operator Software / trunk
Yatra – Travel Booking & Tour Operator Software vtrunk
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 2.0.10 All 83 releases
yatra / app / Migrations / AvailabilityConditionsMigration.php

AvailabilityConditionsMigration.php in Yatra – Travel Booking & Tour Operator Software trunk, at app/Migrations/AvailabilityConditionsMigration.php

316 lines 11.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Yatra\Migration;
4
5 use Yatra\Migration\MigrationProgress;
6 use Yatra\Utils\Logger;
7 use Yatra\Database\Tables\TripAvailabilityRulesTable;
8
9 class AvailabilityConditionsMigration extends BaseMigration
10 {
11 public function __construct(MigrationProgress $service)
12 {
13 parent::__construct($service);
14 }
15
16 public function run(): array
17 {
18 global $wpdb;
19
20 $migrated = 0;
21 $skipped = 0;
22 $failed = 0;
23
24 try {
25 $table = TripAvailabilityRulesTable::getTableName();
26
27 $conditions_count = $wpdb->get_var(
28 "SELECT COUNT(*) FROM {$wpdb->term_taxonomy} WHERE taxonomy = 'availability_conditions'"
29 );
30
31 if ((int) $conditions_count === 0) {
32 return [
33 'migrated' => 0,
34 'skipped' => 0,
35 'failed' => 0,
36 ];
37 }
38
39 $conditions = $wpdb->get_results(
40 "SELECT t.term_id, t.name, t.slug, tt.description
41 FROM {$wpdb->terms} t
42 INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
43 WHERE tt.taxonomy = 'availability_conditions'"
44 );
45
46 $total = count($conditions);
47
48 foreach ($conditions as $condition) {
49 try {
50 $months_raw = $wpdb->get_var($wpdb->prepare(
51 "SELECT meta_value FROM {$wpdb->termmeta} WHERE term_id = %d AND meta_key = 'months'",
52 $condition->term_id
53 ));
54 $months = $months_raw ? maybe_unserialize($months_raw) : [];
55 $months = is_array($months) ? $months : [];
56
57 $week_days_raw = $wpdb->get_var($wpdb->prepare(
58 "SELECT meta_value FROM {$wpdb->termmeta} WHERE term_id = %d AND meta_key = 'week_days'",
59 $condition->term_id
60 ));
61 $week_days = $week_days_raw ? maybe_unserialize($week_days_raw) : [];
62 $week_days = is_array($week_days) ? $week_days : [];
63
64 $start_date = $wpdb->get_var($wpdb->prepare(
65 "SELECT meta_value FROM {$wpdb->termmeta} WHERE term_id = %d AND meta_key = 'start_date'",
66 $condition->term_id
67 ));
68
69 $end_date = $wpdb->get_var($wpdb->prepare(
70 "SELECT meta_value FROM {$wpdb->termmeta} WHERE term_id = %d AND meta_key = 'end_date'",
71 $condition->term_id
72 ));
73
74 $availability = $wpdb->get_var($wpdb->prepare(
75 "SELECT meta_value FROM {$wpdb->termmeta} WHERE term_id = %d AND meta_key = 'availability'",
76 $condition->term_id
77 ));
78
79 $tourObjectIds = $this->resolveTourObjectIdsForCondition((int) $condition->term_id);
80
81 if ($tourObjectIds === []) {
82 $skipped++;
83 continue;
84 }
85
86 foreach ($tourObjectIds as $oldTourId) {
87 $newTripId = $this->getMigratedTripId($oldTourId);
88
89 if (!$newTripId) {
90 continue;
91 }
92
93 if (!$this->isForceMigration()) {
94 $existing = $wpdb->get_var($wpdb->prepare(
95 "SELECT id FROM `{$table}` WHERE trip_id = %d AND name = %s",
96 $newTripId,
97 $condition->name
98 ));
99
100 if ($existing) {
101 $skipped++;
102 continue;
103 }
104 }
105
106 $ruleData = $this->convertToRecurringRule(
107 $condition,
108 $months,
109 $week_days,
110 $start_date ? (string) $start_date : null,
111 $end_date ? (string) $end_date : null,
112 $availability ? (string) $availability : null
113 );
114
115 $result = $this->insertRecurringRule($newTripId, $ruleData);
116
117 if ($result) {
118 $migrated++;
119 } else {
120 $failed++;
121 Logger::error('Availability condition: insert failed', [
122 'source' => 'migration',
123 'condition_id' => $condition->term_id,
124 'old_tour_id' => $oldTourId,
125 'new_trip_id' => $newTripId,
126 'db_error' => $wpdb->last_error,
127 ]);
128 }
129 }
130 } catch (\Exception $e) {
131 $failed++;
132 Logger::error('Availability condition migration exception', [
133 'source' => 'migration',
134 'condition_id' => $condition->term_id,
135 'error' => $e->getMessage(),
136 ]);
137 }
138
139 $this->updateProgress('availability_conditions', 'running', $migrated, $skipped, $failed, $total, null, null);
140 }
141 } catch (\Throwable $e) {
142 Logger::error('Availability conditions migration failed', [
143 'source' => 'migration',
144 'error' => $e->getMessage(),
145 ]);
146 }
147
148 return [
149 'migrated' => $migrated,
150 'skipped' => $skipped,
151 'failed' => $failed,
152 ];
153 }
154
155 /**
156 * Tours linked via term_relationships and/or legacy Pro meta _yatra_availability_conditions_ids_order (term_taxonomy_ids).
157 *
158 * @return int[] Old tour post IDs
159 */
160 private function resolveTourObjectIdsForCondition(int $termId): array
161 {
162 global $wpdb;
163
164 $ttId = (int) $wpdb->get_var($wpdb->prepare(
165 "SELECT term_taxonomy_id FROM {$wpdb->term_taxonomy}
166 WHERE term_id = %d AND taxonomy = 'availability_conditions' LIMIT 1",
167 $termId
168 ));
169
170 $seen = [];
171
172 if ($ttId > 0) {
173 $fromRel = $wpdb->get_col($wpdb->prepare(
174 "SELECT object_id FROM {$wpdb->term_relationships} WHERE term_taxonomy_id = %d",
175 $ttId
176 ));
177 foreach ($fromRel as $oid) {
178 $seen[(int) $oid] = true;
179 }
180
181 // Meta stores comma-separated term_taxonomy_id values (see yatra-pro set_object_terms).
182 $fromMeta = $wpdb->get_col($wpdb->prepare(
183 "SELECT pm.post_id FROM {$wpdb->postmeta} pm
184 INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
185 WHERE pm.meta_key = '_yatra_availability_conditions_ids_order'
186 AND p.post_type = 'tour'
187 AND p.post_status NOT IN ('trash', 'auto-draft')
188 AND FIND_IN_SET(%d, REPLACE(pm.meta_value, ' ', ''))",
189 $ttId
190 ));
191 foreach ($fromMeta as $oid) {
192 $seen[(int) $oid] = true;
193 }
194 }
195
196 return array_keys($seen);
197 }
198
199 /**
200 * Map legacy yatra_tour_availability_status keys (booking|enquiry|none) to new enum.
201 */
202 private function mapLegacyAvailabilityStatus(?string $legacy): string
203 {
204 $key = $legacy !== null ? strtolower(trim($legacy)) : '';
205 switch ($key) {
206 case 'none':
207 case 'unavailable':
208 return 'unavailable';
209 case 'enquiry':
210 case 'limited':
211 return 'limited';
212 default:
213 return 'available';
214 }
215 }
216
217 /**
218 * Convert old availability condition to new recurring rule format
219 */
220 private function convertToRecurringRule(
221 object $condition,
222 array $months,
223 array $week_days,
224 ?string $start_date,
225 ?string $end_date,
226 ?string $availability
227 ): array {
228 $days_of_week = array_values(array_unique(array_map('intval', $week_days)));
229 if ($days_of_week === []) {
230 $days_of_week = [0, 1, 2, 3, 4, 5, 6];
231 }
232
233 $normalized_months = [];
234 if ($months !== []) {
235 foreach ($months as $month) {
236 $monthInt = (int) $month;
237 if ($monthInt >= 0 && $monthInt <= 11) {
238 $normalized_months[] = $monthInt + 1;
239 } elseif ($monthInt >= 1 && $monthInt <= 12) {
240 $normalized_months[] = $monthInt;
241 }
242 }
243 $normalized_months = array_values(array_unique($normalized_months));
244 }
245
246 $recurrencePattern = [];
247 if ($normalized_months !== []) {
248 $recurrencePattern['months'] = $normalized_months;
249 }
250
251 $availabilityStatus = $this->mapLegacyAvailabilityStatus($availability);
252
253 return [
254 'name' => $condition->name,
255 'rule_type' => 'weekly',
256 'recurrence_type' => 'weekly',
257 'status' => 'active',
258 'start_date' => !empty($start_date) ? $start_date : current_time('Y-m-d'),
259 'end_date' => !empty($end_date) ? $end_date : null,
260 'days_of_week' => wp_json_encode($days_of_week),
261 'recurrence_pattern' => $recurrencePattern !== [] ? wp_json_encode($recurrencePattern) : null,
262 'months' => $normalized_months !== [] ? wp_json_encode($normalized_months) : null,
263 'interval' => 1,
264 'availability_status' => $availabilityStatus,
265 'created_at' => current_time('mysql'),
266 ];
267 }
268
269 /**
270 * Insert recurring rule into new system
271 */
272 private function insertRecurringRule(int $tripId, array $ruleData): bool
273 {
274 global $wpdb;
275 $table = TripAvailabilityRulesTable::getTableName();
276
277 $insertData = [
278 'trip_id' => $tripId,
279 'name' => $ruleData['name'],
280 'rule_type' => $ruleData['rule_type'],
281 'recurrence_type' => $ruleData['recurrence_type'],
282 'status' => $ruleData['status'],
283 'start_date' => $ruleData['start_date'],
284 'end_date' => $ruleData['end_date'],
285 'days_of_week' => $ruleData['days_of_week'],
286 'recurrence_pattern' => $ruleData['recurrence_pattern'],
287 'months' => $ruleData['months'],
288 'interval' => (int) $ruleData['interval'],
289 'availability_status' => $ruleData['availability_status'],
290 'created_at' => $ruleData['created_at'],
291 'updated_at' => current_time('mysql'),
292 ];
293
294 $formats = [
295 '%d',
296 '%s',
297 '%s',
298 '%s',
299 '%s',
300 '%s',
301 '%s',
302 '%s',
303 '%s',
304 '%s',
305 '%d',
306 '%s',
307 '%s',
308 '%s',
309 ];
310
311 $result = $wpdb->insert($table, $insertData, $formats);
312
313 return $result !== false;
314 }
315 }
316