| @@ -28,8 +28,17 @@ | ||
| 28 | 28 | return null; |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | 31 | /** |
| 32 | + * Clamp an alert threshold to the column's range (smallint unsigned: 0–65535) | |
| 33 | + * so out-of-range input can't abort the write under MySQL strict mode. | |
| 34 | + */ | |
| 35 | + private function clampAlertThreshold($value): int | |
| 36 | + { | |
| 37 | + return max(0, min(65535, (int) $value)); | |
| 38 | + } | |
| 39 | + | |
| 40 | + /** | |
| 32 | 41 | * Get table name |
| 33 | 42 | */ |
| 34 | 43 | protected function getTableName(): string |
| 35 | 44 | { |
| @@ -63,9 +72,15 @@ | ||
| 63 | 72 | */ |
| 64 | 73 | public function findByTripIdAndDate(int $tripId, string $departureDate): ?object |
| 65 | 74 | { |
| 66 | 75 | $table = esc_sql($this->table); |
| 67 | - | |
| 76 | + | |
| 77 | + // departure_date is a DATE column — strip any time component so a datetime | |
| 78 | + // input still matches (avoids date-vs-datetime string-compare misses). | |
| 79 | + if (preg_match('/^(\d{4}-\d{2}-\d{2})/', $departureDate, $m)) { | |
| 80 | + $departureDate = $m[1]; | |
| 81 | + } | |
| 82 | + | |
| 68 | 83 | $result = $this->wpdb->get_row($this->wpdb->prepare( |
| 69 | 84 | "SELECT * FROM `{$table}` |
| 70 | 85 | WHERE trip_id = %d |
| 71 | 86 | AND departure_date = %s |
| @@ -317,18 +332,22 @@ | ||
| 317 | 332 | 'to_longitude' => $this->sanitizeCoordinate($data['to_longitude'] ?? null), |
| 318 | 333 | 'special_notes' => !empty($data['special_notes']) ? sanitize_textarea_field($data['special_notes']) : null, |
| 319 | 334 | 'cutoff_date' => !empty($data['cutoff_date']) ? sanitize_text_field($data['cutoff_date']) : null, |
| 320 | 335 | 'cutoff_hours' => (int) ($data['cutoff_hours'] ?? 24), |
| 336 | + 'is_blocked' => !empty($data['is_blocked']) ? 1 : 0, | |
| 337 | + 'block_reason' => !empty($data['block_reason']) ? mb_substr(sanitize_textarea_field($data['block_reason']), 0, 255) : null, | |
| 338 | + 'alert_threshold' => (isset($data['alert_threshold']) && $data['alert_threshold'] !== '' && $data['alert_threshold'] !== null) ? $this->clampAlertThreshold($data['alert_threshold']) : null, | |
| 321 | 339 | ]; |
| 322 | - | |
| 340 | + | |
| 323 | 341 | // Calculate discount percentage if not provided |
| 324 | 342 | if (!empty($insertData['original_price']) && !empty($insertData['discounted_price']) && empty($data['discount_percentage'])) { |
| 325 | 343 | $insertData['discount_percentage'] = round((($insertData['original_price'] - $insertData['discounted_price']) / $insertData['original_price']) * 100, 2); |
| 326 | 344 | } |
| 327 | - | |
| 345 | + | |
| 328 | 346 | $this->wpdb->insert($table, $insertData, [ |
| 329 | 347 | '%d', '%s', '%s', '%s', '%s', '%s', '%d', '%d', '%d', '%d', |
| 330 | 348 | '%s', '%f', '%f', '%f', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d', |
| 349 | + '%d', '%s', '%d', | |
| 331 | 350 | ]); |
| 332 | 351 | |
| 333 | 352 | return $this->wpdb->insert_id; |
| 334 | 353 | } |
| @@ -374,9 +393,15 @@ | ||
| 374 | 393 | } |
| 375 | 394 | if (isset($data['special_notes'])) $updateData['special_notes'] = !empty($data['special_notes']) ? sanitize_textarea_field($data['special_notes']) : null; |
| 376 | 395 | if (isset($data['cutoff_date'])) $updateData['cutoff_date'] = !empty($data['cutoff_date']) ? sanitize_text_field($data['cutoff_date']) : null; |
| 377 | 396 | if (isset($data['cutoff_hours'])) $updateData['cutoff_hours'] = (int) $data['cutoff_hours']; |
| 378 | - | |
| 397 | + // array_key_exists (not isset) so an explicit null from the form — e.g. | |
| 398 | + // clearing the block reason / threshold when a date is unblocked — is | |
| 399 | + // honored instead of silently skipped (isset(null) === false). | |
| 400 | + if (array_key_exists('is_blocked', $data)) $updateData['is_blocked'] = !empty($data['is_blocked']) ? 1 : 0; | |
| 401 | + if (array_key_exists('block_reason', $data)) $updateData['block_reason'] = !empty($data['block_reason']) ? mb_substr(sanitize_textarea_field($data['block_reason']), 0, 255) : null; | |
| 402 | + if (array_key_exists('alert_threshold', $data)) $updateData['alert_threshold'] = ($data['alert_threshold'] !== '' && $data['alert_threshold'] !== null) ? $this->clampAlertThreshold($data['alert_threshold']) : null; | |
| 403 | + | |
| 379 | 404 | // Calculate discount percentage if not provided |
| 380 | 405 | if (!empty($updateData['original_price']) && !empty($updateData['discounted_price']) && empty($updateData['discount_percentage'])) { |
| 381 | 406 | $updateData['discount_percentage'] = round((($updateData['original_price'] - $updateData['discounted_price']) / $updateData['original_price']) * 100, 2); |
| 382 | 407 | } |