diff --git a/api/place_order.php b/api/place_order.php index d12316f..7a56c3d 100644 --- a/api/place_order.php +++ b/api/place_order.php @@ -23,7 +23,8 @@ if ($name === '' || $phone === '' || $address === '') { } $items = $input['items']; -$total = 0; +$subtotal = 0; +$totalVat = 0; // Recalculate total for security $db = db(); @@ -32,19 +33,28 @@ foreach ($items as $id => $item) { $qty = (int)$item['qty']; if ($qty <= 0) continue; - // get price from DB - $stmt = $db->prepare("SELECT sku, name, price FROM items WHERE id = ?"); + // get price and vat from DB + $stmt = $db->prepare("SELECT sku, name, price, vat FROM items WHERE id = ?"); $stmt->execute([$id]); $dbItem = $stmt->fetch(); if ($dbItem) { $price = (float)$dbItem['price']; - $total += ($price * $qty); + $vatPercent = (float)($dbItem['vat'] ?? 0); + $lineTotal = $price * $qty; + $itemVat = $lineTotal * ($vatPercent / 100); + + $subtotal += $lineTotal; + $totalVat += $itemVat; + $processedItems[] = [ 'id' => $id, 'sku' => $dbItem['sku'], 'name' => $dbItem['name'], 'price' => $price, - 'qty' => $qty + 'vat' => $vatPercent, + 'vat_amount' => $itemVat, + 'qty' => $qty, + 'line_total' => $lineTotal ]; } } @@ -54,24 +64,29 @@ if (empty($processedItems)) { exit; } +$totalAmount = $subtotal + $totalVat; + try { - $stmt = $db->prepare("INSERT INTO online_orders (customer_name, customer_phone, customer_address, items_json, total_amount) VALUES (?, ?, ?, ?, ?)"); + $stmt = $db->prepare("INSERT INTO online_orders (customer_name, customer_phone, customer_address, items_json, subtotal, vat_amount, total_amount) VALUES (?, ?, ?, ?, ?, ?, ?)"); $stmt->execute([ $name, $phone, $address, json_encode($processedItems, JSON_UNESCAPED_UNICODE), - $total + $subtotal, + $totalVat, + $totalAmount ]); // Optional: send telegram notification if configured try { - // require_once __DIR__ . '/telegram_webhook.php'; // wait, it might not be a function but a script. Let's just do simple notification $orderId = $db->lastInsertId(); $msg = "🛒 *New Online Order #{$orderId}*\n\n"; $msg .= "👤 {$name}\n📞 {$phone}\n📍 {$address}\n\n"; - $msg .= "💰 Total: " . currency($total) . "\n"; - // To send, we'd need to call telegram api directly if token is set. + $msg .= "💰 Subtotal: " . currency($subtotal) . "\n"; + $msg .= "🧾 VAT: " . currency($totalVat) . "\n"; + $msg .= "💵 Total: " . currency($totalAmount) . "\n"; + $botToken = getenv('TELEGRAM_BOT_TOKEN') ?: get_setting('telegram_bot_token'); $chatId = getenv('TELEGRAM_CHAT_ID') ?: get_setting('telegram_chat_id'); if ($botToken && $chatId) { @@ -93,5 +108,5 @@ try { echo json_encode(['success' => true]); } catch (Exception $e) { - echo json_encode(['success' => false, 'error' => 'Database error']); -} + echo json_encode(['success' => false, 'error' => 'Database error: ' . $e->getMessage()]); +} \ No newline at end of file diff --git a/api/settings.php b/api/settings.php index 0559f09..9cd53bf 100644 --- a/api/settings.php +++ b/api/settings.php @@ -13,7 +13,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $pdo = db(); $keys = [ 'company_name_ar', 'company_name_en', 'vat_percentage', - 'company_vat_number', 'company_phone', 'company_email', 'company_address' + 'company_vat_number', 'company_phone', 'company_email', 'company_address', + 'smtp_host', 'smtp_port', 'smtp_user', 'smtp_pass', 'smtp_secure', 'mail_from', 'mail_from_name' ]; $stmt = $pdo->prepare("INSERT INTO settings (setting_key, setting_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)"); diff --git a/edit_online_order.php b/edit_online_order.php new file mode 100644 index 0000000..b8c9aa1 --- /dev/null +++ b/edit_online_order.php @@ -0,0 +1,571 @@ + 0) { + $stmt = db()->prepare('SELECT * FROM online_orders WHERE id = :id'); + $stmt->execute([':id' => $editOrderId]); + $editOrder = $stmt->fetch(); +} +if (!$editOrder) { + die(tr('الطلب غير موجود.', 'Order not found.')); +} + +$pageTitle = tr('تعديل طلب', 'Edit Order') . ' #' . $editOrderId; +$activeNav = 'online_orders'; +$error = ''; +$catalog = catalog(); + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $customerName = trim((string) ($_POST['customer_name'] ?? '')); + $customerPhone = trim((string) ($_POST['customer_phone'] ?? '')); + $customerAddress = trim((string) ($_POST['customer_address'] ?? '')); + $saleStatus = trim((string) ($_POST['sale_status'] ?? 'pending')); + $cartJson = (string) ($_POST['cart_json'] ?? '[]'); + $items = json_decode($cartJson, true); + + if ($customerName === '' || $customerPhone === '' || $customerAddress === '') { + $error = tr('الرجاء تعبئة بيانات العميل الأساسية.', 'Please fill the main customer details.'); + } elseif (!is_array($items) || $items === []) { + $error = tr('أضف صنفاً واحداً على الأقل إلى الطلب.', 'Add at least one item to the order.'); + } else { + $normalized = []; + $subtotal = 0.0; + $totalVat = 0.0; + foreach ($items as $item) { + $sku = (string) ($item['sku'] ?? ''); + $qty = (int) ($item['qty'] ?? 0); + if (!isset($catalog[$sku]) || $qty < 1) { + continue; // if sku doesn't exist in catalog or qty invalid + } + $product = $catalog[$sku]; + $price = (float) $product['price']; + $lineTotal = $price * $qty; + + $vatPercent = (float) ($product['vat'] ?? 0); + $itemVat = $lineTotal * ($vatPercent / 100); + $totalVat += $itemVat; + + $normalized[] = [ + 'id' => $product['id'] ?? 0, + 'sku' => $sku, + 'name' => current_lang() === 'ar' ? $product['name_ar'] : $product['name_en'], + 'name_ar' => $product['name_ar'], + 'name_en' => $product['name_en'], + 'qty' => $qty, + 'price' => $price, + 'line_total' => $lineTotal, + 'vat_percent' => $vatPercent, + 'vat_amount' => $itemVat + ]; + $subtotal += $lineTotal; + } + + if ($normalized === []) { + $error = tr('الطلب غير صالح بعد التحقق من الأصناف.', 'The order is invalid after product validation.'); + } else { + $stmt = db()->prepare('UPDATE online_orders SET + customer_name = :customer_name, + customer_phone = :customer_phone, + customer_address = :customer_address, + items_json = :items_json, + subtotal = :subtotal, + vat_amount = :vat_amount, + total_amount = :total_amount, + status = :status + WHERE id = :id'); + $stmt->execute([ + ':customer_name' => $customerName, + ':customer_phone' => $customerPhone, + ':customer_address' => $customerAddress, + ':items_json' => json_encode($normalized, JSON_UNESCAPED_UNICODE), + ':subtotal' => $subtotal, + ':vat_amount' => $totalVat, + ':total_amount' => $subtotal + $totalVat, + ':status' => $saleStatus, + ':id' => $editOrderId, + ]); + + set_flash('success', tr('تم تحديث الطلب بنجاح.', 'Order updated successfully.')); + redirect_to('online_orders.php'); + } + } +} + +require __DIR__ . '/includes/header.php'; +?> + + + +
+
+

