diff --git a/REST/functions.php b/REST/functions.php index b8a03ec8..ebff4797 100644 --- a/REST/functions.php +++ b/REST/functions.php @@ -18,7 +18,6 @@ function sendInvoice($record) ); echo json_encode($response); } - function sendProduct($record) { require_once('modules/EcmProducts/EcmProduct.php'); @@ -35,7 +34,6 @@ function sendProduct($record) ); echo json_encode($response); } - function copySaleFromTwinpol($record) { $db = $GLOBALS['db']; @@ -118,7 +116,7 @@ function copySaleFromTwinpol($record) $prod['ecmvat_id'] = $vat_id; $prod['ecmvat_value'] = $vat_value; $prod['ecmvat_name'] = $vat_name; - $prod['price_brutto'] = round($prod['price_netto'] + ($prod['price_netto'] * ($prod['ecmvat_value'] / 100)), 2); + $prod['price_netto'] = round((float)$price_start - ((float)$price_start * ((float)$product->discount / 100)), 2); $prod['total_netto'] = round($prod['price_netto'] * $prod['quantity'], 2); $prod['total_brutto'] = round($prod['total_netto'] + ($prod['total_netto'] * ($prod['ecmvat_value'] / 100)), 2); @@ -215,7 +213,6 @@ ILN: " . $sale->shipping_iln; echo 'Utworzono ZS.'; die(); } - // local helpers function getProduct($code) { @@ -230,7 +227,6 @@ function getProduct($code) return $prod; } } - function makeCUrlRequest($url) { $curl = curl_init(); @@ -242,23 +238,22 @@ function makeCUrlRequest($url) curl_setopt($curl, CURLOPT_URL, $url); return curl_exec($curl); } - function brecho($msg) { echo '

'; var_dump($msg); echo '

'; } - function createCSVReports() { - { - $db = $GLOBALS['db']; - $exportDir = __DIR__ . "/export"; + generateProductComponentsCSV(); - $jobs = [ - [ - 'sql' => " + $db = $GLOBALS['db']; + $exportDir = __DIR__ . "/export"; + + $jobs = [ + [ + 'sql' => " SELECT i.document_no, i.register_date, @@ -294,10 +289,10 @@ GROUP BY ii.price_netto ORDER BY i.register_date DESC; ", - 'filename' => 'invoices_2024.csv', - ], // invoices 2024 - [ - 'sql' => " + 'filename' => 'invoices_2024.csv', + ], // invoices 2024 + [ + 'sql' => " SELECT i.document_no, i.register_date, @@ -333,10 +328,10 @@ GROUP BY ii.price_netto ORDER BY i.register_date DESC; ", - 'filename' => 'invoices_2025.csv', - ], // invoices 2025 - [ - 'sql' => " + 'filename' => 'invoices_2025.csv', + ], // invoices 2025 + [ + 'sql' => " SELECT i.document_no, i.register_date, @@ -379,10 +374,10 @@ GROUP BY ii.total_netto_corrected ORDER BY i.register_date DESC; ", - 'filename' => 'correct_invoices_2024.csv', - ], // correct invoices 2024 - [ - 'sql' => " + 'filename' => 'correct_invoices_2024.csv', + ], // correct invoices 2024 + [ + 'sql' => " SELECT i.document_no, i.register_date, @@ -425,10 +420,10 @@ GROUP BY ii.total_netto_corrected ORDER BY i.register_date DESC; ", - 'filename' => 'correct_invoices_2025.csv', - ], // correct invoices 2025 - [ - 'sql' => " + 'filename' => 'correct_invoices_2025.csv', + ], // correct invoices 2025 + [ + 'sql' => " SELECT i.document_no, i.register_date, @@ -463,10 +458,10 @@ GROUP BY ii.quantity ORDER BY i.register_date DESC; ", - 'filename' => 'rw_2025.csv', - ], // rw 2025 - [ - 'sql' => " + 'filename' => 'rw_2025.csv', + ], // rw 2025 + [ + 'sql' => " SELECT i.document_no, i.register_date, @@ -501,34 +496,47 @@ GROUP BY ii.quantity ORDER BY i.register_date DESC; ", - 'filename' => 'rw_2024.csv', - ], // rw 2024 - [ - 'sql' => " + 'filename' => 'rw_2024.csv', + ], // rw 2024 + [ + 'sql' => " SELECT ss.product_code, ss.product_name, ss.product_id, COALESCE(NULLIF(ss.quantity, ''), 0) AS quantity, s.name, - COALESCE(si.ordered_quantity, 0) AS ordered_quantity + CASE + WHEN s.id = 'c7afd71a-4c3a-bde4-138d-4acaee1644e4' THEN COALESCE(si.ordered_quantity, 0) + WHEN s.id = '368479db-22c5-0220-3a14-4bc426b1c709' THEN COALESCE(poi.ordered_quantity, 0) + ELSE 0 + END AS ordered_quantity FROM ecmstockstates AS ss -JOIN ecmstocks AS s ON ss.stock_id = s.id -LEFT JOIN ( + JOIN ecmstocks AS s ON ss.stock_id = s.id + LEFT JOIN ( SELECT i.ecmproduct_id, SUM(i.quantity) AS ordered_quantity FROM ecmsaleitems AS i - JOIN ecmsales AS es ON es.id = i.ecmsale_id + JOIN ecmsales AS es ON es.id = i.ecmsale_id WHERE es.status IN ('s20','s30') AND es.deleted = '0' AND i.deleted = '0' AND es.register_date >= '2025-06-01' GROUP BY i.ecmproduct_id ) AS si ON si.ecmproduct_id = ss.product_id + LEFT JOIN ( + SELECT + poi.ecmproduct_id, + SUM(poi.quantity) AS ordered_quantity + FROM ecmpurchaseorderitems AS poi + JOIN ecmpurchaseorders AS po ON po.id = poi.ecmpurchaseorder_id + WHERE po.status IN ('accepted','registered') AND po.deleted = '0' AND poi.deleted = '0' AND po.register_date >= '2025-06-01' + GROUP BY poi.ecmproduct_id +) AS poi ON poi.ecmproduct_id = ss.product_id WHERE ss.stock_id IN ('c7afd71a-4c3a-bde4-138d-4acaee1644e4','368479db-22c5-0220-3a14-4bc426b1c709') ORDER BY quantity + 0 DESC;", - 'filename' => 'stocks.csv', - ],// stocks - [ - 'sql' => " + 'filename' => 'stocks.csv', + ],// stocks + [ + 'sql' => " SELECT i.code AS product_code, i.name AS product_name, @@ -552,10 +560,10 @@ WHERE es.status IN ('s20','s30') AND es.register_date >= '2025-06-01' ORDER BY es.register_date DESC, es.document_no DESC, i.position; ", - 'filename' => 'zs.csv', - ], //sales - [ - 'sql' => " + 'filename' => 'zs.csv', + ], //sales + [ + 'sql' => " SELECT i.code AS product_code, i.name AS product_name, @@ -578,33 +586,31 @@ WHERE es.status IN ('accepted','registered') AND es.register_date >= '2025-06-01' ORDER BY es.register_date DESC, es.document_no DESC, i.position; ", - 'filename' => 'zz.csv', - ], //orders - ]; + 'filename' => 'zz.csv', + ], //orders + ]; - $report = []; - foreach ($jobs as $job) { - $sql = $job['sql']; - $filename = $job['filename']; - $headers = isset($job['headers']) ? $job['headers'] : null; + $report = []; + foreach ($jobs as $job) { + $sql = $job['sql']; + $filename = $job['filename']; + $headers = isset($job['headers']) ? $job['headers'] : null; - $res = $db->query($sql); - $fullpath = rtrim($exportDir, "/") . "/" . $filename; + $res = $db->query($sql); + $fullpath = rtrim($exportDir, "/") . "/" . $filename; - $result = exportToCSVFile($res, $fullpath, $headers, ';', true); + $result = exportToCSVFile($res, $fullpath, $headers, ';', true); - if ($result['ok']) { - $report[] = "OK → {$result['path']} (wiersze: {$result['rows']})" . PHP_EOL; - } else { - $report[] = "ERR → {$result['path']} ({$result['error']})" . PHP_EOL;; - } + if ($result['ok']) { + $report[] = "OK → {$result['path']} (wiersze: {$result['rows']})" . PHP_EOL; + } else { + $report[] = "ERR → {$result['path']} ({$result['error']})" . PHP_EOL;; } - - echo implode("\n", $report); - exit; } -} + echo implode("\n", $report); + exit; +} function exportToCSVFile($res, $fullpath, array $headers = null, $delimiter = ';', $withBom = true) { $db = $GLOBALS['db']; @@ -670,4 +676,160 @@ function exportToCSVFile($res, $fullpath, array $headers = null, $delimiter = '; fclose($fp); $chmod_ok = @chmod($fullpath, 0664); return ['ok' => true, 'path' => $fullpath, 'rows' => $count, 'chmod' => $chmod_ok, 'error' => null]; -} \ No newline at end of file +} + +function generateProductComponentsCSV() +{ + $db = $GLOBALS['db']; + $exportDir = __DIR__ . "/export"; + $filename = 'product_components.csv'; + $fullpath = rtrim($exportDir, "/") . "/" . $filename; + + if (!is_dir($exportDir)) { + if (!@mkdir($exportDir, 0775, true)) { + echo "Błąd: Nie mogę utworzyć katalogu: $exportDir"; + return; + } + } + + $productsWithComponents = $db->query(" + SELECT DISTINCT p.id, p.code, p.name + FROM ecmproducts p + INNER JOIN ecmproductcomponents c ON p.id = c.ecmproduct_id + WHERE p.deleted = '0' AND c.deleted = '0' AND p.active = '1' + ORDER BY p.code + "); + + $fp = @fopen($fullpath, 'w'); + if ($fp === false) { + echo "Błąd: Nie mogę otworzyć pliku do zapisu: $fullpath"; + return; + } + + fwrite($fp, "\xEF\xBB\xBF"); + + $headers = [ + 'Poziom_1_Kod', 'Poziom_1_Nazwa', 'Poziom_1_Ilosc', + 'Poziom_2_Kod', 'Poziom_2_Nazwa', 'Poziom_2_Ilosc', + 'Poziom_3_Kod', 'Poziom_3_Nazwa', 'Poziom_3_Ilosc', + 'Poziom_4_Kod', 'Poziom_4_Nazwa', 'Poziom_4_Ilosc', + 'Poziom_5_Kod', 'Poziom_5_Nazwa', 'Poziom_5_Ilosc', + 'Poziom_6_Kod', 'Poziom_6_Nazwa', 'Poziom_6_Ilosc', + 'Poziom_7_Kod', 'Poziom_7_Nazwa', 'Poziom_7_Ilosc', + 'Poziom_8_Kod', 'Poziom_8_Nazwa', 'Poziom_8_Ilosc', + 'Poziom_9_Kod', 'Poziom_9_Nazwa', 'Poziom_9_Ilosc', + 'Poziom_10_Kod', 'Poziom_10_Nazwa', 'Poziom_10_Ilosc' + ]; + + fputcsv($fp, $headers, ';'); + + $totalRows = 0; + + while ($product = $db->fetchByAssoc($productsWithComponents)) { + $rows = generateComponentRows($product['id'], $product['code'], $product['name'], 1.0, [], $db); + foreach ($rows as $row) { + fputcsv($fp, $row, ';'); + $totalRows++; + } + } + + fclose($fp); + + echo "Wygenerowano plik CSV: $fullpath (wiersze: $totalRows)"; +} +function generateComponentRows($productId, $productCode, $productName, $quantity, $path, $db, $level = 1) +{ + if (in_array($productId, array_column($path, 'id'))) { + return []; + } + + if ($level > 10) { + return []; + } + + $rows = []; + + $currentPath = $path; + $currentPath[] = [ + 'id' => $productId, + 'code' => $productCode, + 'name' => $productName, + 'quantity' => $quantity + ]; + + $componentsQuery = $db->query(" + SELECT + c.ecmcomponent_id, + c.quantity, + p.code, + p.name + FROM ecmproductcomponents c + INNER JOIN ecmproducts p ON c.ecmcomponent_id = p.id + WHERE c.ecmproduct_id = '$productId' + AND c.deleted = '0' + AND p.deleted = '0' + ORDER BY c.position, p.code + "); + + $hasComponents = false; + + while ($component = $db->fetchByAssoc($componentsQuery)) { + $hasComponents = true; + + // Oblicz rzeczywistą ilość komponentu (ilość z hierarchii wyżej * ilość komponentu) + $totalQuantity = bcmul($quantity, $component['quantity'], 6); + + // Sprawdź czy komponent ma swoje komponenty (rekurencja) + $subRows = generateComponentRows( + $component['ecmcomponent_id'], + $component['code'], + $component['name'], + $totalQuantity, + $currentPath, + $db, + $level + 1 + ); + + if (empty($subRows)) { + // Komponent nie ma pod-komponentów, dodaj wiersz z kompletną ścieżką + $row = createCSVRow($currentPath, $component['ecmcomponent_id'], $component['code'], $component['name'], $totalQuantity); + $rows[] = $row; + } else { + // Komponent ma pod-komponenty, dodaj wszystkie zwrócone wiersze + $rows = array_merge($rows, $subRows); + } + } + + // Jeśli produkt nie ma komponentów i jesteśmy na poziomie > 1, zwróć pusty array + // (główny produkt zawsze musi być pokazany) + if (!$hasComponents && $level > 1) { + $row = createCSVRow($currentPath); + $rows[] = $row; + } + + return $rows; +} +function createCSVRow($path, $lastComponentId = null, $lastComponentCode = null, $lastComponentName = null, $lastQuantity = null) +{ + // Utwórz tablicę z 30 elementami (10 poziomów * 3 kolumny: kod, nazwa, ilość) + $row = array_fill(0, 30, ''); + + // Wypełnij ścieżkę + foreach ($path as $index => $item) { + if ($index < 10) { // Maksymalnie 10 poziomów + $row[$index * 3] = $item['code']; // Kod + $row[$index * 3 + 1] = $item['name']; // Nazwa + $row[$index * 3 + 2] = $item['quantity']; // Ilość + } + } + + // Dodaj ostatni komponent jeśli został przekazany + if ($lastComponentId !== null && count($path) < 10) { + $lastIndex = count($path); + $row[$lastIndex * 3] = $lastComponentCode; + $row[$lastIndex * 3 + 1] = $lastComponentName; + $row[$lastIndex * 3 + 2] = $lastQuantity; + } + + return $row; +}