diff --git a/.vscode/ftp-kr.sync.cache.json b/.vscode/ftp-kr.sync.cache.json index 11d43a9..1d3a1a2 100644 --- a/.vscode/ftp-kr.sync.cache.json +++ b/.vscode/ftp-kr.sync.cache.json @@ -9,8 +9,8 @@ }, "api.php": { "type": "-", - "size": 10947, - "lmtime": 1772982639016, + "size": 14061, + "lmtime": 1773062440871, "modified": false }, "autoload": { @@ -300,6 +300,12 @@ "modified": false }, "docs": { + "api-public-product-management.md": { + "type": "-", + "size": 9285, + "lmtime": 1773062594801, + "modified": false + }, "class-methods.md": { "type": "-", "size": 58706, @@ -341,12 +347,6 @@ "size": 657, "lmtime": 1772115859276, "modified": false - }, - "api-public-product-management.md": { - "type": "-", - "size": 6206, - "lmtime": 1772982690134, - "modified": false } }, "feeds": { diff --git a/api.php b/api.php index 251de82..15f1647 100644 --- a/api.php +++ b/api.php @@ -71,6 +71,37 @@ function api_get_product_by_offer_and_client( $mdb, $offer_id, $client_id ) ) -> fetch( \PDO::FETCH_ASSOC ); } +function api_get_product_by_id_or_offer_id( $mdb, $product_id, $offer_id ) +{ + if ( $product_id > 0 ) + { + return $mdb -> query( + 'SELECT p.id, p.offer_id, p.min_roas + FROM products p + WHERE p.id = :product_id + LIMIT 1', + [ + ':product_id' => (int) $product_id + ] + ) -> fetch( \PDO::FETCH_ASSOC ); + } + + if ( $offer_id !== '' ) + { + return $mdb -> query( + 'SELECT p.id, p.offer_id, p.min_roas + FROM products p + WHERE p.offer_id = :offer_id + LIMIT 1', + [ + ':offer_id' => (string) $offer_id + ] + ) -> fetch( \PDO::FETCH_ASSOC ); + } + + return null; +} + function api_normalize_product_text( $value ) { $value = trim( (string) $value ); @@ -340,6 +371,117 @@ if ( \S::get( 'action' ) == 'product_google_category_get' ) ] ); } +// Odczyt minimalnego ROAS produktu przez API +if ( \S::get( 'action' ) == 'product_min_roas_get' ) +{ + api_validate_api_key( $mdb ); + + $product_id = (int) \S::get( 'product_id' ); + $google_ads_product_id = trim( (string) \S::get( 'google_ads_product_id' ) ); + + if ( $product_id <= 0 && $google_ads_product_id === '' ) + { + api_json_response( [ 'result' => 'error', 'message' => 'Missing required param: product_id or google_ads_product_id' ], 422 ); + } + + if ( $product_id > 0 && $google_ads_product_id !== '' ) + { + api_json_response( [ 'result' => 'error', 'message' => 'Provide only one identifier: product_id or google_ads_product_id' ], 422 ); + } + + $product = api_get_product_by_id_or_offer_id( $mdb, $product_id, $google_ads_product_id ); + + if ( !$product ) + { + api_json_response( [ 'result' => 'error', 'message' => 'Product not found' ], 404 ); + } + + $min_roas_raw = $product['min_roas'] ?? null; + $min_roas = $min_roas_raw !== null && $min_roas_raw !== '' ? (float) $min_roas_raw : null; + + api_json_response( [ + 'result' => 'ok', + 'product_id' => (int) $product['id'], + 'offer_id' => (string) ( $product['offer_id'] ?? '' ), + 'min_roas' => $min_roas + ] ); +} + +// Odczyt sredniego minimalnego ROAS dla klienta +if ( \S::get( 'action' ) == 'client_avg_min_roas_get' ) +{ + api_validate_api_key( $mdb ); + + $client_id = (int) \S::get( 'client_id' ); + $google_ads_id = trim( (string) \S::get( 'google_ads_id' ) ); + + if ( $client_id <= 0 && $google_ads_id === '' ) + { + api_json_response( [ 'result' => 'error', 'message' => 'Missing required param: client_id or google_ads_id' ], 422 ); + } + + if ( $client_id > 0 && $google_ads_id !== '' ) + { + api_json_response( [ 'result' => 'error', 'message' => 'Provide only one identifier: client_id or google_ads_id' ], 422 ); + } + + $resolved_client = null; + + if ( $client_id > 0 ) + { + $resolved_client = $mdb -> query( + 'SELECT id, google_ads_customer_id + FROM clients + WHERE id = :client_id + LIMIT 1', + [ + ':client_id' => $client_id + ] + ) -> fetch( \PDO::FETCH_ASSOC ); + } + else + { + $google_ads_id_clean = str_replace( '-', '', $google_ads_id ); + $resolved_client = $mdb -> query( + 'SELECT id, google_ads_customer_id + FROM clients + WHERE REPLACE( google_ads_customer_id, \'-\', \'\' ) = :google_ads_id + LIMIT 1', + [ + ':google_ads_id' => $google_ads_id_clean + ] + ) -> fetch( \PDO::FETCH_ASSOC ); + } + + if ( !$resolved_client ) + { + api_json_response( [ 'result' => 'error', 'message' => 'Client not found' ], 404 ); + } + + $avg_row = $mdb -> query( + 'SELECT AVG( p.min_roas ) AS avg_min_roas, + COUNT( p.id ) AS products_with_min_roas + FROM products p + WHERE p.client_id = :client_id + AND p.min_roas IS NOT NULL', + [ + ':client_id' => (int) $resolved_client['id'] + ] + ) -> fetch( \PDO::FETCH_ASSOC ); + + $avg_min_roas_raw = $avg_row['avg_min_roas'] ?? null; + $avg_min_roas = $avg_min_roas_raw !== null && $avg_min_roas_raw !== '' ? round( (float) $avg_min_roas_raw, 6 ) : null; + $products_with_min_roas = (int) ( $avg_row['products_with_min_roas'] ?? 0 ); + + api_json_response( [ + 'result' => 'ok', + 'client_id' => (int) $resolved_client['id'], + 'google_ads_id' => (string) ( $resolved_client['google_ads_customer_id'] ?? '' ), + 'products_with_min_roas' => $products_with_min_roas, + 'avg_min_roas' => $avg_min_roas + ] ); +} + // Pobranie 10 produktow do optymalizacji (wg klikniec, bez nowego tytulu lub kategorii Google) if ( \S::get( 'action' ) == 'products_to_optimize' ) { diff --git a/docs/api-public-product-management.md b/docs/api-public-product-management.md index 11bd6bd..9a1e713 100644 --- a/docs/api-public-product-management.md +++ b/docs/api-public-product-management.md @@ -334,6 +334,127 @@ Przyklad odpowiedzi: } ``` +### 4.7 Odczyt minimalnego ROAS produktu + +- `action=product_min_roas_get` +- Cel: odczytuje `products.min_roas` dla wskazanego produktu + +Identyfikacja produktu (wymagany dokladnie jeden z dwoch): +- `product_id` (int) - wewnetrzny identyfikator produktu w adsPRO (`products.id`) +- `google_ads_product_id` (string) - zewnetrzny identyfikator produktu z Google Ads (mapowany do `products.offer_id`) + +Parametry dodatkowe: +- `api_key` (string, wymagany) + +Przyklad z `product_id`: + +```bash +curl -G "https://example.com/api.php" \ + --data-urlencode "action=product_min_roas_get" \ + --data-urlencode "api_key=YOUR_API_KEY" \ + --data-urlencode "product_id=987" +``` + +Przyklad z `google_ads_product_id`: + +```bash +curl -G "https://example.com/api.php" \ + --data-urlencode "action=product_min_roas_get" \ + --data-urlencode "api_key=YOUR_API_KEY" \ + --data-urlencode "google_ads_product_id=SKU-123" +``` + +Przyklad odpowiedzi: + +```json +{ + "result": "ok", + "product_id": 987, + "offer_id": "SKU-123", + "min_roas": 450 +} +``` + +Jesli minimalny ROAS nie jest ustawiony: + +```json +{ + "result": "ok", + "product_id": 987, + "offer_id": "SKU-123", + "min_roas": null +} +``` + +Bledy specyficzne: +- Brak identyfikatora produktu: `422` z `"Missing required param: product_id or google_ads_product_id"` +- Podano oba identyfikatory jednoczesnie: `422` z `"Provide only one identifier: product_id or google_ads_product_id"` +- Produkt nie znaleziony: `404` z `"Product not found"` + +### 4.8 Odczyt sredniego minimalnego ROAS dla klienta + +- `action=client_avg_min_roas_get` +- Cel: zwraca sredni `min_roas` dla produktow danego klienta + +Identyfikacja klienta (wymagany dokladnie jeden z dwoch): +- `client_id` (int) - wewnetrzny identyfikator klienta w adsPRO +- `google_ads_id` (string) - ID konta Google Ads (z myslnikami lub bez) + +Parametry dodatkowe: +- `api_key` (string, wymagany) + +Logika: +- Srednia liczona jest z `products.min_roas` +- Do sredniej wchodza tylko produkty z ustawionym `min_roas` (`IS NOT NULL`) +- Gdy brak produktow z ustawionym `min_roas`, `avg_min_roas` zwracane jest jako `null` + +Przyklad z `client_id`: + +```bash +curl -G "https://example.com/api.php" \ + --data-urlencode "action=client_avg_min_roas_get" \ + --data-urlencode "api_key=YOUR_API_KEY" \ + --data-urlencode "client_id=12" +``` + +Przyklad z `google_ads_id`: + +```bash +curl -G "https://example.com/api.php" \ + --data-urlencode "action=client_avg_min_roas_get" \ + --data-urlencode "api_key=YOUR_API_KEY" \ + --data-urlencode "google_ads_id=123-456-7890" +``` + +Przyklad odpowiedzi: + +```json +{ + "result": "ok", + "client_id": 12, + "google_ads_id": "123-456-7890", + "products_with_min_roas": 24, + "avg_min_roas": 436.25 +} +``` + +Jesli klient nie ma ustawionego `min_roas` na zadnym produkcie: + +```json +{ + "result": "ok", + "client_id": 12, + "google_ads_id": "123-456-7890", + "products_with_min_roas": 0, + "avg_min_roas": null +} +``` + +Bledy specyficzne: +- Brak identyfikatora klienta: `422` z `"Missing required param: client_id or google_ads_id"` +- Podano oba identyfikatory jednoczesnie: `422` z `"Provide only one identifier: client_id or google_ads_id"` +- Klient nie znaleziony: `404` z `"Client not found"` + ## 5. Walidacja i bledy ### 5.1 Brak wymaganych parametrow