diff --git a/admin/client_prices.php b/admin/client_prices.php index f23dd88..0b8a772 100644 --- a/admin/client_prices.php +++ b/admin/client_prices.php @@ -8,28 +8,36 @@ $pdo = db(); $message = ''; // Handle form submission -if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['client_id'], $_POST['product_id'], $_POST['price'])) { +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['client_id'], $_POST['product_id'])) { $clientId = $_POST['client_id']; $productId = $_POST['product_id']; - $price = $_POST['price']; + $priceNet = isset($_POST['price_net']) && is_numeric($_POST['price_net']) ? (float)$_POST['price_net'] : null; + $priceGross = isset($_POST['price_gross']) && is_numeric($_POST['price_gross']) ? (float)$_POST['price_gross'] : null; - if (!empty($clientId) && !empty($productId) && is_numeric($price)) { + // Server-side validation and calculation + if ($priceGross !== null) { + $priceNet = round($priceGross / 1.23, 2); + } elseif ($priceNet !== null) { + $priceGross = round($priceNet * 1.23, 2); + } + + if (!empty($clientId) && !empty($productId) && $priceNet !== null && $priceGross !== null) { // Upsert logic $stmt = $pdo->prepare("SELECT COUNT(*) FROM client_prices WHERE client_id = :client_id AND product_id = :product_id"); $stmt->execute(['client_id' => $clientId, 'product_id' => $productId]); $exists = $stmt->fetchColumn() > 0; if ($exists) { - $stmt = $pdo->prepare("UPDATE client_prices SET price = :price WHERE client_id = :client_id AND product_id = :product_id"); - $stmt->execute(['price' => $price, 'client_id' => $clientId, 'product_id' => $productId]); + $stmt = $pdo->prepare("UPDATE client_prices SET price_net = :price_net, price_gross = :price_gross WHERE client_id = :client_id AND product_id = :product_id"); + $stmt->execute(['price_net' => $priceNet, 'price_gross' => $priceGross, 'client_id' => $clientId, 'product_id' => $productId]); $message = '
Cena została zaktualizowana.
'; } else { - $stmt = $pdo->prepare("INSERT INTO client_prices (client_id, product_id, price) VALUES (:client_id, :product_id, :price)"); - $stmt->execute(['client_id' => $clientId, 'product_id' => $productId, 'price' => $price]); + $stmt = $pdo->prepare("INSERT INTO client_prices (client_id, product_id, price_net, price_gross) VALUES (:client_id, :product_id, :price_net, :price_gross)"); + $stmt->execute(['client_id' => $clientId, 'product_id' => $productId, 'price_net' => $priceNet, 'price_gross' => $priceGross]); $message = '
Nowa cena została dodana.
'; } } else { - $message = '
Wszystkie pola są wymagane.
'; + $message = '
Wszystkie pola są wymagane, a ceny muszą być prawidłowymi liczbami.
'; } } @@ -42,7 +50,8 @@ $pricesStmt = $pdo->query(" SELECT cp.client_id, cp.product_id, - cp.price, + cp.price_net, + cp.price_gross, c.name as client_name, p.name as product_name FROM client_prices cp @@ -80,7 +89,7 @@ $existingPrices = $pricesStmt->fetchAll(PDO::FETCH_ASSOC);
-
+
-
+
- - + + +
+
+ +
@@ -117,20 +130,22 @@ $existingPrices = $pricesStmt->fetchAll(PDO::FETCH_ASSOC); Klient Produkt - Cena (PLN) + Cena netto (PLN) + Cena brutto (PLN) - Brak zdefiniowanych cen indywidualnych. + Brak zdefiniowanych cen indywidualnych. - + + @@ -141,4 +156,30 @@ $existingPrices = $pricesStmt->fetchAll(PDO::FETCH_ASSOC);
+ + \ No newline at end of file diff --git a/admin/edit_client.php b/admin/edit_client.php index 6d39124..6d76e26 100644 --- a/admin/edit_client.php +++ b/admin/edit_client.php @@ -1,8 +1,8 @@ +
diff --git a/admin/order_details.php b/admin/order_details.php index 55d5ad4..b0129b1 100644 --- a/admin/order_details.php +++ b/admin/order_details.php @@ -99,16 +99,23 @@ $pageTitle = 'Szczegóły zamówienia #' . htmlspecialchars($order['id']); Produkt Ilość - Cena jednostkowa - Suma + Cena jedn. netto + Cena jedn. brutto + Suma (brutto) - + - zł + zł + @@ -125,7 +132,7 @@ $pageTitle = 'Szczegóły zamówienia #' . htmlspecialchars($order['id']);

