File manager - Edit - /home/webtrixia/.trash/licenses.1/admin/api.php
Back
<?php /** * ADMIN API — backend for the partner/license management UI. * All actions require the admin session (see auth.php). */ require_once dirname(__DIR__) . '/lib/core.php'; require_once __DIR__ . '/auth.php'; header('Content-Type: application/json; charset=utf-8'); try { $pdo = wt_db(); } catch (Throwable $e) { wt_err('Базата не е конфигурирана. Стартирай install.php', 500); } wt_require_admin(); // 401 if not logged in $action = $_GET['action'] ?? ''; $method = $_SERVER['REQUEST_METHOD']; switch ($action) { // ── DASHBOARD STATS ────────────────────────────────────────── case 'stats': { $today = date('Y-m-d'); $licenses = $pdo->query("SELECT * FROM licenses")->fetchAll(); $mrr = 0; $active = 0; $grace = 0; $locked = 0; foreach ($licenses as $l) { $st = wt_license_state($l, $today); if ($st['state'] === 'active') { $active++; } elseif ($st['state'] === 'grace') { $grace++; } else { $locked++; } if ($st['state'] !== 'locked') { $mrr += (float)$l['base_price']; $mods = json_decode($l['modules'] ?? '{}', true) ?: []; $catalog = wt_modules(); foreach ($mods as $m => $on) { if ($on && isset($catalog[$m])) $mrr += (float)$catalog[$m]['price']; } } } $partners = (int)$pdo->query("SELECT COUNT(*) FROM partners")->fetchColumn(); $overdue = (int)$pdo->query("SELECT COUNT(*) FROM invoices WHERE paid=0 AND due_date < CURDATE()")->fetchColumn(); wt_ok(['partners' => $partners, 'active' => $active, 'grace' => $grace, 'locked' => $locked, 'mrr' => round($mrr, 2), 'overdue' => $overdue]); } // ── LIST PARTNERS + THEIR LICENSE + STATE ──────────────────── case 'partners': { if ($method === 'GET') { $rows = $pdo->query(" SELECT p.*, l.id AS license_id, l.license_key, l.status, l.plan_name, l.base_price, l.currency, l.billing_cycle, l.valid_until, l.grace_days, l.modules, l.hub_url, l.last_check_at FROM partners p LEFT JOIN licenses l ON l.partner_id = p.id ORDER BY p.created_at DESC ")->fetchAll(); $today = date('Y-m-d'); foreach ($rows as &$r) { $r['modules'] = json_decode($r['modules'] ?? '{}', true) ?: []; if ($r['license_id']) { $r['computed'] = wt_license_state($r, $today); $inv = $pdo->prepare("SELECT COUNT(*) c, COALESCE(SUM(paid=0),0) unpaid FROM invoices WHERE license_id=?"); $inv->execute([$r['license_id']]); $r['invoice_summary'] = $inv->fetch(); } } wt_ok($rows); } wt_err('bad method'); } // ── CREATE PARTNER + ISSUE LICENSE (one step) ──────────────── case 'issue': { $b = wt_body(); if (empty($b['name'])) wt_err('Липсва име на клиента'); $pdo->beginTransaction(); try { $st = $pdo->prepare("INSERT INTO partners (name,email,phone,company,eik,notes) VALUES (?,?,?,?,?,?)"); $st->execute([$b['name'], $b['email'] ?? '', $b['phone'] ?? '', $b['company'] ?? '', $b['eik'] ?? '', $b['notes'] ?? '']); $partnerId = (int)$pdo->lastInsertId(); // unique key do { $key = wt_gen_key(); $c = $pdo->prepare("SELECT 1 FROM licenses WHERE license_key=?"); $c->execute([$key]); } while ($c->fetch()); $cycle = ($b['billing_cycle'] ?? 'monthly') === 'yearly' ? 'yearly' : 'monthly'; $price = (float)($b['base_price'] ?? 0); $grace = (int)($b['grace_days'] ?? 7); $modules = $b['modules'] ?? []; $validFrom = $b['start_date'] ?? date('Y-m-d'); $validUntil= wt_add_months($validFrom, 1, $cycle); $st = $pdo->prepare("INSERT INTO licenses (partner_id, license_key, status, plan_name, base_price, currency, billing_cycle, valid_until, grace_days, modules) VALUES (?,?,?,?,?,?,?,?,?,?)"); $st->execute([$partnerId, $key, 'active', $b['plan_name'] ?? 'Standard', $price, $b['currency'] ?? 'EUR', $cycle, $validUntil, $grace, json_encode($modules, JSON_UNESCAPED_UNICODE)]); $licId = (int)$pdo->lastInsertId(); // first invoice wt_create_invoice($pdo, $licId, $price, $b['currency'] ?? 'EUR', $validFrom, $validUntil); wt_log($pdo, $licId, 'issued', 'Лиценз издаден'); $pdo->commit(); wt_ok(['partner_id' => $partnerId, 'license_id' => $licId, 'license_key' => $key, 'valid_until' => $validUntil]); } catch (Throwable $e) { $pdo->rollBack(); wt_err('Грешка при издаване: ' . $e->getMessage(), 500); } } // ── UPDATE LICENSE (price, plan, grace, modules, cycle) ────── case 'update_license': { $b = wt_body(); $id = (int)($b['license_id'] ?? 0); if (!$id) wt_err('license_id'); $fields = ['plan_name','base_price','currency','billing_cycle','grace_days','notes']; $set = []; $vals = []; foreach ($fields as $f) if (array_key_exists($f, $b)) { $set[] = "$f=?"; $vals[] = $b[$f]; } if (isset($b['modules'])) { $set[] = "modules=?"; $vals[] = json_encode($b['modules'], JSON_UNESCAPED_UNICODE); } if ($set) { $vals[] = $id; $pdo->prepare("UPDATE licenses SET ".implode(',', $set)." WHERE id=?")->execute($vals); } wt_log($pdo, $id, 'updated', 'Промяна на лиценз'); wt_ok(true); } // ── SUSPEND / ACTIVATE / CANCEL ────────────────────────────── case 'set_status': { $b = wt_body(); $id = (int)($b['license_id'] ?? 0); $status = $b['status'] ?? ''; if (!$id || !in_array($status, ['active','suspended','cancelled'], true)) wt_err('bad params'); $pdo->prepare("UPDATE licenses SET status=? WHERE id=?")->execute([$status, $id]); wt_log($pdo, $id, 'status', 'Статус → ' . $status); wt_ok(true); } // ── EXTEND (advance valid_until by one cycle) ──────────────── case 'extend': { $b = wt_body(); $id = (int)($b['license_id'] ?? 0); if (!$id) wt_err('license_id'); $l = wt_get_license($pdo, $id); $base = max($l['valid_until'], date('Y-m-d')); $next = wt_add_months($base, 1, $l['billing_cycle']); $pdo->prepare("UPDATE licenses SET valid_until=?, status='active' WHERE id=?")->execute([$next, $id]); wt_log($pdo, $id, 'extend', 'Удължен до ' . $next); wt_ok(['valid_until' => $next]); } // ── GIVE EXTRA GRACE DAYS (bumps valid_until forward) ──────── case 'add_grace': { $b = wt_body(); $id = (int)($b['license_id'] ?? 0); $days = (int)($b['days'] ?? 0); if (!$id || $days <= 0) wt_err('bad params'); $l = wt_get_license($pdo, $id); $base = max($l['valid_until'], date('Y-m-d')); $next = date('Y-m-d', strtotime($base . ' +' . $days . ' days')); $pdo->prepare("UPDATE licenses SET valid_until=?, status='active' WHERE id=?")->execute([$next, $id]); wt_log($pdo, $id, 'grace', "+$days дни гратис → $next"); wt_ok(['valid_until' => $next]); } // ── INVOICES for a license ─────────────────────────────────── case 'invoices': { $id = (int)($_GET['license_id'] ?? 0); $rows = $pdo->prepare("SELECT * FROM invoices WHERE license_id=? ORDER BY issue_date DESC"); $rows->execute([$id]); wt_ok($rows->fetchAll()); } // ── MARK INVOICE PAID → extend license one cycle ───────────── case 'invoice_paid': { $b = wt_body(); $invId = (int)($b['invoice_id'] ?? 0); if (!$invId) wt_err('invoice_id'); $inv = $pdo->prepare("SELECT * FROM invoices WHERE id=?"); $inv->execute([$invId]); $invoice = $inv->fetch(); if (!$invoice) wt_err('not found', 404); $pdo->prepare("UPDATE invoices SET paid=1, paid_at=CURDATE() WHERE id=?")->execute([$invId]); // extend license & auto-generate next invoice $l = wt_get_license($pdo, (int)$invoice['license_id']); $base = max($l['valid_until'], date('Y-m-d')); $next = wt_add_months($base, 1, $l['billing_cycle']); $pdo->prepare("UPDATE licenses SET valid_until=?, status='active' WHERE id=?")->execute([$next, $l['id']]); wt_create_invoice($pdo, $l['id'], (float)$l['base_price'], $l['currency'], $base, $next); wt_log($pdo, $l['id'], 'paid', 'Фактура платена, удължен до ' . $next); wt_ok(['valid_until' => $next]); } // ── MANUAL: create an invoice ──────────────────────────────── case 'create_invoice': { $b = wt_body(); $id = (int)($b['license_id'] ?? 0); if (!$id) wt_err('license_id'); $l = wt_get_license($pdo, $id); $from = $b['issue_date'] ?? date('Y-m-d'); $to = $b['due_date'] ?? wt_add_months($from, 1, $l['billing_cycle']); wt_create_invoice($pdo, $id, (float)($b['amount'] ?? $l['base_price']), $l['currency'], $from, $to); wt_ok(true); } // ── DELETE partner (+ cascade license/invoices) ────────────── case 'delete_partner': { $b = wt_body(); $pid = (int)($b['partner_id'] ?? 0); if (!$pid) wt_err('partner_id'); $lics = $pdo->prepare("SELECT id FROM licenses WHERE partner_id=?"); $lics->execute([$pid]); foreach ($lics->fetchAll() as $l) { $pdo->prepare("DELETE FROM invoices WHERE license_id=?")->execute([$l['id']]); $pdo->prepare("DELETE FROM events WHERE license_id=?")->execute([$l['id']]); } $pdo->prepare("DELETE FROM licenses WHERE partner_id=?")->execute([$pid]); $pdo->prepare("DELETE FROM partners WHERE id=?")->execute([$pid]); wt_ok(true); } // ── EVENT LOG ──────────────────────────────────────────────── case 'events': { $id = (int)($_GET['license_id'] ?? 0); $rows = $pdo->prepare("SELECT * FROM events WHERE license_id=? ORDER BY created_at DESC LIMIT 40"); $rows->execute([$id]); wt_ok($rows->fetchAll()); } // ── MODULE CATALOG ─────────────────────────────────────────── case 'catalog': { wt_ok(wt_modules()); } default: wt_err('Unknown action: ' . $action, 404); } // ── helpers ────────────────────────────────────────────────── function wt_get_license(PDO $pdo, int $id): array { $s = $pdo->prepare("SELECT * FROM licenses WHERE id=?"); $s->execute([$id]); $l = $s->fetch(); if (!$l) wt_err('Лицензът не е намерен', 404); return $l; } function wt_create_invoice(PDO $pdo, int $licId, float $amount, string $cur, string $from, string $to): void { $num = 'ЛФ-' . date('Y') . '-' . str_pad((string)((int)$pdo->query("SELECT COUNT(*) FROM invoices")->fetchColumn() + 1), 5, '0', STR_PAD_LEFT); $st = $pdo->prepare("INSERT INTO invoices (license_id, number, period_label, amount, currency, issue_date, due_date) VALUES (?,?,?,?,?,?,?)"); $st->execute([$licId, $num, $from . ' → ' . $to, $amount, $cur, $from, $to]); }
| ver. 1.4 |
Github
|
.
| PHP 8.2.31 | Generation time: 0 |
proxy
|
phpinfo
|
Settings