PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.4.0
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.4.0
2.4.0 2.4.1 2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.2.0 2.1.21 2.1.20 2.1.19 2.1.18 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.2 All 57 releases
← All changes | includes/Repositories/ClientRepository.php +54 -13 2.3.32.4.0 View file →
@@ -20,8 +20,15 @@
20 20 *
21 21 * Handles data access for client objects using WordPress users.
22 22 */
23 23 class ClientRepository implements ClientRepositoryInterface {
24 + /** @var string Why the last create() returned null, in words for the form. */
25 + protected $last_error = '';
26 +
27 + public function getLastError(): string {
28 + return (string) $this->last_error;
29 + }
30 +
24 31
25 32 /**
26 33 * Find a client by ID
27 34 *
@@ -101,10 +108,14 @@
101 108
102 109 $user_id = wp_insert_user($user_data);
103 110
104 111 if (is_wp_error($user_id)) {
112 + // Keep the reason for the caller: "that email is already registered"
113 + // is something the person at the form can act on, "failed" is not.
114 + $this->last_error = $user_id->get_error_message();
105 115 return null;
106 116 }
117 + $this->last_error = '';
107 118
108 119 // Deny backend access on new clients via a per-user capability
109 120 // override. The user keeps the `customer` role (so Pro Client
110 121 // Portal's `in_array('customer', $user->roles)` check still
@@ -125,8 +136,16 @@
125 136
126 137 // Set the client data
127 138 $this->setClientData($client, $data);
128 139
140 + /**
141 + * Fires once a client (and their WordPress user) has been created.
142 + *
143 + * @param Client $client The new client; its id is the user id.
144 + * @param array $data The submitted client data.
145 + */
146 + do_action('easy_invoice_client_created', $client, $data);
147 +
129 148 return $client;
130 149 }
131 150
132 151 /**
@@ -215,21 +234,28 @@
215 234 foreach ($posts as $post) {
216 235 wp_delete_post($post->ID, true);
217 236 }
218 237
219 - // Delete all payments associated with this client
220 - $payments = $wpdb->get_col($wpdb->prepare(
221 - "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'easy_payment' AND ID IN (
222 - SELECT post_id FROM {$wpdb->postmeta}
223 - WHERE meta_key = '_easy_payment_client_id' AND meta_value = %d
224 - )",
225 - $id
226 - ));
238 + // Payments are deliberately NOT deleted here.
239 + //
240 + // There used to be a query for post type 'easy_payment' on meta
241 + // '_easy_payment_client_id'. Neither exists — payments are
242 + // 'easy_invoice_payment' and record '_invoice_id', with no client id at
243 + // all — so it matched nothing on every run. Deleting a client has never
244 + // removed a payment record.
245 + //
246 + // The query is gone rather than corrected. Resolving payments properly
247 + // (through ClientLedger, which knows the real relationship) would make
248 + // this destroy records it has never touched, on a path a user reaches by
249 + // clicking Delete on a client. Widening a destructive operation as a
250 + // side effect of fixing a broken query is not a safe trade: a payment is
251 + // the evidence money changed hands, and the same reasoning that stops
252 + // InvoiceRetention deleting an issued invoice applies to it.
253 + //
254 + // What changed is that the confirmation dialog now counts payments
255 + // correctly (see EasyInvoiceAjax::handleDeleteClient), so a merchant is
256 + // told what will be left behind instead of being shown zero.
227 257
228 - foreach ($payments as $payment_id) {
229 - wp_delete_post($payment_id, true);
230 - }
231 -
232 258 // Delete the WordPress user (this will also delete all user meta)
233 259 $result = wp_delete_user($id);
234 260
235 261 // Return the result
@@ -304,9 +330,24 @@
304 330 public function search($query) {
305 331 $query = trim((string) $query);
306 332
307 333 if ($query === '') {
308 - return $this->all();
334 + // The picker opens with an empty query to show "some" clients. Build
335 + // only the 50 it can show instead of a model for every user on the site.
336 + $recent = new WP_User_Query([
337 + 'number' => 50,
338 + 'orderby' => 'display_name',
339 + 'order' => 'ASC',
340 + 'role__not_in' => ['Administrator'],
341 + ]);
342 + $clients = [];
343 + foreach ($recent->get_results() as $user) {
344 + $client = $this->createClientFromUser($user);
345 + if ($client) {
346 + $clients[] = $client;
347 + }
348 + }
349 + return $clients;
309 350 }
310 351
311 352 $clients = [];
312 353 $seen_ids = [];