Files
orderPRO/.paul/phases/66-allegro-delivery-tracking/66-02-PLAN.md
2026-04-03 22:35:49 +02:00

9.0 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, delegation
phase plan type wave depends_on files_modified autonomous delegation
66-allegro-delivery-tracking 02 execute 2
66-01
src/Modules/Shipments/DeliveryStatus.php
src/Modules/Shipments/AllegroTrackingService.php
true auto
## Goal 1. Uzupełnić mapę ALLEGRO_EDGE_MAP o brakujące statusy z realnych przesyłek 2. Dodać mechanizm keyword-based fallback (guessStatusFromDescription) dla nieznanych opisów 3. Logować nowe nierozpoznane statusy do activity_log

Purpose

Edge API Allegro zwraca opisy po polsku bez ustalonego słownika — mogą pojawić się nowe warianty. Hardcoded mapa nie wystarczy. Fallback + logowanie = system sam sobie radzi z nowymi opisami i informuje admina.

Output

  • Rozszerzona mapa ALLEGRO_EDGE_MAP o 5 nowych slugów
  • Metoda guessStatusFromDescription() w DeliveryStatus jako keyword fallback
  • Logowanie nieznanych statusów w AllegroTrackingService
## Prior Work @.paul/phases/66-allegro-delivery-tracking/66-01-PLAN.md

Nowe statusy z realnego zamówienia AD0243IOG6

Slug Opis Mapowanie
podjeta_z_maszyny_przez_kuriera Przesyłka została podjęta z maszyny przez kuriera in_transit
przesylka_wyjechala_w_droge_do_punktu_docelowego Przesyłka wyjechała w drogę do punktu docelowego in_transit
wyslana_z_sortowni Wysłana z sortowni in_transit
wydana_do_doreczenia Przesyłka została wydana do doręczenia out_for_delivery
przesylka_oczekuje_na_odbior Przesyłka oczekuje na odbiór ready_for_pickup

<acceptance_criteria>

AC-1: Nowe slugi w mapie

Given opis "Wysłana z sortowni" z edge API
When slugify + normalize
Then zwraca 'in_transit' (nie 'unknown')

AC-2: Fallback keyword matching

Given nieznany opis np. "Paczka jest w drodze do odbiorcy"
When slug nie istnieje w ALLEGRO_EDGE_MAP
Then guessStatusFromDescription() dopasowuje na podstawie słów kluczowych
And zwraca odpowiedni znormalizowany status

AC-3: Logowanie nieznanych statusów

Given opis z edge API którego slug NIE jest w mapie i fallback zwraca unknown
When AllegroTrackingService przetwarza taki status
Then loguje do error_log: "[AllegroTracking] Nowy niezmapowany status: {opis} (slug: {slug})"
And nadal zwraca wynik z status=unknown (nie null)

</acceptance_criteria>

Task 1: Rozszerzenie mapy + guessStatusFromDescription src/Modules/Shipments/DeliveryStatus.php 1. Dodaj brakujące slugi do ALLEGRO_EDGE_MAP: ```php 'podjeta_z_maszyny_przez_kuriera' => self::IN_TRANSIT, 'przesylka_wyjechala_w_droge_do_punktu_docelowego' => self::IN_TRANSIT, 'wyjechala_w_droge_do_punktu_docelowego' => self::IN_TRANSIT, 'wyslana_z_sortowni' => self::IN_TRANSIT, 'wydana_do_doreczenia' => self::OUT_FOR_DELIVERY, 'przesylka_oczekuje_na_odbior' => self::READY_FOR_PICKUP, ```
2. Dodaj odpowiednie opisy do ALLEGRO_EDGE_DESCRIPTIONS:
   ```php
   'podjeta_z_maszyny_przez_kuriera' => 'Podjęta z maszyny przez kuriera',
   'przesylka_wyjechala_w_droge_do_punktu_docelowego' => 'Wyjechała w drogę do punktu docelowego',
   'wyjechala_w_droge_do_punktu_docelowego' => 'Wyjechała w drogę do punktu docelowego',
   'wyslana_z_sortowni' => 'Wysłana z sortowni',
   'wydana_do_doreczenia' => 'Wydana do doręczenia',
   'przesylka_oczekuje_na_odbior' => 'Oczekuje na odbiór',
   ```

