Add initial HTML template for MojeGS1 application with Cookiebot and Google Analytics integration

This commit is contained in:
2026-02-24 23:32:19 +01:00
parent 18d0019c28
commit 12f0c262c8
67 changed files with 50193 additions and 230 deletions

84
bin/cron.php Normal file
View File

@@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
use App\Core\Database\ConnectionFactory;
use App\Core\Support\Env;
use App\Modules\Cron\CronJobProcessor;
use App\Modules\Cron\CronJobRepository;
use App\Modules\Cron\CronJobType;
use App\Modules\Cron\ProductLinksHealthCheckHandler;
use App\Modules\ProductLinks\ChannelOffersRepository;
use App\Modules\ProductLinks\OfferImportService;
use App\Modules\ProductLinks\ProductLinksRepository;
use App\Modules\Settings\IntegrationRepository;
use App\Modules\Settings\ShopProClient;
$basePath = dirname(__DIR__);
$vendorAutoload = $basePath . '/vendor/autoload.php';
if (is_file($vendorAutoload)) {
require $vendorAutoload;
} else {
spl_autoload_register(static function (string $class) use ($basePath): void {
$prefix = 'App\\';
if (!str_starts_with($class, $prefix)) {
return;
}
$relative = substr($class, strlen($prefix));
$file = $basePath . '/src/' . str_replace('\\', '/', $relative) . '.php';
if (is_file($file)) {
require $file;
}
});
}
Env::load($basePath . '/.env');
/** @var array<string, mixed> $dbConfig */
$dbConfig = require $basePath . '/config/database.php';
/** @var array<string, mixed> $appConfig */
$appConfig = require $basePath . '/config/app.php';
$limit = 20;
foreach ($argv as $argument) {
if (!str_starts_with((string) $argument, '--limit=')) {
continue;
}
$limitValue = (int) substr((string) $argument, strlen('--limit='));
if ($limitValue > 0) {
$limit = min(200, $limitValue);
}
}
try {
$pdo = ConnectionFactory::make($dbConfig);
$cronJobs = new CronJobRepository($pdo);
$processor = new CronJobProcessor($cronJobs);
$integrationRepository = new IntegrationRepository(
$pdo,
(string) (($appConfig['integrations']['secret'] ?? '') ?: '')
);
$offersRepository = new ChannelOffersRepository($pdo);
$linksRepository = new ProductLinksRepository($pdo);
$shopProClient = new ShopProClient();
$offerImportService = new OfferImportService($shopProClient, $offersRepository, $pdo);
$linksHealthCheckHandler = new ProductLinksHealthCheckHandler(
$integrationRepository,
$offerImportService,
$linksRepository,
$offersRepository
);
$processor->registerHandler(CronJobType::PRODUCT_LINKS_HEALTH_CHECK, $linksHealthCheckHandler);
$result = $processor->run($limit);
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
} catch (\Throwable $exception) {
fwrite(STDERR, '[error] ' . $exception->getMessage() . PHP_EOL);
exit(1);
}

231
bin/test_gs1_api.php Normal file
View File