+ + + +
+ + +
+ + +
+ + +
+
+ +
+
+
+ +
+
+
+ + +
+ + +
+
+ + +
+ + + + + + + + + + + + + + + +
+ + +
+
+ +
+
+
+ +
+ +
+
+
+ +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + +
+
+ + 0.000 +
+
+ + 0.000 +
+
+ + 0.000 +
+
+ + +
+
+
+
+
+
+ + + + + diff --git a/expense_categories.php b/expense_categories.php new file mode 100644 index 0000000..8097ba9 --- /dev/null +++ b/expense_categories.php @@ -0,0 +1,222 @@ +prepare('INSERT INTO expense_categories (name_ar, name_en) VALUES (?, ?)'); + $stmt->execute([$_POST['name_ar'], $_POST['name_en']]); + set_flash('success', tr('تمت إضافة التصنيف بنجاح', 'Category added successfully')); + redirect_to('expense_categories.php'); + } elseif ($action === 'edit') { + $stmt = $pdo->prepare('UPDATE expense_categories SET name_ar = ?, name_en = ? WHERE id = ?'); + $stmt->execute([$_POST['name_ar'], $_POST['name_en'], $_POST['id']]); + set_flash('success', tr('تم التحديث بنجاح', 'Updated successfully')); + redirect_to('expense_categories.php'); + } elseif ($action === 'delete') { + // Check if there are expenses linked + $checkStmt = $pdo->prepare('SELECT COUNT(*) FROM expenses WHERE category_id = ?'); + $checkStmt->execute([$_POST['id']]); + if ($checkStmt->fetchColumn() > 0) { + set_flash('danger', tr('لا يمكن حذف التصنيف لأنه مرتبط بمصروفات.', 'Cannot delete category because it is linked to expenses.')); + } else { + $stmt = $pdo->prepare('DELETE FROM expense_categories WHERE id = ?'); + $stmt->execute([$_POST['id']]); + set_flash('success', tr('تم الحذف بنجاح', 'Deleted successfully')); + } + redirect_to('expense_categories.php'); + } +} + +// Pagination & Search +$page = max(1, (int)($_GET['p'] ?? 1)); +$limit = 10; +$offset = ($page - 1) * $limit; +$search = $_GET['q'] ?? ''; + +$where = '1=1'; +$params = []; +if ($search) { + $where .= ' AND (name_ar LIKE ? OR name_en LIKE ?)'; + $params[] = "%$search%"; + $params[] = "%$search%"; +} + +$totalStmt = $pdo->prepare("SELECT COUNT(*) FROM expense_categories WHERE $where"); +$totalStmt->execute($params); +$total = $totalStmt->fetchColumn(); +$totalPages = ceil($total / $limit); + +$queryStmt = $pdo->prepare("SELECT * FROM expense_categories WHERE $where ORDER BY id DESC LIMIT $limit OFFSET $offset"); +$queryStmt->execute($params); +$items = $queryStmt->fetchAll(); + +require __DIR__ . '/includes/header.php'; +?> + +
+
+
+

+

+
+ +
+ +
+
+ + +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + +
ID
+ + +
+
+ + 1): ?> + + +
+ + + + + + + + + + + + + diff --git a/expenses.php b/expenses.php new file mode 100644 index 0000000..be24b46 --- /dev/null +++ b/expenses.php @@ -0,0 +1,321 @@ +query("SELECT id, name_ar, name_en FROM expense_categories ORDER BY name_ar"); +$categories = $catStmt->fetchAll(); + +$branchesStmt = $pdo->query("SELECT code, name_ar, name_en FROM branches ORDER BY name_ar"); +$branches = $branchesStmt->fetchAll(); + +// Check if user is restricted to a branch +$userBranch = $user['branch_code'] ?? ''; +$isOwner = $user['role'] === 'owner'; + +// Handle Form Submission +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $action = $_POST['action'] ?? ''; + + if ($action === 'create' && has_permission('expenses', 'add')) { + $branch_code = $isOwner ? ($_POST['branch_code'] ?? null) : $userBranch; + $stmt = $pdo->prepare('INSERT INTO expenses (branch_code, category_id, amount, expense_date, description, created_by) VALUES (?, ?, ?, ?, ?, ?)'); + $stmt->execute([ + $branch_code === '' ? null : $branch_code, + $_POST['category_id'], + $_POST['amount'], + $_POST['expense_date'], + $_POST['description'] ?? '', + $user['id'] + ]); + set_flash('success', tr('تمت إضافة المصروف بنجاح', 'Expense added successfully')); + redirect_to('expenses.php'); + } elseif ($action === 'edit' && has_permission('expenses', 'edit')) { + $branch_code = $isOwner ? ($_POST['branch_code'] ?? null) : $userBranch; + $stmt = $pdo->prepare('UPDATE expenses SET branch_code = ?, category_id = ?, amount = ?, expense_date = ?, description = ? WHERE id = ?'); + $stmt->execute([ + $branch_code === '' ? null : $branch_code, + $_POST['category_id'], + $_POST['amount'], + $_POST['expense_date'], + $_POST['description'] ?? '', + $_POST['id'] + ]); + set_flash('success', tr('تم التحديث بنجاح', 'Updated successfully')); + redirect_to('expenses.php'); + } elseif ($action === 'delete' && has_permission('expenses', 'del')) { + $stmt = $pdo->prepare('DELETE FROM expenses WHERE id = ?'); + $stmt->execute([$_POST['id']]); + set_flash('success', tr('تم الحذف بنجاح', 'Deleted successfully')); + redirect_to('expenses.php'); + } +} + +// Pagination & Search +$page = max(1, (int)($_GET['p'] ?? 1)); +$limit = 10; +$offset = ($page - 1) * $limit; +$search = $_GET['q'] ?? ''; + +$where = '1=1'; +$params = []; +if ($search) { + $where .= ' AND (e.description LIKE ?)'; + $params[] = "%$search%"; +} + +if (!$isOwner && $userBranch) { + $where .= ' AND (e.branch_code = ? OR e.branch_code IS NULL)'; + $params[] = $userBranch; +} + +$totalStmt = $pdo->prepare("SELECT COUNT(*) FROM expenses e WHERE $where"); +$totalStmt->execute($params); +$total = $totalStmt->fetchColumn(); +$totalPages = ceil($total / $limit); + +$queryStmt = $pdo->prepare(" + SELECT e.*, + c.name_ar as category_ar, c.name_en as category_en, + b.name_ar as branch_ar, b.name_en as branch_en, + u.name_ar as user_ar, u.name_en as user_en + FROM expenses e + LEFT JOIN expense_categories c ON e.category_id = c.id + LEFT JOIN branches b ON e.branch_code = b.code + LEFT JOIN users u ON e.created_by = u.id + WHERE $where + ORDER BY e.expense_date DESC, e.id DESC + LIMIT $limit OFFSET $offset +"); +$queryStmt->execute($params); +$items = $queryStmt->fetchAll(); + +require __DIR__ . '/includes/header.php'; +?> + +
+
+
+

