gitea init

This commit is contained in:
skryper
2025-10-08 21:28:30 +04:00
commit d4651a423d
2518 changed files with 522832 additions and 0 deletions
@@ -0,0 +1,26 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../../includes/init.php';
require_once __DIR__ . '/../../models/invoicesmodel.php';
require_once __DIR__ . '/../../../../../vendor/autoload.php';
InvoicesModel::setDb($pdo);
// ინვოისის ნომრის გენერაცია
$generatedInvoiceNumber = InvoicesModel::generateNextInvoiceNumber();
// კლიენტების სია dropdown-სთვის
$clients = InvoicesModel::getClientsList();
// პროდუქტების სია
$products = InvoicesModel::getProductList();
require_once __DIR__ . '/../../views/invoices/create.php';
?>
@@ -0,0 +1,29 @@
<?php
// კონტროლერი: ინვოისის წაშლა
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../../includes/init.php';
require_once __DIR__ . '/../../models/invoicesmodel.php';
require_once __DIR__ . '/../../../../../vendor/autoload.php';
use App\Config;
// ბაზასთან დაკავშირება
InvoicesModel::setDb($pdo);
// GET ID გადამოწმება
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
exit('არასწორი ID.');
}
$id = (int)$_GET['id'];
// წაშლა
InvoicesModel::deleteInvoice($id);
// გადამისამართება ინვოისების სიაზე
require_once __DIR__ . '/../../views/invoices/list.php';
@@ -0,0 +1,31 @@
<?php
// 📄 რედაქტირება
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../../includes/init.php';
require_once __DIR__ . '/../../models/invoicesmodel.php';
require_once __DIR__ . '/../../../../../vendor/autoload.php';
InvoicesModel::setDb($pdo);
// ID შემოწმება
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
exit('არასწორი ID.');
}
$id = (int)$_GET['id'];
// ინვოისის წამოღება
$invoice = InvoicesModel::getInvoiceById($id);
if (!$invoice) {
exit('ინვოისი ვერ მოიძებნა.');
}
// სელექტისთვის საჭირო მონაცემები
$clients = InvoicesModel::getClientsList();
$products = InvoicesModel::getProductList();
// ვიუ ჩატვირთვა
require_once __DIR__ . '/../../views/invoices/edit.php';
@@ -0,0 +1,54 @@
<?php
// 📄 ინვოისის PDF გენერაცია - Controller
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../../includes/init.php';
require_once __DIR__ . '/../../models/invoicesmodel.php';
require_once __DIR__ . '/../../../../vendor/autoload.php';
use Dompdf\Dompdf;
use Dompdf\Options;
use App\Config;
InvoicesModel::setDb($pdo);
// 🧾 ინვოისის ID გადმოსვლა GET-ით
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
exit('არასწორი ID');
}
$id = (int)$_GET['id'];
// 🧾 ინვოისის მონაცემების წამოღება
$invoice = InvoicesModel::getInvoiceById($id);
if (!$invoice) {
exit('ინვოისი ვერ მოიძებნა.');
}
$client_name = $invoice['first_name'] . ' ' . $invoice['last_name'];
// 📄 PDF კონფიგურაცია
$options = new Options();
$options->set('isHtml5ParserEnabled', true);
$options->set('isRemoteEnabled', true);
$dompdf = new Dompdf($options);
// 📄 შაბლონის HTML ჩატვირთვა
ob_start();
require_once realpath(Config::basePath() . '/admin/modules/billing/models/invoices/invoice_template.php');
$html = ob_get_clean();
$dompdf->loadHtml($html, 'UTF-8');
$dompdf->setPaper('A4', 'portrait');
$dompdf->render();
// 📄 PDF-ის შენახვა დროებით
$pdfOutput = $dompdf->output();
$pdfPath = '/tmp/invoice_' . $invoice['id'] . '.pdf';
file_put_contents($pdfPath, $pdfOutput);
// გადამისამართება ან ჩამოტვირთვა შეგიძლიათ დაამატოთ აქ
@@ -0,0 +1,19 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../../includes/init.php';
require_once __DIR__ . '/../../models/invoicesmodel.php';
require_once __DIR__ . '/../../../../../vendor/autoload.php';
use App\Config;
// ვუკავშირებთ ბაზას მოდელს
InvoicesModel::setDb($pdo);
// ინვოისების წამოღება
$invoices = InvoicesModel::getAllInvoices();
// ვიუს ჩატვირთვა
require_once __DIR__ . '/../../views/invoices/list.php';
@@ -0,0 +1,104 @@
<!-- გაგზავნის ლოგიკა -->
<?php
// ინვოისის გაგზავნა ელფოსტაზე PDF-ით
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../../includes/init.php';
require_once __DIR__ . '/../../models/invoicesmodel.php';
require_once __DIR__ . '/../../../../../vendor/autoload.php';
require_once __DIR__ . '/../../../../libs/phpmailer/src/PHPMailer.php';
require_once __DIR__ . '/../../../../libs/phpmailer/src/SMTP.php';
require_once __DIR__ . '/../../../../libs/phpmailer/src/Exception.php';
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
InvoicesModel::setDb($pdo);
// use Dompdf\Dompdf;
// use Dompdf\Options;
// $options = new Options();
// $options->set('isRemoteEnabled', true);
// // ️➡️ უთხარი Dompdf-ს სად არის შენი შრიფტი
// $options->setChroot(__DIR__ . '/../../'); // აქედან იმუშავებს relative path-ებით
// $options->set('defaultFont', 'bpg_glaho');
// $dompdf = new Dompdf($options);
InvoicesModel::setDb($pdo);
// 1. აიდი
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if (!$id) {
exit("არასწორი ინვოისის ID.");
}
// 2. მოიტანე ინვოისი და ნივთები
$invoice = InvoicesModel::getInvoiceWithItems($id);
if (!$invoice) {
exit("ინვოისი ვერ მოიძებნა.");
}
// 3. გენერაცია PDF ფაილის
$pdfPath = InvoicesModel::generateInvoicePDF($invoice);
// Email გაგზავნა
$mail = new PHPMailer(true);
try {
$mail->isSMTP();
$mail->Host = 'vps-7146dd3a.vps.ovh.ca'; // შეცვალე
$mail->SMTPAuth = true;
$mail->Username = 'noreply@selfhosting.ge'; // შეცვალე
$mail->Password = 'FSZtTIIIlubk'; // შეცვალე
$mail->SMTPSecure = 'ssl'; // ან ssl
$mail->Port = 465; // ან 465
$mail->setFrom('noreply@selfhosting.ge', 'ბილინგ სერვისი');
$mail->addAddress($invoice['email'], $invoice['first_name'] . ' ' . $invoice['last_name']);
$mail->CharSet = 'UTF-8'; // ✅ ეს არის მთავარი!
$mail->Encoding = 'base64'; // ხშირად დაეხმარება UTF-8-ის სწორ გადაცემას
$mail->isHTML(true);
$mail->Subject = "ინვოისი #" . $invoice['invoice_number'];
$mail->Body = "
გამარჯობა {$invoice['first_name']},<br><br>
თქვენთვის შემუშავებულია ახალი ინვოისი ჯამური თანხით <strong>{$invoice['total_amount']} ₾</strong>.<br>
გადახდის ვადა: {$invoice['due_date']}<br><br>
იხილეთ დეტალურად: ინვოისის სანახავად იხილეთ მიმაგრებული ფაილი<br><br>
მადლობა თანამშრომლობისთვის.
";
$invoice = InvoicesModel::getInvoiceWithClientById($id);
$invoice['company_name'] = $invoice['client_company_name'];
$invoice['vat_number'] = $invoice['client_vat_number'];
$invoice['address1'] = $invoice['client_address1'];
$client_name = $invoice['first_name'] . ' ' . $invoice['last_name'];
// ინვოისის HTML
$html = InvoicesModel::renderInvoiceHTML($invoice);
$mail->addAttachment($pdfPath, 'Invoice_' . $invoice['invoice_number'] . '.pdf');
$mail->send();
// ✅ წარმატებული გაგზავნის შემდეგ
header("Location: dashboard.php?module=billing&submodule=invoices&action=view&id={$invoice['id']}&sent=1");
exit;
} catch (Exception $e) {
echo "შეცდომა გაგზავნისას: {$mail->ErrorInfo}";
}
?>
@@ -0,0 +1,50 @@
<?php
// 📬 გადახდის შეხსენების გაგზავნა
ini_set('display_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../../includes/init.php';
require_once __DIR__ . '/../../models/invoicesmodel.php';
require '../../libs/phpmailer/src/PHPMailer.php';
require '../../libs/phpmailer/src/SMTP.php';
require '../../libs/phpmailer/src/Exception.php';
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
foreach ($invoices as $invoice) {
$mail = new PHPMailer(true);
try {
// SMTP პარამეტრები
$mail->isSMTP();
$mail->Host = 'vps-7146dd3a.vps.ovh.ca';
$mail->SMTPAuth = true;
$mail->Username = 'levan@arabuli.info';
$mail->Password = 'Aqsxcs@1211';
$mail->SMTPSecure = 'ssl';
$mail->Port = 465;
$clientName = $invoice['first_name'] . ' ' . $invoice['last_name'];
$mail->setFrom('levan@arabuli.info', 'Billing System');
$mail->addAddress($invoice['email'], $clientName);
$mail->CharSet = 'UTF-8';
$mail->isHTML(true);
$mail->Subject = "გადახდის შეხსენება ინვოისზე #{$invoice['invoice_number']}";
$mail->Body = "
გამარჯობა {$clientName},<br><br>
გთხოვთ გადაიხადოთ ინვოისი #{$invoice['invoice_number']} <strong>{$invoice['total_amount']} ₾</strong><br>
გადახდის ბოლო ვადაა: <strong>{$invoice['due_date']}</strong><br><br>
იხილეთ ინვოისი: <a href='https://yourdomain.com/dashboard.php?module=billing&submodule=invoices&action=view&id={$invoice['id']}'>იხილეთ ინვოისი</a>
";
$mail->send();
echo "✅ შეხსენება გაიგზავნა {$clientName} ({$invoice['email']})<br>";
} catch (Exception $e) {
echo "❌ შეცდომა: {$mail->ErrorInfo}<br>";
}
}
@@ -0,0 +1,36 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../../includes/init.php';
require_once __DIR__ . '/../../models/invoicesmodel.php';
InvoicesModel::setDb($pdo);
// POST მონაცემების დამუშავება
$data = $_POST;
$data['recurring'] = isset($data['recurring']) ? 1 : 0;
// სტატუსის ვალიდაცია
if (!InvoicesModel::isValidStatus($data['status'])) {
die('არასწორი სტატუსის მნიშვნელობა');
}
// 🔢 ინვოისის ნომრის გენერაცია
if (empty($data['invoice_number'])) {
$data['invoice_number'] = InvoicesModel::generateInvoiceNumber();
}
// დუბლიკატის შემოწმება
if (InvoicesModel::isDuplicateInvoiceNumber($data['invoice_number'])) {
die('ინვოისის ნომერი უკვე გამოიყენება!');
}
// ჩასმა მოდელის მეშვეობით
$invoice_id = InvoicesModel::createInvoiceWithItems($data);
// გადამისამართება
header("Location: dashboard.php?module=billing&submodule=invoices&action=view&id=" . $invoice_id);
exit;
@@ -0,0 +1,28 @@
<?php
// ⚙️ ინვოისის განახლება
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../../includes/init.php';
require_once __DIR__ . '/../../models/invoicesmodel.php';
require_once __DIR__ . '/../../../../../vendor/autoload.php';
InvoicesModel::setDb($pdo);
// 📨 მონაცემების მიღება
if (!isset($_POST['id']) || !is_numeric($_POST['id'])) {
exit('არასწორი ID.');
}
$id = (int)$_POST['id'];
$data = $_POST;
// ინვოისის განახლება
InvoicesModel::updateInvoice($id, $data);
// ↪️ გადამისამართება
header("Location: dashboard.php?module=billing&submodule=invoices&action=view&id=$id");
exit;
@@ -0,0 +1,37 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../../includes/init.php';
require_once __DIR__ . '/../../models/invoicesmodel.php';
require_once __DIR__ . '/../../../../../vendor/autoload.php';
use App\Config;
// ბაზასთან დაკავშირება
InvoicesModel::setDb($pdo);
// ID შემოწმება
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
echo "არასწორი ID.";
exit;
}
$id = (int) $_GET['id'];
$showAlert = isset($_GET['sent']) && $_GET['sent'] == 1;
// ინვოისის წამოღება
$invoice = InvoicesModel::getInvoiceWithClient($id);
if (!$invoice) {
echo "ინვოისი ვერ მოიძებნა.";
exit;
}
// პროდუქტის items
$productItems = InvoicesModel::getInvoiceItems($id);
// ვიუ ფაილის ჩატვირთვა
require_once __DIR__ . '/../../views/invoices/view.php';
@@ -0,0 +1,21 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../../includes/init.php';
require_once __DIR__ . '/../../models/transactionsmodel.php';
require_once __DIR__ . '/../../../../../vendor/autoload.php';
TransactionsModel::setDb($pdo);
// მომხმარებლები და ინვოისები ფორმის select-ებისთვის
$clients = TransactionsModel::getClients();
$invoices = TransactionsModel::getInvoices();
// POST დამუშავება
$errors = TransactionsModel::handleTransactionFormSubmission();
require_once __DIR__ . '/../../views/transactions/create.php';
@@ -0,0 +1,24 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../../includes/init.php';
require_once __DIR__ . '/../../models/transactionsmodel.php';
require_once __DIR__ . '/../../../../../vendor/autoload.php';
TransactionsModel::setDb($pdo);
// ID გადმოსვლის შემოწმება
$id = $_GET['id'] ?? null;
if (!$id || !is_numeric($id)) {
exit('არასწორი ID.');
}
// წაშლის მცდელობა
TransactionsModel::deleteTransaction((int)$id);
// გადამისამართება
header('Location: dashboard.php?module=billing&submodule=transactions&action=list&deleted=1');
exit;
@@ -0,0 +1,36 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../../includes/init.php';
require_once __DIR__ . '/../../models/transactionsmodel.php';
require_once __DIR__ . '/../../../../../vendor/autoload.php';
TransactionsModel::setDb($pdo);
$id = $_GET['id'] ?? null;
$transaction = TransactionsModel::getTransactionById($id);
if (!$transaction) {
echo "ტრანზაქცია ვერ მოიძებნა.";
exit;
}
// შენახვა
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$data = [
'status' => $_POST['status'],
'method' => $_POST['method'],
'notes' => $_POST['notes'],
];
TransactionsModel::updateTransaction($id, $data);
header("Location: dashboard.php?module=billing&submodule=transactions&action=list&updated=1");
exit;
}
require_once __DIR__ . '/../../views/transactions/edit.php';
@@ -0,0 +1,25 @@
<!-- გადახდების ისტორია -->
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../../includes/init.php';
require_once __DIR__ . '/../../models/transactionsmodel.php';
require_once __DIR__ . '/../../../../../vendor/autoload.php';
TransactionsModel::setDb($pdo);
$clientId = $_GET['client_id'] ?? null;
$client = TransactionsModel::getClientInfo($clientId);
if (!$client) {
echo "კლიენტი ვერ მოიძებნა.";
exit;
}
$transactions = TransactionsModel::getClientTransactions($clientId);
require_once __DIR__ . '/../../views/transactions/history.php';
@@ -0,0 +1,29 @@
<!-- ტრანზაქციების სია -->
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../../includes/init.php';
require_once __DIR__ . '/../../models/transactionsmodel.php';
require_once __DIR__ . '/../../../../../vendor/autoload.php';
// წაკითხვა GET-პარამეტრებიდან
$successMessage = null;
if (isset($_GET['added']) && $_GET['added'] == 1) {
$successMessage = "ტრანზაქცია წარმატებით დაემატა.";
} elseif (isset($_GET['updated']) && $_GET['updated'] == 1) {
$successMessage = "ტრანზაქცია წარმატებით განახლდა.";
} elseif (isset($_GET['deleted']) && $_GET['deleted'] == 1) {
$successMessage = "ტრანზაქცია წარმატებით წაიშალა.";
}
TransactionsModel::setDb($pdo);
$transactions = TransactionsModel::getAllTransactions();
require_once __DIR__ . '/../../views/transactions/list.php';
@@ -0,0 +1 @@
<!-- გენერირება, გამოთვლები -->
@@ -0,0 +1,2 @@
<!-- გენერირება, გამოთვლები -->
@@ -0,0 +1,323 @@
<?php
class InvoicesModel
{
protected static $db;
public static function setDb($pdo)
{
self::$db = $pdo;
}
// ყველა ინვოისის წამოღება
public static function getAllInvoicesWithClientNames()
{
$stmt = self::$db->query("
SELECT i.*, CONCAT(c.first_name, ' ', c.last_name) AS client_name
FROM invoices i
JOIN clients c ON i.client_id = c.id
ORDER BY i.id DESC
");
return $stmt->fetchAll();
}
// ყველა ინვოისის წამოღება
public static function getAllInvoices()
{
$stmt = self::$db->query("SELECT i.*, c.first_name, c.last_name FROM invoices i JOIN clients c ON i.client_id = c.id ORDER BY i.id DESC");
return $stmt->fetchAll();
}
// ერთი ინვოისის წამოღება დეტალურად
public static function getInvoiceById($id)
{
$stmt = self::$db->prepare("SELECT * FROM invoices WHERE id = ?");
$stmt->execute([$id]);
return $stmt->fetch();
}
// ინვოისის დამატება
public static function createInvoice($data)
{
$stmt = self::$db->prepare("INSERT INTO invoices (invoice_number, client_id, description, payment_method, status, total_amount, is_recurring, issue_date, due_date, payment_date, recurring) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([
$data['invoice_number'],
$data['client_id'],
$data['description'],
$data['payment_method'],
$data['status'],
$data['total_amount'],
$data['is_recurring'],
$data['issue_date'],
$data['due_date'],
$data['payment_date'],
$data['recurring']
]);
return self::$db->lastInsertId();
}
// ინვოისის განახლება
public static function updateInvoice($id, $data)
{
$stmt = self::$db->prepare("UPDATE invoices SET
client_id = ?, invoice_number = ?, description = ?, status = ?,
total_amount = ?, payment_method = ?, issue_date = ?, due_date = ?, recurring = ?
WHERE id = ?");
return $stmt->execute([
$data['client_id'],
$data['invoice_number'],
$data['description'],
$data['status'],
$data['total_amount'],
$data['payment_method'],
$data['issue_date'],
$data['due_date'],
isset($data['recurring']) ? 1 : 0,
$id
]);
}
// ინვოისის წაშლა
public static function deleteInvoice($id)
{
$stmt = self::$db->prepare("DELETE FROM invoices WHERE id = ?");
return $stmt->execute([$id]);
}
// ინვოისთან დაკავშირებული ნივთების წამოღება
public static function getInvoiceItems2($invoice_id)
{
$stmt = self::$db->prepare("SELECT * FROM invoice_items WHERE invoice_id = ?");
$stmt->execute([$invoice_id]);
return $stmt->fetchAll();
}
// ინვოისის ნივთების დამატება
public static function addInvoiceItem($invoice_id, $item)
{
$stmt = self::$db->prepare("INSERT INTO invoice_items (invoice_id, product_id, description, amount) VALUES (?, ?, ?, ?)");
return $stmt->execute([
$invoice_id,
$item['product_id'],
$item['description'],
$item['amount']
]);
}
// ინვოისის ნივთების წაშლა
public static function deleteInvoiceItems($invoice_id)
{
$stmt = self::$db->prepare("DELETE FROM invoice_items WHERE invoice_id = ?");
return $stmt->execute([$invoice_id]);
}
public static function getInvoiceWithClient($id)
{
$stmt = self::$db->prepare("
SELECT i.*, c.first_name, c.last_name, c.email
FROM invoices i
JOIN clients c ON c.id = i.client_id
WHERE i.id = ?
");
$stmt->execute([$id]);
return $stmt->fetch();
}
public static function getInvoiceItems($invoiceId)
{
$stmt = self::$db->prepare("
SELECT ii.*, p.name
FROM invoice_items ii
JOIN products p ON p.id = ii.product_id
WHERE ii.invoice_id = ?
");
$stmt->execute([$invoiceId]);
return $stmt->fetchAll();
}
public static function generateNextInvoiceNumber(): string
{
$currentYear = date('Y');
$prefix = 'INV-' . $currentYear . '-';
$stmt = self::$db->prepare("SELECT invoice_number FROM invoices WHERE invoice_number LIKE ? ORDER BY invoice_number DESC LIMIT 1");
$stmt->execute([$prefix . '%']);
$lastInvoice = $stmt->fetchColumn();
if ($lastInvoice) {
$lastNumber = (int) substr($lastInvoice, strrpos($lastInvoice, '-') + 1);
$newNumber = str_pad($lastNumber + 1, 3, '0', STR_PAD_LEFT);
} else {
$newNumber = '001';
}
return $prefix . $newNumber;
}
public static function getClientsList(): array
{
$stmt = self::$db->query("SELECT id, first_name, last_name FROM clients ORDER BY first_name");
return $stmt->fetchAll();
}
public static function getProductList(): array
{
$stmt = self::$db->query("SELECT id, name, price FROM products ORDER BY name");
return $stmt->fetchAll();
}
public static function createInvoiceWithItems($data)
{
$stmt = self::$db->prepare("INSERT INTO invoices
(client_id, invoice_number, description, total_amount, payment_method, status, issue_date, due_date, recurring)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([
$data['client_id'],
$data['invoice_number'],
$data['description'],
$data['total_amount'],
$data['payment_method'],
$data['status'],
$data['issue_date'],
$data['due_date'],
$data['recurring']
]);
$invoice_id = self::$db->lastInsertId();
$stmtItem = self::$db->prepare("INSERT INTO invoice_items (invoice_id, product_id, amount, description) VALUES (?, ?, ?, ?)");
for ($i = 0; $i < count($data['products']); $i++) {
$stmtItem->execute([
$invoice_id,
$data['products'][$i],
$data['amounts'][$i],
$data['descriptions'][$i]
]);
}
return $invoice_id;
}
public static function generateInvoiceNumber(): string
{
$year = date('Y');
$prefix = 'INV-' . $year . '-';
$stmt = self::$db->prepare("SELECT invoice_number FROM invoices WHERE invoice_number LIKE ? ORDER BY invoice_number DESC LIMIT 1");
$stmt->execute([$prefix . '%']);
$last = $stmt->fetchColumn();
$lastNumber = $last ? (int) substr($last, strrpos($last, '-') + 1) : 0;
$newNumber = str_pad($lastNumber + 1, 3, '0', STR_PAD_LEFT);
return $prefix . $newNumber;
}
public static function isValidStatus(string $status): bool
{
$allowed = ['დრაფტი', 'გადაუხდელი', 'გადასახდელი', 'გადახდილი', 'გაუქმებული'];
return in_array($status, $allowed);
}
public static function isDuplicateInvoiceNumber(string $invoice_number): bool
{
$stmt = self::$db->prepare("SELECT COUNT(*) FROM invoices WHERE invoice_number = ?");
$stmt->execute([$invoice_number]);
return $stmt->fetchColumn() > 0;
}
public static function getInvoicesDueTomorrow()
{
$tomorrow = date('Y-m-d', strtotime('+1 day'));
$stmt = self::$db->prepare("
SELECT invoices.*, clients.first_name, clients.last_name, clients.email
FROM invoices
JOIN clients ON invoices.client_id = clients.id
WHERE invoices.due_date = ? AND invoices.status IN ('გადაუხდელი', 'გადასახდელი')
");
$stmt->execute([$tomorrow]);
return $stmt->fetchAll();
}
public static function getInvoiceWithItems($id)
{
$stmt = self::$db->prepare("
SELECT invoices.*, clients.email, clients.first_name, clients.last_name
FROM invoices
JOIN clients ON invoices.client_id = clients.id
WHERE invoices.id = ?
");
$stmt->execute([$id]);
$invoice = $stmt->fetch();
if (!$invoice) {
return null;
}
$stmtItems = self::$db->prepare("
SELECT products.name, ii.description, ii.amount
FROM invoice_items ii
JOIN products ON products.id = ii.product_id
WHERE ii.invoice_id = ?
");
$stmtItems->execute([$id]);
$invoice['items'] = $stmtItems->fetchAll(PDO::FETCH_ASSOC);
return $invoice;
}
public static function generateInvoicePDF($invoice)
{
$html = self::renderInvoiceHTML($invoice);
$options = new \Dompdf\Options();
$options->set('isRemoteEnabled', true);
$options->set('defaultFont', 'DejaVu Sans');
$dompdf = new \Dompdf\Dompdf($options);
$dompdf->loadHtml($html, 'UTF-8');
$dompdf->setPaper('A4', 'portrait');
$dompdf->render();
$pdfPath = '/tmp/invoice_' . $invoice['id'] . '.pdf';
file_put_contents($pdfPath, $dompdf->output());
return $pdfPath;
}
public static function renderInvoiceHTML($invoice)
{
ob_start();
include __DIR__ . '/../views/invoices/pdf_template.php'; // თუ გინდა გამოყავი ცალკე template ფაილად
return ob_get_clean();
}
// მოაქვს პდფ ფაილში კლიენტის ბაზიდან დამატებითი მონაცემები
public static function getInvoiceWithClientById($id)
{
$stmt = self::$db->prepare("
SELECT
invoices.*,
clients.company_name,
clients.vat_number,
clients.address1,
clients.first_name AS client_first_name,
clients.last_name AS client_last_name
FROM invoices
LEFT JOIN clients ON invoices.client_id = clients.id
WHERE invoices.id = ?
");
$stmt->execute([$id]);
return $stmt->fetch();
}
}
@@ -0,0 +1,130 @@
<?php
class TransactionsModel
{
private static $db;
public static function setDb($pdo)
{
self::$db = $pdo;
}
public static function getClients()
{
$stmt = self::$db->query("SELECT id, first_name, last_name FROM clients ORDER BY first_name ASC");
return $stmt->fetchAll();
}
public static function getInvoices()
{
$stmt = self::$db->query("SELECT id, invoice_number FROM invoices ORDER BY invoice_number ASC");
return $stmt->fetchAll();
}
public static function handleTransactionFormSubmission()
{
$errors = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$invoice_id = $_POST['invoice_id'] ?? '';
$client_id = $_POST['client_id'] ?? '';
$amount = $_POST['amount'] ?? '';
$method = $_POST['method'] ?? '';
$status = $_POST['status'] ?? '';
$notes = $_POST['notes'] ?? '';
if (!$invoice_id || !$client_id || !$amount || !$method || !$status) {
$errors[] = "გთხოვ შეავსო ყველა სავალდებულო ველი.";
}
if (empty($errors)) {
$stmt = self::$db->prepare("INSERT INTO transactions (invoice_id, client_id, amount, method, status, notes) VALUES (?, ?, ?, ?, ?, ?)");
$stmt->execute([$invoice_id, $client_id, $amount, $method, $status, $notes]);
header("Location: dashboard.php?module=billing&submodule=transactions&action=list&added=1");
exit;
}
}
return $errors;
}
public static function getTransactionById($id)
{
if (!$id || !is_numeric($id)) {
return null;
}
$stmt = self::$db->prepare("
SELECT t.*, c.first_name, c.last_name, i.invoice_number
FROM transactions t
JOIN clients c ON c.id = t.client_id
JOIN invoices i ON i.id = t.invoice_id
WHERE t.id = ?
");
$stmt->execute([$id]);
return $stmt->fetch();
}
public static function updateTransaction($id, $data)
{
$stmt = self::$db->prepare("
UPDATE transactions
SET status = ?, method = ?, notes = ?
WHERE id = ?
");
return $stmt->execute([
$data['status'],
trim($data['method']),
trim($data['notes']),
$id
]);
}
public static function getClientInfo($clientId)
{
if (!$clientId || !is_numeric($clientId)) {
return null;
}
$stmt = self::$db->prepare("SELECT first_name, last_name FROM clients WHERE id = ?");
$stmt->execute([$clientId]);
return $stmt->fetch();
}
public static function getClientTransactions($clientId)
{
if (!$clientId || !is_numeric($clientId)) {
return [];
}
$stmt = self::$db->prepare("
SELECT t.*, i.invoice_number
FROM transactions t
JOIN invoices i ON i.id = t.invoice_id
WHERE t.client_id = ?
ORDER BY t.created_at DESC
");
$stmt->execute([$clientId]);
return $stmt->fetchAll();
}
public static function getAllTransactions()
{
$stmt = self::$db->query("
SELECT t.*, c.first_name, c.last_name, i.invoice_number
FROM transactions t
JOIN clients c ON t.client_id = c.id
JOIN invoices i ON t.invoice_id = i.id
ORDER BY t.created_at DESC
");
return $stmt->fetchAll();
}
public static function deleteTransaction($id)
{
$stmt = self::$db->prepare("DELETE FROM transactions WHERE id = ?");
return $stmt->execute([$id]);
}
}
@@ -0,0 +1,143 @@
<?php
require_once __DIR__ . '/../../models/invoicesmodel.php';
use App\Config;
require_once Config::includePath('head.php');
require_once Config::includePath('navbar.php');
require_once Config::includePath('pageheader.php');
require_once Config::includePath('pagebodystart.php');
?>
<!-- CONTENT START -->
<div class="container-xl mt-4">
<h2 class="mb-4">ახალი ინვოისის დამატება</h2>
<form action="dashboard.php?module=billing&submodule=invoices&action=store" method="POST">
<div class="mb-3">
<label class="form-label">კლიენტი</label>
<select name="client_id" class="form-select" required>
<option value="">აირჩიე კლიენტი</option>
<?php foreach ($clients as $client): ?>
<option value="<?= $client['id'] ?>">
<?= htmlspecialchars($client['first_name'] . ' ' . $client['last_name']) ?>
</option>
<?php endforeach ?>
</select>
</div>
<div class="mb-4">
<label class="form-label">პროდუქტები</label>
<div id="product-container">
<div class="row product-item mb-2">
<div class="col-md-5">
<select name="products[]" class="form-select" required>
<option value="">აირჩიე პროდუქტი</option>
<?php foreach ($products as $product): ?>
<option value="<?= $product['id'] ?>">
<?= htmlspecialchars($product['name']) ?> (<?= $product['price'] ?> ₾)
</option>
<?php endforeach ?>
</select>
</div>
<div class="col-md-3">
<input type="number" name="amounts[]" step="0.01" class="form-control" placeholder="თანხა ₾" required>
</div>
<div class="col-md-3">
<input type="text" name="descriptions[]" class="form-control" placeholder="აღწერა (არასავალდებულო)">
</div>
<div class="col-md-1">
<button type="button" class="btn btn-danger btn-remove">-</button>
</div>
</div>
</div>
<button type="button" id="add-product" class="btn btn-secondary btn-sm mt-2">+ პროდუქტის დამატება</button>
</div>
<div class="mb-3">
<label class="form-label">ინვოისის ნომერი (არასავალდებულო)</label>
<input type="text" name="invoice_number" class="form-control"
placeholder="მაგ: INV-2025-001"
value="<?= htmlspecialchars($generatedInvoiceNumber) ?>" />
</div>
<div class="mb-3">
<label class="form-label">ინვოისის აღწერა</label>
<textarea name="description" class="form-control" rows="3"></textarea>
</div>
<div class="mb-3">
<label class="form-label">გადასახდელი თანხა (₾)</label>
<input type="number" step="0.01" name="total_amount" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">გადახდის მეთოდი</label>
<input type="text" name="payment_method" class="form-control" value="საბანკო გადმორიცხვა" required>
</div>
<div class="mb-3">
<label class="form-label">სტატუსი</label>
<select name="status" class="form-select" required>
<option value="დრაფტი">დრაფტი</option>
<option value="გადაუხდელი">გადაუხდელი</option>
<option value="გადასახდელი">გადასახდელი</option>
<option value="გადახდილი">გადახდილი</option>
<option value="გაუქმებული">გაუქმებული</option>
</select>
</div>
<div class="mb-3 row">
<div class="col">
<label class="form-label">ინვოისის თარიღი</label>
<input type="date" name="issue_date" class="form-control" value="<?= date('Y-m-d') ?>" required>
</div>
<div class="col">
<label class="form-label">გადახდის ბოლო ვადა</label>
<input type="date" name="due_date" class="form-control" required>
</div>
</div>
<div class="mb-3">
<label class="form-check">
<input type="checkbox" name="recurring" value="1" class="form-check-input">
<span class="form-check-label">გადახდა განმეორებით (ყოველთვიურად)</span>
</label>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary">ინვოისის შექმნა</button>
<a href="list.php" class="btn btn-secondary">გაუქმება</a>
</div>
</form>
</div></div>
<?php require_once Config::includePath('footer.php'); ?>
<script>
document.getElementById('add-product').addEventListener('click', function () {
const container = document.getElementById('product-container');
const item = container.querySelector('.product-item');
const clone = item.cloneNode(true);
// reset values
clone.querySelectorAll('input, select').forEach(el => el.value = '');
container.appendChild(clone);
});
// remove button
document.addEventListener('click', function (e) {
if (e.target.classList.contains('btn-remove')) {
const allItems = document.querySelectorAll('.product-item');
if (allItems.length > 1) {
e.target.closest('.product-item').remove();
}
}
});
</script>
@@ -0,0 +1,90 @@
<?php
require_once __DIR__ . '/../../models/invoicesmodel.php';
use App\Config;
require_once Config::includePath('head.php');
require_once Config::includePath('navbar.php');
require_once Config::includePath('pageheader.php');
require_once Config::includePath('pagebodystart.php');
?>
<!-- CONTENT START -->
<div class="page-wrapper">
<div class="container-xl mt-4">
<h2 class="mb-4">ინვოისის რედაქტირება</h2>
<form action="dashboard.php?module=billing&submodule=invoices&action=update" method="POST">
<input type="hidden" name="id" value="<?= $invoice['id'] ?>">
<div class="mb-3">
<label class="form-label">კლიენტი</label>
<select name="client_id" class="form-select" required>
<?php foreach ($clients as $client): ?>
<option value="<?= $client['id'] ?>" <?= $invoice['client_id'] == $client['id'] ? 'selected' : '' ?>>
<?= htmlspecialchars($client['first_name'] . ' ' . $client['last_name']) ?>
</option>
<?php endforeach ?>
</select>
</div>
<div class="mb-3">
<label class="form-label">ინვოისის ნომერი</label>
<input type="text" name="invoice_number" class="form-control" value="<?= htmlspecialchars($invoice['invoice_number']) ?>" required>
</div>
<div class="mb-3">
<label class="form-label">აღწერა</label>
<textarea name="description" class="form-control"><?= htmlspecialchars($invoice['description']) ?></textarea>
</div>
<div class="row mb-3">
<div class="col-md-6">
<label class="form-label">გადახდის მეთოდი</label>
<input type="text" name="payment_method" class="form-control" value="<?= htmlspecialchars($invoice['payment_method']) ?>" required>
</div>
<div class="col-md-6">
<label class="form-label">სტატუსი</label>
<select name="status" class="form-select">
<?php foreach (['დრაფტი', 'გადაუხდელი', 'გადასახდელი', 'გადახდილი', 'გაუქმებული'] as $status): ?>
<option value="<?= $status ?>" <?= $invoice['status'] == $status ? 'selected' : '' ?>><?= $status ?></option>
<?php endforeach ?>
</select>
</div>
</div>
<div class="mb-3">
<label class="form-label">თანხა (₾)</label>
<input type="number" name="total_amount" class="form-control" step="0.01" value="<?= $invoice['total_amount'] ?>" required>
</div>
<div class="row mb-3">
<div class="col-md-6">
<label class="form-label">ინვოისის თარიღი</label>
<input type="date" name="issue_date" class="form-control" value="<?= $invoice['issue_date'] ?>" required>
</div>
<div class="col-md-6">
<label class="form-label">გადახდის ბოლო ვადა</label>
<input type="date" name="due_date" class="form-control" value="<?= $invoice['due_date'] ?>" required>
</div>
</div>
<div class="mb-3">
<label class="form-check">
<input class="form-check-input" type="checkbox" name="recurring" value="1" <?= $invoice['recurring'] ? 'checked' : '' ?>>
<span class="form-check-label">გადახდა განმეორებით (ყოველთვიურად)</span>
</label>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary">შენახვა</button>
<a href="dashboard.php?module=billing&submodule=invoices&action=view&id=<?= $invoice['id'] ?>" class="btn btn-secondary">უკან</a>
</div>
</form>
</div>
</div>
<?php require_once Config::includePath('footer.php'); ?>
@@ -0,0 +1,64 @@
<!-- ინვოისების სია + ფილტრები -->
<?php require_once __DIR__ . '/../../models/invoicesmodel.php'; ?>
<?php
use App\Config;
InvoicesModel::setDb($pdo);
$invoices = InvoicesModel::getAllInvoicesWithClientNames();
require_once Config::includePath('head.php');
require_once Config::includePath('navbar.php');
require_once Config::includePath('pageheader.php');
require_once Config::includePath('pagebodystart.php');
?>
<div class="container-xl mt-4">
<div class="d-flex justify-content-between mb-3">
<h2>ინვოისების სია</h2>
<a href="dashboard.php?module=billing&submodule=invoices&action=create" class="btn btn-primary">+ ახალი ინვოისი</a>
</div>
<div class="card">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>კლიენტი</th>
<th>თანხა</th>
<th>სტატუსი</th>
<th>თარიღი</th>
<th>ვადა</th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($invoices as $invoice): ?>
<tr>
<td><?= $invoice['id'] ?></td>
<td><?= htmlspecialchars($invoice['client_name']) ?></td>
<td><?= number_format($invoice['total_amount'], 2) ?> ₾</td>
<td>
<span class="badge bg-light">
<?= htmlspecialchars($invoice['status']) ?>
</span>
</td>
<td><?= $invoice['issue_date'] ?></td>
<td><?= $invoice['due_date'] ?></td>
<td>
<a href="dashboard.php?module=billing&submodule=invoices&action=view&id=<?= $invoice['id'] ?>" class="btn btn-sm btn-info">ნახვა</a>
<a href="dashboard.php?module=billing&submodule=invoices&action=edit&id=<?= $invoice['id'] ?>" class="btn btn-sm btn-warning">რედაქტირება</a>
<a href="dashboard.php?module=billing&submodule=invoices&action=delete&id=<?= $invoice['id'] ?>" class="btn btn-sm btn-danger" onclick="return confirm('ნამდვილად გსურს წაშლა?')">წაშლა</a>
</td>
</tr>
<?php endforeach ?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Content END -->
</div>
</div>
<?php require_once Config::includePath('footer.php'); ?>
@@ -0,0 +1,167 @@
<!DOCTYPE html>
<html lang="ka">
<head>
<meta charset="UTF-8">
<title>ინვოისი</title>
<style>
@font-face {
font-family: DejaVu Sans;
}
body {
font-family: DejaVu Sans;
font-size: 14px;
color: #333;
}
.invoice-box {
max-width: 800px;
margin: auto;
padding: 30px;
border: 1px solid #eee;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
}
.top-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.top-header img {
max-width: 250px;
}
.bank-info {
text-align: right;
font-size: 13px;
line-height: 1.6;
}
.green-banner {
position: absolute;
top: 0;
right: 0;
background: #4CAF50;
color: white;
padding: 5px 20px;
transform: rotate(45deg);
transform-origin: top right;
font-size: 16px;
}
.section {
margin-top: 20px;
}
.gray-box {
background: #eee;
padding: 10px;
font-weight: bold;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 15px;
}
table, th, td {
border: 1px solid #ccc;
}
th, td {
padding: 10px;
text-align: left;
}
th {
background: #f9f9f9;
}
.footer {
margin-top: 30px;
font-size: 12px;
text-align: center;
color: #777;
}
</style>
</head>
<body>
<div class="invoice-box">
<!-- <div class="green-banner">გადახდილია</div> -->
<div class="top-header">
<div>
<h3>SELFHOSTING.GE</h3>
</div>
<div class="bank-info">
/ ლევან არაბული<br>
/: 01001080490<br><br>
ბანკი: თიბისი ბანკი<br>
/: GE79TB7902736010100047<br><br>
ბანკი: საქართველოს ბანკი<br>
/: GE85BG0000000534211842<br>
იდენტიფიკატორი: 01001080490
</div>
</div>
<div class="section gray-box">
ინვოისი #: <?= htmlspecialchars($invoice['invoice_number']) ?><br>
ინვოისის თარიღი: <?= htmlspecialchars($invoice['issue_date']) ?><br>
გადახდის თარიღი: <?= htmlspecialchars($invoice['due_date']) ?>
</div>
<div class="section">
<strong>მიმღები:</strong><br>
<?= htmlspecialchars($invoice['first_name'] . ' ' . $invoice['last_name']) ?><br>
<?php if (!empty($invoice['company_name'])): ?>
<?= htmlspecialchars($invoice['company_name']) ?><br>
<?php endif; ?>
<?php if (!empty($invoice['address1'])): ?>
<?= htmlspecialchars($invoice['address1']) ?><br>
<?php endif; ?>
<?php if (!empty($invoice['vat_number'])): ?>
VAT: <?= htmlspecialchars($invoice['vat_number']) ?>
<?php endif; ?>
</div>
<div class="section">
<table>
<thead>
<tr>
<th>დასახელება</th>
<th>აღწერა</th>
<th>თანხა</th>
</tr>
</thead>
<tbody>
<?php foreach ($invoice['items'] as $item): ?>
<tr>
<td><?= htmlspecialchars($item['name']) ?></td>
<td><?= htmlspecialchars($item['description']) ?></td>
<td><?= number_format($item['amount'], 2) ?> ლარი</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="section">
<h3>ტრანზაქციები</h3>
<table>
<thead>
<tr>
<th>ინვოისის ნომერი</th>
<th>გადახდის მეთოდი</th>
<th>ტრანზაქციის ID</th>
<th>თანხა</th>
</tr>
</thead>
<tbody>
<tr>
<td># <?= htmlspecialchars($invoice['invoice_number']) ?></td>
<td><?= htmlspecialchars($invoice['payment_method']) ?></td>
<td>-</td>
<td><?= number_format($invoice['total_amount'], 2) ?></td>
</tr>
<tr>
<td colspan="3">ბალანსი</td>
<td>0.00 GEL</td>
</tr>
</tbody>
</table>
</div>
<div class="footer">
Powered By Stack.ge | შექმნილია Stack.ge-ს მიერ
</div>
</div>
</body>
</html>
@@ -0,0 +1,69 @@
<!-- კონკრეტული ინვოისის ხილვა -->
<?php require_once __DIR__ . '/../../models/invoicesmodel.php'; ?>
<?php
use App\Config;
require_once Config::includePath('head.php');
require_once Config::includePath('navbar.php');
require_once Config::includePath('pageheader.php');
require_once Config::includePath('pagebodystart.php');
?>
<!-- CONTENT START -->
<?php if ($showAlert): ?>
<div class="alert alert-success alert-dismissible fade show" role="alert" id="invoiceAlert">
✅ ინვოისი წარმატებით გაიგზავნა!
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<script>
setTimeout(() => {
const alertBox = document.getElementById('invoiceAlert');
if (alertBox) alertBox.remove();
}, 5000);
</script>
<?php endif; ?>
<div class="container-xl mt-4">
<h2>ინვოისი # <?= $invoice['invoice_number'] ? htmlspecialchars($invoice['invoice_number']) : '' ?></h2>
<p><strong>კლიენტი:</strong> <?= htmlspecialchars($invoice['first_name'] . ' ' . $invoice['last_name']) ?></p>
<p><strong>სტატუსი:</strong> <?= htmlspecialchars($invoice['status']) ?></p>
<p><strong>თარიღი:</strong> <?= $invoice['issue_date'] ?></p>
<p><strong>ბოლო ვადა:</strong> <?= $invoice['due_date'] ?></p>
<p><strong>გადასახდელი თანხა:</strong> <?= number_format($invoice['total_amount'], 2) ?> ₾</p>
<p><strong>გადახდის მეთოდი:</strong> <?= htmlspecialchars($invoice['payment_method']) ?></p>
<p><strong>აღწერა:</strong> <?= nl2br(htmlspecialchars($invoice['description'])) ?></p>
<?php if (!empty($productItems)): ?>
<h4 class="mt-4">პროდუქტები</h4>
<table class="table">
<thead>
<tr>
<th>პროდუქტი</th>
<th>თანხა</th>
<th>აღწერა</th>
</tr>
</thead>
<tbody>
<?php foreach ($productItems as $item): ?>
<tr>
<td><?= htmlspecialchars($item['name']) ?></td>
<td><?= number_format($item['amount'], 2) ?> ₾</td>
<td><?= htmlspecialchars($item['description']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
<div class="mt-4">
<a href="dashboard.php?module=billing&submodule=invoices&action=send&id=<?= $invoice['id'] ?>" class="btn btn-primary">გაგზავნა</a>
<a href="dashboard.php?module=billing&submodule=invoices&action=edit&id=<?= $invoice['id'] ?>" class="btn btn-secondary">რედაქტირება</a>
<a href="dashboard.php?module=billing&submodule=invoices&action=delete&id=<?= $invoice['id'] ?>" class="btn btn-danger">წაშლა</a>
<a href="dashboard.php?module=billing&submodule=invoices&action=list" class="btn btn-light">უკან</a>
</div>
</div>
<?php require_once Config::includePath('footer.php'); ?>
@@ -0,0 +1,70 @@
<?php
require_once __DIR__ . '/../../models/transactionsmodel.php';
use App\Config;
require_once Config::includePath('head.php');
require_once Config::includePath('navbar.php');
require_once Config::includePath('pageheader.php');
require_once Config::includePath('pagebodystart.php');
?>
<div class="container-xl mt-4">
<h2>ტრანზაქციის დამატება</h2>
<?php if (!empty($errors)): ?>
<div class="alert alert-danger"><?= implode('<br>', $errors) ?></div>
<?php endif; ?>
<form method="post">
<div class="mb-3">
<label class="form-label">ინვოისი</label>
<select name="invoice_id" class="form-select" required>
<option value="">აირჩიე</option>
<?php foreach ($invoices as $inv): ?>
<option value="<?= $inv['id'] ?>"><?= htmlspecialchars($inv['invoice_number']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label class="form-label">კლიენტი</label>
<select name="client_id" class="form-select" required>
<option value="">აირჩიე</option>
<?php foreach ($clients as $cl): ?>
<option value="<?= $cl['id'] ?>"><?= htmlspecialchars($cl['first_name'] . ' ' . $cl['last_name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label class="form-label">თანხა</label>
<input type="number" name="amount" step="0.01" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">მეთოდი</label>
<input type="text" name="method" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">სტატუსი</label>
<select name="status" class="form-select" required>
<option value="success">წარმატებული</option>
<option value="failed">წარუმატებელი</option>
<option value="pending">მოლოდინში</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">შენიშვნა</label>
<textarea name="notes" class="form-control"></textarea>
</div>
<button type="submit" class="btn btn-success">შენახვა</button>
<a href="list.php" class="btn btn-secondary">გაუქმება</a>
</form>
</div>
<?php require_once Config::includePath('footer.php'); ?>
@@ -0,0 +1,50 @@
<?php
require_once __DIR__ . '/../../models/transactionsmodel.php';
use App\Config;
require_once Config::includePath('head.php');
require_once Config::includePath('navbar.php');
require_once Config::includePath('pageheader.php');
require_once Config::includePath('pagebodystart.php');
?>
<div class="container-xl mt-4">
<h2>ტრანზაქციის რედაქტირება</h2>
<form method="post">
<div class="mb-3">
<label class="form-label">ინვოისი</label>
<input type="text" class="form-control" value="#<?= $transaction['invoice_number'] ?>" disabled>
</div>
<div class="mb-3">
<label class="form-label">კლიენტი</label>
<input type="text" class="form-control" value="<?= $transaction['first_name'] . ' ' . $transaction['last_name'] ?>" disabled>
</div>
<div class="mb-3">
<label class="form-label">თანხა</label>
<input type="text" class="form-control" value="<?= number_format($transaction['amount'], 2) ?> ₾" disabled>
</div>
<div class="mb-3">
<label class="form-label">სტატუსი</label>
<select name="status" class="form-select" required>
<option value="success" <?= $transaction['status'] === 'success' ? 'selected' : '' ?>>დადასტურებული</option>
<option value="failed" <?= $transaction['status'] === 'failed' ? 'selected' : '' ?>>ჩავარდა</option>
<option value="pending" <?= $transaction['status'] === 'pending' ? 'selected' : '' ?>>მოლოდინში</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">გადახდის მეთოდი</label>
<input type="text" name="method" class="form-control" value="<?= htmlspecialchars($transaction['method']) ?>">
</div>
<div class="mb-3">
<label class="form-label">შენიშვნა</label>
<textarea name="notes" class="form-control"><?= htmlspecialchars($transaction['notes']) ?></textarea>
</div>
<button type="submit" class="btn btn-primary">შენახვა</button>
<a href="list.php" class="btn btn-secondary">უკან</a>
</form>
</div>
<?php require_once Config::includePath('footer.php'); ?>
@@ -0,0 +1,52 @@
<?php
require_once __DIR__ . '/../../models/transactionsmodel.php';
use App\Config;
require_once Config::includePath('head.php');
require_once Config::includePath('navbar.php');
require_once Config::includePath('pageheader.php');
require_once Config::includePath('pagebodystart.php');
?>
<div class="container-xl mt-4">
<h2>ტრანზაქციების ისტორია - <?= htmlspecialchars($client['first_name'] . ' ' . $client['last_name']) ?></h2>
<?php if (empty($transactions)): ?>
<div class="alert alert-info">ტრანზაქცია არ მოიძებნა.</div>
<?php else: ?>
<table class="table table-hover">
<thead>
<tr>
<th>ინვოისი</th>
<th>თანხა</th>
<th>მეთოდი</th>
<th>სტატუსი</th>
<th>შენიშვნა</th>
<th>თარიღი</th>
</tr>
</thead>
<tbody>
<?php foreach ($transactions as $t): ?>
<tr>
<td>#<?= htmlspecialchars($t['invoice_number']) ?></td>
<td><?= number_format($t['amount'], 2) ?> ₾</td>
<td><?= htmlspecialchars($t['method']) ?></td>
<td>
<span class="badge bg-<?= $t['status'] === 'success' ? 'success' : ($t['status'] === 'failed' ? 'danger' : 'warning') ?>">
<?= htmlspecialchars($t['status']) ?>
</span>
</td>
<td><?= nl2br(htmlspecialchars($t['notes'])) ?></td>
<td><?= $t['created_at'] ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
<a href="/admin/clients/view.php?id=<?= $clientId ?>" class="btn btn-light">🔙 უკან კლიენტის პროფილში</a>
</div>
<?php require_once Config::includePath('footer.php'); ?>
@@ -0,0 +1,54 @@
<?php
require_once __DIR__ . '/../../models/transactionsmodel.php';
use App\Config;
require_once Config::includePath('head.php');
require_once Config::includePath('navbar.php');
require_once Config::includePath('pageheader.php');
require_once Config::includePath('pagebodystart.php');
?>
<?php if (!empty($successMessage)): ?>
<div class="alert alert-success">
<?= htmlspecialchars($successMessage) ?>
</div>
<?php endif; ?>
<div class="container-xl mt-4">
<h2>ტრანზაქციები</h2>
<a href="dashboard.php?module=billing&submodule=transactions&action=create" class="btn btn-primary mb-3"> დამატება</a>
<table class="table table-bordered">
<thead>
<tr>
<th>ინვოისი</th>
<th>კლიენტი</th>
<th>თანხა</th>
<th>მეთოდი</th>
<th>სტატუსი</th>
<th>თარიღი</th>
<th>ქმედებები</th>
</tr>
</thead>
<tbody>
<?php foreach ($transactions as $tx): ?>
<tr>
<td><?= htmlspecialchars($tx['invoice_number']) ?></td>
<td><?= htmlspecialchars($tx['first_name'] . ' ' . $tx['last_name']) ?></td>
<td><?= number_format($tx['amount'], 2) ?> ₾</td>
<td><?= htmlspecialchars($tx['method']) ?></td>
<td><?= htmlspecialchars($tx['status']) ?></td>
<td><?= $tx['created_at'] ?></td>
<td>
<a href="dashboard.php?module=billing&submodule=transactions&action=edit&id=<?= $tx['id'] ?>" class="btn btn-sm btn-warning">✏️</a>
<a href="dashboard.php?module=billing&submodule=transactions&action=delete&id=<?= $tx['id'] ?>" class="btn btn-sm btn-danger" onclick="return confirm('დარწმუნებული ხარ?')">🗑️</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php require_once Config::includePath('footer.php'); ?>