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 / CustomerMigration.php

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

210 lines 8.8 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\Database\Tables\CustomersTable;
6 use Yatra\Migration\MigrationProgress;
7 use Yatra\Utils\Logger;
8
9 /**
10 * CustomerMigration - Migrates customers from old Yatra CPT (yatra-customers) to new custom table.
11 *
12 * Old system: Custom Post Type 'yatra-customers'
13 * - post_title = customer email
14 * - post_meta keys from yatra_tour_customer_info: fullname, email, phone, country, etc.
15 * - post_meta 'yatra_customer_booking_meta' = array of booking meta params
16 * - post_meta 'yatra_user_id' = WordPress user ID
17 *
18 * New system: Custom table wp_yatra_customers
19 */
20 class CustomerMigration extends BaseMigration
21 {
22 public function __construct(MigrationProgress $service)
23 {
24 parent::__construct($service);
25 }
26
27 public function run(): array
28 {
29 $migrated = 0;
30 $skipped = 0;
31 $failed = 0;
32
33 // Old customers are stored as CPT 'yatra-customers' in wp_posts
34 $oldCustomers = $this->wpdb->get_results(
35 "SELECT * FROM {$this->wpdb->posts}
36 WHERE post_type = 'yatra-customers'
37 AND post_status NOT IN ('trash', 'auto-draft')"
38 );
39 $total = count($oldCustomers);
40
41 if ($total === 0) {
42 return compact('migrated', 'skipped', 'failed');
43 }
44
45 Logger::info("Found {$total} old customers to migrate", ['source' => 'migration', 'data_type' => 'customers']);
46
47 foreach ($oldCustomers as $oldCustomer) {
48 try {
49 // Check if already migrated
50 $migratedId = $this->getRawPostMeta($oldCustomer->ID, '_migrated_to_customer_id');
51 if ($migratedId && !$this->isForceMigration()) {
52 $skipped++;
53 $this->updateProgress('customers', 'running', $migrated, $skipped, $failed, $total, null, null);
54 continue;
55 }
56
57 $meta = $this->getPostMeta($oldCustomer->ID);
58
59 // In old system, post_title is the customer email
60 $email = $oldCustomer->post_title;
61
62 // Customer info is stored as individual post meta keys.
63 // These come from $yatra_tour_customer_info saved during booking via
64 // Yatra_Customers::update() which iterates the form array and calls
65 // update_post_meta() for each key.
66 //
67 // Checkout form field keys (class-yatra-checkout-form.php):
68 // fullname, email, country, phone_number <-- note: phone_NUMBER not phone
69 $fullname = $meta['fullname'] ?? $meta['full_name'] ?? $meta['name'] ?? '';
70 // Always try phone_number first — that is the real checkout form field name.
71 $phone = $meta['phone_number'] ?? $meta['phone'] ?? $meta['contact'] ?? '';
72 $country = $meta['country'] ?? '';
73 $address = $meta['address'] ?? '';
74 $city = $meta['city'] ?? '';
75 $wpUserId = $meta['yatra_user_id'] ?? null;
76
77 // Parse fullname into first/last
78 $nameParts = $this->parseFullName($fullname);
79
80 // Check if customer with this email already exists in new table
81 $existingCustomerId = $this->wpdb->get_var($this->wpdb->prepare(
82 "SELECT id FROM " . CustomersTable::getTableName() . " WHERE email = %s",
83 $email
84 ));
85
86 $customerData = [
87 'first_name' => $nameParts['first_name'],
88 'last_name' => $nameParts['last_name'],
89 'email' => $email,
90 'phone' => $phone,
91 'country' => $country,
92 'city' => $city,
93 'address' => $address,
94 'user_id' => !empty($wpUserId) ? (int) $wpUserId : null,
95 'status' => 'active',
96 'created_at' => $oldCustomer->post_date,
97 'updated_at' => $oldCustomer->post_modified,
98 ];
99
100 if ($existingCustomerId && !$this->isForceMigration()) {
101 // Update existing customer
102 $updateData = $customerData;
103 unset($updateData['created_at']);
104
105 $this->wpdb->update(
106 CustomersTable::getTableName(),
107 $updateData,
108 ['id' => $existingCustomerId]
109 );
110 $newCustomerId = $existingCustomerId;
111 $migrated++;
112 } elseif ($existingCustomerId && $this->isForceMigration()) {
113 // Update existing customer during force migration
114 $updateData = $customerData;
115 unset($updateData['created_at']);
116
117 $this->wpdb->update(
118 CustomersTable::getTableName(),
119 $updateData,
120 ['id' => $existingCustomerId]
121 );
122 $newCustomerId = $existingCustomerId;
123 Logger::debug("Customer updated (force migration): {$email}", [
124 'source' => 'migration',
125 'customer_id' => $oldCustomer->ID,
126 'existing_customer_id' => $existingCustomerId
127 ]);
128 $migrated++;
129 } else {
130 // Insert new customer
131 $inserted = $this->wpdb->insert(
132 CustomersTable::getTableName(),
133 $customerData
134 );
135
136 if ($inserted) {
137 $newCustomerId = $this->wpdb->insert_id;
138 $migrated++;
139 } else {
140 // Check if it's a duplicate key error and handle gracefully
141 if (strpos($this->wpdb->last_error, 'Duplicate entry') !== false) {
142 // Try to find existing customer by email
143 $existingCustomer = $this->wpdb->get_row($this->wpdb->prepare(
144 "SELECT id FROM " . CustomersTable::getTableName() . " WHERE email = %s LIMIT 1",
145 $email
146 ));
147
148 if ($existingCustomer) {
149 $newCustomerId = $existingCustomer->id;
150 $skipped++;
151 Logger::debug("Customer skipped (email already exists): {$email}", [
152 'source' => 'migration',
153 'customer_id' => $oldCustomer->ID,
154 'existing_customer_id' => $existingCustomer->id
155 ]);
156 $this->updateProgress('customers', 'running', $migrated, $skipped, $failed, $total, null, null);
157 continue;
158 }
159 }
160
161 $failed++;
162 Logger::error("Failed to insert customer ID {$oldCustomer->ID}: {$this->wpdb->last_error}", [
163 'source' => 'migration',
164 'data_type' => 'customers',
165 'customer_id' => $oldCustomer->ID,
166 'email' => $email,
167 ]);
168 $this->updateProgress('customers', 'running', $migrated, $skipped, $failed, $total, null, null);
169 continue;
170 }
171 }
172
173 // Mark as migrated
174 $this->setRawPostMeta($oldCustomer->ID, '_migrated_to_customer_id', (string) $newCustomerId);
175
176 $this->updateProgress('customers', 'running', $migrated, $skipped, $failed, $total, null, null);
177 } catch (\Exception $e) {
178 $failed++;
179 Logger::error("Exception migrating customer ID {$oldCustomer->ID}: {$e->getMessage()}", [
180 'source' => 'migration',
181 'data_type' => 'customers',
182 'customer_id' => $oldCustomer->ID,
183 ]);
184 $this->updateProgress('customers', 'running', $migrated, $skipped, $failed, $total, null, null);
185 }
186 }
187
188 return compact('migrated', 'skipped', 'failed');
189 }
190
191 /**
192 * Parse a full name string into first and last name parts
193 */
194 private function parseFullName(string $fullname): array
195 {
196 $fullname = trim($fullname);
197
198 if (empty($fullname)) {
199 return ['first_name' => '', 'last_name' => ''];
200 }
201
202 $parts = preg_split('/\s+/', $fullname, 2);
203
204 return [
205 'first_name' => $parts[0] ?? '',
206 'last_name' => $parts[1] ?? '',
207 ];
208 }
209 }
210