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;
+}