Poprawki w API rachunków i kds

This commit is contained in:
2026-05-24 22:20:23 +02:00
parent 58fae2f0e6
commit f95f578bab
10 changed files with 597 additions and 53 deletions

179
api_bills.php Normal file
View File

@@ -0,0 +1,179 @@
<?php
header('Content-Type: application/json; charset=utf-8');
$serverName = '192.168.20.20';
$connectionOptions = [
'Database' => 'Gastro',
'Uid' => 'sa',
'PWD' => 'karczma!@#26',
'CharacterSet' => 'UTF-8',
];
$conn = sqlsrv_connect($serverName, $connectionOptions);
if (!$conn) {
die(json_encode(['status' => 'error', 'message' => 'Błąd połączenia.']));
}
$tableParam = isset($_GET['table']) ? strtolower(trim($_GET['table'])) : '';
// Usunąłem die() na pustym tableParam, aby ułatwić Ci testowanie w przeglądarce!
// 1. & 2. & 3. Pobranie dzisiejszych rachunków ze statusem 0
$tsqlBills = "
SELECT
r.ID,
r.Numer,
r.Opis,
s.Nazwa as NazwaStolika
FROM dbo.NGastroDTRachunek r
LEFT JOIN dbo.NGastroStolik s ON s.ID = r.StolikID
WHERE CAST(r.DataOtwarcia as DATE) = CAST(GETDATE() as DATE)
AND r.Status = 0
";
$stmtBills = sqlsrv_query($conn, $tsqlBills);
if ($stmtBills === false) {
die(json_encode(['status' => 'error', 'message' => 'Błąd pobierania rachunków.', 'errors' => sqlsrv_errors()]));
}
$matchedBillIds = [];
$bills = [];
// 4. Filtrujemy rachunki po nazwie stolika (tak jak w JS)
while ($row = sqlsrv_fetch_array($stmtBills, SQLSRV_FETCH_ASSOC)) {
$stolikNazwa = strtolower($row['NazwaStolika'] ?? '');
$opis = strtolower($row['Opis'] ?? '');
// Elastyczne dopasowanie, uwzględnia literówkę 0 zamiast O
$normalizedTableParam = str_replace('o', '0', $tableParam);
$normalizedStolikNazwa = str_replace('o', '0', $stolikNazwa);
$normalizedOpis = str_replace('o', '0', $opis);
$isMatched = false;
if (!$tableParam) {
// Jeśli testujesz w przeglądarce bez parametru ?table=, pokażemy WSZYSTKIE otwarte rachunki
$isMatched = true;
} else {
$pattern = '/\b' . preg_quote($normalizedTableParam, '/') . '\b/i';
if (
$normalizedStolikNazwa === $normalizedTableParam ||
$normalizedOpis === $normalizedTableParam ||
preg_match($pattern, $normalizedStolikNazwa) ||
preg_match($pattern, $normalizedOpis)
) {
$isMatched = true;
}
}
if ($isMatched) {
$billId = $row['ID'];
$matchedBillIds[] = $billId;
$bills[$billId] = [
'id' => $billId,
'numer' => $row['Numer'],
'opis' => $row['Opis'],
'suma' => 0,
'pozycje' => []
];
}
}
if (empty($matchedBillIds)) {
die(json_encode(['status' => 'success', 'data' => []]));
}
// 5. Pobranie pozycji dla dopasowanych rachunków
$inClause = implode("','", $matchedBillIds);
$tsqlItems = "
SELECT
rp.DTRachunekID,
rp.ID as PozycjaID,
ISNULL(NULLIF(t.NazwaNaZamowieniu, ''), t.NazwaTowaru) as NazwaTowaru,
ISNULL(NULLIF(tz.NazwaNaZamowieniu, ''), tz.NazwaTowaru) as NazwaZestawu,
rp.GrupaZestawuID,
rp.ZestawID,
rp.Ilosc,
rp.Cena,
rp._c_Wartosc
FROM dbo.NGastroDTRachunekPozycja rp
LEFT JOIN dbo.NGastroTowar t ON t.ID = rp.TowarID
LEFT JOIN dbo.NGastroTowar tz ON tz.ID = rp.ZestawID
WHERE rp.DTRachunekID IN ('$inClause')
";
$stmtItems = sqlsrv_query($conn, $tsqlItems);
if ($stmtItems === false) {
die(json_encode(['status' => 'error', 'message' => 'Błąd pobierania pozycji.', 'errors' => sqlsrv_errors()]));
}
// 1. Grupujemy najpierw w fizyczne "Dania" (składniki pizzy łączą się w jedną pizzę)
$dishes = [];
while ($row = sqlsrv_fetch_array($stmtItems, SQLSRV_FETCH_ASSOC)) {
$billId = $row['DTRachunekID'];
$groupId = !empty($row['GrupaZestawuID']) ? $row['GrupaZestawuID'] : $row['PozycjaID'];
if (!isset($dishes[$billId])) {
$dishes[$billId] = [];
}
$ilosc = floatval($row['Ilosc']);
$wartosc = floatval($row['_c_Wartosc']);
if (!isset($dishes[$billId][$groupId])) {
$nazwa = trim(!empty($row['NazwaZestawu']) ? $row['NazwaZestawu'] : $row['NazwaTowaru']);
$dishes[$billId][$groupId] = [
'nazwa' => $nazwa ?: 'Brak nazwy',
'ilosc' => $ilosc,
'wartosc' => 0
];
} else {
// Zabezpieczenie: bierzemy największą ilość ze składników (np. jak ktoś usunął składnik i ma ilość 0)
if ($ilosc > $dishes[$billId][$groupId]['ilosc']) {
$dishes[$billId][$groupId]['ilosc'] = $ilosc;
}
}
// Zawsze sumujemy wartość składników (ser 53zł + ciasto 0zł = 53zł)
$dishes[$billId][$groupId]['wartosc'] += $wartosc;
}
// 2. Mając pełne dania, redukujemy je (np. dwie takie same pizze "ZADYMIONA BACÓWKA" w jeden wiersz x2)
foreach ($dishes as $billId => $billDishes) {
$groupedByMenu = [];
foreach ($billDishes as $dish) {
$nazwa = $dish['nazwa'];
$ilosc = $dish['ilosc'];
$wartosc = $dish['wartosc'];
// Cena jednostkowa uśredniona
$cenaJednostkowa = $ilosc > 0 ? ($wartosc / $ilosc) : $wartosc;
$key = $nazwa . "_" . number_format($cenaJednostkowa, 2, '.', '');
if (!isset($groupedByMenu[$key])) {
$groupedByMenu[$key] = [
'nazwa' => $nazwa,
'ilosc' => 0,
'cena' => $cenaJednostkowa,
'wartosc' => 0
];
}
$groupedByMenu[$key]['ilosc'] += $ilosc;
$groupedByMenu[$key]['wartosc'] += $wartosc;
$bills[$billId]['suma'] += $wartosc;
}
$bills[$billId]['pozycje'] = array_values($groupedByMenu);
}
$finalData = [];
foreach ($bills as $bill) {
$finalData[] = $bill;
}
echo json_encode([
'status' => 'success',
'data' => $finalData
], JSON_UNESCAPED_UNICODE);

