- DictionariesApiController: nowy endpoint POST ensure_producer (znajdź lub utwórz producenta) - ProducerRepository: metoda ensureProducerForApi() - ProductRepository: pole producer_name w odpowiedzi GET product - ApiRouter: wstrzyknięto ProducerRepository do DictionariesApiController - Zaktualizowano docs/API.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
548 lines
12 KiB
Markdown
548 lines
12 KiB
Markdown
# shopPRO REST API
|
|
|
|
REST API do integracji z ordersPRO i innymi systemami zewnetrznymi.
|
|
|
|
## Autentykacja
|
|
|
|
Kazde zapytanie wymaga headera `X-Api-Key` z kluczem API.
|
|
|
|
```
|
|
X-Api-Key: {klucz_api}
|
|
```
|
|
|
|
Klucz przechowywany jest w `pp_settings` jako parametr `api_key`. API jest stateless (bez sesji).
|
|
|
|
## Format odpowiedzi
|
|
|
|
### Sukces (HTTP 200)
|
|
```json
|
|
{
|
|
"status": "ok",
|
|
"data": { ... }
|
|
}
|
|
```
|
|
|
|
### Blad
|
|
```json
|
|
{
|
|
"status": "error",
|
|
"code": "UNAUTHORIZED",
|
|
"message": "Invalid or missing API key"
|
|
}
|
|
```
|
|
|
|
Kody bledow:
|
|
| Kod | HTTP | Opis |
|
|
|-----|------|------|
|
|
| `UNAUTHORIZED` | 401 | Brak lub nieprawidlowy klucz API |
|
|
| `BAD_REQUEST` | 400 | Brakujace lub niepoprawne parametry |
|
|
| `NOT_FOUND` | 404 | Nie znaleziono zasobu/endpointu/akcji |
|
|
| `METHOD_NOT_ALLOWED` | 405 | Nieprawidlowa metoda HTTP |
|
|
| `INTERNAL_ERROR` | 500 | Blad wewnetrzny serwera |
|
|
|
|
## Endpointy
|
|
|
|
### Zamowienia
|
|
|
|
#### Lista zamowien
|
|
```
|
|
GET api.php?endpoint=orders&action=list
|
|
```
|
|
|
|
Parametry filtrowania (opcjonalne):
|
|
| Parametr | Typ | Opis |
|
|
|----------|-----|------|
|
|
| `status` | int | Filtruj po statusie zamowienia |
|
|
| `paid` | int (0/1) | Filtruj po statusie platnosci |
|
|
| `date_from` | date (YYYY-MM-DD) | Zamowienia od daty |
|
|
| `date_to` | date (YYYY-MM-DD) | Zamowienia do daty |
|
|
| `updated_since` | datetime (YYYY-MM-DD HH:MM:SS) | Zamowienia zmodyfikowane od podanej daty (klucz do pollingu) |
|
|
| `number` | string | Szukaj po numerze zamowienia |
|
|
| `client` | string | Szukaj po imieniu, nazwisku lub emailu klienta |
|
|
| `page` | int | Numer strony (domyslnie 1) |
|
|
| `per_page` | int | Wynikow na strone (domyslnie 50, max 100) |
|
|
|
|
Odpowiedz:
|
|
```json
|
|
{
|
|
"status": "ok",
|
|
"data": {
|
|
"items": [
|
|
{
|
|
"id": 42,
|
|
"number": "2026/02/001",
|
|
"date_order": "2026-02-19 10:30:00",
|
|
"updated_at": "2026-02-19 12:00:00",
|
|
"status": 4,
|
|
"paid": 1,
|
|
"client_name": "Jan",
|
|
"client_surname": "Kowalski",
|
|
"client_email": "jan@example.com",
|
|
"client_phone": "111222333",
|
|
"client_street": "Testowa 1",
|
|
"client_postal_code": "00-000",
|
|
"client_city": "Warszawa",
|
|
"firm_name": null,
|
|
"firm_nip": null,
|
|
"transport": "Kurier DPD",
|
|
"transport_cost": 15.00,
|
|
"payment_method": "Przelew bankowy",
|
|
"summary": 150.00
|
|
}
|
|
],
|
|
"total": 1,
|
|
"page": 1,
|
|
"per_page": 50
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Szczegoly zamowienia
|
|
```
|
|
GET api.php?endpoint=orders&action=get&id={order_id}
|
|
```
|
|
|
|
Zwraca pelne dane zamowienia z produktami i historia statusow.
|
|
|
|
#### Zmiana statusu zamowienia
|
|
```
|
|
PUT api.php?endpoint=orders&action=change_status&id={order_id}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"status_id": 5,
|
|
"send_email": true
|
|
}
|
|
```
|
|
|
|
Odpowiedz:
|
|
```json
|
|
{
|
|
"status": "ok",
|
|
"data": {
|
|
"order_id": 42,
|
|
"status_id": 5,
|
|
"changed": true
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Oznacz jako oplacone
|
|
```
|
|
PUT api.php?endpoint=orders&action=set_paid&id={order_id}
|
|
```
|
|
|
|
Opcjonalnie w body: `{"send_email": true}`
|
|
|
|
#### Oznacz jako nieoplacone
|
|
```
|
|
PUT api.php?endpoint=orders&action=set_unpaid&id={order_id}
|
|
```
|
|
|
|
### Produkty
|
|
|
|
#### Lista produktow
|
|
```
|
|
GET api.php?endpoint=products&action=list
|
|
```
|
|
|
|
Parametry filtrowania (opcjonalne):
|
|
| Parametr | Typ | Opis |
|
|
|----------|-----|------|
|
|
| `search` | string | Szukaj po nazwie, EAN lub SKU |
|
|
| `status` | int (0/1) | Filtruj po statusie (1 = aktywny, 0 = nieaktywny) |
|
|
| `promoted` | int (0/1) | Filtruj po promocji |
|
|
| `attribute_{id}` | int | Filtruj po atrybucie — `attribute_1=3` oznacza atrybut 1 = wartosc 3 (wiele filtrow AND) |
|
|
| `sort` | string | Sortuj po: id, name, price_brutto, status, promoted, quantity (domyslnie id) |
|
|
| `sort_dir` | string | Kierunek: ASC lub DESC (domyslnie DESC) |
|
|
| `page` | int | Numer strony (domyslnie 1) |
|
|
| `per_page` | int | Wynikow na strone (domyslnie 50, max 100) |
|
|
|
|
Odpowiedz:
|
|
```json
|
|
{
|
|
"status": "ok",
|
|
"data": {
|
|
"items": [
|
|
{
|
|
"id": 1,
|
|
"sku": "PROD-001",
|
|
"ean": "5901234123457",
|
|
"name": "Produkt testowy",
|
|
"price_brutto": 99.99,
|
|
"price_brutto_promo": null,
|
|
"price_netto": 81.29,
|
|
"price_netto_promo": null,
|
|
"quantity": 10,
|
|
"status": 1,
|
|
"promoted": 0,
|
|
"vat": 23,
|
|
"weight": 0.5,
|
|
"main_image": "product1.jpg",
|
|
"date_add": "2026-01-15 10:00:00",
|
|
"date_modify": "2026-02-19 12:00:00"
|
|
}
|
|
],
|
|
"total": 1,
|
|
"page": 1,
|
|
"per_page": 50
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Szczegoly produktu
|
|
```
|
|
GET api.php?endpoint=products&action=get&id={product_id}
|
|
```
|
|
|
|
Zwraca pelne dane produktu z jezykami, zdjeciami, kategoriami i atrybutami.
|
|
|
|
Odpowiedz:
|
|
```json
|
|
{
|
|
"status": "ok",
|
|
"data": {
|
|
"id": 1,
|
|
"sku": "PROD-001",
|
|
"ean": "5901234123457",
|
|
"price_brutto": 99.99,
|
|
"price_brutto_promo": null,
|
|
"price_netto": 81.29,
|
|
"price_netto_promo": null,
|
|
"quantity": 10,
|
|
"status": 1,
|
|
"promoted": 0,
|
|
"vat": 23,
|
|
"weight": 0.5,
|
|
"stock_0_buy": 0,
|
|
"custom_label_0": null,
|
|
"set_id": null,
|
|
"product_unit_id": 1,
|
|
"producer_id": 3,
|
|
"producer_name": "Nike",
|
|
"date_add": "2026-01-15 10:00:00",
|
|
"date_modify": "2026-02-19 12:00:00",
|
|
"languages": {
|
|
"pl": {
|
|
"name": "Produkt testowy",
|
|
"short_description": "Krotki opis",
|
|
"description": "<p>Pelny opis produktu</p>",
|
|
"meta_description": null,
|
|
"meta_keywords": null,
|
|
"meta_title": null,
|
|
"seo_link": "produkt-testowy",
|
|
"copy_from": null,
|
|
"warehouse_message_zero": null,
|
|
"warehouse_message_nonzero": null,
|
|
"tab_name_1": null,
|
|
"tab_description_1": null,
|
|
"tab_name_2": null,
|
|
"tab_description_2": null,
|
|
"canonical": null,
|
|
"security_information": null
|
|
}
|
|
},
|
|
"images": [
|
|
{"id": 1, "src": "product1.jpg", "alt": "Zdjecie produktu"}
|
|
],
|
|
"categories": [1, 5],
|
|
"attributes": [
|
|
{
|
|
"attribute_id": 1,
|
|
"attribute_type": 1,
|
|
"attribute_names": {"pl": "Kolor", "en": "Color"},
|
|
"value_id": 3,
|
|
"value_names": {"pl": "Czerwony", "en": "Red"}
|
|
}
|
|
],
|
|
"custom_fields": [
|
|
{"name": "Napis na koszulce", "type": "text", "is_required": 1}
|
|
],
|
|
"variants": [
|
|
{
|
|
"id": 101,
|
|
"permutation_hash": "1-3|2-5",
|
|
"sku": "PROD-001-RED-L",
|
|
"ean": null,
|
|
"price_brutto": 109.99,
|
|
"price_brutto_promo": null,
|
|
"price_netto": 89.42,
|
|
"price_netto_promo": null,
|
|
"quantity": 5,
|
|
"stock_0_buy": 0,
|
|
"weight": 0.5,
|
|
"status": 1,
|
|
"attributes": [
|
|
{"attribute_id": 1, "attribute_names": {"pl": "Kolor"}, "value_id": 3, "value_names": {"pl": "Czerwony"}},
|
|
{"attribute_id": 2, "attribute_names": {"pl": "Rozmiar"}, "value_id": 5, "value_names": {"pl": "L"}}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Tworzenie produktu
|
|
```
|
|
POST api.php?endpoint=products&action=create
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"price_brutto": 99.99,
|
|
"vat": 23,
|
|
"quantity": 10,
|
|
"status": 1,
|
|
"sku": "PROD-001",
|
|
"ean": "5901234123457",
|
|
"weight": 0.5,
|
|
"languages": {
|
|
"pl": {
|
|
"name": "Nowy produkt",
|
|
"description": "<p>Opis produktu</p>"
|
|
}
|
|
},
|
|
"categories": [1, 5],
|
|
"products_related": [10, 20]
|
|
}
|
|
```
|
|
|
|
Wymagane: `languages` (min. 1 jezyk z `name`) oraz `price_brutto`.
|
|
|
|
Odpowiedz (HTTP 201):
|
|
```json
|
|
{
|
|
"status": "ok",
|
|
"data": {
|
|
"id": 42
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Aktualizacja produktu
|
|
```
|
|
PUT api.php?endpoint=products&action=update&id={product_id}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"price_brutto": 129.99,
|
|
"status": 1,
|
|
"languages": {
|
|
"pl": {
|
|
"name": "Zaktualizowana nazwa"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Partial update — wystarczy przeslac tylko zmienione pola. Pola nieprzeslane zachowuja aktualna wartosc.
|
|
|
|
Odpowiedz: pelne dane produktu (jak w `get`).
|
|
|
|
### Warianty produktow
|
|
|
|
#### Lista wariantow produktu
|
|
```
|
|
GET api.php?endpoint=products&action=variants&id={product_id}
|
|
```
|
|
|
|
Zwraca warianty produktu nadrzednego wraz z dostepnymi atrybutami.
|
|
|
|
Odpowiedz:
|
|
```json
|
|
{
|
|
"status": "ok",
|
|
"data": {
|
|
"product_id": 1,
|
|
"available_attributes": [
|
|
{
|
|
"id": 1,
|
|
"type": 1,
|
|
"status": 1,
|
|
"names": {"pl": "Kolor", "en": "Color"},
|
|
"values": [
|
|
{"id": 3, "names": {"pl": "Czerwony", "en": "Red"}, "is_default": 0, "impact_on_the_price": null},
|
|
{"id": 4, "names": {"pl": "Niebieski", "en": "Blue"}, "is_default": 0, "impact_on_the_price": 10.0}
|
|
]
|
|
}
|
|
],
|
|
"variants": [
|
|
{
|
|
"id": 101,
|
|
"permutation_hash": "1-3",
|
|
"sku": "PROD-001-RED",
|
|
"ean": null,
|
|
"price_brutto": 109.99,
|
|
"price_brutto_promo": null,
|
|
"price_netto": 89.42,
|
|
"price_netto_promo": null,
|
|
"quantity": 5,
|
|
"stock_0_buy": 0,
|
|
"weight": 0.5,
|
|
"status": 1,
|
|
"attributes": [
|
|
{"attribute_id": 1, "attribute_names": {"pl": "Kolor"}, "value_id": 3, "value_names": {"pl": "Czerwony"}}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Tworzenie wariantu
|
|
```
|
|
POST api.php?endpoint=products&action=create_variant&id={product_id}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"attributes": {"1": 3, "2": 5},
|
|
"sku": "PROD-001-RED-L",
|
|
"ean": "5901234123458",
|
|
"price_brutto": 109.99,
|
|
"quantity": 5,
|
|
"weight": 0.5
|
|
}
|
|
```
|
|
|
|
Wymagane: `attributes` (mapa attribute_id -> value_id, min. 1). Kombinacja atrybutow musi byc unikalna.
|
|
|
|
Odpowiedz (HTTP 201): pelne dane wariantu.
|
|
|
|
#### Aktualizacja wariantu
|
|
```
|
|
PUT api.php?endpoint=products&action=update_variant&id={variant_id}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"sku": "PROD-001-RED-XL",
|
|
"price_brutto": 119.99,
|
|
"quantity": 3
|
|
}
|
|
```
|
|
|
|
Partial update — mozna zmienic: sku, ean, price_brutto, price_netto, price_brutto_promo, price_netto_promo, quantity, stock_0_buy, weight, status.
|
|
|
|
Odpowiedz: pelne dane wariantu.
|
|
|
|
#### Usuwanie wariantu
|
|
```
|
|
DELETE api.php?endpoint=products&action=delete_variant&id={variant_id}
|
|
```
|
|
|
|
Odpowiedz:
|
|
```json
|
|
{
|
|
"status": "ok",
|
|
"data": {"id": 101, "deleted": true}
|
|
}
|
|
```
|
|
|
|
### Slowniki
|
|
|
|
#### Lista statusow zamowien
|
|
```
|
|
GET api.php?endpoint=dictionaries&action=statuses
|
|
```
|
|
|
|
Odpowiedz:
|
|
```json
|
|
{
|
|
"status": "ok",
|
|
"data": [
|
|
{"id": 0, "name": "Nowe"},
|
|
{"id": 1, "name": "Oplacone"},
|
|
{"id": 4, "name": "W realizacji"},
|
|
{"id": 6, "name": "Wyslane"}
|
|
]
|
|
}
|
|
```
|
|
|
|
#### Lista metod transportu
|
|
```
|
|
GET api.php?endpoint=dictionaries&action=transports
|
|
```
|
|
|
|
#### Lista metod platnosci
|
|
```
|
|
GET api.php?endpoint=dictionaries&action=payment_methods
|
|
```
|
|
|
|
#### Lista atrybutow
|
|
```
|
|
GET api.php?endpoint=dictionaries&action=attributes
|
|
```
|
|
|
|
Zwraca aktywne atrybuty z wartosciami i wielojezycznymi nazwami.
|
|
|
|
#### Znajdz lub utworz producenta
|
|
```
|
|
POST api.php?endpoint=dictionaries&action=ensure_producer
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"name": "Nike"
|
|
}
|
|
```
|
|
|
|
Zwraca istniejacego producenta po nazwie lub tworzy nowego. Uzyc przed tworzeniem produktu, jesli producent moze nie istniec.
|
|
|
|
Odpowiedz:
|
|
```json
|
|
{
|
|
"status": "ok",
|
|
"data": {
|
|
"id": 5,
|
|
"created": false
|
|
}
|
|
}
|
|
```
|
|
|
|
`created: true` gdy producent zostal nowo dodany, `false` gdy juz istnial.
|
|
|
|
Odpowiedz:
|
|
```json
|
|
{
|
|
"status": "ok",
|
|
"data": [
|
|
{
|
|
"id": 1,
|
|
"type": 1,
|
|
"status": 1,
|
|
"names": {"pl": "Kolor", "en": "Color"},
|
|
"values": [
|
|
{"id": 3, "names": {"pl": "Czerwony"}, "is_default": 0, "impact_on_the_price": null},
|
|
{"id": 4, "names": {"pl": "Niebieski"}, "is_default": 1, "impact_on_the_price": 10.0}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Polling
|
|
|
|
Aby pobierac tylko nowe/zmienione zamowienia, uzyj parametru `updated_since`:
|
|
|
|
```
|
|
GET api.php?endpoint=orders&action=list&updated_since=2026-02-19 12:00:00
|
|
```
|
|
|
|
Kolumna `updated_at` w `pp_shop_orders` jest aktualizowana automatycznie przy kazdej modyfikacji zamowienia (zmiana statusu, platnosci, edycja danych, tworzenie zamowienia).
|
|
|
|
## Konfiguracja
|
|
|
|
Klucz API ustawia sie w panelu admina w ustawieniach sklepu lub bezposrednio w bazie:
|
|
|
|
```sql
|
|
INSERT INTO pp_settings (param, value) VALUES ('api_key', 'twoj-klucz-api');
|
|
-- lub
|
|
UPDATE pp_settings SET value = 'twoj-klucz-api' WHERE param = 'api_key';
|
|
```
|
|
|
|
## Architektura
|
|
|
|
- Entry point: `api.php`
|
|
- Router: `\api\ApiRouter` (`autoload/api/ApiRouter.php`)
|
|
- Kontrolery: `autoload/api/Controllers/`
|
|
- `OrdersApiController` — zamowienia (5 akcji)
|
|
- `ProductsApiController` — produkty (8 akcji: list, get, create, update, variants, create_variant, update_variant, delete_variant)
|
|
- `DictionariesApiController` — slowniki (5 akcji: statuses, transports, payment_methods, attributes, ensure_producer)
|