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
+39
View File
@@ -0,0 +1,39 @@
<?php
require_once __DIR__ . '/../../../includes/init.php'; // ბაზასთან კავშირი
require_once __DIR__ . '/../models/client.php'; // Client მოდელის ჩასმა
Client::setDb($pdo); // აქ ვუკავშირებთ PDO ობიექტს მოდელს
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// ყველა მონაცემის შეგროვება ერთი მასივში
$data = [
'first_name' => trim($_POST['first_name'] ?? ''),
'last_name' => trim($_POST['last_name'] ?? ''),
'company_name' => trim($_POST['company'] ?? null),
'vat_number' => trim($_POST['vat_number'] ?? null),
'email' => trim($_POST['email'] ?? ''),
'password' => password_hash($_POST['password'], PASSWORD_BCRYPT),
'address1' => trim($_POST['address1'] ?? null),
'address2' => trim($_POST['address2'] ?? null),
'city' => trim($_POST['city'] ?? null),
'state' => trim($_POST['state'] ?? null),
'postcode' => trim($_POST['postcode'] ?? null),
'country' => trim($_POST['country'] ?? null),
'phone' => trim($_POST['phone'] ?? null),
'payment_method' => trim($_POST['payment_method'] ?? null),
'billing_contact' => trim($_POST['billing_contact'] ?? null),
'currency' => trim($_POST['currency'] ?? 'USD'),
'language' => trim($_POST['language'] ?? 'default'),
'status' => trim($_POST['status'] ?? 'active'),
'client_group' => trim($_POST['client_group'] ?? 'none'),
'admin_notes' => trim($_POST['admin_notes'] ?? null),
];
// მონაცემის დამატება მოდელიდან
Client::create($data);
header("Location: dashboard.php?module=clients&action=list");
exit;
}
// view-ის ჩატვირთვა
require_once __DIR__ . '/../views/clients_add.php';
@@ -0,0 +1,15 @@
<?php
require_once __DIR__ . '/../../../includes/init.php';
require_once __DIR__ . '/../models/client.php';
Client::setDb($pdo); // ვუთითებთ PDO ობიექტს
if (isset($_GET['id']) && is_numeric($_GET['id'])) {
$id = (int)$_GET['id'];
// გადავცემთ ID-ს მოდელს წასაშლელად
Client::delete($id);
}
header("Location: dashboard.php?module=clients&action=list");
exit;
@@ -0,0 +1,45 @@
<?php
require_once __DIR__ . '/../../../includes/init.php';
require_once __DIR__ . '/../models/client.php';
// შემოწმება GET id-ზე
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
header("Location: dashboard.php?module=clients&action=list");
exit;
}
$id = (int)$_GET['id'];
// მომხმარებლის წამოღება
Client::setDb($pdo);
$client = Client::find($id);
if (!$client) {
echo "კლიენტი ვერ მოიძებნა.";
exit;
}
// თუ შენახვის ფორმა გამოიგზავნა
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$data = [
'first_name' => trim($_POST['first_name'] ?? ''),
'last_name' => trim($_POST['last_name'] ?? ''),
'company_name' => trim($_POST['company'] ?? null),
'email' => trim($_POST['email'] ?? ''),
'phone' => trim($_POST['phone'] ?? null),
'status' => trim($_POST['status'] ?? 'active'),
'client_group' => trim($_POST['client_group'] ?? 'none'),
'admin_notes' => trim($_POST['admin_notes'] ?? null),
];
Client::update($id, $data);
header("Location: dashboard.php?module=clients&action=profile&id=$id");
exit;
}
// view-ის ჩატვირთვა
require_once __DIR__ . '/../views/clients_edit.php';
@@ -0,0 +1,8 @@
<?php
require_once __DIR__ . '/../../../includes/init.php';
require_once __DIR__ . '/../models/client.php';
Client::setDb($pdo);
$clients = Client::all(); // მოდელიდან იღებ ყველა კლიენტს
include __DIR__ . '/../views/clients_list.php'; // აჩვენე View
@@ -0,0 +1,83 @@
<?php
require_once __DIR__ . '/../../../includes/init.php';
// ID გადმოწოდებულია URL-იდან
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
header("Location: clients_list.php");
exit;
}
$id = (int)$_GET['id'];
$stmt = $pdo->prepare("SELECT * FROM clients WHERE id = ?");
$stmt->execute([$id]);
$client = $stmt->fetch();
if (!$client) {
echo "კლიენტი ვერ მოიძებნა.";
exit;
}
// Ჩვენ ვიღებთ კლიენტის ID-ს
$client_id = $_GET['id'];
// ყველა ინვოისი ამ მომხმარებლისთვის
$stmt = $pdo->prepare("SELECT status, total_amount FROM invoices WHERE client_id = ?");
$stmt->execute([$client_id]);
$invoices = $stmt->fetchAll(PDO::FETCH_ASSOC);
// ინიციალიზაცია
$paid = $draft = $unpaid_due = $cancelled = $refunded = 0;
// გამოთვლა
foreach ($invoices as $inv) {
$amount = (float)$inv['total_amount'];
switch ($inv['status']) {
case 'გადახდილი':
$paid += $amount;
break;
case 'დრაფტი':
$draft += $amount;
break;
case 'გადაუხდელი':
case 'გადასახდელი':
$unpaid_due += $amount;
break;
case 'გაუქმებული':
$cancelled += $amount;
break;
case 'დაბრუნებული':
$refunded += $amount;
break;
}
}
$gross_revenue = $paid + $unpaid_due + $draft;
$net_income = $paid;
$credit_balance = 0.00; // შეგიძლია დაამატო ცალკე ცხრილიდან
$client_id = $_GET['id'];
// სერვისების მიღება
$stmt = $pdo->prepare("
SELECT p.name AS product_name, ii.amount, ii.description, i.issue_date
FROM invoice_items ii
JOIN invoices i ON ii.invoice_id = i.id
JOIN products p ON ii.product_id = p.id
WHERE i.client_id = ?
ORDER BY i.issue_date DESC
");
$stmt->execute([$client_id]);
$services = $stmt->fetchAll(PDO::FETCH_ASSOC);
require_once __DIR__ . '/../views/client_profile.php';
?>
+130
View File
@@ -0,0 +1,130 @@
<?php
class Client
{
// ➤ ბაზასთან კავშირის ცვლადი (გლობალური ან Dependency Injection)
protected static $db;
public static function setDb($pdo)
{
self::$db = $pdo;
}
// ➤ კლიენტის დამატება
public static function create($data)
{
$sql = "INSERT INTO clients (
first_name, last_name, company_name, vat_number, email, password,
address1, address2, city, state, postcode, country, phone,
payment_method, billing_contact, currency, language, status,
client_group, admin_notes
) VALUES (
:first_name, :last_name, :company_name, :vat_number, :email, :password,
:address1, :address2, :city, :state, :postcode, :country, :phone,
:payment_method, :billing_contact, :currency, :language, :status,
:client_group, :admin_notes
)";
$stmt = self::$db->prepare($sql);
$stmt->execute([
':first_name' => $data['first_name'],
':last_name' => $data['last_name'],
':company_name' => $data['company_name'] ?? null,
':vat_number' => $data['vat_number'] ?? null,
':email' => $data['email'],
':password' => $data['password'],
':address1' => $data['address1'] ?? null,
':address2' => $data['address2'] ?? null,
':city' => $data['city'] ?? null,
':state' => $data['state'] ?? null,
':postcode' => $data['postcode'] ?? null,
':country' => $data['country'] ?? null,
':phone' => $data['phone'] ?? null,
':payment_method' => $data['payment_method'] ?? null,
':billing_contact' => $data['billing_contact'] ?? null,
':currency' => $data['currency'] ?? 'USD',
':language' => $data['language'] ?? 'default',
':status' => $data['status'] ?? 'active',
':client_group' => $data['client_group'] ?? 'none',
':admin_notes' => $data['admin_notes'] ?? null
]);
}
// ➤ ყველა კლიენტის წამოღება
public static function all()
{
$stmt = self::$db->query("SELECT * FROM clients ORDER BY id DESC");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// ➤ ერთი კლიენტის წამოღება ID-ით
public static function find($id)
{
$stmt = self::$db->prepare("SELECT * FROM clients WHERE id = ?");
$stmt->execute([$id]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
// ➤ კლიენტის განახლება
public static function update($id, $data)
{
$sql = "UPDATE clients SET
first_name = :first_name,
last_name = :last_name,
company_name = :company_name,
vat_number = :vat_number,
email = :email,
address1 = :address1,
address2 = :address2,
city = :city,
state = :state,
postcode = :postcode,
country = :country,
phone = :phone,
payment_method = :payment_method,
billing_contact = :billing_contact,
currency = :currency,
language = :language,
status = :status,
client_group = :client_group,
admin_notes = :admin_notes
WHERE id = :id";
$stmt = self::$db->prepare($sql);
// აუცილებელია ყველა პარამეტრი იყოს განსაზღვრული
$params = [
':first_name' => $data['first_name'] ?? '',
':last_name' => $data['last_name'] ?? '',
':company_name' => $data['company_name'] ?? null,
':vat_number' => $data['vat_number'] ?? null,
':email' => $data['email'] ?? '',
':address1' => $data['address1'] ?? null,
':address2' => $data['address2'] ?? null,
':city' => $data['city'] ?? null,
':state' => $data['state'] ?? null,
':postcode' => $data['postcode'] ?? null,
':country' => $data['country'] ?? null,
':phone' => $data['phone'] ?? null,
':payment_method' => $data['payment_method'] ?? null,
':billing_contact' => $data['billing_contact'] ?? null,
':currency' => $data['currency'] ?? 'USD',
':language' => $data['language'] ?? 'default',
':status' => $data['status'] ?? 'active',
':client_group' => $data['client_group'] ?? 'none',
':admin_notes' => $data['admin_notes'] ?? null,
':id' => $id
];
$stmt->execute($params);
}
// ➤ კლიენტის წაშლა
public static function delete($id)
{
$stmt = self::$db->prepare("DELETE FROM clients WHERE id = ?");
$stmt->execute([$id]);
}
}
@@ -0,0 +1,110 @@
<?php
require_once __DIR__ . '/../../../../vendor/autoload.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="d-flex justify-content-between align-items-center mb-3">
<h2>კლიენტის პროფილი: <?= htmlspecialchars($client['first_name'] . ' ' . $client['last_name']) ?></h2>
<a href="dashboard.php?module=clients&action=list" class="btn btn-secondary">← უკან სიისკენ</a>
</div>
<div class="row row-cards">
<div class="col-md-6">
<div class="card">
<div class="card-header"><strong>Clients Information</strong></div>
<div class="card-body">
<p><strong>First Name:</strong> <?= htmlspecialchars($client['first_name']) ?></p>
<p><strong>Last Name:</strong> <?= htmlspecialchars($client['last_name']) ?></p>
<p><strong>Company:</strong> <?= htmlspecialchars($client['company_name']) ?></p>
<p><strong>Email:</strong> <?= htmlspecialchars($client['email']) ?></p>
<p><strong>Phone:</strong> <?= htmlspecialchars($client['phone']) ?></p>
<p><strong>Address 1:</strong> <?= htmlspecialchars($client['address1']) ?></p>
<p><strong>Address 2:</strong> <?= htmlspecialchars($client['address2']) ?></p>
<p><strong>City:</strong> <?= htmlspecialchars($client['city']) ?></p>
<p><strong>State/Region:</strong> <?= htmlspecialchars($client['state']) ?></p>
<p><strong>Postcode:</strong> <?= htmlspecialchars($client['postcode']) ?></p>
<p><strong>Country:</strong> <?= htmlspecialchars($client['country']) ?></p>
</div>
</div>
</div>
<?php
?>
<div class="col-md-6">
<div class="card">
<div class="card-header"><strong>Invoices / Billing</strong></div>
<div class="card-body">
<p><strong>Paid:</strong> ₾<?= number_format($paid, 2) ?></p>
<p><strong>Draft:</strong> ₾<?= number_format($draft, 2) ?></p>
<p><strong>Unpaid / Due:</strong> ₾<?= number_format($unpaid_due, 2) ?></p>
<p><strong>Cancelled:</strong> ₾<?= number_format($cancelled, 2) ?></p>
<p><strong>Refunded:</strong> ₾<?= number_format($refunded, 2) ?></p>
<hr>
<p><strong>Gross Revenue:</strong> ₾<?= number_format($gross_revenue, 2) ?></p>
<p><strong>Net Income:</strong> ₾<?= number_format($net_income, 2) ?></p>
<p><strong>Credit Balance:</strong> ₾<?= number_format($credit_balance, 2) ?></p>
<div class="mt-3">
<a href="#" class="btn btn-outline-primary btn-sm"> Create Invoice</a>
<a href="#" class="btn btn-outline-success btn-sm"> Add Funds Invoice</a>
<a href="#" class="btn btn-outline-info btn-sm">🔁 Generate Due Invoices</a>
<a href="#" class="btn btn-outline-warning btn-sm">💳 Manage Credits</a>
<a href="/admin/billing/transactions/history.php?client_id=<?= $client['id'] ?>" class="btn btn-outline-warning btn-sm">ტრანზაქციების ისტორია</a>
</div>
</div>
</div>
</div>
</div>
<div class="row row-cards mt-4">
<div class="col-md-6">
<div class="card">
<div class="card-header"><strong>Admin Notes</strong></div>
<div class="card-body">
<p><?= nl2br(htmlspecialchars($client['admin_notes'])) ?></p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header"><strong>Products / Services</strong></div>
<div class="card-body">
<?php if (count($services) > 0): ?>
<ul class="list-group list-group-flush">
<?php foreach ($services as $service): ?>
<li class="list-group-item">
<strong><?= htmlspecialchars($service['product_name']) ?></strong>
- <?= number_format($service['amount'], 2) ?> ₾
<br>
<small class="text-muted"> <?= htmlspecialchars($service['description']) ?> </small>
<br>
<small class="text-muted"> თარიღი: <?= htmlspecialchars($service['issue_date']) ?> </small>
</li>
<?php endforeach ?>
</ul>
<?php else: ?>
<p class="text-muted">სერვისები არ მოიძებნა.</p>
<?php endif ?>
</div>
</div>
</div>
</div>
<?php require_once Config::includePath('footer.php'); ?>
+173
View File
@@ -0,0 +1,173 @@
<?php
require_once __DIR__ . '/../../../../vendor/autoload.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 -->
<h2 class="mb-4">ახალი კლიენტის დამატება</h2>
<form action="dashboard.php?module=clients&action=add" method="post">
<div class="row">
<!-- მარცხენა სვეტი -->
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">სახელი</label>
<input type="text" class="form-control" name="first_name" required>
</div>
<div class="mb-3">
<label class="form-label">გვარი</label>
<input type="text" class="form-control" name="last_name" required>
</div>
<div class="mb-3">
<label class="form-label">კომპანიის სახელი <span class="text-muted">(სურვილისამებრ)</span></label>
<input type="text" class="form-control" name="company">
</div>
<div class="mb-3">
<label class="form-label">საიდ. ნომ <span class="text-muted">(სურვილისამებრ)</span></label>
<input type="text" class="form-control" name="vat_number">
</div>
<div class="mb-3">
<label class="form-label">ელ-ფოსტა</label>
<input type="email" class="form-control" name="email" required>
</div>
<div class="mb-3">
<label class="form-label">პაროლი</label>
<div class="input-group">
<input type="text" class="form-control" id="password" name="password" required>
<button class="btn btn-outline-secondary" type="button" onclick="generatePassword()">გენერირება</button>
</div>
</div>
<div class="mb-3">
<label class="form-label">ენა</label>
<select class="form-select" name="language">
<option value="default">ნაგულისხმევი</option>
<option value="en">English</option>
<option value="ka">Georgian</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">სტატუსი</label>
<select class="form-select" name="status">
<option value="active">აქტიური</option>
<option value="inactive">გაუქმებული</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">ჯგუფი</label>
<select class="form-select" name="client_group">
<option value="none">ცარიელი</option>
<option value="vip">VIP</option>
<option value="reseller">Reseller</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">Email შეტყობინებები</label>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="emails[]" value="general" checked>
<label class="form-check-label">General Emails</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="emails[]" value="invoice" checked>
<label class="form-check-label">Invoice Emails</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="emails[]" value="support">
<label class="form-check-label">Support Emails</label>
</div>
<!-- სხვა Checkbox-ები შეგიძლია დაამატო ასე -->
</div>
</div>
<!-- მარჯვენა სვეტი -->
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">მისამართი 1</label>
<input type="text" class="form-control" name="address1">
</div>
<div class="mb-3">
<label class="form-label">მისამართი 2</label>
<input type="text" class="form-control" name="address2">
</div>
<div class="mb-3">
<label class="form-label">ქალაქი</label>
<input type="text" class="form-control" name="city">
</div>
<div class="mb-3">
<label class="form-label">შტატი/რეგიონი</label>
<input type="text" class="form-control" name="state">
</div>
<div class="mb-3">
<label class="form-label">საფოსტო ინდექსი</label>
<input type="text" class="form-control" name="postcode">
</div>
<div class="mb-3">
<label class="form-label">ქვეყანა</label>
<select class="form-select" name="country">
<option value="US">United States</option>
<option value="GE">საქართველო</option>
<!-- სხვა ქვეყნები -->
</select>
</div>
<div class="mb-3">
<label class="form-label">ტელეფონი</label>
<input type="text" class="form-control" name="phone">
</div>
<div class="mb-3">
<label class="form-label">გადახდის მეთოდი</label>
<select class="form-select" name="payment_method">
<option value="default">Default</option>
<option value="paypal">PayPal</option>
<option value="bank">საბანკო გადმორიცხვა</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">Billing Contact</label>
<select class="form-select" name="billing_contact">
<option value="default">Default</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">ვალუტა</label>
<select class="form-select" name="currency">
<option value="USD">USD</option>
<option value="GEL">GEL</option>
</select>
</div>
</div>
</div>
<div class="mb-3">
<label class="form-label">Admin ჩანაწერი</label>
<textarea class="form-control" name="admin_notes" rows="3"></textarea>
</div>
<div class="form-footer">
<button type="submit" class="btn btn-primary">დამატება</button>
</div>
</form>
</div>
</div>
<?php require_once Config::includePath('footer.php'); ?>
<script>
function generatePassword(length = 10) {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()";
let password = "";
for (let i = 0; i < length; i++) {
const randomIndex = Math.floor(Math.random() * charset.length);
password += charset[randomIndex];
}
document.getElementById('password').value = password;
}
</script>
@@ -0,0 +1,63 @@
<?php
require_once __DIR__ . '/../../../../vendor/autoload.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');
?>
<h2 class="mb-4">კლიენტის რედაქტირება</h2>
<form action="dashboard.php?module=clients&action=edit" method="POST">
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">First Name</label>
<input type="text" class="form-control" name="first_name" value="<?= htmlspecialchars($client['first_name']) ?>" required>
</div>
<div class="mb-3">
<label class="form-label">Last Name</label>
<input type="text" class="form-control" name="last_name" value="<?= htmlspecialchars($client['last_name']) ?>" required>
</div>
<div class="mb-3">
<label class="form-label">Company</label>
<input type="text" class="form-control" name="company" value="<?= htmlspecialchars($client['company_name']) ?>">
</div>
<div class="mb-3">
<label class="form-label">Email</label>
<input type="email" class="form-control" name="email" value="<?= htmlspecialchars($client['email']) ?>" required>
</div>
<div class="mb-3">
<label class="form-label">Phone</label>
<input type="text" class="form-control" name="phone" value="<?= htmlspecialchars($client['phone']) ?>">
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Status</label>
<select class="form-select" name="status">
<option value="active" <?= $client['status'] === 'active' ? 'selected' : '' ?>>Active</option>
<option value="inactive" <?= $client['status'] === 'inactive' ? 'selected' : '' ?>>Inactive</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">Client Group</label>
<input type="text" class="form-control" name="client_group" value="<?= htmlspecialchars($client['client_group']) ?>">
</div>
<div class="mb-3">
<label class="form-label">Admin Notes</label>
<textarea class="form-control" name="admin_notes" rows="5"><?= htmlspecialchars($client['admin_notes']) ?></textarea>
</div>
</div>
</div>
<div class="form-footer">
<button type="submit" class="btn btn-primary">შენახვა</button>
<a href="dashboard.php?module=clients&action=profile&id=<?= $client['id'] ?>" class="btn btn-secondary">გაუქმება</a>
</div>
</form>
<?php require_once Config::includePath('footer.php'); ?>
@@ -0,0 +1,58 @@
<?php
require_once __DIR__ . '/../../../../vendor/autoload.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 -->
<h2 class="mb-4">კლიენტების სია</h2>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Last Name</th>
<th>კომპანია</th>
<th>ელ.ფოსტა</th>
<th>ტელეფონი</th>
<th>შექმნის თარიღი</th>
<th>სტატუს</th>
</tr>
</thead>
<tbody>
<?php foreach ($clients as $client): ?>
<tr>
<td><?= htmlspecialchars($client['id']) ?></td>
<td><?= htmlspecialchars($client['first_name']) ?></td>
<td><?= htmlspecialchars($client['last_name']) ?></td>
<td><?= htmlspecialchars($client['company_name']) ?></td>
<td><?= htmlspecialchars($client['email']) ?></td>
<td><?= htmlspecialchars($client['phone']) ?></td>
<td><?= date('d/m/Y', strtotime($client['created_at'])) ?></td>
<td>
<span class="badge bg-light">
<?= strtoupper($client['status']) ?>
</span>
</td>
<td>
<a href="dashboard.php?module=clients&action=profile&id=<?= $client['id'] ?>" class="btn btn-sm btn-info">პროფილი</a>
<a href="dashboard.php?module=clients&action=edit&id=<?= $client['id'] ?>" class="btn btn-sm btn-warning">რედ.</a>
<a href="dashboard.php?module=clients&action=delete&id=<?= $client['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'); ?>