| @@ -66,10 +66,9 @@ | ||
| 66 | 66 | */ |
| 67 | 67 | public static function maybeCreateCustomer($customerData) |
| 68 | 68 | { |
| 69 | 69 | $customer = self::getCustomerFromData($customerData); |
| 70 | - $email = Arr::get($customerData, 'email'); | |
| 71 | - $user = $email ? get_user_by('email', $email) : false; | |
| 70 | + $user = get_user_by('email', $customerData['email']); | |
| 72 | 71 | if ($user) { |
| 73 | 72 | if ($user->first_name) { |
| 74 | 73 | $customerData['first_name'] = $user->first_name; |
| 75 | 74 | } |
| @@ -99,49 +98,16 @@ | ||
| 99 | 98 | * @param object $customer |
| 100 | 99 | */ |
| 101 | 100 | do_action('fluent_support/customer_created', $customer); |
| 102 | 101 | |
| 103 | - return $customer; | |
| 102 | + } else { | |
| 103 | + if (!empty($customerData['user_id']) || !empty($customerData['remote_uid'])) { | |
| 104 | + $customerData = array_filter($customerData); | |
| 105 | + $customer->fill($customerData); | |
| 106 | + $customer->save(); | |
| 107 | + } | |
| 104 | 108 | } |
| 105 | 109 | |
| 106 | - // An existing row may never be claimed for a WordPress account it is not | |
| 107 | - // already linked to. Binding happens when the row is first created, when | |
| 108 | - // the account registers (ProfileInfoService::onWPUserRegister), or when | |
| 109 | - // an agent sets it explicitly from the customer profile. Allowing an | |
| 110 | - // email match to write user_id here is what made a portal takeover | |
| 111 | - // persistent. | |
| 112 | - $incomingUserId = (int) Arr::get($customerData, 'user_id'); | |
| 113 | - | |
| 114 | - if ($incomingUserId && $incomingUserId !== (int) $customer->user_id) { | |
| 115 | - unset($customerData['user_id']); | |
| 116 | - } | |
| 117 | - | |
| 118 | - // Intake may not move the contact address of a record that belongs to a | |
| 119 | - // WordPress account. Every caller here builds its payload from an | |
| 120 | - // address it has not verified -- most of them from the signed-in | |
| 121 | - // account's own email, which WordPress lets that account change with no | |
| 122 | - // confirmation at all. | |
| 123 | - // | |
| 124 | - // Without this, ProfileInfoService::onWPProfileUpdate holding the | |
| 125 | - // address is worth nothing: it refuses the unverified change, and then | |
| 126 | - // the next POST to /customer-portal/tickets resolves the same record | |
| 127 | - // through here and writes the new address anyway. It also produced | |
| 128 | - // duplicate rows on an address belonging to somebody else, without the | |
| 129 | - // collision check the profile_update path applies. | |
| 130 | - // | |
| 131 | - // The address moves through the two paths that prove something instead: | |
| 132 | - // EmailClaimService, where the customer opens a link sent to the address | |
| 133 | - // being claimed, and an agent editing the record directly. | |
| 134 | - if ((int) $customer->user_id) { | |
| 135 | - unset($customerData['email']); | |
| 136 | - } | |
| 137 | - | |
| 138 | - if (!empty($customerData['user_id']) || !empty($customerData['remote_uid'])) { | |
| 139 | - $customerData = array_filter($customerData); | |
| 140 | - $customer->fill($customerData); | |
| 141 | - $customer->save(); | |
| 142 | - } | |
| 143 | - | |
| 144 | 110 | return $customer; |
| 145 | 111 | } |
| 146 | 112 | |
| 147 | 113 | |
| @@ -167,38 +133,25 @@ | ||
| 167 | 133 | */ |
| 168 | 134 | public static function getCustomerFromData($customerData) |
| 169 | 135 | { |
| 170 | 136 | $remoteUid = Arr::get($customerData, 'remote_uid'); |
| 171 | - $email = Arr::get($customerData, 'email'); | |
| 172 | - $userId = (int) Arr::get($customerData, 'user_id'); | |
| 137 | + $email = $customerData['email']; | |
| 173 | 138 | |
| 139 | + $customer = false; | |
| 174 | 140 | if ($remoteUid) { |
| 175 | 141 | $customer = self::where('remote_uid', $remoteUid)->first(); |
| 142 | + } | |
| 176 | 143 | |
| 177 | - if ($customer) { | |
| 178 | - return $customer; | |
| 144 | + if (!$customer) { | |
| 145 | + if (!empty($customerData['user_id'])) { | |
| 146 | + $customer = self::where('user_id', $customerData['user_id'])->first(); | |
| 179 | 147 | } |
| 148 | + if (!$customer) { | |
| 149 | + $customer = self::where('email', $email)->first(); | |
| 150 | + } | |
| 180 | 151 | } |
| 181 | 152 | |
| 182 | - // A WordPress user id is the only identity that can be trusted here. An | |
| 183 | - // account email is editable by its own holder with no verification: the | |
| 184 | - // REST users endpoint calls wp_update_user() directly and skips the | |
| 185 | - // confirmation flow that profile.php runs. An email must therefore never | |
| 186 | - // be able to reach a customer row that belongs to somebody else. | |
| 187 | - // Both lookups order by id so the row that wins is always the oldest | |
| 188 | - // match rather than whatever the storage engine returns first. The email | |
| 189 | - // column carries a plain index, not a unique one, so duplicates are | |
| 190 | - // possible and an inbound reply must keep threading onto the original | |
| 191 | - // record. Helper::getCurrentPerson() orders for the same reason. | |
| 192 | - if ($userId) { | |
| 193 | - return self::where('user_id', $userId)->orderBy('id', 'ASC')->first() ?: false; | |
| 194 | - } | |
| 195 | - | |
| 196 | - if ($email) { | |
| 197 | - return self::where('email', $email)->orderBy('id', 'ASC')->first() ?: false; | |
| 198 | - } | |
| 199 | - | |
| 200 | - return false; | |
| 153 | + return $customer; | |
| 201 | 154 | } |
| 202 | 155 | |
| 203 | 156 | /** |
| 204 | 157 | * getTicketCounts method will return the number of tickets by a customer |