| @@ -178,8 +178,80 @@ | ||
| 178 | 178 | return $result; |
| 179 | 179 | } |
| 180 | 180 | |
| 181 | 181 | /** |
| 182 | + * Bulk-save activities for a single day in one DB transaction-equivalent batch. | |
| 183 | + * | |
| 184 | + * Accepts an `activities` array; each row with `id` is updated, each row | |
| 185 | + * without `id` is created. Returns per-row result objects so the caller can | |
| 186 | + * surface partial failures. Cache invalidation fires once at the end (via | |
| 187 | + * the existing per-row hooks already invoked by the repository). | |
| 188 | + * | |
| 189 | + * @param int $dayId The yatra_trip_itinerary_days.id row. | |
| 190 | + * @param int $tripId The trip id (used for the create branch). | |
| 191 | + * @param array $activities Array of activity payloads. Each row may include | |
| 192 | + * an `id` (update) or omit it (create). | |
| 193 | + * @return array {created: int, updated: int, results: array} | |
| 194 | + */ | |
| 195 | + public function bulkSaveDayActivities(int $dayId, int $tripId, array $activities): array | |
| 196 | + { | |
| 197 | + $results = []; | |
| 198 | + $created = 0; | |
| 199 | + $updated = 0; | |
| 200 | + $failed = 0; | |
| 201 | + | |
| 202 | + foreach ($activities as $i => $row) { | |
| 203 | + if (!is_array($row)) { | |
| 204 | + $results[] = ['index' => $i, 'ok' => false, 'error' => 'Row is not an object']; | |
| 205 | + $failed++; | |
| 206 | + continue; | |
| 207 | + } | |
| 208 | + // The repo expects day_id + trip_id on creates; inject here so the | |
| 209 | + // client doesn't have to repeat them per row. | |
| 210 | + $row['day_id'] = $dayId; | |
| 211 | + if ($tripId > 0 && empty($row['trip_id'])) { | |
| 212 | + $row['trip_id'] = $tripId; | |
| 213 | + } | |
| 214 | + | |
| 215 | + try { | |
| 216 | + if (!empty($row['id'])) { | |
| 217 | + $entryId = (int) $row['id']; | |
| 218 | + unset($row['id']); | |
| 219 | + $ok = $this->repository->updateEntry($entryId, $row, 'activity'); | |
| 220 | + if ($ok) { | |
| 221 | + $updated++; | |
| 222 | + $results[] = ['index' => $i, 'ok' => true, 'id' => $entryId, 'op' => 'update']; | |
| 223 | + } else { | |
| 224 | + $failed++; | |
| 225 | + $results[] = ['index' => $i, 'ok' => false, 'id' => $entryId, 'error' => 'updateEntry returned false']; | |
| 226 | + } | |
| 227 | + } else { | |
| 228 | + $newId = $this->repository->createEntry($row); | |
| 229 | + if ($newId > 0) { | |
| 230 | + $created++; | |
| 231 | + $results[] = ['index' => $i, 'ok' => true, 'id' => $newId, 'op' => 'create']; | |
| 232 | + } else { | |
| 233 | + $failed++; | |
| 234 | + $results[] = ['index' => $i, 'ok' => false, 'error' => 'createEntry returned 0']; | |
| 235 | + } | |
| 236 | + } | |
| 237 | + } catch (\Throwable $e) { | |
| 238 | + $failed++; | |
| 239 | + $results[] = ['index' => $i, 'ok' => false, 'error' => $e->getMessage()]; | |
| 240 | + } | |
| 241 | + } | |
| 242 | + | |
| 243 | + return [ | |
| 244 | + 'day_id' => $dayId, | |
| 245 | + 'trip_id' => $tripId, | |
| 246 | + 'created' => $created, | |
| 247 | + 'updated' => $updated, | |
| 248 | + 'failed' => $failed, | |
| 249 | + 'results' => $results, | |
| 250 | + ]; | |
| 251 | + } | |
| 252 | + | |
| 253 | + /** | |
| 182 | 254 | * Get itinerary entry by ID |
| 183 | 255 | */ |
| 184 | 256 | public function find(int $id): ?\stdClass |
| 185 | 257 | { |
| @@ -209,25 +281,24 @@ | ||
| 209 | 281 | * Bulk delete itinerary entries |
| 210 | 282 | * @param array $ids Array of entry IDs to delete |
| 211 | 283 | * @return array ['deleted' => count, 'failed' => count] |
| 212 | 284 | */ |
| 213 | - public function bulkDelete(array $ids): array | |
| 285 | + public function bulkDelete(array $ids, array $dayIds = []): array | |
| 214 | 286 | { |
| 215 | - if (empty($ids)) { | |
| 216 | - return ['deleted' => 0, 'failed' => 0]; | |
| 217 | - } | |
| 218 | - | |
| 219 | - // Validate all IDs are integers | |
| 220 | - $ids = array_map('intval', $ids); | |
| 221 | - $ids = array_filter($ids, function($id) { | |
| 287 | + // Activity entry ids and day ids are validated independently — see | |
| 288 | + // ItineraryRepository::bulkDelete() for why they must stay separate. | |
| 289 | + $ids = array_values(array_filter(array_map('intval', $ids), function ($id) { | |
| 222 | 290 | return $id > 0; |
| 223 | - }); | |
| 291 | + })); | |
| 292 | + $dayIds = array_values(array_filter(array_map('intval', $dayIds), function ($id) { | |
| 293 | + return $id > 0; | |
| 294 | + })); | |
| 224 | 295 | |
| 225 | - if (empty($ids)) { | |
| 296 | + if (empty($ids) && empty($dayIds)) { | |
| 226 | 297 | return ['deleted' => 0, 'failed' => 0]; |
| 227 | 298 | } |
| 228 | 299 | |
| 229 | - return $this->repository->bulkDelete($ids); | |
| 300 | + return $this->repository->bulkDelete($ids, $dayIds); | |
| 230 | 301 | } |
| 231 | 302 | |
| 232 | 303 | /** |
| 233 | 304 | * Get all itinerary entries for a specific trip |