View File

@@ -22,6 +22,8 @@ if (!$conn) {
]));
}
$tableParam = isset($_GET['table']) ? strtolower(trim($_GET['table'])) : '';
// Zapytanie SQL wyciągające aktywne pozycje (StatusRealizacji < 4)
// Łączymy NGastroDTRachunekPozycja z NGastroDTRachunek (żeby mieć stolik) i z NGastroTowar (żeby mieć nazwę)
$tsql = "
@@ -29,6 +31,7 @@ $tsql = "
r.StolikID,
s.Nazwa AS NazwaStolika,
r.Numer AS NumerRachunku,
r.Opis,
r.NumerReczny AS NumerRecznyRachunku,
rp.ID AS PozycjaID,
rp.StatusRealizacji,
@@ -47,10 +50,12 @@ $tsql = "
LEFT JOIN dbo.NGastroTowar t ON t.ID = rp.TowarID
LEFT JOIN dbo.NGastroTowar tz ON tz.ID = rp.ZestawID
LEFT JOIN dbo.NGastroStolik s ON s.ID = r.StolikID
WHERE rp.StatusRealizacji = 1
LEFT JOIN dbo.NGastroKonfiguracjaDrukowaniaZamowien kdz ON kdz.ID = ISNULL(rp.KonfiguracjaDrukowaniaZamowienID, t.KonfiguracjaDrukowaniaZamowienID)
WHERE r.Status = 0
AND rp.StatusRealizacji > 0
AND rp.StatusRealizacji < 4
AND kdz.ID IS NOT NULL
AND CAST(rp.DataDodania AS DATE) = CAST(GETDATE() AS DATE)
-- Opcjonalnie: pominięcie usuniętych pozycji, zazwyczaj posiadają DataUsuniecia różną od domyślnej,
-- lub oznaczane są poprzez inny mechanizm, ale na razie trzymajmy się StatusRealizacji
AND rp.DataUsuniecia = '1900-01-01'
ORDER BY rp.DataDodania ASC
";
@@ -67,17 +72,38 @@ if ($stmt === false) {
$pozycje = [];
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
// Formatowanie daty dla JSON (obiekt DateTime w PHP do ISO 8601)
if ($row['DataDodania'] instanceof DateTime) {
$row['DataDodania'] = $row['DataDodania']->format('Y-m-d H:i:s');
$stolikNazwa = strtolower($row['NazwaStolika'] ?? '');
$opis = strtolower($row['Opis'] ?? '');
$normalizedTableParam = str_replace('o', '0', $tableParam);
$normalizedStolikNazwa = str_replace('o', '0', $stolikNazwa);
$normalizedOpis = str_replace('o', '0', $opis);
$isMatched = false;
if (!$tableParam) {
$isMatched = true;
} else {
$pattern = '/\b' . preg_quote($normalizedTableParam, '/') . '\b/i';
if (
$normalizedStolikNazwa === $normalizedTableParam ||
$normalizedOpis === $normalizedTableParam ||
preg_match($pattern, $normalizedStolikNazwa) ||
preg_match($pattern, $normalizedOpis)
) {
$isMatched = true;
}
}
// Rzutowanie wartości, aby uniknąć problemów w JSON
$row['StolikID'] = $row['StolikID'] ? strtoupper($row['StolikID']) : null;
$row['PozycjaID'] = strtoupper($row['PozycjaID']);
$row['TowarID'] = strtoupper($row['TowarID']);
$pozycje[] = $row;
if ($isMatched) {
if ($row['DataDodania'] instanceof DateTime) {
$row['DataDodania'] = $row['DataDodania']->format('Y-m-d H:i:s');
}
$row['StolikID'] = $row['StolikID'] ? strtoupper($row['StolikID']) : null;
$row['PozycjaID'] = strtoupper($row['PozycjaID']);
$row['TowarID'] = strtoupper($row['TowarID']);
$pozycje[] = $row;
}
}
// Zwracamy czysty JSON

16
check_o61.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
$serverName = '192.168.20.20';
$connectionOptions = ['Database' => 'Gastro', 'Uid' => 'sa', 'PWD' => 'karczma!@#26', 'CharacterSet' => 'UTF-8'];
$conn = sqlsrv_connect($serverName, $connectionOptions);
$tsql = "
SELECT
r.ID, r.Numer, r.Opis, s.Nazwa as NazwaStolika, r.Status, r.FlgRozliczony, r.DataOtwarcia, r.DataZamkniecia
FROM dbo.NGastroDTRachunek r
LEFT JOIN dbo.NGastroStolik s ON s.ID = r.StolikID
WHERE (r.Opis LIKE '%61%' OR s.Nazwa LIKE '%61%')
";
$stmt = sqlsrv_query($conn, $tsql);
while($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
echo "Num: {$row['Numer']} | Opis: {$row['Opis']} | Stolik: {$row['NazwaStolika']} | Stat: {$row['Status']} | Rozl: {$row['FlgRozliczony']} | Otw: {$row['DataOtwarcia']->format('Y-m-d H:i')} | Zamkn: {$row['DataZamkniecia']->format('Y-m-d H:i')}\n";
}

View File

@@ -251,27 +251,13 @@ const params = new URLSearchParams(location.search);
});
});
// Pozycje, które były wcześniej, ale zniknęły z WS -> zostają jako gotowe
// Pozycje, które były wcześniej, ale zniknęły z API -> przesyłamy od razu do historii globalnej
persistedMap.forEach((oldItem, name) => {
if (current.has(name)) return;
const qty = Number.isFinite(oldItem?.qty) ? oldItem.qty : 0;
const archivedAt = Number.isFinite(oldItem?.archivedAt) ? oldItem.archivedAt : Date.now();
const shouldMoveToGlobal = (Date.now() - archivedAt) > HOT_WINDOW_MS;
if (shouldMoveToGlobal) {
addItemsToGlobalHistory([{ name, qty }], tableParam);
return;
}
merged.push({
name,
qty,
done: qty,
present: false,
completedByDisappear: true,
archivedAt,
updatedAt: Date.now()
});
// Zniknęło z bieżącego rachunku (np. rachunek został zamknięty), od razu leci do osobnego bloku historii!
addItemsToGlobalHistory([{ name, qty }], tableParam);
});
// Aktywne na górze, gotowe (zniknięte) na dole
@@ -352,38 +338,40 @@ const params = new URLSearchParams(location.search);
// API Fetch Logic
async function fetchOrders() {
try {
const response = await fetch('../api_kds.php');
if (!tableParam) {
updateUI([]);
return;
}
const response = await fetch(`../api_kds.php?table=${encodeURIComponent(tableParam)}`);
const result = await response.json();
if (result.status === 'success') {
if (!tableParam) {
updateUI([]);
return;
}
// API teraz samo filtruje i zwraca tylko to co nas interesuje (za pomocą mocnego wyrażenia regularnego)
const matches = result.data;
const myTable = tableParam.toLowerCase();
// Filtrowanie pozycji dla wybranego stolika
const matches = result.data.filter(item => {
const stolikNazwa = (item.NazwaStolika || '').toLowerCase();
const stolikId = (item.StolikID || '').toLowerCase();
// Sprawdzamy czy nazwa stolika z bazy zawiera numer szukany (np. O-61) lub czy ID się zgadza
return stolikNazwa === myTable || stolikId === myTable || stolikNazwa.includes(myTable);
});
// Grupowanie składników w główne dania, żeby klient widział "Pierogi" a nie "Opakowanie"
// Grupowanie składników w główne dania
const groups = {};
matches.forEach(item => {
const groupId = item.GrupaZestawuID || item.PozycjaID;
if (!groups[groupId]) {
groups[groupId] = {
Name: item.NazwaZestawu || item.NazwaTowaru,
QuantitySet: item.GrupaZestawuID ? 1 : parseFloat(item.Ilosc)
QuantitySet: item.GrupaZestawuID ? 1 : parseFloat(item.Ilosc),
Done: 0
};
}
// StatusRealizacji >= 2 oznacza, że kucharz wcisnął "Gotowe" na swoim ekranie
if (parseInt(item.StatusRealizacji, 10) >= 2) {
groups[groupId].Done = groups[groupId].QuantitySet;
}
});
const transformedArticles = Object.values(groups);
const transformedArticles = Object.values(groups).map(g => ({
Name: g.Name,
QuantitySet: g.QuantitySet,
QuantityDone: g.Done
}));
// Najnowszy czas dodania (do pokazania w stopce)
const latestDate = matches.length > 0
@@ -436,10 +424,93 @@ const params = new URLSearchParams(location.search);
}
};
window.openBillDialog = function() {
billState = { payment: '', doc: '', nip: '', company: null };
window.openBillDialog = async function() {
billState = { payment: '', doc: '', nip: '', company: null, selectedBillId: null };
document.getElementById("billModal").classList.add("active");
goToStep("stepPayment");
document.getElementById("billLoading").classList.remove("hidden");
document.getElementById("billListContainer").classList.add("hidden");
goToStep("stepBillList");
try {
const res = await fetch(`../api_bills.php?table=${encodeURIComponent(tableParam)}`);
const result = await res.json();
if (result.status === 'success' && result.data.length > 0) {
const bills = result.data;
if (bills.length === 1) {
showBillReview(bills[0]);
document.getElementById("btnBackToBills").style.display = 'none';
} else {
renderBillList(bills);
document.getElementById("btnBackToBills").style.display = 'block';
}
} else {
document.getElementById("billLoading").innerHTML = "Brak otwartych rachunków do opłacenia.";
}
} catch (err) {
document.getElementById("billLoading").innerHTML = "Błąd pobierania rachunków.";
}
};
function renderBillList(bills) {
document.getElementById("billLoading").classList.add("hidden");
document.getElementById("billListContainer").classList.remove("hidden");
const container = document.getElementById("billListItems");
container.innerHTML = "";
bills.forEach(b => {
const div = document.createElement("div");
div.className = "option-card";
div.style.flexDirection = "row";
div.style.justifyContent = "space-between";
div.style.padding = "15px";
div.onclick = () => showBillReview(b);
const numerFormat = b.numer ? `#${b.numer}` : "Rachunek";
div.innerHTML = `
<div>
<div style="font-weight:bold;">${numerFormat}</div>
<div style="font-size:12px; color:var(--text-muted);">${b.opis}</div>
</div>
<div style="font-weight:bold; color:var(--primary);">${b.suma.toFixed(2)} PLN</div>
`;
container.appendChild(div);
});
}
window.goBackToBillList = function() {
goToStep("stepBillList");
};
window.showBillReview = function(bill) {
billState.selectedBillId = bill.id;
const content = document.getElementById("billReviewContent");
content.innerHTML = "";
bill.pozycje.forEach(p => {
const div = document.createElement("div");
div.style.display = "flex";
div.style.justifyContent = "space-between";
div.style.marginBottom = "8px";
div.style.borderBottom = "1px solid rgba(255,255,255,0.05)";
div.style.paddingBottom = "8px";
div.innerHTML = `
<div style="flex:1;">
<div style="font-weight:600; font-size: 14px;">${p.nazwa}</div>
<div style="font-size:12px; color:var(--text-muted);">${p.ilosc} x ${p.cena.toFixed(2)} PLN</div>
</div>
<div style="font-weight:600;">${p.wartosc.toFixed(2)} PLN</div>
`;
content.appendChild(div);
});
document.getElementById("billTotalAmount").textContent = bill.suma.toFixed(2) + " PLN";
goToStep("stepBillReview");
};
window.closeBillDialog = function() {
@@ -460,7 +531,7 @@ const params = new URLSearchParams(location.search);
billState.doc = docType;
if (docType === 'paragon') {
closeBillDialog();
sendApiSimulated("CallWaiter_Bill", { table: tableParam, payment: billState.payment, doc: 'paragon' });
sendApiSimulated("CallWaiter_Bill", { table: tableParam, billId: billState.selectedBillId, payment: billState.payment, doc: 'paragon' });
showToast("Kelner przyniesie paragon do opłacenia!");
} else {
goToStep("stepNIP");
@@ -527,6 +598,7 @@ const params = new URLSearchParams(location.search);
closeBillDialog();
sendApiSimulated("CallWaiter_Bill", {
table: tableParam,
billId: billState.selectedBillId,
payment: billState.payment,
doc: 'faktura',
nip: billState.nip,

View File

@@ -84,8 +84,34 @@
<button class="close-btn" onclick="closeBillDialog()">&times;</button>
</div>
<!-- Step 0: Loading or List of Bills -->
<div class="step active" id="stepBillList">
<div id="billLoading" style="text-align:center; padding: 20px;">
⏳ Pobieranie rachunków...
</div>
<div id="billListContainer" class="hidden">
<p style="margin-top:0; color:var(--text-muted); font-size:14px; margin-bottom: 20px;">Mamy kilka otwartych rachunków na tym stoliku. Który chcesz opłacić?</p>
<div id="billListItems" style="display:flex; flex-direction:column; gap:10px;"></div>
</div>
</div>
<!-- Step 0.5: Bill Review -->
<div class="step" id="stepBillReview">
<p style="margin-top:0; color:var(--text-muted); font-size:14px; margin-bottom: 20px;">Podsumowanie rachunku:</p>
<div id="billReviewContent" style="background: var(--surface-light); padding: 15px; border-radius: 12px; max-height: 40vh; overflow-y: auto; margin-bottom: 15px;">
</div>
<div style="display:flex; justify-content:space-between; font-weight:700; font-size:18px; margin-bottom: 20px;">
<span>Do zapłaty:</span>
<span id="billTotalAmount" style="color:var(--primary);">0.00 PLN</span>
</div>
<div style="display:flex; gap:12px;">
<button class="btn btn-secondary" style="flex:1;" onclick="goBackToBillList()" id="btnBackToBills">Wróć</button>
<button class="btn btn-primary" style="flex:2;" onclick="goToStep('stepPayment')">Dalej</button>
</div>
</div>
<!-- Step 1: Payment Method -->
<div class="step active" id="stepPayment">
<div class="step" id="stepPayment">
<p style="margin-top:0; color:var(--text-muted); font-size:14px; margin-bottom: 20px;">Wybierz preferowaną formę płatności:</p>
<div class="option-grid">
<div class="option-card" onclick="selectPayment('karta')">
@@ -97,6 +123,7 @@
<span class="option-label">Gotówka</span>
</div>
</div>
<button class="btn btn-secondary" onclick="goToStep('stepBillReview')" style="margin-top: 15px;">Wróć do podsumowania</button>
</div>
<!-- Step 2: Document Type -->

25
test_all_open.php Normal file
View File

@@ -0,0 +1,25 @@
<?php
$serverName = '192.168.20.20';
$connectionOptions = ['Database' => 'Gastro', 'Uid' => 'sa', 'PWD' => 'karczma!@#26', 'CharacterSet' => 'UTF-8'];
$conn = sqlsrv_connect($serverName, $connectionOptions);
$tsql = "
SELECT
r.ID as RachunekID,
r.Numer as RachunekNumer,
r.Opis,
s.Nazwa as NazwaStolika,
r.DataOtwarcia
FROM dbo.NGastroDTRachunek r
LEFT JOIN dbo.NGastroStolik s ON s.ID = r.StolikID
WHERE r.Status = 0
";
$stmt = sqlsrv_query($conn, $tsql);
$count = 0;
while($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
$count++;
if ($count <= 20) {
echo "Rachunek: " . $row['RachunekNumer'] . " | Opis: " . $row['Opis'] . " | Stolik: " . $row['NazwaStolika'] . " | Otwarcia: " . $row['DataOtwarcia']->format('Y-m-d') . "\n";
}
}
echo "Total open bills: $count\n";

134
test_api_bills.php Normal file
View File

@@ -0,0 +1,134 @@
<?php
$_GET['table'] = 'O-47';
header('Content-Type: application/json; charset=utf-8');
$serverName = '192.168.20.20';
$connectionOptions = [
'Database' => 'Gastro',
'Uid' => 'sa',
'PWD' => 'karczma!@#26',
'CharacterSet' => 'UTF-8',
];
$conn = sqlsrv_connect($serverName, $connectionOptions);
if (!$conn) {
die(json_encode(['status' => 'error', 'message' => 'Błąd połączenia.']));
}
$tableParam = isset($_GET['table']) ? strtolower(trim($_GET['table'])) : '';
if (!$tableParam) {
die(json_encode(['status' => 'success', 'data' => []]));
}
// 1. & 2. & 3. Pobranie dzisiejszych rachunków ze statusem 0
$tsqlBills = "
SELECT
r.ID,
r.Numer,
r.Opis,
s.Nazwa as NazwaStolika
FROM dbo.NGastroDTRachunek r
LEFT JOIN dbo.NGastroStolik s ON s.ID = r.StolikID
WHERE CAST(r.DataOtwarcia as DATE) = CAST(GETDATE() as DATE)
AND r.Status = 0
";
$stmtBills = sqlsrv_query($conn, $tsqlBills);
if ($stmtBills === false) {
die(json_encode(['status' => 'error', 'message' => 'Błąd pobierania rachunków.', 'errors' => sqlsrv_errors()]));
}
$matchedBillIds = [];
$bills = [];
// 4. Filtrujemy rachunki po nazwie stolika (tak jak w JS)
while ($row = sqlsrv_fetch_array($stmtBills, SQLSRV_FETCH_ASSOC)) {
$stolikNazwa = strtolower($row['NazwaStolika'] ?? '');
$opis = strtolower($row['Opis'] ?? '');
// Elastyczne dopasowanie, uwzględnia literówkę 0 zamiast O
$normalizedTableParam = str_replace('o', '0', $tableParam);
$normalizedStolikNazwa = str_replace('o', '0', $stolikNazwa);
$normalizedOpis = str_replace('o', '0', $opis);
if (
$stolikNazwa === $tableParam ||
strpos($stolikNazwa, $tableParam) !== false ||
$opis === $tableParam ||
strpos($opis, $tableParam) !== false ||
$normalizedStolikNazwa === $normalizedTableParam ||
strpos($normalizedStolikNazwa, $normalizedTableParam) !== false ||
strpos($normalizedOpis, $normalizedTableParam) !== false
) {
$billId = $row['ID'];
$matchedBillIds[] = $billId;
$bills[$billId] = [
'id' => $billId,
'numer' => $row['Numer'],
'opis' => $row['Opis'],
'suma' => 0,
'pozycje' => []
];
}
}
if (empty($matchedBillIds)) {
die(json_encode(['status' => 'success', 'data' => []]));
}
// 5. Pobranie pozycji dla dopasowanych rachunków
$inClause = implode("','", $matchedBillIds);
$tsqlItems = "
SELECT
rp.DTRachunekID,
rp.ID as PozycjaID,
ISNULL(NULLIF(t.NazwaNaZamowieniu, ''), t.NazwaTowaru) as NazwaTowaru,
rp.Ilosc,
rp.Cena,
rp._c_Wartosc
FROM dbo.NGastroDTRachunekPozycja rp
LEFT JOIN dbo.NGastroTowar t ON t.ID = rp.TowarID
WHERE rp.DTRachunekID IN ('$inClause')
";
$stmtItems = sqlsrv_query($conn, $tsqlItems);
if ($stmtItems === false) {
die(json_encode(['status' => 'error', 'message' => 'Błąd pobierania pozycji.', 'errors' => sqlsrv_errors()]));
}
while ($row = sqlsrv_fetch_array($stmtItems, SQLSRV_FETCH_ASSOC)) {
$billId = $row['DTRachunekID'];
$nazwa = trim($row['NazwaTowaru'] ?? 'Brak nazwy');
$ilosc = floatval($row['Ilosc']);
$wartosc = floatval($row['_c_Wartosc']);
$cena = floatval($row['Cena']);
// Grouping
$key = $nazwa . "_" . $cena;
if (!isset($bills[$billId]['pozycje'][$key])) {
$bills[$billId]['pozycje'][$key] = [
'nazwa' => $nazwa,
'ilosc' => 0,
'cena' => $cena,
'wartosc' => 0
];
}
$bills[$billId]['pozycje'][$key]['ilosc'] += $ilosc;
$bills[$billId]['pozycje'][$key]['wartosc'] += $wartosc;
$bills[$billId]['suma'] += $wartosc;
}
$finalData = [];
foreach ($bills as $bill) {
$bill['pozycje'] = array_values($bill['pozycje']);
$finalData[] = $bill;
}
echo json_encode([
'status' => 'success',
'data' => $finalData
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

23
test_kdz.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
$serverName = '192.168.20.20';
$connectionOptions = ['Database' => 'Gastro', 'Uid' => 'sa', 'PWD' => 'karczma!@#26', 'CharacterSet' => 'UTF-8'];
$conn = sqlsrv_connect($serverName, $connectionOptions);
$tsql = "
SELECT TOP 20
ISNULL(NULLIF(t.NazwaNaZamowieniu, ''), t.NazwaTowaru) as NazwaTowaru,
rp.KonfiguracjaDrukowaniaZamowienID as RP_Konf,
t.KonfiguracjaDrukowaniaZamowienID as T_Konf,
kdz.SposobDrukowaniaZamowienID,
kdz.DrukarkaZamowienID,
kdz.DrukarkaFiskalnaID
FROM dbo.NGastroDTRachunekPozycja rp
LEFT JOIN dbo.NGastroTowar t ON t.ID = rp.TowarID
LEFT JOIN dbo.NGastroKonfiguracjaDrukowaniaZamowien kdz ON kdz.ID = ISNULL(rp.KonfiguracjaDrukowaniaZamowienID, t.KonfiguracjaDrukowaniaZamowienID)
WHERE CAST(rp.DataDodania AS DATE) = CAST(GETDATE() AS DATE)
AND rp.StatusRealizacji = 1
";
$stmt = sqlsrv_query($conn, $tsql);
while($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
print_r($row);
}

22
test_match.php Normal file
View File

@@ -0,0 +1,22 @@
<?php
$serverName = '192.168.20.20';
$connectionOptions = ['Database' => 'Gastro', 'Uid' => 'sa', 'PWD' => 'karczma!@#26', 'CharacterSet' => 'UTF-8'];
$conn = sqlsrv_connect($serverName, $connectionOptions);
$tableParam = 'O-61';
$tsql = "
SELECT
r.ID as RachunekID,
r.Numer as RachunekNumer,
r.Opis,
s.Nazwa as NazwaStolika
FROM dbo.NGastroDTRachunek r
LEFT JOIN dbo.NGastroStolik s ON s.ID = r.StolikID
WHERE CAST(r.DataOtwarcia as DATE) = CAST(GETDATE() as DATE)
AND r.Status = 0
";
$stmt = sqlsrv_query($conn, $tsql);
while($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
echo "Rachunek: " . $row['RachunekNumer'] . " | Opis: " . $row['Opis'] . " | Stolik: " . $row['NazwaStolika'] . "\n";
}

20
test_today.php Normal file
View File

@@ -0,0 +1,20 @@
<?php
$serverName = '192.168.20.20';
$connectionOptions = ['Database' => 'Gastro', 'Uid' => 'sa', 'PWD' => 'karczma!@#26', 'CharacterSet' => 'UTF-8'];
$conn = sqlsrv_connect($serverName, $connectionOptions);
$tsql = "
SELECT
r.ID as RachunekID,
r.Numer as RachunekNumer,
r.Opis,
s.Nazwa as NazwaStolika,
r.DataOtwarcia
FROM dbo.NGastroDTRachunek r
LEFT JOIN dbo.NGastroStolik s ON s.ID = r.StolikID
WHERE CAST(r.DataOtwarcia as DATE) = CAST(GETDATE() as DATE)
";
$stmt = sqlsrv_query($conn, $tsql);
while($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
echo "Rachunek: " . $row['RachunekNumer'] . " | Opis: " . $row['Opis'] . " | Stolik: " . $row['NazwaStolika'] . " | Otwarcia: " . $row['DataOtwarcia']->format('Y-m-d H:i:s') . "\n";
}