+

+
+ + + +
+ +
+
+ + +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
'.h(tr('عام', 'General')).'' ?> + + + + + + +
+
+ + 1): ?> + + +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/includes/app.php b/includes/app.php index 84a6e83..bb69dbf 100644 --- a/includes/app.php +++ b/includes/app.php @@ -180,7 +180,7 @@ function require_auth(): array return $user; } -function get_app_modules(): array { return ["pos" => ["name_ar" => "نقاط البيع", "name_en" => "POS", "actions" => ["show", "add"]], "normal_sale" => ["name_ar" => "بيع عادي", "name_en" => "Normal Sale", "actions" => ["show", "add"]], "sales" => ["name_ar" => "المبيعات", "name_en" => "Sales", "actions" => ["show", "edit", "del"]], "purchases" => ["name_ar" => "المشتريات", "name_en" => "Purchases", "actions" => ["show", "add", "edit", "del"]], "stock" => ["name_ar" => "المخزون", "name_en" => "Stock", "actions" => ["show", "add", "edit", "del"]], "reports" => ["name_ar" => "التقارير", "name_en" => "Reports", "actions" => ["show"]], "customers" => ["name_ar" => "العملاء", "name_en" => "Customers", "actions" => ["show", "add", "edit", "del"]], "suppliers" => ["name_ar" => "الموردين", "name_en" => "Suppliers", "actions" => ["show", "add", "edit", "del"]], "categories" => ["name_ar" => "التصنيفات", "name_en" => "Categories", "actions" => ["show", "add", "edit", "del"]], "units" => ["name_ar" => "الوحدات", "name_en" => "Units", "actions" => ["show", "add", "edit", "del"]], "users" => ["name_ar" => "المستخدمين", "name_en" => "Users", "actions" => ["show", "add", "edit", "del"]], "settings" => ["name_ar" => "الإعدادات", "name_en" => "Settings", "actions" => ["show", "edit"]]]; } function has_permission(string $m, string $a = "show"): bool { $u = current_user(); if (!$u) return false; if ($u["role"] === "owner") return true; $p = !empty($u["permissions"]) ? (is_array($u["permissions"]) ? $u["permissions"] : json_decode($u["permissions"], true)) : []; return !empty($p[$m][$a]); } function require_permission(string $m, string $a = "show"): array { $u = require_auth(); if (!has_permission($m, $a)) { set_flash("warning", tr("ليس لديك صلاحية.", "You do not have permission.")); redirect_to("index.php"); } return $u; } +function get_app_modules(): array { return ["pos" => ["name_ar" => "نقاط البيع", "name_en" => "POS", "actions" => ["show", "add"]], "normal_sale" => ["name_ar" => "بيع عادي", "name_en" => "Normal Sale", "actions" => ["show", "add"]], "sales" => ["name_ar" => "المبيعات", "name_en" => "Sales", "actions" => ["show", "edit", "del"]], "purchases" => ["name_ar" => "المشتريات", "name_en" => "Purchases", "actions" => ["show", "add", "edit", "del"]], "stock" => ["name_ar" => "المخزون", "name_en" => "Stock", "actions" => ["show", "add", "edit", "del"]], "reports" => ["name_ar" => "التقارير", "name_en" => "Reports", "actions" => ["show"]], "customers" => ["name_ar" => "العملاء", "name_en" => "Customers", "actions" => ["show", "add", "edit", "del"]], "suppliers" => ["name_ar" => "الموردين", "name_en" => "Suppliers", "actions" => ["show", "add", "edit", "del"]], "categories" => ["name_ar" => "التصنيفات", "name_en" => "Categories", "actions" => ["show", "add", "edit", "del"]], "units" => ["name_ar" => "الوحدات", "name_en" => "Units", "actions" => ["show", "add", "edit", "del"]], "users" => ["name_ar" => "المستخدمين", "name_en" => "Users", "actions" => ["show", "add", "edit", "del"]], "settings" => ["name_ar" => "الإعدادات", "name_en" => "Settings", "actions" => ["show", "edit"]], "expense_categories" => ["name_ar" => "تصنيفات المصروفات", "name_en" => "Expense Categories", "actions" => ["show", "add", "edit", "del"]], "expenses" => ["name_ar" => "المصروفات", "name_en" => "Expenses", "actions" => ["show", "add", "edit", "del"]]]; } function has_permission(string $m, string $a = "show"): bool { $u = current_user(); if (!$u) return false; if ($u["role"] === "owner") return true; $p = !empty($u["permissions"]) ? (is_array($u["permissions"]) ? $u["permissions"] : json_decode($u["permissions"], true)) : []; return !empty($p[$m][$a]); } function require_permission(string $m, string $a = "show"): array { $u = require_auth(); if (!has_permission($m, $a)) { set_flash("warning", tr("ليس لديك صلاحية.", "You do not have permission.")); redirect_to("index.php"); } return $u; } function require_roles(array $roles): array { $user = require_auth(); diff --git a/includes/footer_settings.php b/includes/footer_settings.php index 6652257..4b25295 100644 --- a/includes/footer_settings.php +++ b/includes/footer_settings.php @@ -52,6 +52,42 @@
+
+
+
+
+
+ + "> +
+
+ + "> +
+
+ + "> +
+
+ + "> +
+
+ + +
+
+ + "> +
+
+ + "> +
+ + + +
+ + +
+
+
+
+ + + + + + + + + + +
+
+ + diff --git a/mail/config.php b/mail/config.php index c3bdb73..f7c11d0 100644 --- a/mail/config.php +++ b/mail/config.php @@ -1,21 +1,48 @@ config array for MailService. +// Mail configuration sourced from DB settings with environment variables fallback. function env_val(string $key, $default = null) { $v = getenv($key); return ($v === false || $v === null || $v === '') ? $default : $v; } -$transport = env_val('MAIL_TRANSPORT', 'smtp'); -$smtp_host = env_val('SMTP_HOST'); -$smtp_port = (int) env_val('SMTP_PORT', 587); -$smtp_secure = env_val('SMTP_SECURE', 'tls'); // tls | ssl | null -$smtp_user = env_val('SMTP_USER'); -$smtp_pass = env_val('SMTP_PASS'); +$db_settings = []; +if (file_exists(__DIR__ . '/../db/config.php')) { + try { + require_once __DIR__ . '/../db/config.php'; + if (function_exists('db')) { + $pdo = db(); + if ($pdo) { + $stmt = $pdo->query("SELECT setting_key, setting_value FROM settings WHERE setting_key IN ('smtp_host', 'smtp_port', 'smtp_user', 'smtp_pass', 'smtp_secure', 'mail_from', 'mail_from_name')"); + while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { + $db_settings[$row['setting_key']] = $row['setting_value']; + } + } + } + } catch (\Throwable $e) { + // ignore DB errors during config loading + } +} -$from_email = env_val('MAIL_FROM', 'no-reply@localhost'); -$from_name = env_val('MAIL_FROM_NAME', 'App'); +// Function to get config value with fallback +function get_cfg($db_settings, $key, $env_key, $default = null, $allow_empty = false) { + if (isset($db_settings[$key])) { + if ($allow_empty || $db_settings[$key] !== '') { + return $db_settings[$key]; + } + } + return env_val($env_key, $default); +} + +$transport = env_val('MAIL_TRANSPORT', 'smtp'); +$smtp_host = get_cfg($db_settings, 'smtp_host', 'SMTP_HOST'); +$smtp_port = (int) get_cfg($db_settings, 'smtp_port', 'SMTP_PORT', 587); +$smtp_secure = get_cfg($db_settings, 'smtp_secure', 'SMTP_SECURE', 'tls', true); +$smtp_user = get_cfg($db_settings, 'smtp_user', 'SMTP_USER'); +$smtp_pass = get_cfg($db_settings, 'smtp_pass', 'SMTP_PASS', null, true); + +$from_email = get_cfg($db_settings, 'mail_from', 'MAIL_FROM', 'no-reply@localhost'); +$from_name = get_cfg($db_settings, 'mail_from_name', 'MAIL_FROM_NAME', 'App'); $reply_to = env_val('MAIL_REPLY_TO'); $dkim_domain = env_val('DKIM_DOMAIN'); diff --git a/online_orders.php b/online_orders.php index 498fd93..99481d5 100644 --- a/online_orders.php +++ b/online_orders.php @@ -15,21 +15,79 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { $stmt->execute([$status, $id]); set_flash('success', tr('تم تحديث حالة الطلب', 'Order status updated')); redirect_to('online_orders.php'); + } elseif ($_POST['action'] === 'delete') { + $id = (int)$_POST['id']; + $stmt = $db->prepare("DELETE FROM online_orders WHERE id = ?"); + $stmt->execute([$id]); + set_flash('success', tr('تم حذف الطلب بنجاح', 'Order deleted successfully')); + redirect_to('online_orders.php'); } + } -$stmt = $db->query("SELECT * FROM online_orders ORDER BY created_at DESC"); +$search = $_GET['search'] ?? ''; +$date_from = $_GET['date_from'] ?? date('Y-m-d', strtotime('-30 days')); +$date_to = $_GET['date_to'] ?? date('Y-m-d'); + +$query = "SELECT * FROM online_orders WHERE DATE(created_at) >= ? AND DATE(created_at) <= ?"; +$params = [$date_from, $date_to]; + +if ($search !== '') { + $query .= " AND (customer_name LIKE ? OR customer_phone LIKE ?)"; + $params[] = "%$search%"; + $params[] = "%$search%"; +} + +$query .= " ORDER BY created_at DESC"; +$stmt = $db->prepare($query); +$stmt->execute($params); $orders = $stmt->fetchAll(PDO::FETCH_ASSOC); require __DIR__ . '/includes/header.php'; ?> -
+ + +

+
+

+

-

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
@@ -42,14 +100,17 @@ require __DIR__ . '/includes/header.php'; - + - + - "> - + + + + + + + +
- + +
+ + + +
- -