diff --git a/.env b/.env new file mode 100644 index 0000000..8d654d9 --- /dev/null +++ b/.env @@ -0,0 +1,16 @@ +# DATABASE CONFIG +DB_HOST=localhost +DB_NAME=tnjyfpbpkz +DB_USER=tnjyfpbpkz +DB_PASS=Gn6mtJVy3y + +# WOOCOMMERCE CONFIG +WC_URL=https://telvero.nl +WC_KEY=ck_f20c3d254df090816aa552dd312998cffac41866 +WC_SECRET=cs_6d2df33dc9e003a3804d20f8079dead853b8e689 + +# MOLLIE CONFIG +MOLLIE_KEY=test_sfUxawrmbxWSTdqhmg5vm3hc7yvmNP + +# API KEYS +POSTCODE_TECH_KEY=7d9136fb-3633-446d-b5d2-fe26a999bd62 \ No newline at end of file diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..4bbbf23 --- /dev/null +++ b/.htaccess @@ -0,0 +1,4 @@ + + Order allow,deny + Deny from all + \ No newline at end of file diff --git a/api.php b/api.php index 33d14eb..ca86764 100644 --- a/api.php +++ b/api.php @@ -1,42 +1,79 @@ load(); + use Automattic\WooCommerce\Client; use Mollie\Api\MollieApiClient; header('Content-Type: application/json'); -// --- CONFIGURATIE --- -$postcode_tech_key = '7d9136fb-3633-446d-b5d2-fe26a999bd62'; -$mollie_api_key = 'test_sfUxawrmbxWSTdqhmg5vm3hc7yvmNP'; -$site_url = 'https://telvero.nl'; +// --- DATABASE CONNECTIE VIA ENV --- +$db = new mysqli($_ENV['DB_HOST'], $_ENV['DB_USER'], $_ENV['DB_PASS'], $_ENV['DB_NAME']); -$woocommerce = new Client( - $site_url, - 'ck_f20c3d254df090816aa552dd312998cffac41866', - 'cs_6d2df33dc9e003a3804d20f8079dead853b8e689', - ['version' => 'wc/v3', 'timeout' => 400, 'verify_ssl' => false] -); +if ($db->connect_error) { + die(json_encode(['error' => 'Database connectie mislukt'])); +} + +function writeLog($action, $details) { + global $db; + $user = $_SESSION['user'] ?? 'system'; + $stmt = $db->prepare("INSERT INTO sales_logs (username, action, details, created_at) VALUES (?, ?, ?, NOW())"); + $stmt->bind_param("sss", $user, $action, $details); + $stmt->execute(); +} $action = $_GET['action'] ?? ''; -// 1. POSTCODE CHECK +// --- AUTH ACTIONS --- +if ($action === 'login') { + $input = json_decode(file_get_contents('php://input'), true); + $stmt = $db->prepare("SELECT password, full_name FROM sales_users WHERE username = ?"); + $stmt->bind_param("s", $input['username']); + $stmt->execute(); + $res = $stmt->get_result()->fetch_assoc(); + if ($res && password_verify($input['password'], $res['password'])) { + $_SESSION['user'] = $input['username']; + $_SESSION['full_name'] = $res['full_name']; + writeLog('LOGIN', 'Gebruiker ingelogd'); + echo json_encode(['success' => true, 'user' => $res['full_name']]); + } else { + http_response_code(401); echo json_encode(['error' => 'Login mislukt']); + } + exit; +} + +if (!isset($_SESSION['user']) && $action !== 'login') { + http_response_code(403); echo json_encode(['error' => 'Auth required']); exit; +} + +// --- WOOCOMMERCE CLIENT VIA ENV --- +$woocommerce = new Client( + $_ENV['WC_URL'], + $_ENV['WC_KEY'], + $_ENV['WC_SECRET'], + ['version' => 'wc/v3', 'timeout' => 400, 'verify_ssl' => false] +); + +// --- POSTCODE CHECK --- if ($action === 'postcode_check') { $postcode = str_replace(' ', '', $_GET['postcode']); $url = "https://postcode.tech/api/v1/postcode?postcode={$postcode}&number=" . $_GET['number']; - $ch = curl_init($url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer {$postcode_tech_key}"]); - echo curl_exec($ch); curl_close($ch); exit; + $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer " . $_ENV['POSTCODE_TECH_KEY']]); + echo curl_exec($ch); exit; } -// 2. PRODUCTEN OPHALEN (Inclusief Variatie Details) +// --- GET PRODUCTS (FIX VOOR VARIATIES & UPSELLS) --- if ($action === 'get_products') { try { $products = $woocommerce->get('products', ['status' => 'publish', 'per_page' => 100]); @@ -44,8 +81,10 @@ if ($action === 'get_products') { foreach ($products as $product) { $p = (array)$product; if ($product->type === 'variable') { - $p['variation_details'] = $woocommerce->get("products/{$product->id}/variations", ['per_page' => 100]); - } else { $p['variation_details'] = []; } + $p['variation_details'] = (array)$woocommerce->get("products/{$product->id}/variations", ['per_page' => 100]); + } else { + $p['variation_details'] = []; + } $enriched[] = $p; } echo json_encode($enriched); @@ -53,85 +92,51 @@ if ($action === 'get_products') { exit; } -// 3. ORDER AANMAKEN +// --- CREATE ORDER --- if ($action === 'create_order') { $input = json_decode(file_get_contents('php://input'), true); - try { - $method_input = $input['payment_method']; $mediacode = $input['mediacode_internal'] ?? 'Geen'; + $method_input = $input['payment_method']; - // Map methoden naar officiële Mollie plugin IDs - if ($method_input === 'mollie_methods_ideal') { - $wc_gateway_id = 'mollie_wc_gateway_ideal'; - $mollie_id = 'ideal'; - } elseif ($method_input === 'rve_riverty') { - $wc_gateway_id = 'mollie_wc_gateway_riverty'; - $mollie_id = 'riverty'; - } elseif ($method_input === 'mollie_methods_creditcard') { - $wc_gateway_id = 'mollie_wc_gateway_creditcard'; - $mollie_id = 'creditcard'; - } + $map = [ + 'mollie_methods_ideal' => ['wc' => 'mollie_wc_gateway_ideal', 'm' => 'ideal'], + 'rve_riverty' => ['wc' => 'mollie_wc_gateway_riverty', 'm' => 'riverty'], + 'mollie_methods_creditcard' => ['wc' => 'mollie_wc_gateway_creditcard', 'm' => 'creditcard'] + ]; + $gw = $map[$method_input]; - // --- ATTRIBUTION DATA & ORDER INITIALISATIE --- - $input['payment_method'] = $wc_gateway_id; + $input['payment_method'] = $gw['wc']; $input['payment_method_title'] = 'iDEAL (via Mollie)'; - $input['customer_note'] = "Bron: Sales Panel | Mediacode: " . $mediacode; - - // Metadata toevoegen bij creatie (Direct zichtbaar in Custom Fields) + $input['customer_note'] = "Agent: {$_SESSION['user']} | Mediacode: $mediacode"; + $input['meta_data'][] = ['key' => 'Mediacode', 'value' => $mediacode]; - $input['meta_data'][] = ['key' => 'Origin', 'value' => 'Sales Panel']; $input['meta_data'][] = ['key' => '_wc_order_attribution_utm_campaign', 'value' => $mediacode]; $input['meta_data'][] = ['key' => '_wc_order_attribution_utm_source', 'value' => 'SalesPanel']; - // A. WooCommerce Order aanmaken $order = $woocommerce->post('orders', $input); - if (!$order || !isset($order->id)) throw new Exception("WooCommerce order mislukt."); - // B. Mollie Setup $mollie = new MollieApiClient(); - $mollie->setApiKey($mollie_api_key); + $mollie->setApiKey($_ENV['MOLLIE_KEY']); $is_sub = (stripos(json_encode($order->line_items), 'abonnement') !== false); - $payment_value = number_format((float)$order->total, 2, '.', ''); - if ($mollie_id === 'ideal' && $is_sub) $payment_value = "0.01"; - - // C. Webhook & Redirect URLs - $webhookUrl = "{$site_url}/wc-api/mollie_wc_gateway_ideal?order_id={$order->id}&key={$order->order_key}&filter_flag=1"; - $redirectUrl = "{$site_url}/checkout/order-received/{$order->id}/?key={$order->order_key}&order_id={$order->id}&filter_flag=onMollieReturn&utm_campaign={$mediacode}"; - - $paymentData = [ - "amount" => ["currency" => "EUR", "value" => $payment_value], - "description" => "Order #" . $order->id . " [" . $mediacode . "]", - "redirectUrl" => $redirectUrl, - "webhookUrl" => $webhookUrl, - "method" => $mollie_id, - "metadata" => ["order_id" => (string)$order->id, "mediacode" => $mediacode] - ]; - - $payment = $mollie->payments->create($paymentData); - - // D. MATCHING & PERMANENTE MEDIACODE (Update met Mollie ID) - $woocommerce->put("orders/" . $order->id, [ - 'meta_data' => [ - ['key' => '_mollie_payment_id', 'value' => $payment->id], - ['key' => '_transaction_id', 'value' => $payment->id], - ['key' => '_payment_method', 'value' => $wc_gateway_id], - ['key' => 'Mediacode', 'value' => $mediacode], - ['key' => '_mediacode', 'value' => $mediacode] - ] + + $payment = $mollie->payments->create([ + "amount" => ["currency" => "EUR", "value" => ($gw['m'] === 'ideal' && $is_sub) ? "0.01" : number_format((float)$order->total, 2, '.', '')], + "description" => "Order #{$order->id} [$mediacode]", + "redirectUrl" => $_ENV['WC_URL'] . "/checkout/order-received/{$order->id}/?key={$order->order_key}&order_id={$order->id}&filter_flag=onMollieReturn", + "webhookUrl" => $_ENV['WC_URL'] . "/wc-api/mollie_wc_gateway_ideal?order_id={$order->id}&key={$order->order_key}&filter_flag=1", + "method" => $gw['m'], + "metadata" => ["order_id" => (string)$order->id] ]); - // E. Email trigger (Customer Note) - $woocommerce->post("orders/{$order->id}/notes", [ - 'note' => "Betaallink voor uw bestelling: " . $payment->getCheckoutUrl(), - 'customer_note' => true - ]); - - echo json_encode(['id' => $order->id, 'payment_url' => $payment->getCheckoutUrl()]); + $woocommerce->put("orders/{$order->id}", ['meta_data' => [['key' => '_mollie_payment_id', 'value' => $payment->id], ['key' => '_transaction_id', 'value' => $payment->id]]]); + $woocommerce->post("orders/{$order->id}/notes", ['note' => "Betaallink: " . $payment->getCheckoutUrl(), 'customer_note' => true]); + writeLog('ORDER_CREATED', "Order #{$order->id} voor {$input['billing']['email']}"); + echo json_encode(['payment_url' => $payment->getCheckoutUrl()]); } catch (Exception $e) { - http_response_code(422); - echo json_encode(['error' => $e->getMessage()]); + writeLog('ERROR', $e->getMessage()); + http_response_code(422); echo json_encode(['error' => $e->getMessage()]); } exit; } \ No newline at end of file diff --git a/composer.json b/composer.json index 6a9e6ad..dc3861f 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,7 @@ { "require": { "automattic/woocommerce": "^3.1", - "mollie/mollie-api-php": "^3.7" + "mollie/mollie-api-php": "^3.7", + "vlucas/phpdotenv": "^5.6" } } diff --git a/composer.lock b/composer.lock index f8b745c..a3b95c9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7cef855c8b424b0d2fadd4ba6b160e3f", + "content-hash": "0c72a561a268c0c3393507cc6ba72b09", "packages": [ { "name": "automattic/woocommerce", @@ -131,6 +131,68 @@ ], "time": "2025-12-08T15:06:51+00:00" }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.4", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:43:20+00:00" + }, { "name": "mollie/mollie-api-php", "version": "v3.7.0", @@ -305,6 +367,81 @@ ], "time": "2024-09-09T07:06:30+00:00" }, + { + "name": "phpoption/phpoption", + "version": "1.9.5", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.5" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:41:33+00:00" + }, { "name": "psr/http-client", "version": "1.0.3", @@ -464,6 +601,342 @@ "source": "https://github.com/php-fig/http-message/tree/2.0" }, "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-23T08:48:59+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-02T08:10:11+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.3", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "955e7815d677a3eaa7075231212f2110983adecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", + "reference": "955e7815d677a3eaa7075231212f2110983adecc", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.4", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5", + "symfony/polyfill-ctype": "^1.26", + "symfony/polyfill-mbstring": "^1.26", + "symfony/polyfill-php80": "^1.26" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:49:13+00:00" } ], "packages-dev": [], diff --git a/index.html b/index.html index 5c4eb7b..2818742 100644 --- a/index.html +++ b/index.html @@ -2,58 +2,78 @@ - Telvero Sales Dashboard + Telvero Sales - + -
-
-

TELVERO ORDER ENTRY

-
- Bron: - + + +
+
+

TELVERO PANEL

+
+ +
-
-

1. Klantgegevens

+
+
+ + +
+ +

Klantgegevens

- - + +
- - - + + +
- - - - + + + + +
-
-

2. Productselectie

- -
- + @@ -61,19 +81,19 @@
-

Aanbevolen Extra's:

+

Aanbevolen Extra's

-
-

Winkelmand

+
+

Overzicht