Klient:

Data:

Metoda płatności:

-

Suma:

+

Suma (brutto):

diff --git a/admin/orders.php b/admin/orders.php index 4659330..d3da23a 100644 --- a/admin/orders.php +++ b/admin/orders.php @@ -125,7 +125,7 @@ $pageTitle = "Zarządzanie zamówieniami"; Data Status Źródło - Suma + Suma (brutto) Akcje diff --git a/cart.php b/cart.php index 6f55f12..65729bb 100644 --- a/cart.php +++ b/cart.php @@ -18,38 +18,32 @@ if (!empty($cart)) { try { $pdo = db(); - $client_id = $_SESSION['client_id'] ?? null; - $params = []; - $sql = 'SELECT p.*, '; - if ($client_id) { - $sql .= 'COALESCE(cp.price, p.price) as final_price FROM products p'; - $sql .= ' LEFT JOIN client_prices cp ON p.id = cp.product_id AND cp.client_id = ?'; - $params[] = $client_id; - } else { - $sql .= 'p.price as final_price FROM products p'; - } - - $sql .= " WHERE p.id IN ($placeholders)"; - - $params = array_merge($params, $product_ids); - - $stmt = $pdo->prepare($sql); - $stmt->execute($params); + $stmt = $pdo->prepare("SELECT * FROM products WHERE id IN ($placeholders)"); + $stmt->execute($product_ids); $products = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($products as $product) { $quantity = $cart[$product['id']]; - $line_total = $product['final_price'] * $quantity; + + // Use the new centralized price function + $price_info = getEffectivePrice($pdo, $product['id'], $client_id); + $price_net = $price_info['net']; + $price_gross = $price_info['gross']; + + $line_total_gross = $price_gross * $quantity; + $cart_products[] = [ 'id' => $product['id'], 'name' => $product['name'], - 'price' => $product['final_price'], + 'price_net' => $price_net, + 'price_gross' => $price_gross, 'quantity' => $quantity, - 'line_total' => $line_total, + 'line_total' => $line_total_gross, // Use gross for calculations ]; - $total_price += $line_total; + + $total_price += $line_total_gross; // Sum up the gross total } } catch (PDOException $e) { die("Błąd połączenia z bazą danych: " . $e->getMessage()); @@ -126,7 +120,8 @@ $user_role = get_user_role(); Produkt - Cena + Cena netto + Cena brutto Ilość Razem @@ -136,7 +131,8 @@ $user_role = get_user_role(); - zł + zł + @@ -161,7 +157,7 @@ $user_role = get_user_role(); - Razem: + Razem (brutto): diff --git a/checkout.php b/checkout.php index 98a8ac1..1718a65 100644 --- a/checkout.php +++ b/checkout.php @@ -30,20 +30,25 @@ if (!empty($cart)) { $credit_info = $stmt->fetch(PDO::FETCH_ASSOC); } - $sql = "SELECT p.id, p.name, p.units_per_pallet, COALESCE(cp.price, p.price_gross) as price FROM products p LEFT JOIN client_prices cp ON p.id = cp.product_id AND cp.client_id = ? WHERE p.id IN ($placeholders)"; + $sql = "SELECT p.id, p.name, p.units_per_pallet FROM products p WHERE p.id IN ($placeholders)"; $stmt = $pdo->prepare($sql); - $params = array_merge([$client_id], $product_ids); - $stmt->execute($params); + $stmt->execute($product_ids); $products = $stmt->fetchAll(PDO::FETCH_ASSOC); $is_supplier_delivery = false; foreach ($products as $product) { $quantity = $cart[$product['id']]; - $line_total = $product['price'] * $quantity; + + $price_info = getEffectivePrice($pdo, $product['id'], $client_id); + $price_net = $price_info['net']; + $price_gross = $price_info['gross']; + + $line_total = $price_gross * $quantity; $cart_products[] = [ 'id' => $product['id'], 'name' => $product['name'], - 'price' => $product['price'], + 'price_net' => $price_net, + 'price_gross' => $price_gross, 'quantity' => $quantity, 'line_total' => $line_total, ]; @@ -134,8 +139,9 @@ $user_role = get_user_role(); Produkt Ilość - Cena jedn. - Suma + Cena netto + Cena brutto + Suma (brutto) @@ -143,14 +149,15 @@ $user_role = get_user_role(); - zł + zł + - Suma: + Suma (brutto): diff --git a/db/migrations/026_add_net_gross_to_client_prices.sql b/db/migrations/026_add_net_gross_to_client_prices.sql new file mode 100644 index 0000000..c23ca45 --- /dev/null +++ b/db/migrations/026_add_net_gross_to_client_prices.sql @@ -0,0 +1,10 @@ +-- Add net and gross price columns to client_prices +ALTER TABLE client_prices +ADD COLUMN price_net DECIMAL(10, 2) NULL, +ADD COLUMN price_gross DECIMAL(10, 2) NULL; + +-- Migrate existing price to price_gross (assuming it was gross) +UPDATE client_prices SET price_gross = price WHERE price IS NOT NULL; + +-- Calculate price_net from price_gross +UPDATE client_prices SET price_net = ROUND(price_gross / 1.23, 2) WHERE price_gross IS NOT NULL; diff --git a/includes/helpers.php b/includes/helpers.php index 991ce5a..1022e70 100644 --- a/includes/helpers.php +++ b/includes/helpers.php @@ -75,3 +75,58 @@ function upload_error_message($error_code) { return 'Unknown upload error'; } } + +function getEffectivePrice(PDO $db, int $productId, ?int $clientId): array { + $vatRate = 1.23; + $net = null; + $gross = null; + $priceFound = false; + + // Priority A: Try to fetch from client_prices + if ($clientId) { + $stmt = $db->prepare("SELECT price_net, price_gross FROM client_prices WHERE client_id = :client_id AND product_id = :product_id LIMIT 1"); + $stmt->execute(['client_id' => $clientId, 'product_id' => $productId]); + $priceRow = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($priceRow) { + $net = $priceRow['price_net'] !== null ? (float)$priceRow['price_net'] : null; + $gross = $priceRow['price_gross'] !== null ? (float)$priceRow['price_gross'] : null; + + if ($net !== null || $gross !== null) { + $priceFound = true; + } + } + } + + // Priority B: Fallback to product base prices if no client-specific price was found + if (!$priceFound) { + $stmt = $db->prepare("SELECT price_net, price_gross FROM products WHERE id = :product_id"); + $stmt->execute(['product_id' => $productId]); + $priceRow = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($priceRow) { + $net = $priceRow['price_net'] !== null ? (float)$priceRow['price_net'] : null; + $gross = $priceRow['price_gross'] !== null ? (float)$priceRow['price_gross'] : null; + } + } + + // If we have one price, calculate the other + if ($gross !== null && $net === null) { + $net = round($gross / $vatRate, 2); + } elseif ($net !== null && $gross === null) { + $gross = round($net * $vatRate, 2); + } + + // Sanity check: gross must not be less than net. If so, log it and fix it. + if ($gross !== null && $net !== null && $gross < $net) { + error_log("Price inconsistency for product ID $productId: gross ($gross) is less than net ($net). Recalculating net from gross."); + $net = round($gross / $vatRate, 2); + } + + // Final check for nulls before returning + if ($net === null || $gross === null) { + return ['net' => 0.0, 'gross' => 0.0]; + } + + return ['net' => $net, 'gross' => $gross]; +} diff --git a/index.php b/index.php index 66bb697..0b5f6e3 100644 --- a/index.php +++ b/index.php @@ -11,9 +11,7 @@ try { // Fetch products and their primary images $sql = "SELECT - p.*, - COALESCE(cp.price, p.price_gross) as final_price, - p.price_net as final_price_net, + p.*, (SELECT file_path FROM product_images WHERE product_id = p.id @@ -21,17 +19,13 @@ try { LIMIT 1) AS image_path FROM products p - LEFT JOIN - users u ON u.id = :user_id - LEFT JOIN - client_prices cp ON cp.product_id = p.id AND cp.client_id = u.client_id WHERE p.is_active = 1 ORDER BY CASE p.product_role WHEN 'membrana' THEN 1 WHEN 'akcesoria' THEN 2 ELSE 3 END, p.name ASC"; $stmt = $pdo->prepare($sql); - $stmt->execute(['user_id' => $_SESSION['user_id']]); + $stmt->execute(); $products = $stmt->fetchAll(PDO::FETCH_ASSOC); // Separate products into main and accessories @@ -132,7 +126,8 @@ $page_title = 'Katalog';
- 100 ? substr($desc, 0, 100) . '...' : $desc); ?>

-

PLN /

+
+

zł netto

+

zł brutto

+
@@ -174,19 +174,25 @@ $lang = 'pl'; Zdjęcie Produkt - Cena jednostkowa + Cena jedn. netto + Cena jedn. brutto Ilość - Suma częściowa + Suma (brutto) - <?php echo htmlspecialchars($item['product_name']); ?> - zł + zł + zł diff --git a/order_process.php b/order_process.php index 18f55e3..5b5b15c 100644 --- a/order_process.php +++ b/order_process.php @@ -31,27 +31,28 @@ try { $products_by_id = $stmt->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_ASSOC); - // 2. Calculate total amount & total pallets - $total_amount = 0; - $is_supplier_delivery = false; + // 2. Calculate total amount + $total_amount_gross = 0; $client_id = $_SESSION['client_id'] ?? null; - $product_prices = []; - if ($client_id) { - $price_placeholders = implode(',', array_fill(0, count($product_ids), '?')); - $sql = "SELECT p.id, COALESCE(cp.price, p.price) as price FROM products p LEFT JOIN client_prices cp ON p.id = cp.product_id AND cp.client_id = ? WHERE p.id IN ($price_placeholders)"; - $stmt = $pdo->prepare($sql); - $params = array_merge([$client_id], $product_ids); - $stmt->execute($params); - $product_prices = $stmt->fetchAll(PDO::FETCH_KEY_PAIR); - } + $order_items_data = []; $is_supplier_delivery = false; foreach ($cart as $product_id => $quantity) { if (isset($products_by_id[$product_id])) { $product = $products_by_id[$product_id]; - $price = $product_prices[$product_id] ?? $product['price']; - $total_amount += $price * $quantity; + + $price_info = getEffectivePrice($pdo, $product_id, $client_id); + $price_gross = $price_info['gross']; + + $total_amount_gross += $price_gross * $quantity; + + $order_items_data[] = [ + 'product_id' => $product_id, + 'quantity' => $quantity, + 'unit_price' => $price_gross, // Save gross price + 'line_total' => $price_gross * $quantity, + ]; $units_per_pallet = $product['units_per_pallet']; if (isset($units_per_pallet) && $units_per_pallet > 0) { @@ -69,11 +70,11 @@ try { $stmt->execute([$client_id]); $credit_info = $stmt->fetch(); - if (!$credit_info || !$credit_info['credit_enabled'] || $credit_info['credit_balance'] < $total_amount) { + if (!$credit_info || !$credit_info['credit_enabled'] || $credit_info['credit_balance'] < $total_amount_gross) { throw new Exception('Invalid payment method or insufficient credit.'); } - $new_balance = $credit_info['credit_balance'] - $total_amount; + $new_balance = $credit_info['credit_balance'] - $total_amount_gross; $stmt = $pdo->prepare('UPDATE clients SET credit_balance = ? WHERE id = ?'); $stmt->execute([$new_balance, $client_id]); } @@ -84,7 +85,7 @@ try { ); $stmt->execute([ $client_id, - $total_amount, + $total_amount_gross, $_POST['payment_method'], $delivery_source, $_POST['notes'], @@ -96,18 +97,14 @@ try { $stmt = $pdo->prepare( 'INSERT INTO order_items (order_id, product_id, quantity, unit_price, line_total) VALUES (?, ?, ?, ?, ?)' ); - foreach ($cart as $product_id => $quantity) { - if (isset($products_by_id[$product_id])) { - $product = $products_by_id[$product_id]; - $price = $product_prices[$product_id] ?? $product['price']; - $stmt->execute([ - $order_id, - $product_id, - $quantity, - $price, - $price * $quantity - ]); - } + foreach ($order_items_data as $item) { + $stmt->execute([ + $order_id, + $item['product_id'], + $item['quantity'], + $item['unit_price'], + $item['line_total'], + ]); } // 5. Commit the transaction diff --git a/orders.php b/orders.php index 5a3e5e7..e5608f9 100644 --- a/orders.php +++ b/orders.php @@ -126,7 +126,7 @@ $lang = 'pl'; Numer zamówienia Data zamówienia Status - Suma + Suma (brutto) diff --git a/product.php b/product.php index c118734..726ddf7 100644 --- a/product.php +++ b/product.php @@ -15,25 +15,17 @@ if (!$product_id) { try { $pdo = db(); - $stmt = $pdo->prepare("SELECT p.*, - COALESCE(cp.price, p.price_gross) as final_price, - p.price_net as final_price_net - FROM products p - LEFT JOIN users u ON u.id = :user_id - LEFT JOIN client_prices cp ON cp.product_id = p.id AND cp.client_id = u.client_id - WHERE p.id = :product_id"); - $stmt->execute(['user_id' => $_SESSION['user_id'], 'product_id' => $product_id]); + $stmt = $pdo->prepare("SELECT p.* FROM products p WHERE p.id = :product_id"); + $stmt->execute(['product_id' => $product_id]); $product = $stmt->fetch(PDO::FETCH_ASSOC); if (!$product) { header('Location: index.php'); exit; } - - // If client-specific price is used, re-calculate net price from it - if (!empty($product['final_price']) && empty($product['final_price_net'])) { - $product['final_price_net'] = round($product['final_price'] / 1.23, 2); - } + + // Get the correct price pair using the centralized function + $prices = getEffectivePrice($pdo, $product['id'], $_SESSION['client_id']); // Fetch product images @@ -139,9 +131,10 @@ $user_role = get_user_role();

-

PLN /

- Cena brutto -

PLN netto

+

brutto

+

netto

+
+ Cena za:
diff --git a/related_suggestions.php b/related_suggestions.php index a295242..2ca49a2 100644 --- a/related_suggestions.php +++ b/related_suggestions.php @@ -27,15 +27,13 @@ $stmt = $db->prepare(" p.name, p.unit, p.price_net, - COALESCE(cp.price, p.price_gross) as final_price, + p.price_gross, pi.file_path AS primary_image FROM products p - LEFT JOIN users u ON u.id = :user_id - LEFT JOIN client_prices cp ON cp.product_id = p.id AND cp.client_id = u.client_id LEFT JOIN product_images pi ON pi.product_id = p.id AND pi.is_primary = 1 WHERE p.id = :product_id "); -$stmt->execute(['user_id' => $user_id, 'product_id' => $product_id]); +$stmt->execute(['product_id' => $product_id]); $added_product = $stmt->fetch(PDO::FETCH_ASSOC); // If product somehow doesn't exist, redirect away @@ -43,6 +41,8 @@ if (!$added_product) { header('Location: cart.php'); exit; } +$added_product_price = getEffectivePrice($db, $added_product['id'], $_SESSION['client_id'] ?? null); + // If image is not found, use a placeholder if (empty($added_product['primary_image'])) { @@ -57,16 +57,14 @@ $related_products_stmt = $db->prepare(" p.name, p.unit, p.price_net, - COALESCE(cp.price, p.price_gross) as final_price, + p.price_gross, pi.file_path as primary_image FROM products p JOIN product_relations pr ON p.id = pr.related_product_id - LEFT JOIN users u ON u.id = :user_id - LEFT JOIN client_prices cp ON cp.product_id = p.id AND cp.client_id = u.client_id LEFT JOIN product_images pi ON p.id = pi.product_id AND pi.is_primary = 1 WHERE pr.product_id = :product_id AND p.product_role = 'akcesoria' "); -$related_products_stmt->execute(['user_id' => $user_id, 'product_id' => $product_id]); +$related_products_stmt->execute(['product_id' => $product_id]); $related_products = $related_products_stmt->fetchAll(PDO::FETCH_ASSOC); $user_role = get_user_role(); @@ -165,8 +163,8 @@ $page_title = 'Dodano do koszyka';
-

brutto

-

netto

+

brutto

+

netto

@@ -178,7 +176,9 @@ $page_title = 'Dodano do koszyka';

Polecamy także produkty powiązane:

- +
@@ -198,8 +198,8 @@ $page_title = 'Dodano do koszyka';
-

brutto

-

netto

+

brutto

+

netto