@@ -0,0 +1,231 @@
<?php
declare(strict_types=1);
/**
* GS1 API diagnostic
*
* Usage:
* php bin/test_gs1_api.php <login> <password> [gtin]
*
* If login/password are not provided, script tries to read them from DB app_settings.
*/
$login = $argv[1] ?? '';
$password = $argv[2] ?? '';
$targetGtin = $argv[3] ?? '5905323904514';
if ($login === '' || $password === '') {
$envFile = dirname(__DIR__) . '/.env';
$env = [];
if (is_file($envFile)) {
foreach (file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
$line = trim($line);
if ($line === '' || $line[0] === '#') {
continue;
}
$pos = strpos($line, '=');
if ($pos === false) {
continue;
}
$env[trim(substr($line, 0, $pos))] = trim(trim(substr($line, $pos + 1)), "\"'");
}
}
try {
$pdo = new PDO(
sprintf(
'mysql:host=%s;port=%s;dbname=%s;charset=utf8mb4',
$env['DB_HOST'] ?? '127.0.0.1',
$env['DB_PORT'] ?? '3306',
$env['DB_DATABASE'] ?? 'orderpro'
),
$env['DB_USERNAME'] ?? 'root',
$env['DB_PASSWORD'] ?? '',
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
$stmt = $pdo->prepare('SELECT setting_key, setting_value FROM app_settings WHERE setting_key IN (?, ?)');
$stmt->execute(['gs1_api_login', 'gs1_api_password']);
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
if ($row['setting_key'] === 'gs1_api_login') {
$login = (string) $row['setting_value'];
}
if ($row['setting_key'] === 'gs1_api_password') {
$password = (string) $row['setting_value'];
}
}
} catch (Throwable) {
// Ignore and use CLI args fallback.
}
}
if ($login === '' || $password === '') {
fwrite(STDERR, "Brak credentials. Uzyj: php bin/test_gs1_api.php <login> <password> [gtin]\n");
exit(1);
}
if (!preg_match('/^\d{13,14}$/', $targetGtin)) {
fwrite(STDERR, "Nieprawidlowy GTIN: {$targetGtin}. Oczekiwane 13 lub 14 cyfr.\n");
exit(1);
}
const GS1_BASE = 'https://mojegs1.pl/api/v2';
/**
* @return array{status:int, body:string, error:string}
*/
function gs1Request(
string $method,
string $url,
string $login,
string $password,
?string $rawBody = null,
string $contentType = 'application/json',
string $accept = 'application/json'
): array {
$curl = curl_init($url);
if ($curl === false) {
return ['status' => 0, 'body' => '', 'error' => 'Nie mozna zainicjalizowac cURL'];
}
$headers = ['Accept: ' . $accept];
if ($rawBody !== null) {
$headers[] = 'Content-Type: ' . $contentType;
}
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_USERPWD => $login . ':' . $password,
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_CUSTOMREQUEST => $method,
]);
if ($rawBody !== null) {
curl_setopt($curl, CURLOPT_POSTFIELDS, $rawBody);
}
$body = curl_exec($curl);
$status = (int) curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
$error = curl_error($curl);
curl_close($curl);
return [
'status' => $status,
'body' => is_string($body) ? $body : '',
'error' => $error,
];
}
function toJson(mixed $value): string
{
$json = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
return $json === false ? '[json_encode error]' : $json;
}
function printResponse(string $label, array $response): void
{
echo $label . PHP_EOL;
echo 'HTTP: ' . $response['status'] . PHP_EOL;
if ($response['error'] !== '') {
echo 'cURL error: ' . $response['error'] . PHP_EOL;
}
if ($response['body'] === '') {
echo "BODY: [empty]\n\n";
return;
}
$decoded = json_decode($response['body'], true);
if (is_array($decoded)) {
echo "BODY:\n" . toJson($decoded) . PHP_EOL;
if (!empty($decoded['errors'])) {
echo "ERRORS:\n" . toJson($decoded['errors']) . PHP_EOL;
}
} else {
echo "BODY:\n" . $response['body'] . PHP_EOL;
}
echo PHP_EOL;
}
function putProduct(string $gtin, array $attributes, string $login, string $password): array
{
$payload = [
'data' => [
'type' => 'products',
'id' => $gtin,
'attributes' => $attributes,
],
];
return gs1Request(
'PUT',
GS1_BASE . '/products/' . rawurlencode($gtin),
$login,
$password,
json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
);
}
echo "=== GS1 Diagnostic v5 ===\n";
echo "Target GTIN: {$targetGtin}\n\n";
// 1) Check target GTIN
$targetGet = gs1Request('GET', GS1_BASE . '/products/' . rawurlencode($targetGtin), $login, $password);
printResponse('--- Step 1: GET target GTIN ---', $targetGet);
// 2) PUT with values aligned to external API swagger example (language as `pl`)
$attrsSwaggerLike = [
'brandName' => 'Test Marka',
'subBrandName' => 'Test Podmarka',
'commonName' => 'Test produkt',
'name' => 'Test produkt API',
'description' => 'Test opisu produktu',
'gpcCode' => 10000002,
'netContent' => 1.5,
'netContentUnit' => 'kg',
'status' => 'ACT',
'targetMarket' => ['PL'],
'descriptionLanguage' => 'pl',
];
$putTargetSwaggerLike = putProduct($targetGtin, $attrsSwaggerLike, $login, $password);
printResponse('--- Step 2: PUT target GTIN (swagger-like payload) ---', $putTargetSwaggerLike);
// 3) PUT with original app defaults (for direct comparison with old script behavior)
$attrsAppLike = [
'brandName' => 'marianek.pl',
'subBrandName' => 'marianek.pl',
'commonName' => 'Produkt testowy',
'name' => 'Produkt testowy API',
'gpcCode' => 10008365,
'netContent' => 1,
'netContentUnit' => 'szt',
'status' => 'ACT',
'targetMarket' => ['PL'],
'descriptionLanguage' => 'PL',
];
$putTargetAppLike = putProduct($targetGtin, $attrsAppLike, $login, $password);
printResponse('--- Step 3: PUT target GTIN (app-like payload) ---', $putTargetAppLike);
// 4) Permission check: read an existing product and try no-op PUT.
$list = gs1Request('GET', GS1_BASE . '/products?page[offset]=1&page[limit]=1&sort=name', $login, $password);
printResponse('--- Step 4a: GET list (first product) ---', $list);
$existingGtin = null;
$existingAttributes = null;
$listDecoded = json_decode($list['body'], true);
if (is_array($listDecoded) && isset($listDecoded['data'][0]['id'])) {
$existingGtin = (string) $listDecoded['data'][0]['id'];
$existingAttributes = $listDecoded['data'][0]['attributes'] ?? null;
}
if ($existingGtin !== null && is_array($existingAttributes)) {
$noOpPut = putProduct($existingGtin, $existingAttributes, $login, $password);
printResponse('--- Step 4b: PUT existing product with attributes from GET (no-op) ---', $noOpPut);
} else {
echo "--- Step 4b: skipped (no product data from list) ---\n\n";
}
echo "=== DONE ===\n";