3. Dodaj nową statyczną metodę `guessStatusFromDescription(string $description): string` — keyword-based fallback. Umieść ją po slugifyAllegroDescription():

   ```php
   public static function guessStatusFromDescription(string $description): string
   {
       $lower = mb_strtolower($description, 'UTF-8');

       // Terminal statuses first
       if (str_contains($lower, 'doręczon') || str_contains($lower, 'dostarczono') || str_contains($lower, 'odebrana przez odbiorc')) {
           return self::DELIVERED;
       }
       if (str_contains($lower, 'zwrócon') || str_contains($lower, 'zwrocona')) {
           return self::RETURNED;
       }
       if (str_contains($lower, 'anulowan')) {
           return self::CANCELLED;
       }

       // Active statuses
       if (str_contains($lower, 'doręczeni') || str_contains($lower, 'doreczenia') || str_contains($lower, 'wydana do')) {
           return self::OUT_FOR_DELIVERY;
       }
       if (str_contains($lower, 'odbiór') || str_contains($lower, 'odbior') || str_contains($lower, 'oczekuje na odb')) {
           return self::READY_FOR_PICKUP;
       }
       if (str_contains($lower, 'sortowni') || str_contains($lower, 'magazyn') || str_contains($lower, 'w drodze') || str_contains($lower, 'tranzyt') || str_contains($lower, 'kurier') || str_contains($lower, 'podjęta') || str_contains($lower, 'podjeta') || str_contains($lower, 'wyjechał') || str_contains($lower, 'wyjechala')) {
           return self::IN_TRANSIT;
       }
       if (str_contains($lower, 'nadana') || str_contains($lower, 'nadano')) {
           return self::CONFIRMED;
       }
       if (str_contains($lower, 'przygotowan') || str_contains($lower, 'utworzon')) {
           return self::CREATED;
       }
       if (str_contains($lower, 'uszkodzon') || str_contains($lower, 'problem') || str_contains($lower, 'zagubiła') || str_contains($lower, 'zagubion')) {
           return self::PROBLEM;
       }

       return self::UNKNOWN;
   }
   ```

WAŻNE: NIE zmieniaj istniejących metod normalize(), description(), slugifyAllegroDescription(). Tylko DODAWAJ nowe wpisy do map i nową metodę.
php -l przechodzi. Test: DeliveryStatus::normalize('allegro_edge', 'wyslana_z_sortowni') zwraca 'in_transit'. Test: DeliveryStatus::guessStatusFromDescription('Paczka jest w drodze') zwraca 'in_transit'. AC-1 satisfied: nowe slugi w mapie. AC-2 satisfied: fallback method istnieje. Task 2: Integracja fallback + logowanie w AllegroTrackingService src/Modules/Shipments/AllegroTrackingService.php Zmodyfikuj metodę `fetchAllegroEdgeStatus()` — dodaj fallback i logowanie.
Po linii:
```php
$slug = DeliveryStatus::slugifyAllegroDescription($description);
```

Zamień blok return na:
```php
$normalized = DeliveryStatus::normalize('allegro_edge', $slug);

// Fallback: jeśli slug nieznany, próbuj keyword matching
if ($normalized === DeliveryStatus::UNKNOWN) {
    $normalized = DeliveryStatus::guessStatusFromDescription($description);

    // Loguj niezmapowany status (do uzupełnienia mapy w przyszłości)
    error_log(sprintf(
        '[AllegroTracking] Niezmapowany status: "%s" (slug: %s, guessed: %s)',
        $description,
        $slug,
        $normalized
    ));
}

return [
    'status' => $normalized,
    'status_raw' => $description,
    'description' => $description,
];
```

To zastępuje istniejący blok:
```php
return [
    'status' => DeliveryStatus::normalize('allegro_edge', $slug),
    'status_raw' => $description,
    'description' => $description,
];
```

WAŻNE: Nie zmieniaj nic innego w tym pliku. Tylko modyfikacja wewnątrz fetchAllegroEdgeStatus().
php -l przechodzi. Metoda fetchAllegroEdgeStatus zawiera fallback guessStatusFromDescription i error_log. AC-2 partially satisfied: fallback zintegrowany. AC-3 satisfied: logowanie nieznanych statusów.

DO NOT CHANGE

  • Istniejące mapy INPOST_MAP, APACZKA_MAP, ALLEGRO_MAP
  • Metody: normalize(), description(), slugifyAllegroDescription(), fetchInpostStatus()
  • src/Modules/Cron/ShipmentTrackingHandler.php (rate limit z 66-01 bez zmian)
  • Wszystkie inne pliki

SCOPE LIMITS

  • Nie tworzymy UI do zarządzania mapowaniem (istniejący Delivery Status Mapping UI wystarczy)
  • Nie tworzymy unit testów w tym planie
- [ ] php -l na obu plikach - [ ] DeliveryStatus::normalize('allegro_edge', 'wyslana_z_sortowni') === 'in_transit' - [ ] DeliveryStatus::normalize('allegro_edge', 'wydana_do_doreczenia') === 'out_for_delivery' - [ ] DeliveryStatus::guessStatusFromDescription('Paczka jest w drodze do odbiorcy') === 'in_transit' - [ ] DeliveryStatus::guessStatusFromDescription('Przesyłka odebrana w punkcie') !== 'unknown' - [ ] fetchAllegroEdgeStatus fallback + error_log działa

<success_criteria>

  • Oba taski completed
  • Wszystkie realne opisy z API (obu zamówień) mapują się na właściwe statusy
  • Nieznane przyszłe opisy są obsługiwane przez keyword fallback
  • Nieznane statusy logowane do error_log </success_criteria>
After completion, create `.paul/phases/66-allegro-delivery-tracking/66-02-SUMMARY.md`