feat: P4 backend kvalita - SELECT * fix, overdue konsolidace, Validator
- SELECT * nahrazen explicitnimi sloupci ve 22 PHP souborech (69+ vyskytu) - users-handlers.php: password_hash explicitne vyloucen z dotazu - Overdue detekce presunuta do invoices.php routeru (1x pred dispatch misto 3x v handlerech) - Validator.php: validacni helper s pravidly required, string, int, email, in, numeric - PaginationHelper: PHPStan typy opraveny Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,11 @@ function handleGetCurrent(PDO $pdo, int $userId): void
|
|||||||
$today = date('Y-m-d');
|
$today = date('Y-m-d');
|
||||||
|
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
SELECT * FROM attendance
|
SELECT id, user_id, shift_date, arrival_time, arrival_lat, arrival_lng,
|
||||||
|
arrival_accuracy, arrival_address, break_start, break_end,
|
||||||
|
departure_time, departure_lat, departure_lng, departure_accuracy,
|
||||||
|
departure_address, notes, project_id, leave_type, leave_hours, created_at
|
||||||
|
FROM attendance
|
||||||
WHERE user_id = ? AND departure_time IS NULL AND (leave_type IS NULL OR leave_type = 'work')
|
WHERE user_id = ? AND departure_time IS NULL AND (leave_type IS NULL OR leave_type = 'work')
|
||||||
ORDER BY created_at DESC LIMIT 1
|
ORDER BY created_at DESC LIMIT 1
|
||||||
");
|
");
|
||||||
@@ -17,7 +21,10 @@ function handleGetCurrent(PDO $pdo, int $userId): void
|
|||||||
$projectLogs = [];
|
$projectLogs = [];
|
||||||
$activeProjectId = null;
|
$activeProjectId = null;
|
||||||
if ($ongoingShift) {
|
if ($ongoingShift) {
|
||||||
$stmt = $pdo->prepare('SELECT * FROM attendance_project_logs WHERE attendance_id = ? ORDER BY started_at ASC');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, attendance_id, project_id, started_at, ended_at, hours, minutes
|
||||||
|
FROM attendance_project_logs WHERE attendance_id = ? ORDER BY started_at ASC'
|
||||||
|
);
|
||||||
$stmt->execute([$ongoingShift['id']]);
|
$stmt->execute([$ongoingShift['id']]);
|
||||||
$projectLogs = $stmt->fetchAll();
|
$projectLogs = $stmt->fetchAll();
|
||||||
foreach ($projectLogs as $log) {
|
foreach ($projectLogs as $log) {
|
||||||
@@ -29,7 +36,11 @@ function handleGetCurrent(PDO $pdo, int $userId): void
|
|||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
SELECT * FROM attendance
|
SELECT id, user_id, shift_date, arrival_time, arrival_lat, arrival_lng,
|
||||||
|
arrival_accuracy, arrival_address, break_start, break_end,
|
||||||
|
departure_time, departure_lat, departure_lng, departure_accuracy,
|
||||||
|
departure_address, notes, project_id, leave_type, leave_hours, created_at
|
||||||
|
FROM attendance
|
||||||
WHERE user_id = ? AND shift_date = ?
|
WHERE user_id = ? AND shift_date = ?
|
||||||
AND departure_time IS NOT NULL
|
AND departure_time IS NOT NULL
|
||||||
AND (leave_type IS NULL OR leave_type = 'work')
|
AND (leave_type IS NULL OR leave_type = 'work')
|
||||||
@@ -43,7 +54,8 @@ function handleGetCurrent(PDO $pdo, int $userId): void
|
|||||||
if (!empty($completedShiftIds)) {
|
if (!empty($completedShiftIds)) {
|
||||||
$placeholders = implode(',', array_fill(0, count($completedShiftIds), '?'));
|
$placeholders = implode(',', array_fill(0, count($completedShiftIds), '?'));
|
||||||
$stmt = $pdo->prepare(
|
$stmt = $pdo->prepare(
|
||||||
"SELECT * FROM attendance_project_logs
|
"SELECT id, attendance_id, project_id, started_at, ended_at, hours, minutes
|
||||||
|
FROM attendance_project_logs
|
||||||
WHERE attendance_id IN ($placeholders)
|
WHERE attendance_id IN ($placeholders)
|
||||||
ORDER BY started_at ASC"
|
ORDER BY started_at ASC"
|
||||||
);
|
);
|
||||||
@@ -65,7 +77,9 @@ function handleGetCurrent(PDO $pdo, int $userId): void
|
|||||||
$endDate = date('Y-m-t');
|
$endDate = date('Y-m-t');
|
||||||
|
|
||||||
$stmt = $pdo->prepare('
|
$stmt = $pdo->prepare('
|
||||||
SELECT * FROM attendance
|
SELECT id, user_id, shift_date, arrival_time, break_start, break_end,
|
||||||
|
departure_time, notes, project_id, leave_type, leave_hours
|
||||||
|
FROM attendance
|
||||||
WHERE user_id = ? AND shift_date BETWEEN ? AND ?
|
WHERE user_id = ? AND shift_date BETWEEN ? AND ?
|
||||||
');
|
');
|
||||||
$stmt->execute([$userId, $startDate, $endDate]);
|
$stmt->execute([$userId, $startDate, $endDate]);
|
||||||
@@ -167,7 +181,10 @@ function handleGetHistory(PDO $pdo, int $userId): void
|
|||||||
$endDate = date('Y-m-t', strtotime($startDate));
|
$endDate = date('Y-m-t', strtotime($startDate));
|
||||||
|
|
||||||
$stmt = $pdo->prepare('
|
$stmt = $pdo->prepare('
|
||||||
SELECT * FROM attendance
|
SELECT id, user_id, shift_date, arrival_time, arrival_address,
|
||||||
|
break_start, break_end, departure_time, departure_address,
|
||||||
|
notes, project_id, leave_type, leave_hours, created_at
|
||||||
|
FROM attendance
|
||||||
WHERE user_id = ? AND shift_date BETWEEN ? AND ?
|
WHERE user_id = ? AND shift_date BETWEEN ? AND ?
|
||||||
ORDER BY shift_date DESC
|
ORDER BY shift_date DESC
|
||||||
');
|
');
|
||||||
@@ -245,7 +262,9 @@ function handlePunch(PDO $pdo, int $userId): void
|
|||||||
$address = !empty($input['address']) ? $input['address'] : null;
|
$address = !empty($input['address']) ? $input['address'] : null;
|
||||||
|
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
SELECT * FROM attendance
|
SELECT id, user_id, shift_date, arrival_time, break_start, break_end,
|
||||||
|
departure_time, notes, project_id, leave_type, created_at
|
||||||
|
FROM attendance
|
||||||
WHERE user_id = ? AND departure_time IS NULL AND (leave_type IS NULL OR leave_type = 'work')
|
WHERE user_id = ? AND departure_time IS NULL AND (leave_type IS NULL OR leave_type = 'work')
|
||||||
ORDER BY created_at DESC LIMIT 1
|
ORDER BY created_at DESC LIMIT 1
|
||||||
");
|
");
|
||||||
@@ -529,7 +548,10 @@ function handleGetProjectLogs(PDO $pdo, int $currentUserId, array $authData): vo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM attendance_project_logs WHERE attendance_id = ? ORDER BY started_at ASC');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, attendance_id, project_id, started_at, ended_at, hours, minutes
|
||||||
|
FROM attendance_project_logs WHERE attendance_id = ? ORDER BY started_at ASC'
|
||||||
|
);
|
||||||
$stmt->execute([$attendanceId]);
|
$stmt->execute([$attendanceId]);
|
||||||
$logs = $stmt->fetchAll();
|
$logs = $stmt->fetchAll();
|
||||||
|
|
||||||
@@ -556,7 +578,7 @@ function handleSaveProjectLogs(PDO $pdo): void
|
|||||||
errorResponse('attendance_id je povinné');
|
errorResponse('attendance_id je povinné');
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM attendance WHERE id = ?');
|
$stmt = $pdo->prepare('SELECT id FROM attendance WHERE id = ?');
|
||||||
$stmt->execute([$attendanceId]);
|
$stmt->execute([$attendanceId]);
|
||||||
$record = $stmt->fetch();
|
$record = $stmt->fetch();
|
||||||
if (!$record) {
|
if (!$record) {
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
function handleGetBankAccountList(PDO $pdo): void
|
function handleGetBankAccountList(PDO $pdo): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->query('SELECT * FROM bank_accounts ORDER BY position, id');
|
$stmt = $pdo->query(
|
||||||
|
'SELECT id, account_name, bank_name, account_number, iban, bic,
|
||||||
|
currency, is_default, position, created_at, modified_at
|
||||||
|
FROM bank_accounts ORDER BY position, id'
|
||||||
|
);
|
||||||
successResponse($stmt->fetchAll());
|
successResponse($stmt->fetchAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +82,11 @@ function handleCreateBankAccount(PDO $pdo): void
|
|||||||
|
|
||||||
function handleUpdateBankAccount(PDO $pdo, int $id): void
|
function handleUpdateBankAccount(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM bank_accounts WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, account_name, bank_name, account_number, iban, bic,
|
||||||
|
currency, is_default, position
|
||||||
|
FROM bank_accounts WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$account = $stmt->fetch();
|
$account = $stmt->fetch();
|
||||||
|
|
||||||
@@ -145,7 +153,7 @@ function handleUpdateBankAccount(PDO $pdo, int $id): void
|
|||||||
|
|
||||||
function handleDeleteBankAccount(PDO $pdo, int $id): void
|
function handleDeleteBankAccount(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM bank_accounts WHERE id = ?');
|
$stmt = $pdo->prepare('SELECT id, account_name FROM bank_accounts WHERE id = ?');
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$account = $stmt->fetch();
|
$account = $stmt->fetch();
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,13 @@ declare(strict_types=1);
|
|||||||
function getOrCreateSettings(PDO $pdo, bool $includeLogo = false): array
|
function getOrCreateSettings(PDO $pdo, bool $includeLogo = false): array
|
||||||
{
|
{
|
||||||
if ($includeLogo) {
|
if ($includeLogo) {
|
||||||
$stmt = $pdo->query('SELECT * FROM company_settings LIMIT 1');
|
$stmt = $pdo->query('
|
||||||
|
SELECT id, company_name, company_id, vat_id, street, city, postal_code,
|
||||||
|
country, quotation_prefix, default_currency, default_vat_rate,
|
||||||
|
custom_fields, logo_data, uuid, modified_at, sync_version,
|
||||||
|
order_type_code, invoice_type_code, is_deleted, require_2fa
|
||||||
|
FROM company_settings LIMIT 1
|
||||||
|
');
|
||||||
} else {
|
} else {
|
||||||
$stmt = $pdo->query('
|
$stmt = $pdo->query('
|
||||||
SELECT id, company_name, company_id, vat_id, street, city, postal_code, country,
|
SELECT id, company_name, company_id, vat_id, street, city, postal_code, country,
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ function encodeCustomerCustomFields(array $input, ?string $existingJson): ?strin
|
|||||||
function handleGetAll(PDO $pdo): void
|
function handleGetAll(PDO $pdo): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->query('
|
$stmt = $pdo->query('
|
||||||
SELECT c.*, COUNT(q.id) as quotation_count
|
SELECT c.id, c.name, c.street, c.city, c.postal_code, c.country,
|
||||||
|
c.company_id, c.vat_id, c.custom_fields, c.created_at,
|
||||||
|
COUNT(q.id) as quotation_count
|
||||||
FROM customers c
|
FROM customers c
|
||||||
LEFT JOIN quotations q ON q.customer_id = c.id
|
LEFT JOIN quotations q ON q.customer_id = c.id
|
||||||
GROUP BY c.id
|
GROUP BY c.id
|
||||||
@@ -72,7 +74,11 @@ function handleGetAll(PDO $pdo): void
|
|||||||
|
|
||||||
function handleGetOne(PDO $pdo, int $id): void
|
function handleGetOne(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM customers WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, name, street, city, postal_code, country,
|
||||||
|
company_id, vat_id, custom_fields, created_at
|
||||||
|
FROM customers WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$customer = $stmt->fetch();
|
$customer = $stmt->fetch();
|
||||||
|
|
||||||
@@ -93,7 +99,9 @@ function handleSearch(PDO $pdo): void
|
|||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare('
|
$stmt = $pdo->prepare('
|
||||||
SELECT * FROM customers
|
SELECT id, name, street, city, postal_code, country,
|
||||||
|
company_id, vat_id, custom_fields
|
||||||
|
FROM customers
|
||||||
WHERE name LIKE ? OR company_id LIKE ? OR city LIKE ?
|
WHERE name LIKE ? OR company_id LIKE ? OR city LIKE ?
|
||||||
ORDER BY name ASC
|
ORDER BY name ASC
|
||||||
LIMIT 20
|
LIMIT 20
|
||||||
@@ -177,7 +185,11 @@ function handleCreateCustomer(PDO $pdo): void
|
|||||||
|
|
||||||
function handleUpdateCustomer(PDO $pdo, int $id): void
|
function handleUpdateCustomer(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM customers WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, name, street, city, postal_code, country,
|
||||||
|
company_id, vat_id, custom_fields
|
||||||
|
FROM customers WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$existing = $stmt->fetch();
|
$existing = $stmt->fetch();
|
||||||
|
|
||||||
@@ -248,7 +260,7 @@ function handleUpdateCustomer(PDO $pdo, int $id): void
|
|||||||
|
|
||||||
function handleDeleteCustomer(PDO $pdo, int $id): void
|
function handleDeleteCustomer(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM customers WHERE id = ?');
|
$stmt = $pdo->prepare('SELECT id, name FROM customers WHERE id = ?');
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$customer = $stmt->fetch();
|
$customer = $stmt->fetch();
|
||||||
|
|
||||||
|
|||||||
@@ -99,9 +99,6 @@ function handleGetStats(PDO $pdo): void
|
|||||||
$month = max(1, min(12, (int) ($_GET['month'] ?? (int) date('n'))));
|
$month = max(1, min(12, (int) ($_GET['month'] ?? (int) date('n'))));
|
||||||
$year = max(2020, min(2099, (int) ($_GET['year'] ?? (int) date('Y'))));
|
$year = max(2020, min(2099, (int) ($_GET['year'] ?? (int) date('Y'))));
|
||||||
|
|
||||||
// Lazy overdue detekce
|
|
||||||
$pdo->exec("UPDATE invoices SET status = 'overdue' WHERE status = 'issued' AND due_date < CURDATE()");
|
|
||||||
|
|
||||||
$monthStart = sprintf('%04d-%02d-01', $year, $month);
|
$monthStart = sprintf('%04d-%02d-01', $year, $month);
|
||||||
$monthEnd = date('Y-m-t', strtotime($monthStart));
|
$monthEnd = date('Y-m-t', strtotime($monthStart));
|
||||||
|
|
||||||
@@ -186,9 +183,6 @@ function handleGetList(PDO $pdo): void
|
|||||||
|
|
||||||
$p = PaginationHelper::parseParams($sortMap);
|
$p = PaginationHelper::parseParams($sortMap);
|
||||||
|
|
||||||
// Lazy overdue detekce
|
|
||||||
$pdo->exec("UPDATE invoices SET status = 'overdue' WHERE status = 'issued' AND due_date < CURDATE()");
|
|
||||||
|
|
||||||
$where = 'WHERE 1=1';
|
$where = 'WHERE 1=1';
|
||||||
$params = [];
|
$params = [];
|
||||||
|
|
||||||
@@ -253,13 +247,14 @@ function handleGetList(PDO $pdo): void
|
|||||||
|
|
||||||
function handleGetDetail(PDO $pdo, int $id): void
|
function handleGetDetail(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
// Lazy overdue
|
|
||||||
$pdo->prepare(
|
|
||||||
"UPDATE invoices SET status = 'overdue' WHERE id = ? AND status = 'issued' AND due_date < CURDATE()"
|
|
||||||
)->execute([$id]);
|
|
||||||
|
|
||||||
$stmt = $pdo->prepare('
|
$stmt = $pdo->prepare('
|
||||||
SELECT i.*, c.name as customer_name, o.order_number
|
SELECT i.id, i.invoice_number, i.order_id, i.customer_id, i.status,
|
||||||
|
i.currency, i.vat_rate, i.apply_vat, i.payment_method,
|
||||||
|
i.constant_symbol, i.bank_name, i.bank_swift, i.bank_iban,
|
||||||
|
i.bank_account, i.issue_date, i.due_date, i.tax_date,
|
||||||
|
i.paid_date, i.issued_by, i.notes, i.internal_notes,
|
||||||
|
i.created_at, i.modified_at,
|
||||||
|
c.name as customer_name, o.order_number
|
||||||
FROM invoices i
|
FROM invoices i
|
||||||
LEFT JOIN customers c ON i.customer_id = c.id
|
LEFT JOIN customers c ON i.customer_id = c.id
|
||||||
LEFT JOIN orders o ON i.order_id = o.id
|
LEFT JOIN orders o ON i.order_id = o.id
|
||||||
@@ -273,7 +268,10 @@ function handleGetDetail(PDO $pdo, int $id): void
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Polozky
|
// Polozky
|
||||||
$stmt = $pdo->prepare('SELECT * FROM invoice_items WHERE invoice_id = ? ORDER BY position');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, invoice_id, description, quantity, unit, unit_price, vat_rate, position
|
||||||
|
FROM invoice_items WHERE invoice_id = ? ORDER BY position'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$invoice['items'] = $stmt->fetchAll();
|
$invoice['items'] = $stmt->fetchAll();
|
||||||
|
|
||||||
@@ -317,7 +315,11 @@ function handleGetOrderData(PDO $pdo, int $id): void
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Polozky objednavky
|
// Polozky objednavky
|
||||||
$stmt = $pdo->prepare('SELECT * FROM order_items WHERE order_id = ? ORDER BY position');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, order_id, description, item_description, quantity, unit,
|
||||||
|
unit_price, is_included_in_total, position
|
||||||
|
FROM order_items WHERE order_id = ? ORDER BY position'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$order['items'] = $stmt->fetchAll();
|
$order['items'] = $stmt->fetchAll();
|
||||||
|
|
||||||
@@ -506,7 +508,14 @@ function handleCreateInvoice(PDO $pdo, array $authData): void
|
|||||||
|
|
||||||
function handleUpdateInvoice(PDO $pdo, int $id): void
|
function handleUpdateInvoice(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM invoices WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, invoice_number, order_id, customer_id, status, currency,
|
||||||
|
vat_rate, apply_vat, payment_method, constant_symbol,
|
||||||
|
bank_name, bank_swift, bank_iban, bank_account,
|
||||||
|
issue_date, due_date, tax_date, paid_date,
|
||||||
|
issued_by, notes, internal_notes
|
||||||
|
FROM invoices WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$invoice = $stmt->fetch();
|
$invoice = $stmt->fetch();
|
||||||
|
|
||||||
@@ -657,7 +666,9 @@ function handleUpdateInvoice(PDO $pdo, int $id): void
|
|||||||
|
|
||||||
function handleDeleteInvoice(PDO $pdo, int $id): void
|
function handleDeleteInvoice(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM invoices WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, invoice_number, customer_id FROM invoices WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$invoice = $stmt->fetch();
|
$invoice = $stmt->fetch();
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,10 @@ function getLeaveBalanceForRequest(PDO $pdo, int $userId, ?int $year = null): ar
|
|||||||
{
|
{
|
||||||
$year = $year ?: (int)date('Y');
|
$year = $year ?: (int)date('Y');
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM leave_balances WHERE user_id = ? AND year = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, user_id, year, vacation_total, vacation_used, sick_used
|
||||||
|
FROM leave_balances WHERE user_id = ? AND year = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$userId, $year]);
|
$stmt->execute([$userId, $year]);
|
||||||
$balance = $stmt->fetch();
|
$balance = $stmt->fetch();
|
||||||
|
|
||||||
@@ -77,7 +80,9 @@ function getPendingVacationHours(PDO $pdo, int $userId, int $year): float
|
|||||||
function handleGetMyRequests(PDO $pdo, int $userId): void
|
function handleGetMyRequests(PDO $pdo, int $userId): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
SELECT lr.*,
|
SELECT lr.id, lr.user_id, lr.leave_type, lr.date_from, lr.date_to,
|
||||||
|
lr.total_hours, lr.total_days, lr.notes, lr.status,
|
||||||
|
lr.reviewer_id, lr.reviewer_note, lr.reviewed_at, lr.created_at,
|
||||||
CONCAT(u.first_name, ' ', u.last_name) as reviewer_name
|
CONCAT(u.first_name, ' ', u.last_name) as reviewer_name
|
||||||
FROM leave_requests lr
|
FROM leave_requests lr
|
||||||
LEFT JOIN users u ON lr.reviewer_id = u.id
|
LEFT JOIN users u ON lr.reviewer_id = u.id
|
||||||
@@ -96,7 +101,9 @@ function handleGetMyRequests(PDO $pdo, int $userId): void
|
|||||||
function handleGetPending(PDO $pdo): void
|
function handleGetPending(PDO $pdo): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
SELECT lr.*,
|
SELECT lr.id, lr.user_id, lr.leave_type, lr.date_from, lr.date_to,
|
||||||
|
lr.total_hours, lr.total_days, lr.notes, lr.status,
|
||||||
|
lr.reviewer_id, lr.reviewer_note, lr.reviewed_at, lr.created_at,
|
||||||
CONCAT(u.first_name, ' ', u.last_name) as employee_name,
|
CONCAT(u.first_name, ' ', u.last_name) as employee_name,
|
||||||
CONCAT(rv.first_name, ' ', rv.last_name) as reviewer_name
|
CONCAT(rv.first_name, ' ', rv.last_name) as reviewer_name
|
||||||
FROM leave_requests lr
|
FROM leave_requests lr
|
||||||
@@ -138,7 +145,9 @@ function handleGetAll(PDO $pdo): void
|
|||||||
$whereClause = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
$whereClause = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||||||
|
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
SELECT lr.*,
|
SELECT lr.id, lr.user_id, lr.leave_type, lr.date_from, lr.date_to,
|
||||||
|
lr.total_hours, lr.total_days, lr.notes, lr.status,
|
||||||
|
lr.reviewer_id, lr.reviewer_note, lr.reviewed_at, lr.created_at,
|
||||||
CONCAT(u.first_name, ' ', u.last_name) as employee_name,
|
CONCAT(u.first_name, ' ', u.last_name) as employee_name,
|
||||||
CONCAT(rv.first_name, ' ', rv.last_name) as reviewer_name
|
CONCAT(rv.first_name, ' ', rv.last_name) as reviewer_name
|
||||||
FROM leave_requests lr
|
FROM leave_requests lr
|
||||||
@@ -270,7 +279,11 @@ function handleCancelRequest(PDO $pdo, int $userId): void
|
|||||||
errorResponse('ID žádosti je povinné');
|
errorResponse('ID žádosti je povinné');
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM leave_requests WHERE id = ? AND user_id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, user_id, leave_type, date_from, date_to, total_hours,
|
||||||
|
total_days, notes, status
|
||||||
|
FROM leave_requests WHERE id = ? AND user_id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$requestId, $userId]);
|
$stmt->execute([$requestId, $userId]);
|
||||||
$request = $stmt->fetch();
|
$request = $stmt->fetch();
|
||||||
|
|
||||||
@@ -310,7 +323,11 @@ function handleApproveRequest(PDO $pdo, int $reviewerId, array $authData): void
|
|||||||
errorResponse('ID žádosti je povinné');
|
errorResponse('ID žádosti je povinné');
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM leave_requests WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, user_id, leave_type, date_from, date_to, total_hours,
|
||||||
|
total_days, status
|
||||||
|
FROM leave_requests WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$requestId]);
|
$stmt->execute([$requestId]);
|
||||||
$request = $stmt->fetch();
|
$request = $stmt->fetch();
|
||||||
|
|
||||||
@@ -427,7 +444,9 @@ function handleRejectRequest(PDO $pdo, int $reviewerId, array $authData): void
|
|||||||
errorResponse('Důvod zamítnutí je povinný');
|
errorResponse('Důvod zamítnutí je povinný');
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM leave_requests WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, user_id, status FROM leave_requests WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$requestId]);
|
$stmt->execute([$requestId]);
|
||||||
$request = $stmt->fetch();
|
$request = $stmt->fetch();
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,11 @@ function handleGetList(PDO $pdo): void
|
|||||||
function handleGetDetail(PDO $pdo, int $id): void
|
function handleGetDetail(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('
|
$stmt = $pdo->prepare('
|
||||||
SELECT q.*, c.name as customer_name
|
SELECT q.id, q.quotation_number, q.project_code, q.customer_id,
|
||||||
|
q.created_at, q.valid_until, q.currency, q.language,
|
||||||
|
q.vat_rate, q.apply_vat, q.exchange_rate, q.order_id,
|
||||||
|
q.status, q.scope_title, q.scope_description,
|
||||||
|
c.name as customer_name
|
||||||
FROM quotations q
|
FROM quotations q
|
||||||
LEFT JOIN customers c ON q.customer_id = c.id
|
LEFT JOIN customers c ON q.customer_id = c.id
|
||||||
WHERE q.id = ?
|
WHERE q.id = ?
|
||||||
@@ -68,7 +72,9 @@ function handleGetDetail(PDO $pdo, int $id): void
|
|||||||
|
|
||||||
// Get items
|
// Get items
|
||||||
$stmt = $pdo->prepare('
|
$stmt = $pdo->prepare('
|
||||||
SELECT * FROM quotation_items
|
SELECT id, quotation_id, position, description, item_description,
|
||||||
|
quantity, unit, unit_price, is_included_in_total
|
||||||
|
FROM quotation_items
|
||||||
WHERE quotation_id = ?
|
WHERE quotation_id = ?
|
||||||
ORDER BY position
|
ORDER BY position
|
||||||
');
|
');
|
||||||
@@ -77,7 +83,8 @@ function handleGetDetail(PDO $pdo, int $id): void
|
|||||||
|
|
||||||
// Get scope sections
|
// Get scope sections
|
||||||
$stmt = $pdo->prepare('
|
$stmt = $pdo->prepare('
|
||||||
SELECT * FROM scope_sections
|
SELECT id, quotation_id, position, title, title_cz, content
|
||||||
|
FROM scope_sections
|
||||||
WHERE quotation_id = ?
|
WHERE quotation_id = ?
|
||||||
ORDER BY position
|
ORDER BY position
|
||||||
');
|
');
|
||||||
@@ -264,7 +271,12 @@ function handleCreateOffer(PDO $pdo): void
|
|||||||
|
|
||||||
function handleUpdateOffer(PDO $pdo, int $id): void
|
function handleUpdateOffer(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM quotations WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, quotation_number, project_code, customer_id, created_at,
|
||||||
|
valid_until, currency, language, vat_rate, apply_vat,
|
||||||
|
exchange_rate, order_id, status, scope_title, scope_description
|
||||||
|
FROM quotations WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$existing = $stmt->fetch();
|
$existing = $stmt->fetch();
|
||||||
|
|
||||||
@@ -349,7 +361,12 @@ function handleUpdateOffer(PDO $pdo, int $id): void
|
|||||||
|
|
||||||
function handleDuplicate(PDO $pdo, int $sourceId): void
|
function handleDuplicate(PDO $pdo, int $sourceId): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM quotations WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, quotation_number, project_code, customer_id, currency,
|
||||||
|
language, vat_rate, apply_vat, exchange_rate,
|
||||||
|
scope_title, scope_description
|
||||||
|
FROM quotations WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$sourceId]);
|
$stmt->execute([$sourceId]);
|
||||||
$source = $stmt->fetch();
|
$source = $stmt->fetch();
|
||||||
|
|
||||||
@@ -357,11 +374,18 @@ function handleDuplicate(PDO $pdo, int $sourceId): void
|
|||||||
errorResponse('Zdrojová nabídka nebyla nalezena', 404);
|
errorResponse('Zdrojová nabídka nebyla nalezena', 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM quotation_items WHERE quotation_id = ? ORDER BY position');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT description, item_description, quantity, unit, unit_price,
|
||||||
|
is_included_in_total, position
|
||||||
|
FROM quotation_items WHERE quotation_id = ? ORDER BY position'
|
||||||
|
);
|
||||||
$stmt->execute([$sourceId]);
|
$stmt->execute([$sourceId]);
|
||||||
$sourceItems = $stmt->fetchAll();
|
$sourceItems = $stmt->fetchAll();
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM scope_sections WHERE quotation_id = ? ORDER BY position');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT title, title_cz, content, position
|
||||||
|
FROM scope_sections WHERE quotation_id = ? ORDER BY position'
|
||||||
|
);
|
||||||
$stmt->execute([$sourceId]);
|
$stmt->execute([$sourceId]);
|
||||||
$sourceSections = $stmt->fetchAll();
|
$sourceSections = $stmt->fetchAll();
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
function handleGetItemTemplates(PDO $pdo): void
|
function handleGetItemTemplates(PDO $pdo): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->query('SELECT * FROM item_templates ORDER BY category, name');
|
$stmt = $pdo->query(
|
||||||
|
'SELECT id, name, description, default_price, category
|
||||||
|
FROM item_templates ORDER BY category, name'
|
||||||
|
);
|
||||||
successResponse(['templates' => $stmt->fetchAll()]);
|
successResponse(['templates' => $stmt->fetchAll()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,13 +103,17 @@ function handleDeleteItemTemplate(PDO $pdo, int $id): void
|
|||||||
|
|
||||||
function handleGetScopeTemplates(PDO $pdo): void
|
function handleGetScopeTemplates(PDO $pdo): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->query('SELECT * FROM scope_templates ORDER BY name');
|
$stmt = $pdo->query(
|
||||||
|
'SELECT id, name, title, description FROM scope_templates ORDER BY name'
|
||||||
|
);
|
||||||
successResponse(['templates' => $stmt->fetchAll()]);
|
successResponse(['templates' => $stmt->fetchAll()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleGetScopeDetail(PDO $pdo, int $id): void
|
function handleGetScopeDetail(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM scope_templates WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, name, title, description FROM scope_templates WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$template = $stmt->fetch();
|
$template = $stmt->fetch();
|
||||||
|
|
||||||
@@ -114,7 +121,10 @@ function handleGetScopeDetail(PDO $pdo, int $id): void
|
|||||||
errorResponse('Šablona nebyla nalezena', 404);
|
errorResponse('Šablona nebyla nalezena', 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM scope_template_sections WHERE scope_template_id = ? ORDER BY position');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, scope_template_id, position, title, title_cz, content
|
||||||
|
FROM scope_template_sections WHERE scope_template_id = ? ORDER BY position'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$template['sections'] = $stmt->fetchAll();
|
$template['sections'] = $stmt->fetchAll();
|
||||||
|
|
||||||
|
|||||||
@@ -96,12 +96,19 @@ function handleGetDetail(PDO $pdo, int $id): void
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get items
|
// Get items
|
||||||
$stmt = $pdo->prepare('SELECT * FROM order_items WHERE order_id = ? ORDER BY position');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, order_id, description, item_description, quantity, unit,
|
||||||
|
unit_price, is_included_in_total, position
|
||||||
|
FROM order_items WHERE order_id = ? ORDER BY position'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$order['items'] = $stmt->fetchAll();
|
$order['items'] = $stmt->fetchAll();
|
||||||
|
|
||||||
// Get sections
|
// Get sections
|
||||||
$stmt = $pdo->prepare('SELECT * FROM order_sections WHERE order_id = ? ORDER BY position');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, order_id, title, title_cz, content, position
|
||||||
|
FROM order_sections WHERE order_id = ? ORDER BY position'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$order['sections'] = $stmt->fetchAll();
|
$order['sections'] = $stmt->fetchAll();
|
||||||
|
|
||||||
@@ -202,7 +209,12 @@ function handleCreateOrder(PDO $pdo): void
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify quotation exists and has no order yet
|
// Verify quotation exists and has no order yet
|
||||||
$stmt = $pdo->prepare('SELECT * FROM quotations WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, quotation_number, project_code, customer_id, currency,
|
||||||
|
language, vat_rate, apply_vat, exchange_rate, order_id,
|
||||||
|
scope_title, scope_description
|
||||||
|
FROM quotations WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$quotationId]);
|
$stmt->execute([$quotationId]);
|
||||||
$quotation = $stmt->fetch();
|
$quotation = $stmt->fetch();
|
||||||
|
|
||||||
@@ -215,11 +227,18 @@ function handleCreateOrder(PDO $pdo): void
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get quotation items and sections
|
// Get quotation items and sections
|
||||||
$stmt = $pdo->prepare('SELECT * FROM quotation_items WHERE quotation_id = ? ORDER BY position');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT description, item_description, quantity, unit,
|
||||||
|
unit_price, is_included_in_total, position
|
||||||
|
FROM quotation_items WHERE quotation_id = ? ORDER BY position'
|
||||||
|
);
|
||||||
$stmt->execute([$quotationId]);
|
$stmt->execute([$quotationId]);
|
||||||
$quotationItems = $stmt->fetchAll();
|
$quotationItems = $stmt->fetchAll();
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM scope_sections WHERE quotation_id = ? ORDER BY position');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT title, title_cz, content, position
|
||||||
|
FROM scope_sections WHERE quotation_id = ? ORDER BY position'
|
||||||
|
);
|
||||||
$stmt->execute([$quotationId]);
|
$stmt->execute([$quotationId]);
|
||||||
$quotationSections = $stmt->fetchAll();
|
$quotationSections = $stmt->fetchAll();
|
||||||
|
|
||||||
@@ -354,7 +373,9 @@ function handleCreateOrder(PDO $pdo): void
|
|||||||
|
|
||||||
function handleUpdateOrder(PDO $pdo, int $id): void
|
function handleUpdateOrder(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM orders WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, order_number, status, notes FROM orders WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$order = $stmt->fetch();
|
$order = $stmt->fetch();
|
||||||
|
|
||||||
@@ -461,7 +482,9 @@ function handleUpdateOrder(PDO $pdo, int $id): void
|
|||||||
|
|
||||||
function handleDeleteOrder(PDO $pdo, int $id): void
|
function handleDeleteOrder(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM orders WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, order_number, quotation_id FROM orders WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$order = $stmt->fetch();
|
$order = $stmt->fetch();
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,9 @@ function handleCreateProject(PDO $pdo): void
|
|||||||
|
|
||||||
function handleDeleteProject(PDO $pdo, int $id): void
|
function handleDeleteProject(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM projects WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, project_number, name, order_id, status FROM projects WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$project = $stmt->fetch();
|
$project = $stmt->fetch();
|
||||||
|
|
||||||
@@ -207,7 +209,10 @@ function handleGetList(PDO $pdo): void
|
|||||||
function handleGetDetail(PDO $pdo, int $id): void
|
function handleGetDetail(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('
|
$stmt = $pdo->prepare('
|
||||||
SELECT p.*,
|
SELECT p.id, p.project_number, p.name, p.customer_id,
|
||||||
|
p.quotation_id, p.order_id, p.status,
|
||||||
|
p.start_date, p.end_date, p.notes,
|
||||||
|
p.created_at, p.modified_at,
|
||||||
c.name as customer_name,
|
c.name as customer_name,
|
||||||
o.order_number, o.status as order_status,
|
o.order_number, o.status as order_status,
|
||||||
q.quotation_number
|
q.quotation_number
|
||||||
@@ -229,7 +234,10 @@ function handleGetDetail(PDO $pdo, int $id): void
|
|||||||
|
|
||||||
function handleUpdateProject(PDO $pdo, int $id): void
|
function handleUpdateProject(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM projects WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, project_number, name, status, start_date, end_date, notes
|
||||||
|
FROM projects WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$project = $stmt->fetch();
|
$project = $stmt->fetch();
|
||||||
|
|
||||||
|
|||||||
@@ -358,7 +358,12 @@ function handleBulkUpload(PDO $pdo, array $authData): void
|
|||||||
|
|
||||||
function handleUpdateReceivedInvoice(PDO $pdo, int $id): void
|
function handleUpdateReceivedInvoice(PDO $pdo, int $id): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM received_invoices WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, supplier_name, invoice_number, description,
|
||||||
|
amount, currency, vat_rate, vat_amount,
|
||||||
|
issue_date, due_date, paid_date, status, notes
|
||||||
|
FROM received_invoices WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$invoice = $stmt->fetch();
|
$invoice = $stmt->fetch();
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ function handleGetRole(PDO $pdo): void
|
|||||||
{
|
{
|
||||||
// Get all roles with user count (LEFT JOIN instead of correlated subquery)
|
// Get all roles with user count (LEFT JOIN instead of correlated subquery)
|
||||||
$stmt = $pdo->query('
|
$stmt = $pdo->query('
|
||||||
SELECT r.*, COUNT(u.id) as user_count
|
SELECT r.id, r.name, r.display_name, r.description, r.created_at,
|
||||||
|
COUNT(u.id) as user_count
|
||||||
FROM roles r
|
FROM roles r
|
||||||
LEFT JOIN users u ON u.role_id = r.id
|
LEFT JOIN users u ON u.role_id = r.id
|
||||||
GROUP BY r.id
|
GROUP BY r.id
|
||||||
@@ -133,7 +134,9 @@ function handleCreateRole(PDO $pdo): void
|
|||||||
function handleUpdateRole(PDO $pdo, int $roleId): void
|
function handleUpdateRole(PDO $pdo, int $roleId): void
|
||||||
{
|
{
|
||||||
// Get existing role
|
// Get existing role
|
||||||
$stmt = $pdo->prepare('SELECT * FROM roles WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, name, display_name, description FROM roles WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$roleId]);
|
$stmt->execute([$roleId]);
|
||||||
$role = $stmt->fetch();
|
$role = $stmt->fetch();
|
||||||
|
|
||||||
@@ -205,7 +208,9 @@ function handleUpdateRole(PDO $pdo, int $roleId): void
|
|||||||
*/
|
*/
|
||||||
function handleDeleteRole(PDO $pdo, int $roleId): void
|
function handleDeleteRole(PDO $pdo, int $roleId): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM roles WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, name, display_name, description FROM roles WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$roleId]);
|
$stmt->execute([$roleId]);
|
||||||
$role = $stmt->fetch();
|
$role = $stmt->fetch();
|
||||||
|
|
||||||
|
|||||||
@@ -181,7 +181,9 @@ function handleVerify(PDO $pdo, TwoFactorAuth $tfa): void
|
|||||||
$userId = $tokenData['user_id'];
|
$userId = $tokenData['user_id'];
|
||||||
|
|
||||||
$stmt = $pdo->prepare('
|
$stmt = $pdo->prepare('
|
||||||
SELECT u.*, r.name as role_name, r.display_name as role_display_name
|
SELECT u.id, u.username, u.email, u.first_name, u.last_name,
|
||||||
|
u.role_id, u.is_active, u.totp_secret, u.totp_enabled,
|
||||||
|
r.name as role_name, r.display_name as role_display_name
|
||||||
FROM users u
|
FROM users u
|
||||||
LEFT JOIN roles r ON u.role_id = r.id
|
LEFT JOIN roles r ON u.role_id = r.id
|
||||||
WHERE u.id = ? AND u.totp_enabled = 1
|
WHERE u.id = ? AND u.totp_enabled = 1
|
||||||
@@ -230,7 +232,9 @@ function handleBackupVerify(PDO $pdo): void
|
|||||||
$userId = $tokenData['user_id'];
|
$userId = $tokenData['user_id'];
|
||||||
|
|
||||||
$stmt = $pdo->prepare('
|
$stmt = $pdo->prepare('
|
||||||
SELECT u.*, r.name as role_name, r.display_name as role_display_name
|
SELECT u.id, u.username, u.email, u.first_name, u.last_name,
|
||||||
|
u.role_id, u.is_active, u.totp_enabled, u.totp_backup_codes,
|
||||||
|
r.name as role_name, r.display_name as role_display_name
|
||||||
FROM users u
|
FROM users u
|
||||||
LEFT JOIN roles r ON u.role_id = r.id
|
LEFT JOIN roles r ON u.role_id = r.id
|
||||||
WHERE u.id = ? AND u.totp_enabled = 1
|
WHERE u.id = ? AND u.totp_enabled = 1
|
||||||
@@ -355,7 +359,8 @@ function verifyLoginToken(PDO $pdo, string $token): ?array
|
|||||||
$hashedToken = hash('sha256', $token);
|
$hashedToken = hash('sha256', $token);
|
||||||
|
|
||||||
$stmt = $pdo->prepare('
|
$stmt = $pdo->prepare('
|
||||||
SELECT * FROM totp_login_tokens
|
SELECT id, user_id, token_hash, expires_at, created_at
|
||||||
|
FROM totp_login_tokens
|
||||||
WHERE token_hash = ? AND expires_at > NOW()
|
WHERE token_hash = ? AND expires_at > NOW()
|
||||||
');
|
');
|
||||||
$stmt->execute([$hashedToken]);
|
$stmt->execute([$hashedToken]);
|
||||||
|
|||||||
@@ -37,7 +37,10 @@ function handleGetCurrent(PDO $pdo, int $userId): void
|
|||||||
$endDate = date('Y-m-t', strtotime($startDate));
|
$endDate = date('Y-m-t', strtotime($startDate));
|
||||||
|
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT t.*, v.spz, v.name as vehicle_name, v.brand, v.model,
|
SELECT t.id, t.vehicle_id, t.user_id, t.trip_date, t.start_km,
|
||||||
|
t.end_km, t.distance, t.route_from, t.route_to,
|
||||||
|
t.is_business, t.notes, t.created_at,
|
||||||
|
v.spz, v.name as vehicle_name, v.brand, v.model,
|
||||||
CONCAT(u.first_name, ' ', u.last_name) as driver_name
|
CONCAT(u.first_name, ' ', u.last_name) as driver_name
|
||||||
FROM trips t
|
FROM trips t
|
||||||
JOIN vehicles v ON t.vehicle_id = v.id
|
JOIN vehicles v ON t.vehicle_id = v.id
|
||||||
@@ -101,7 +104,10 @@ function handleGetHistory(PDO $pdo, int $userId): void
|
|||||||
$endDate = date('Y-m-t', strtotime($startDate));
|
$endDate = date('Y-m-t', strtotime($startDate));
|
||||||
|
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT t.*, v.spz, v.name as vehicle_name, v.brand, v.model,
|
SELECT t.id, t.vehicle_id, t.user_id, t.trip_date, t.start_km,
|
||||||
|
t.end_km, t.distance, t.route_from, t.route_to,
|
||||||
|
t.is_business, t.notes, t.created_at,
|
||||||
|
v.spz, v.name as vehicle_name, v.brand, v.model,
|
||||||
CONCAT(u.first_name, ' ', u.last_name) as driver_name
|
CONCAT(u.first_name, ' ', u.last_name) as driver_name
|
||||||
FROM trips t
|
FROM trips t
|
||||||
JOIN vehicles v ON t.vehicle_id = v.id
|
JOIN vehicles v ON t.vehicle_id = v.id
|
||||||
@@ -173,7 +179,10 @@ function handleGetAdmin(PDO $pdo): void
|
|||||||
}
|
}
|
||||||
|
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT t.*, v.spz, v.name as vehicle_name,
|
SELECT t.id, t.vehicle_id, t.user_id, t.trip_date, t.start_km,
|
||||||
|
t.end_km, t.distance, t.route_from, t.route_to,
|
||||||
|
t.is_business, t.notes, t.created_at,
|
||||||
|
v.spz, v.name as vehicle_name,
|
||||||
CONCAT(u.first_name, ' ', u.last_name) as driver_name
|
CONCAT(u.first_name, ' ', u.last_name) as driver_name
|
||||||
FROM trips t
|
FROM trips t
|
||||||
JOIN vehicles v ON t.vehicle_id = v.id
|
JOIN vehicles v ON t.vehicle_id = v.id
|
||||||
@@ -239,7 +248,10 @@ function handleGetAdmin(PDO $pdo): void
|
|||||||
function handleGetVehicles(PDO $pdo): void
|
function handleGetVehicles(PDO $pdo): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->query('
|
$stmt = $pdo->query('
|
||||||
SELECT v.*, COUNT(t.id) as trip_count,
|
SELECT v.id, v.spz, v.name, v.brand, v.model,
|
||||||
|
v.initial_km, v.actual_km, v.is_active,
|
||||||
|
v.created_at, v.updated_at,
|
||||||
|
COUNT(t.id) as trip_count,
|
||||||
COALESCE(MAX(t.end_km), v.initial_km) as current_km
|
COALESCE(MAX(t.end_km), v.initial_km) as current_km
|
||||||
FROM vehicles v
|
FROM vehicles v
|
||||||
LEFT JOIN trips t ON t.vehicle_id = v.id
|
LEFT JOIN trips t ON t.vehicle_id = v.id
|
||||||
@@ -415,7 +427,11 @@ function handleVehicle(PDO $pdo): void
|
|||||||
*/
|
*/
|
||||||
function handleUpdateTrip(PDO $pdo, int $id, int $userId, array $authData): void
|
function handleUpdateTrip(PDO $pdo, int $id, int $userId, array $authData): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM trips WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, vehicle_id, user_id, trip_date, start_km, end_km,
|
||||||
|
route_from, route_to, is_business, notes
|
||||||
|
FROM trips WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$trip = $stmt->fetch();
|
$trip = $stmt->fetch();
|
||||||
|
|
||||||
@@ -467,7 +483,11 @@ function handleUpdateTrip(PDO $pdo, int $id, int $userId, array $authData): void
|
|||||||
*/
|
*/
|
||||||
function handleDeleteTrip(PDO $pdo, int $id, int $userId, array $authData): void
|
function handleDeleteTrip(PDO $pdo, int $id, int $userId, array $authData): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM trips WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, vehicle_id, user_id, trip_date, start_km, end_km,
|
||||||
|
route_from, route_to, is_business, notes
|
||||||
|
FROM trips WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$trip = $stmt->fetch();
|
$trip = $stmt->fetch();
|
||||||
|
|
||||||
@@ -497,7 +517,9 @@ function handleDeleteVehicle(PDO $pdo, int $id): void
|
|||||||
errorResponse('ID je povinné');
|
errorResponse('ID je povinné');
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM vehicles WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, spz, name, brand, model, is_active FROM vehicles WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$vehicle = $stmt->fetch();
|
$vehicle = $stmt->fetch();
|
||||||
|
|
||||||
@@ -573,7 +595,10 @@ function handleGetPrint(PDO $pdo): void
|
|||||||
}
|
}
|
||||||
|
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT t.*, v.spz, v.name as vehicle_name, v.brand, v.model,
|
SELECT t.id, t.vehicle_id, t.user_id, t.trip_date, t.start_km,
|
||||||
|
t.end_km, t.distance, t.route_from, t.route_to,
|
||||||
|
t.is_business, t.notes, t.created_at,
|
||||||
|
v.spz, v.name as vehicle_name, v.brand, v.model,
|
||||||
CONCAT(u.first_name, ' ', u.last_name) as driver_name
|
CONCAT(u.first_name, ' ', u.last_name) as driver_name
|
||||||
FROM trips t
|
FROM trips t
|
||||||
JOIN vehicles v ON t.vehicle_id = v.id
|
JOIN vehicles v ON t.vehicle_id = v.id
|
||||||
|
|||||||
@@ -142,7 +142,11 @@ function handleCreateUser(PDO $pdo, array $authData): void
|
|||||||
function handleUpdateUser(PDO $pdo, int $userId, int $currentUserId, array $authData): void
|
function handleUpdateUser(PDO $pdo, int $userId, int $currentUserId, array $authData): void
|
||||||
{
|
{
|
||||||
// Get existing user
|
// Get existing user
|
||||||
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
|
$stmt = $pdo->prepare('
|
||||||
|
SELECT id, username, email, first_name, last_name, role_id, is_active,
|
||||||
|
last_login, created_at
|
||||||
|
FROM users WHERE id = ?
|
||||||
|
');
|
||||||
$stmt->execute([$userId]);
|
$stmt->execute([$userId]);
|
||||||
$existingUser = $stmt->fetch();
|
$existingUser = $stmt->fetch();
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,14 @@ $lang = in_array($_GET['lang'] ?? '', ['cs', 'en']) ? $_GET['lang'] : 'cs';
|
|||||||
try {
|
try {
|
||||||
$pdo = db();
|
$pdo = db();
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM invoices WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, invoice_number, order_id, customer_id, status, currency,
|
||||||
|
vat_rate, apply_vat, payment_method, constant_symbol,
|
||||||
|
bank_name, bank_swift, bank_iban, bank_account,
|
||||||
|
issue_date, due_date, tax_date, paid_date,
|
||||||
|
issued_by, notes
|
||||||
|
FROM invoices WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$invoice = $stmt->fetch();
|
$invoice = $stmt->fetch();
|
||||||
if (!$invoice) {
|
if (!$invoice) {
|
||||||
@@ -52,20 +59,32 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Polozky
|
// Polozky
|
||||||
$stmt = $pdo->prepare('SELECT * FROM invoice_items WHERE invoice_id = ? ORDER BY position');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, invoice_id, description, quantity, unit, unit_price, vat_rate, position
|
||||||
|
FROM invoice_items WHERE invoice_id = ? ORDER BY position'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$items = $stmt->fetchAll();
|
$items = $stmt->fetchAll();
|
||||||
|
|
||||||
// Zakaznik
|
// Zakaznik
|
||||||
$customer = null;
|
$customer = null;
|
||||||
if ($invoice['customer_id']) {
|
if ($invoice['customer_id']) {
|
||||||
$stmt = $pdo->prepare('SELECT * FROM customers WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, name, street, city, postal_code, country,
|
||||||
|
company_id, vat_id, custom_fields
|
||||||
|
FROM customers WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$invoice['customer_id']]);
|
$stmt->execute([$invoice['customer_id']]);
|
||||||
$customer = $stmt->fetch();
|
$customer = $stmt->fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Firemni udaje
|
// Firemni udaje
|
||||||
$stmt = $pdo->query('SELECT * FROM company_settings LIMIT 1');
|
$stmt = $pdo->query(
|
||||||
|
'SELECT id, company_name, company_id, vat_id, street, city,
|
||||||
|
postal_code, country, custom_fields, logo_data,
|
||||||
|
default_currency, default_vat_rate
|
||||||
|
FROM company_settings LIMIT 1'
|
||||||
|
);
|
||||||
$settings = $stmt->fetch();
|
$settings = $stmt->fetch();
|
||||||
|
|
||||||
// Logo
|
// Logo
|
||||||
|
|||||||
@@ -37,6 +37,11 @@ $id = isset($_GET['id']) ? (int) $_GET['id'] : null;
|
|||||||
try {
|
try {
|
||||||
$pdo = db();
|
$pdo = db();
|
||||||
|
|
||||||
|
// Overdue detekce - jednou pred dispatchem (misto v kazdem handleru)
|
||||||
|
if ($method === 'GET') {
|
||||||
|
$pdo->exec("UPDATE invoices SET status = 'overdue' WHERE status = 'issued' AND due_date < CURDATE()");
|
||||||
|
}
|
||||||
|
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
case 'GET':
|
case 'GET':
|
||||||
requirePermission($authData, 'invoices.view');
|
requirePermission($authData, 'invoices.view');
|
||||||
|
|||||||
@@ -38,7 +38,12 @@ if (!$id) {
|
|||||||
try {
|
try {
|
||||||
$pdo = db();
|
$pdo = db();
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM quotations WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, quotation_number, project_code, customer_id, created_at,
|
||||||
|
valid_until, currency, language, vat_rate, apply_vat,
|
||||||
|
exchange_rate, scope_title, scope_description
|
||||||
|
FROM quotations WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$quotation = $stmt->fetch();
|
$quotation = $stmt->fetch();
|
||||||
if (!$quotation) {
|
if (!$quotation) {
|
||||||
@@ -48,20 +53,36 @@ try {
|
|||||||
|
|
||||||
$customer = null;
|
$customer = null;
|
||||||
if ($quotation['customer_id']) {
|
if ($quotation['customer_id']) {
|
||||||
$stmt = $pdo->prepare('SELECT * FROM customers WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, name, street, city, postal_code, country,
|
||||||
|
company_id, vat_id, custom_fields
|
||||||
|
FROM customers WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$quotation['customer_id']]);
|
$stmt->execute([$quotation['customer_id']]);
|
||||||
$customer = $stmt->fetch();
|
$customer = $stmt->fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM quotation_items WHERE quotation_id = ? ORDER BY position');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, quotation_id, position, description, item_description,
|
||||||
|
quantity, unit, unit_price, is_included_in_total
|
||||||
|
FROM quotation_items WHERE quotation_id = ? ORDER BY position'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$items = $stmt->fetchAll();
|
$items = $stmt->fetchAll();
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM scope_sections WHERE quotation_id = ? ORDER BY position');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, quotation_id, position, title, title_cz, content
|
||||||
|
FROM scope_sections WHERE quotation_id = ? ORDER BY position'
|
||||||
|
);
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
$sections = $stmt->fetchAll();
|
$sections = $stmt->fetchAll();
|
||||||
|
|
||||||
$stmt = $pdo->query('SELECT * FROM company_settings LIMIT 1');
|
$stmt = $pdo->query(
|
||||||
|
'SELECT id, company_name, company_id, vat_id, street, city,
|
||||||
|
postal_code, country, custom_fields, logo_data,
|
||||||
|
quotation_prefix, default_currency, default_vat_rate
|
||||||
|
FROM company_settings LIMIT 1'
|
||||||
|
);
|
||||||
$settings = $stmt->fetch();
|
$settings = $stmt->fetch();
|
||||||
|
|
||||||
$logoBase64 = '';
|
$logoBase64 = '';
|
||||||
|
|||||||
@@ -35,7 +35,11 @@ try {
|
|||||||
$userId = $authData['user_id'];
|
$userId = $authData['user_id'];
|
||||||
|
|
||||||
// Get existing user
|
// Get existing user
|
||||||
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
|
$stmt = $pdo->prepare('
|
||||||
|
SELECT id, username, email, first_name, last_name, role_id, is_active,
|
||||||
|
last_login, created_at
|
||||||
|
FROM users WHERE id = ?
|
||||||
|
');
|
||||||
$stmt->execute([$userId]);
|
$stmt->execute([$userId]);
|
||||||
$existingUser = $stmt->fetch();
|
$existingUser = $stmt->fetch();
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,10 @@ function handleGetAdmin(PDO $pdo): void
|
|||||||
$endDate = date('Y-m-t', strtotime($startDate));
|
$endDate = date('Y-m-t', strtotime($startDate));
|
||||||
|
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT a.*, CONCAT(u.first_name, ' ', u.last_name) as user_name
|
SELECT a.id, a.user_id, a.shift_date, a.arrival_time, a.arrival_address,
|
||||||
|
a.break_start, a.break_end, a.departure_time, a.departure_address,
|
||||||
|
a.notes, a.project_id, a.leave_type, a.leave_hours, a.created_at,
|
||||||
|
CONCAT(u.first_name, ' ', u.last_name) as user_name
|
||||||
FROM attendance a
|
FROM attendance a
|
||||||
JOIN users u ON a.user_id = u.id
|
JOIN users u ON a.user_id = u.id
|
||||||
WHERE a.shift_date BETWEEN ? AND ?
|
WHERE a.shift_date BETWEEN ? AND ?
|
||||||
@@ -112,7 +115,11 @@ function handleGetWorkFund(PDO $pdo): void
|
|||||||
$startDate = sprintf('%04d-01-01', $year);
|
$startDate = sprintf('%04d-01-01', $year);
|
||||||
$endDate = sprintf('%04d-%02d-%02d', $year, $maxMonth, cal_days_in_month(CAL_GREGORIAN, $maxMonth, $year));
|
$endDate = sprintf('%04d-%02d-%02d', $year, $maxMonth, cal_days_in_month(CAL_GREGORIAN, $maxMonth, $year));
|
||||||
|
|
||||||
$stmt = $pdo->prepare('SELECT * FROM attendance WHERE shift_date BETWEEN ? AND ? ORDER BY shift_date');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, user_id, shift_date, arrival_time, break_start, break_end,
|
||||||
|
departure_time, notes, project_id, leave_type, leave_hours
|
||||||
|
FROM attendance WHERE shift_date BETWEEN ? AND ? ORDER BY shift_date'
|
||||||
|
);
|
||||||
$stmt->execute([$startDate, $endDate]);
|
$stmt->execute([$startDate, $endDate]);
|
||||||
$allRecords = $stmt->fetchAll();
|
$allRecords = $stmt->fetchAll();
|
||||||
|
|
||||||
@@ -206,7 +213,13 @@ function handleGetWorkFund(PDO $pdo): void
|
|||||||
function handleGetLocation(PDO $pdo, int $recordId): void
|
function handleGetLocation(PDO $pdo, int $recordId): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare("
|
$stmt = $pdo->prepare("
|
||||||
SELECT a.*, CONCAT(u.first_name, ' ', u.last_name) as user_name
|
SELECT a.id, a.user_id, a.shift_date, a.arrival_time,
|
||||||
|
a.arrival_lat, a.arrival_lng, a.arrival_accuracy, a.arrival_address,
|
||||||
|
a.break_start, a.break_end, a.departure_time,
|
||||||
|
a.departure_lat, a.departure_lng, a.departure_accuracy,
|
||||||
|
a.departure_address, a.notes, a.project_id,
|
||||||
|
a.leave_type, a.leave_hours, a.created_at,
|
||||||
|
CONCAT(u.first_name, ' ', u.last_name) as user_name
|
||||||
FROM attendance a
|
FROM attendance a
|
||||||
JOIN users u ON a.user_id = u.id
|
JOIN users u ON a.user_id = u.id
|
||||||
WHERE a.id = ?
|
WHERE a.id = ?
|
||||||
@@ -467,7 +480,11 @@ function handleUpdateBalance(PDO $pdo): void
|
|||||||
|
|
||||||
function handleUpdateAttendance(PDO $pdo, int $recordId): void
|
function handleUpdateAttendance(PDO $pdo, int $recordId): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM attendance WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, user_id, shift_date, arrival_time, break_start, break_end,
|
||||||
|
departure_time, notes, project_id, leave_type, leave_hours
|
||||||
|
FROM attendance WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$recordId]);
|
$stmt->execute([$recordId]);
|
||||||
$record = $stmt->fetch();
|
$record = $stmt->fetch();
|
||||||
|
|
||||||
@@ -593,7 +610,10 @@ function handleUpdateAttendance(PDO $pdo, int $recordId): void
|
|||||||
|
|
||||||
function handleDeleteAttendance(PDO $pdo, int $recordId): void
|
function handleDeleteAttendance(PDO $pdo, int $recordId): void
|
||||||
{
|
{
|
||||||
$stmt = $pdo->prepare('SELECT * FROM attendance WHERE id = ?');
|
$stmt = $pdo->prepare(
|
||||||
|
'SELECT id, user_id, shift_date, leave_type, leave_hours
|
||||||
|
FROM attendance WHERE id = ?'
|
||||||
|
);
|
||||||
$stmt->execute([$recordId]);
|
$stmt->execute([$recordId]);
|
||||||
$record = $stmt->fetch();
|
$record = $stmt->fetch();
|
||||||
|
|
||||||
@@ -920,7 +940,10 @@ function handleGetPrint(PDO $pdo): void
|
|||||||
$users = $stmt->fetchAll();
|
$users = $stmt->fetchAll();
|
||||||
|
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT a.*, CONCAT(u.first_name, ' ', u.last_name) as user_name
|
SELECT a.id, a.user_id, a.shift_date, a.arrival_time, a.arrival_address,
|
||||||
|
a.break_start, a.break_end, a.departure_time, a.departure_address,
|
||||||
|
a.notes, a.project_id, a.leave_type, a.leave_hours, a.created_at,
|
||||||
|
CONCAT(u.first_name, ' ', u.last_name) as user_name
|
||||||
FROM attendance a
|
FROM attendance a
|
||||||
JOIN users u ON a.user_id = u.id
|
JOIN users u ON a.user_id = u.id
|
||||||
WHERE a.shift_date BETWEEN ? AND ?
|
WHERE a.shift_date BETWEEN ? AND ?
|
||||||
|
|||||||
@@ -217,7 +217,9 @@ function enrichRecordsWithProjectLogs(PDO $pdo, array &$records): void
|
|||||||
if (!empty($recordIds)) {
|
if (!empty($recordIds)) {
|
||||||
$placeholders = implode(',', array_fill(0, count($recordIds), '?'));
|
$placeholders = implode(',', array_fill(0, count($recordIds), '?'));
|
||||||
$stmt = $pdo->prepare(
|
$stmt = $pdo->prepare(
|
||||||
"SELECT * FROM attendance_project_logs WHERE attendance_id IN ($placeholders) ORDER BY started_at ASC"
|
"SELECT id, attendance_id, project_id, started_at, ended_at, hours, minutes
|
||||||
|
FROM attendance_project_logs
|
||||||
|
WHERE attendance_id IN ($placeholders) ORDER BY started_at ASC"
|
||||||
);
|
);
|
||||||
$stmt->execute($recordIds);
|
$stmt->execute($recordIds);
|
||||||
foreach ($stmt->fetchAll() as $log) {
|
foreach ($stmt->fetchAll() as $log) {
|
||||||
|
|||||||
@@ -460,7 +460,9 @@ class AuditLog
|
|||||||
|
|
||||||
// Get logs
|
// Get logs
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT *
|
SELECT id, user_id, username, user_ip, action,
|
||||||
|
entity_type, entity_id, description,
|
||||||
|
old_values, new_values, created_at
|
||||||
FROM audit_logs
|
FROM audit_logs
|
||||||
$whereClause
|
$whereClause
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
@@ -503,7 +505,9 @@ class AuditLog
|
|||||||
$pdo = db();
|
$pdo = db();
|
||||||
|
|
||||||
$stmt = $pdo->prepare('
|
$stmt = $pdo->prepare('
|
||||||
SELECT *
|
SELECT id, user_id, username, user_ip, action,
|
||||||
|
entity_type, entity_id, description,
|
||||||
|
old_values, new_values, created_at
|
||||||
FROM audit_logs
|
FROM audit_logs
|
||||||
WHERE user_id = ?
|
WHERE user_id = ?
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
@@ -531,7 +535,9 @@ class AuditLog
|
|||||||
$pdo = db();
|
$pdo = db();
|
||||||
|
|
||||||
$stmt = $pdo->prepare('
|
$stmt = $pdo->prepare('
|
||||||
SELECT *
|
SELECT id, user_id, username, user_ip, action,
|
||||||
|
entity_type, entity_id, description,
|
||||||
|
old_values, new_values, created_at
|
||||||
FROM audit_logs
|
FROM audit_logs
|
||||||
WHERE entity_type = ? AND entity_id = ?
|
WHERE entity_type = ? AND entity_id = ?
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
|
|||||||
@@ -245,8 +245,11 @@ class JWTAuth
|
|||||||
|
|
||||||
// First check if token exists (regardless of expiry)
|
// First check if token exists (regardless of expiry)
|
||||||
$stmt = $pdo->prepare('
|
$stmt = $pdo->prepare('
|
||||||
SELECT rt.*, u.id as user_id, u.username, u.email, u.first_name, u.last_name,
|
SELECT rt.id, rt.user_id, rt.token_hash, rt.expires_at,
|
||||||
u.is_active, r.name as role_name, r.display_name as role_display_name
|
rt.replaced_at, rt.remember_me,
|
||||||
|
u.id as user_id, u.username, u.email,
|
||||||
|
u.first_name, u.last_name, u.is_active,
|
||||||
|
r.name as role_name, r.display_name as role_display_name
|
||||||
FROM refresh_tokens rt
|
FROM refresh_tokens rt
|
||||||
JOIN users u ON rt.user_id = u.id
|
JOIN users u ON rt.user_id = u.id
|
||||||
LEFT JOIN roles r ON u.role_id = r.id
|
LEFT JOIN roles r ON u.role_id = r.id
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class PaginationHelper
|
|||||||
/**
|
/**
|
||||||
* Nacte pagination parametry z GET requestu.
|
* Nacte pagination parametry z GET requestu.
|
||||||
*
|
*
|
||||||
|
* @param array<string, string> $sortMap
|
||||||
* @return array{page: int, per_page: int, sort: string, order: string, search: string}
|
* @return array{page: int, per_page: int, sort: string, order: string, search: string}
|
||||||
*/
|
*/
|
||||||
public static function parseParams(array $sortMap, string $defaultSort = 'created_at'): array
|
public static function parseParams(array $sortMap, string $defaultSort = 'created_at'): array
|
||||||
@@ -43,9 +44,10 @@ class PaginationHelper
|
|||||||
* @param PDO $pdo
|
* @param PDO $pdo
|
||||||
* @param string $countSql - COUNT(*) dotaz
|
* @param string $countSql - COUNT(*) dotaz
|
||||||
* @param string $dataSql - SELECT dotaz (bez LIMIT/OFFSET)
|
* @param string $dataSql - SELECT dotaz (bez LIMIT/OFFSET)
|
||||||
* @param array $params - parametry pro prepared statement
|
* @param array<int, mixed> $params - parametry pro prepared statement
|
||||||
* @param array{page: int, per_page: int, sort: string, order: string} $pagination
|
* @param array{page: int, per_page: int, sort: string, order: string} $pagination
|
||||||
* @return array{items: array, pagination: array}
|
* @return array{items: array<int, array<string, mixed>>,
|
||||||
|
* pagination: array{total: int, page: int, per_page: int, total_pages: int}}
|
||||||
*/
|
*/
|
||||||
public static function paginate(
|
public static function paginate(
|
||||||
PDO $pdo,
|
PDO $pdo,
|
||||||
|
|||||||
139
api/includes/Validator.php
Normal file
139
api/includes/Validator.php
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validacni helper pro API vstupy.
|
||||||
|
*
|
||||||
|
* Pouziti:
|
||||||
|
* $v = new Validator($input);
|
||||||
|
* $v->required('name')->string('name', 1, 255);
|
||||||
|
* $v->required('email')->email('email');
|
||||||
|
* $v->int('amount', 0, 1000000);
|
||||||
|
* $v->in('status', ['active', 'inactive']);
|
||||||
|
* if ($v->fails()) errorResponse($v->firstError());
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
class Validator
|
||||||
|
{
|
||||||
|
/** @var array<string, mixed> */
|
||||||
|
private array $data;
|
||||||
|
|
||||||
|
/** @var array<string, string> */
|
||||||
|
private array $errors = [];
|
||||||
|
|
||||||
|
/** @param array<string, mixed> $data */
|
||||||
|
public function __construct(array $data)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function required(string $field, string $label = ''): self
|
||||||
|
{
|
||||||
|
$value = $this->data[$field] ?? null;
|
||||||
|
if ($value === null || $value === '') {
|
||||||
|
$this->errors[$field] = ($label ?: $field) . ' je povinné pole';
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function string(string $field, int $min = 0, int $max = 0, string $label = ''): self
|
||||||
|
{
|
||||||
|
$value = $this->data[$field] ?? null;
|
||||||
|
if ($value === null || $value === '') {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
if (!is_string($value)) {
|
||||||
|
$this->errors[$field] = ($label ?: $field) . ' musí být text';
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
$len = mb_strlen($value);
|
||||||
|
if ($min > 0 && $len < $min) {
|
||||||
|
$this->errors[$field] = ($label ?: $field) . " musí mít alespoň {$min} znaků";
|
||||||
|
} elseif ($max > 0 && $len > $max) {
|
||||||
|
$this->errors[$field] = ($label ?: $field) . " nesmí překročit {$max} znaků";
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function int(string $field, ?int $min = null, ?int $max = null, string $label = ''): self
|
||||||
|
{
|
||||||
|
$value = $this->data[$field] ?? null;
|
||||||
|
if ($value === null || $value === '') {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
if (!is_numeric($value)) {
|
||||||
|
$this->errors[$field] = ($label ?: $field) . ' musí být číslo';
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
$intVal = (int) $value;
|
||||||
|
if ($min !== null && $intVal < $min) {
|
||||||
|
$this->errors[$field] = ($label ?: $field) . " musí být alespoň {$min}";
|
||||||
|
} elseif ($max !== null && $intVal > $max) {
|
||||||
|
$this->errors[$field] = ($label ?: $field) . " nesmí překročit {$max}";
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function email(string $field, string $label = ''): self
|
||||||
|
{
|
||||||
|
$value = $this->data[$field] ?? null;
|
||||||
|
if ($value === null || $value === '') {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
if (!is_string($value) || !filter_var($value, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$this->errors[$field] = ($label ?: $field) . ' musí být platný e-mail';
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param list<string> $allowed
|
||||||
|
*/
|
||||||
|
public function in(string $field, array $allowed, string $label = ''): self
|
||||||
|
{
|
||||||
|
$value = $this->data[$field] ?? null;
|
||||||
|
if ($value === null || $value === '') {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
if (!in_array($value, $allowed, true)) {
|
||||||
|
$this->errors[$field] = ($label ?: $field) . ' má neplatnou hodnotu';
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function numeric(string $field, ?float $min = null, ?float $max = null, string $label = ''): self
|
||||||
|
{
|
||||||
|
$value = $this->data[$field] ?? null;
|
||||||
|
if ($value === null || $value === '') {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
if (!is_numeric($value)) {
|
||||||
|
$this->errors[$field] = ($label ?: $field) . ' musí být číslo';
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
$numVal = (float) $value;
|
||||||
|
if ($min !== null && $numVal < $min) {
|
||||||
|
$this->errors[$field] = ($label ?: $field) . " musí být alespoň {$min}";
|
||||||
|
} elseif ($max !== null && $numVal > $max) {
|
||||||
|
$this->errors[$field] = ($label ?: $field) . " nesmí překročit {$max}";
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fails(): bool
|
||||||
|
{
|
||||||
|
return count($this->errors) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function firstError(): string
|
||||||
|
{
|
||||||
|
return reset($this->errors) ?: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return array<string, string> */
|
||||||
|
public function errors(): array
|
||||||
|
{
|
||||||
|
return $this->errors;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user