temp/cleanup_20260422_1312/api/products.php.bak-20260422-1308

Code: DEV-0C163F65 Size: 19.0 KB Lines: 409 Path: /home/prodconfig.wenesthosting.com/dev.solargroup.wenest.se/temp/cleanup_20260422_1312/api/products.php.bak-20260422-1308

Task / Comment

Open report form
<?php
/**
 * Products API
 * GET    /api/products.php              — lista alla produkter
 * GET    /api/products.php?id=SOL01     — hämta en produkt
 * POST   /api/products.php              — skapa/uppdatera produkt (JSON)
 * POST   /api/products.php?upload=1     — ladda upp produktbild (multipart)
 * POST   /api/products.php?upload=1&gallery=1  — ladda upp galleribild
 * POST   /api/products.php?upload=1&document=1 — ladda upp dokument
 * POST   /api/products.php?remove_gallery=1    — ta bort galleribild
 * POST   /api/products.php?remove_document=1   — ta bort dokument
 * DELETE /api/products.php?id=SOL01     — ta bort produkt
 */
require_once __DIR__ . '/config.php';

function normalizeLinkNumber($value): ?float {
    if ($value === '' || $value === null) return null;
    if (!is_numeric($value)) return null;
    return (float)$value;
}

function saveProductLinks(PDO $db, string $productId, array $links): void {
    $db->prepare('DELETE FROM product_services WHERE product_id = ?')->execute([$productId]);
    $ins = $db->prepare('INSERT INTO product_services (product_id, service_id, default_on, hidden, mandatory, default_variant, default_qty, min_qty, max_qty, sort_order) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
    foreach ($links as $idx => $link) {
        if (is_string($link)) {
            $link = ['service_id' => $link];
        }
        $serviceId = $link['service_id'] ?? $link['id'] ?? '';
        if ($serviceId === '') continue;
        $ins->execute([
            $productId,
            $serviceId,
            !empty($link['default_on']) ? 1 : 0,
            !empty($link['hidden']) ? 1 : 0,
            !empty($link['mandatory']) ? 1 : 0,
            ($link['default_variant'] ?? '') !== '' ? ($link['default_variant'] ?? null) : null,
            normalizeLinkNumber($link['default_qty'] ?? null),
            normalizeLinkNumber($link['min_qty'] ?? null),
            normalizeLinkNumber($link['max_qty'] ?? null),
            $idx + 1,
        ]);
    }
}

header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }

try {
    $db = getDB();

    // Ensure table exists
    $db->exec("CREATE TABLE IF NOT EXISTS products (
        id VARCHAR(20) PRIMARY KEY,
        name VARCHAR(255) NOT NULL,
        cat VARCHAR(50) NOT NULL DEFAULT '',
        cat_label VARCHAR(100) NOT NULL DEFAULT '',
        description TEXT,
        price DECIMAL(12,2) NOT NULL DEFAULT 0,
        stock VARCHAR(50) DEFAULT 'I lager',
        stock_class VARCHAR(20) DEFAULT 'green',
        img VARCHAR(500) DEFAULT '',
        watt INT DEFAULT NULL,
        kwh_capacity DECIMAL(10,2) DEFAULT NULL,
        specs JSON DEFAULT NULL,
        sort_order INT DEFAULT 0,
        active TINYINT(1) DEFAULT 1,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    $db->exec("CREATE TABLE IF NOT EXISTS product_services (
        id INT AUTO_INCREMENT PRIMARY KEY,
        product_id VARCHAR(20) NOT NULL,
        service_id VARCHAR(20) NOT NULL,
        default_on TINYINT(1) NOT NULL DEFAULT 0,
        hidden TINYINT(1) NOT NULL DEFAULT 0,
        mandatory TINYINT(1) NOT NULL DEFAULT 0,
        default_variant VARCHAR(100) DEFAULT NULL,
        default_qty DECIMAL(10,2) DEFAULT NULL,
        min_qty DECIMAL(10,2) DEFAULT NULL,
        max_qty DECIMAL(10,2) DEFAULT NULL,
        sort_order INT DEFAULT 0,
        UNIQUE KEY uniq_product_service (product_id, service_id),
        KEY idx_service_id (service_id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
    foreach ([
        "ALTER TABLE product_services ADD COLUMN default_qty DECIMAL(10,2) DEFAULT NULL AFTER default_variant",
        "ALTER TABLE product_services ADD COLUMN min_qty DECIMAL(10,2) DEFAULT NULL AFTER default_qty",
        "ALTER TABLE product_services ADD COLUMN max_qty DECIMAL(10,2) DEFAULT NULL AFTER min_qty",
    ] as $sql) {
        try { $db->exec($sql); } catch (Throwable $e) { /* already exists */ }
    }

    if ($_SERVER['REQUEST_METHOD'] === 'GET') {
        // Hämta leverantörer
        if (isset($_GET['suppliers'])) {
            $stmt = $db->query('SELECT id, name FROM suppliers ORDER BY name');
            echo json_encode(['success' => true, 'suppliers' => $stmt->fetchAll()]);
            exit;
        }

        // Hämta kopplade tjänster för en produkt
        $servicesFor = $_GET['services_for'] ?? '';
        if ($servicesFor) {
            $stmt = $db->prepare('SELECT ps.service_id, ps.default_on, ps.hidden, ps.mandatory, ps.default_variant, ps.default_qty, ps.min_qty, ps.max_qty, ps.sort_order FROM product_services ps WHERE ps.product_id = ? ORDER BY ps.sort_order');
            $stmt->execute([$servicesFor]);
            echo json_encode(['success' => true, 'services' => $stmt->fetchAll()]);
            exit;
        }

        // Hämta vilka produkter denna produkt är kopplad till (reverse lookup)
        $usedBy = $_GET["used_by"] ?? "";
        if ($usedBy) {
            $stmt = $db->prepare("SELECT p.id, p.name, p.cat_label, p.price, ps.default_on, ps.hidden, ps.mandatory, ps.default_variant, ps.default_qty, ps.min_qty, ps.max_qty FROM product_services ps JOIN products p ON p.id = ps.product_id WHERE ps.service_id = ? ORDER BY p.name");
            $stmt->execute([$usedBy]);
            echo json_encode(["success" => true, "products" => $stmt->fetchAll()]);
            exit;
        }

        $id = $_GET['id'] ?? '';
        if ($id) {
            $stmt = $db->prepare('SELECT * FROM products WHERE id = ?');
            $stmt->execute([$id]);
            $product = $stmt->fetch();
            if (!$product) { http_response_code(404); echo json_encode(['error' => 'Produkt ej hittad']); exit; }
            echo json_encode(['success' => true, 'product' => $product]);
        } else {
            $cat = $_GET['cat'] ?? '';
            $subcat = $_GET['subcat'] ?? null;
            $active = $_GET['active'] ?? '1';
            $sql = 'SELECT * FROM products WHERE active = ?';
            $params = [$active];
            if ($cat) { $sql .= ' AND cat = ?'; $params[] = $cat; }
            if ($subcat !== null) { $sql .= ' AND subcat = ?'; $params[] = $subcat; }
            $sql .= ' ORDER BY subcat, sort_order, cat, name';
            $stmt = $db->prepare($sql);
            $stmt->execute($params);
            $products = $stmt->fetchAll();
            echo json_encode(['success' => true, 'products' => $products]);
        }

    } elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {


        // === UPDATE LINK FLAGS (per-koppling) ===
        if (isset($_GET["update_link"])) {
            $body = json_decode(file_get_contents("php://input"), true);
            $productId = $body["product_id"] ?? "";
            $serviceId = $body["service_id"] ?? "";
            $field = $body["field"] ?? "";
            if (!in_array($field, ["mandatory", "default_on", "hidden", "default_variant", "default_qty", "min_qty", "max_qty"], true)) {
                echo json_encode(["success" => false, "error" => "Invalid field"]);
                exit;
            }
            if (in_array($field, ["default_variant"], true)) {
                $value = ($body["value"] ?? '') !== '' ? ($body["value"] ?? null) : null;
            } elseif (in_array($field, ["default_qty", "min_qty", "max_qty"], true)) {
                $value = normalizeLinkNumber($body["value"] ?? null);
            } else {
                $value = intval($body["value"] ?? 0);
            }
            $stmt = $db->prepare("UPDATE product_services SET $field = ? WHERE product_id = ? AND service_id = ?");
            $stmt->execute([$value, $productId, $serviceId]);
            echo json_encode(["success" => true]);
            exit;
        }
        // === REMOVE GALLERY IMAGE ===
        if (isset($_GET['remove_gallery'])) {
            $body = json_decode(file_get_contents('php://input'), true);
            $productId = $body['id'] ?? '';
            $imgPath = $body['img_path'] ?? '';
            if (!$productId || !$imgPath) throw new Exception('id och img_path krävs');

            $stmt = $db->prepare('SELECT gallery FROM products WHERE id = ?');
            $stmt->execute([$productId]);
            $row = $stmt->fetch();
            $gallery = $row && $row['gallery'] ? json_decode($row['gallery'], true) : [];
            $gallery = array_values(array_filter($gallery, fn($g) => $g !== $imgPath));

            $stmt = $db->prepare('UPDATE products SET gallery = ? WHERE id = ?');
            $stmt->execute([json_encode($gallery), $productId]);

            // Delete file
            $filePath = __DIR__ . '/../' . $imgPath;
            if (file_exists($filePath)) unlink($filePath);

            echo json_encode(['success' => true, 'gallery' => $gallery]);
            exit;
        }

        // === REMOVE DOCUMENT ===
        if (isset($_GET['remove_document'])) {
            $body = json_decode(file_get_contents('php://input'), true);
            $productId = $body['id'] ?? '';
            $docFile = $body['doc_file'] ?? '';
            if (!$productId || !$docFile) throw new Exception('id och doc_file krävs');

            $stmt = $db->prepare('SELECT documents FROM products WHERE id = ?');
            $stmt->execute([$productId]);
            $row = $stmt->fetch();
            $docs = $row && $row['documents'] ? json_decode($row['documents'], true) : [];
            $docs = array_values(array_filter($docs, fn($d) => $d['file'] !== $docFile));

            $stmt = $db->prepare('UPDATE products SET documents = ? WHERE id = ?');
            $stmt->execute([json_encode($docs), $productId]);

            $filePath = __DIR__ . '/../' . $docFile;
            if (file_exists($filePath)) unlink($filePath);

            echo json_encode(['success' => true, 'documents' => $docs]);
            exit;
        }

        // === FILE UPLOADS ===
        if (isset($_GET['upload'])) {

            // --- DOCUMENT UPLOAD ---
            if (isset($_GET['document']) && !empty($_FILES['document'])) {
                $productId = $_POST['id'] ?? '';
                if (!$productId) throw new Exception('id krävs');

                $file = $_FILES['document'];
                if ($file['error'] !== UPLOAD_ERR_OK) throw new Exception('Uppladdningsfel: ' . $file['error']);

                $maxSize = 20 * 1024 * 1024; // 20MB
                if ($file['size'] > $maxSize) throw new Exception('Filen är för stor (max 20MB)');

                $allowedMime = ['application/pdf','application/msword','application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
                $mime = mime_content_type($file['tmp_name']);
                if (!in_array($mime, $allowedMime)) throw new Exception('Otillåten filtyp: ' . $mime);

                $uploadDir = __DIR__ . '/../Docs/';
                if (!is_dir($uploadDir)) mkdir($uploadDir, 0755, true);

                $ext = pathinfo($file['name'], PATHINFO_EXTENSION) ?: 'pdf';
                $safeName = preg_replace('/[^a-z0-9_-]/i', '_', pathinfo($file['name'], PATHINFO_FILENAME));
                $filename = strtolower($productId) . '_' . $safeName . '_' . time() . '.' . $ext;
                $dest = $uploadDir . $filename;

                if (!move_uploaded_file($file['tmp_name'], $dest)) {
                    throw new Exception('Kunde inte spara dokumentet');
                }

                $docPath = 'Docs/' . $filename;
                $docName = $_POST['doc_name'] ?? pathinfo($file['name'], PATHINFO_FILENAME);
                $docType = $_POST['doc_type'] ?? 'manual';

                // Append to documents JSON
                $stmt = $db->prepare('SELECT documents FROM products WHERE id = ?');
                $stmt->execute([$productId]);
                $row = $stmt->fetch();
                $docs = $row && $row['documents'] ? json_decode($row['documents'], true) : [];
                $docs[] = ['name' => $docName, 'file' => $docPath, 'type' => $docType, 'size' => $file['size']];

                $stmt = $db->prepare('UPDATE products SET documents = ? WHERE id = ?');
                $stmt->execute([json_encode($docs), $productId]);

                echo json_encode(['success' => true, 'documents' => $docs]);
                exit;
            }

            // --- IMAGE UPLOAD (main or gallery) ---
            if (!empty($_FILES['image'])) {
                $productId = $_POST['id'] ?? '';
                if (!$productId) throw new Exception('id krävs för bilduppladdning');

                $file = $_FILES['image'];
                if ($file['error'] !== UPLOAD_ERR_OK) throw new Exception('Uppladdningsfel: ' . $file['error']);

                $maxSize = 10 * 1024 * 1024; // 10MB
                if ($file['size'] > $maxSize) throw new Exception('Bilden är för stor (max 10MB)');

                $allowed = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
                $mime = mime_content_type($file['tmp_name']);
                if (!in_array($mime, $allowed)) throw new Exception('Otillåten filtyp: ' . $mime);

                $uploadDir = __DIR__ . '/../Photo/';
                if (!is_dir($uploadDir)) mkdir($uploadDir, 0755, true);

                $ext = pathinfo($file['name'], PATHINFO_EXTENSION) ?: 'webp';
                $suffix = isset($_GET['gallery']) ? '_g' . time() : '_' . time();
                $filename = strtolower($productId) . $suffix . '.' . $ext;
                $dest = $uploadDir . $filename;

                if (!move_uploaded_file($file['tmp_name'], $dest)) {
                    throw new Exception('Kunde inte spara bilden');
                }

                $imgPath = 'Photo/' . $filename;

                if (isset($_GET['gallery'])) {
                    // Append to gallery JSON
                    $stmt = $db->prepare('SELECT gallery FROM products WHERE id = ?');
                    $stmt->execute([$productId]);
                    $row = $stmt->fetch();
                    $gallery = $row && $row['gallery'] ? json_decode($row['gallery'], true) : [];
                    $gallery[] = $imgPath;

                    $stmt = $db->prepare('UPDATE products SET gallery = ? WHERE id = ?');
                    $stmt->execute([json_encode($gallery), $productId]);

                    echo json_encode(['success' => true, 'img' => $imgPath, 'gallery' => $gallery]);
                } else {
                    // Update main image
                    $stmt = $db->prepare('UPDATE products SET img = ? WHERE id = ?');
                    $stmt->execute([$imgPath, $productId]);
                    echo json_encode(['success' => true, 'img' => $imgPath]);
                }
                exit;
            }

            throw new Exception('Ingen fil bifogad');
        }

        // === CREATE/UPDATE PRODUCT ===
        $body = json_decode(file_get_contents('php://input'), true);
        if (!$body) throw new Exception('JSON body krävs');

        $id = $body['id'] ?? '';
        if (!$id) throw new Exception('id krävs');

        $stmt = $db->prepare('SELECT id FROM products WHERE id = ?');
        $stmt->execute([$id]);
        $exists = $stmt->fetch();

        if ($exists) {
            // Update
            $fields = [];
            $params = [];
            foreach (['name','cat','cat_label','subcat','description','price','cost_price','cost_currency','stock','stock_class','img','watt','kwh_capacity','sort_order','active','green_tech_eligible','rot_eligible','supplier_id','unit','markup_type','markup_value','tillval_obligatorisk','tillval_hidden'] as $f) {
                if (array_key_exists($f, $body)) {
                    $fields[] = "$f = ?";
                    $params[] = $body[$f];
                }
            }
            if (!empty($body['specs'])) {
                $fields[] = 'specs = ?';
                $params[] = json_encode($body['specs']);
            }
            if (array_key_exists('gallery', $body)) {
                $fields[] = 'gallery = ?';
                $params[] = is_array($body['gallery']) ? json_encode($body['gallery']) : $body['gallery'];
            }
            if (array_key_exists('documents', $body)) {
                $fields[] = 'documents = ?';
                $params[] = is_array($body['documents']) ? json_encode($body['documents']) : $body['documents'];
            }
            if (empty($fields)) throw new Exception('Inget att uppdatera');
            $params[] = $id;
            $stmt = $db->prepare('UPDATE products SET ' . implode(', ', $fields) . ' WHERE id = ?');
            $stmt->execute($params);

            // Uppdatera tjänst-kopplingar om skickade
            if (isset($body['_services']) && is_array($body['_services'])) {
                saveProductLinks($db, $id, $body['_services']);
            }

            echo json_encode(['success' => true, 'action' => 'updated']);
        } else {
            // Insert
            $stmt = $db->prepare('INSERT INTO products (id, name, cat, cat_label, subcat, description, price, cost_price, cost_currency, stock, stock_class, img, watt, kwh_capacity, specs, sort_order, active, green_tech_eligible, rot_eligible, supplier_id, unit, markup_type, markup_value, tillval_obligatorisk, tillval_hidden) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)');
            $stmt->execute([
                $id,
                $body['name'] ?? '',
                $body['cat'] ?? '',
                $body['cat_label'] ?? $body['catLabel'] ?? '',
                $body['subcat'] ?? '',
                $body['description'] ?? $body['desc'] ?? '',
                $body['price'] ?? 0,
                $body['cost_price'] ?? null,
                $body['cost_currency'] ?? 'SEK',
                $body['stock'] ?? 'I lager',
                $body['stock_class'] ?? $body['stockClass'] ?? 'green',
                $body['img'] ?? '',
                $body['watt'] ?? null,
                $body['kwh_capacity'] ?? null,
                !empty($body['specs']) ? json_encode($body['specs']) : null,
                $body['sort_order'] ?? 0,
                $body['active'] ?? 1,
                $body['green_tech_eligible'] ?? 0,
                $body['rot_eligible'] ?? 0,
                $body['supplier_id'] ?? null,
                $body['unit'] ?? 'st',
                $body['markup_type'] ?? 'percent',
                $body['markup_value'] ?? 0
            ]);
            if (isset($body['_services']) && is_array($body['_services'])) {
                saveProductLinks($db, $id, $body['_services']);
            }
            echo json_encode(['success' => true, 'action' => 'created']);
        }

    } elseif ($_SERVER['REQUEST_METHOD'] === 'DELETE') {
        $id = $_GET['id'] ?? '';
        if (!$id) throw new Exception('id krävs');
        $stmt = $db->prepare('DELETE FROM products WHERE id = ?');
        $stmt->execute([$id]);
        echo json_encode(['success' => true, 'action' => 'deleted']);
    }

} catch (Exception $e) {
    http_response_code(500);
    echo json_encode(['error' => $e->getMessage()]);
}