From 096a24971d0d665c31ebd3209d6c46c2999868ac Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sat, 28 Feb 2026 19:07:09 +0000 Subject: [PATCH] v27 --- db/migrations/11_startup_financials.sql | 6 + start_funding.php | 192 +++++++++++++++++------- startup_details.php | 51 +++++-- 3 files changed, 179 insertions(+), 70 deletions(-) create mode 100644 db/migrations/11_startup_financials.sql diff --git a/db/migrations/11_startup_financials.sql b/db/migrations/11_startup_financials.sql new file mode 100644 index 0000000..4203365 --- /dev/null +++ b/db/migrations/11_startup_financials.sql @@ -0,0 +1,6 @@ +-- Migration: Add financial and return rate fields to startups table +ALTER TABLE startups +ADD COLUMN equity_structure TEXT AFTER description, +ADD COLUMN financial_doc_path VARCHAR(255) AFTER industry, +ADD COLUMN recommended_return_rate DECIMAL(5, 2) AFTER followers_count, +ADD COLUMN founder_return_rate DECIMAL(5, 2) AFTER recommended_return_rate; diff --git a/start_funding.php b/start_funding.php index 37001c0..19985db 100644 --- a/start_funding.php +++ b/start_funding.php @@ -6,6 +6,7 @@ if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'founder') { } require_once __DIR__ . '/db/config.php'; +require_once __DIR__ . '/ai/LocalAIApi.php'; $error = ''; $success = ''; @@ -35,37 +36,90 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $name = trim($_POST['name'] ?? ''); $description = trim($_POST['description'] ?? ''); $industry = trim($_POST['industry'] ?? ''); + $equity_structure = trim($_POST['equity_structure'] ?? ''); $target = (float)($_POST['funding_target'] ?? 0); $status = $_POST['status'] ?? 'public'; + $founder_return_rate = isset($_POST['founder_return_rate']) && $_POST['founder_return_rate'] !== '' ? (float)$_POST['founder_return_rate'] : null; - if ((!$existingStartup && (empty($name) || empty($description) || empty($industry))) || $target < 50) { - $error = "Please fill in all required fields. Minimum target is £50."; - } else { - db()->beginTransaction(); - try { - if ($existingStartup) { - // Just create a new round for existing startup - $stmt = db()->prepare("INSERT INTO funding_rounds (startup_id, funding_goal, status) VALUES (?, ?, 'Active')"); - $stmt->execute([$existingStartup['id'], $target]); - $final_id = $existingStartup['id']; - } else { - // 1. Insert startup - $stmt = db()->prepare("INSERT INTO startups (name, description, industry, founder_id, funding_target, status) VALUES (?, ?, ?, ?, ?, ?)"); - $stmt->execute([$name, $description, $industry, $_SESSION['user_id'], $target, $status]); - $new_startup_id = db()->lastInsertId(); - - // 2. Insert initial funding round - $stmt = db()->prepare("INSERT INTO funding_rounds (startup_id, funding_goal, status) VALUES (?, ?, 'Active')"); - $stmt->execute([$new_startup_id, $target]); - $final_id = $new_startup_id; - } + // Financial Document Upload + $financial_doc_path = ''; + if (isset($_FILES['financial_doc']) && $_FILES['financial_doc']['error'] === UPLOAD_ERR_OK) { + $upload_dir = 'assets/docs/financials/'; + if (!is_dir($upload_dir)) { + mkdir($upload_dir, 0775, true); + } + $file_ext = pathinfo($_FILES['financial_doc']['name'], PATHINFO_EXTENSION); + $file_name = uniqid('fin_', true) . '.' . $file_ext; + $dest_path = $upload_dir . $file_name; + + if (move_uploaded_file($_FILES['financial_doc']['tmp_name'], $dest_path)) { + $financial_doc_path = $dest_path; + } else { + $error = "Failed to upload financial documentation."; + } + } elseif (!$existingStartup) { + $error = "Financial documentation is mandatory for new startups."; + } + + if (!$error) { + if ((!$existingStartup && (empty($name) || empty($description) || empty($industry) || empty($equity_structure) || empty($financial_doc_path))) || $target < 50) { + $error = "Please fill in all required fields and upload financial documents. Minimum target is £50."; + } else { + // AI Calculation for Recommended Return Rate + $recommended_return_rate = 5.0; // Default fallback - db()->commit(); - $success = "Funding round is now active!"; - header("refresh:2;url=startup_details.php?id=" . $final_id); - } catch (PDOException $e) { - db()->rollBack(); - $error = "Database error: " . $e->getMessage(); + $prompt = "As a financial analyst for a startup investment platform, calculate a recommended annual dividend yield (interest percentage) for the following startup. + Startup Name: {$name} + Industry: {$industry} + Description: {$description} + Funding Target: £{$target} + Equity Structure: {$equity_structure} + + Respond ONLY with a JSON object containing a single key 'recommended_rate' with a numeric value (percentage). Example: {\"recommended_rate\": 8.5}"; + + $aiResponse = LocalAIApi::createResponse([ + 'input' => [['role' => 'system', 'content' => 'You are a professional financial analyst. Return JSON only.'], + ['role' => 'user', 'content' => $prompt], + ], + ]); + + if (!empty($aiResponse['success'])) { + $decoded = LocalAIApi::decodeJsonFromResponse($aiResponse); + if (isset($decoded['recommended_rate'])) { + $recommended_return_rate = (float)$decoded['recommended_rate']; + } + } + + db()->beginTransaction(); + try { + if ($existingStartup) { + // Update existing startup with new return rates if provided + $stmt = db()->prepare("UPDATE startups SET recommended_return_rate = ?, founder_return_rate = ? WHERE id = ?"); + $stmt->execute([$recommended_return_rate, $founder_return_rate, $existingStartup['id']]); + + // Create a new round + $stmt = db()->prepare("INSERT INTO funding_rounds (startup_id, funding_goal, status) VALUES (?, ?, 'Active')"); + $stmt->execute([$existingStartup['id'], $target]); + $final_id = $existingStartup['id']; + } else { + // 1. Insert startup with new fields + $stmt = db()->prepare("INSERT INTO startups (name, description, industry, equity_structure, financial_doc_path, founder_id, funding_target, status, recommended_return_rate, founder_return_rate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + $stmt->execute([$name, $description, $industry, $equity_structure, $financial_doc_path, $_SESSION['user_id'], $target, $status, $recommended_return_rate, $founder_return_rate]); + $new_startup_id = db()->lastInsertId(); + + // 2. Insert initial funding round + $stmt = db()->prepare("INSERT INTO funding_rounds (startup_id, funding_goal, status) VALUES (?, ?, 'Active')"); + $stmt->execute([$new_startup_id, $target]); + $final_id = $new_startup_id; + } + + db()->commit(); + $success = "Startup successfully listed with a recommended return rate of " . number_format($recommended_return_rate, 2) . "%!"; + header("refresh:3;url=startup_details.php?id=" . $final_id); + } catch (PDOException $e) { + db()->rollBack(); + $error = "Database error: " . $e->getMessage(); + } } } } @@ -77,55 +131,70 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby'; - <?= $existingStartup ? 'Start New Round' : 'Start Funding Round' ?> — <?= htmlspecialchars($platformName) ?> + <?= $existingStartup ? 'Start New Round' : 'Launch Startup' ?> — <?= htmlspecialchars($platformName) ?> -
-

+
+

- +

- +
- +
-
+ -
- - +
+
+ + +
+
+ + +
+
- - + +
+
- - + +
-
+ +
+ + + Upload revenue statements, projections, or balance sheets. +
+ +
- Min investment per user will be £50. +
+
+ + +
+
+ + +
- + Cancel
- \ No newline at end of file + diff --git a/startup_details.php b/startup_details.php index 21b6456..e1e4b1b 100644 --- a/startup_details.php +++ b/startup_details.php @@ -75,7 +75,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { $title = $_POST['update_title'] ?? ''; $content = $_POST['update_content'] ?? ''; if ($title && $content) { - // FIX: Added founder_id to the query to avoid 500 error $stmt = db()->prepare("INSERT INTO startup_updates (startup_id, founder_id, title, content) VALUES (?, ?, ?, ?)"); $stmt->execute([$startup_id, $user_id, $title, $content]); @@ -99,21 +98,17 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { } elseif ($_POST['action'] === 'cancel_round' && $user['role'] === 'founder' && $startup['founder_id'] == $user_id) { db()->beginTransaction(); try { - // Find active round $stmt = db()->prepare("SELECT id FROM funding_rounds WHERE startup_id = ? AND status = 'Active'"); $stmt->execute([$startup_id]); $round = $stmt->fetch(); if ($round) { - // Cancel round $stmt = db()->prepare("UPDATE funding_rounds SET status = 'Cancelled' WHERE id = ?"); $stmt->execute([$round['id']]); - // Refund all investments in this round $stmt = db()->prepare("UPDATE investments SET status = 'Refunded' WHERE funding_round_id = ?"); $stmt->execute([$round['id']]); - // Deduct from startup total raised $stmt = db()->prepare("SELECT SUM(amount) as total FROM investments WHERE funding_round_id = ? AND status = 'Refunded'"); $stmt->execute([$round['id']]); $totalRefunded = $stmt->fetch()['total'] ?? 0; @@ -124,7 +119,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { db()->commit(); $success = "Funding round cancelled and all investments marked for refund."; - // Refresh data $stmt = db()->prepare("SELECT * FROM startups WHERE id = ?"); $stmt->execute([$startup_id]); $startup = $stmt->fetch(); @@ -143,10 +137,8 @@ $stmt = db()->prepare("SELECT * FROM funding_rounds WHERE startup_id = ? AND sta $stmt->execute([$startup_id]); $activeRound = $stmt->fetch(); -// Permission check for Funding History: Founders see their own, Investors see all. $canSeeHistory = ($user['role'] === 'investor' || ($user['role'] === 'founder' && $startup['founder_id'] == $user_id)); -// Fetch Funding History $fundingHistory = []; if ($canSeeHistory) { $stmt = db()->prepare(" @@ -224,6 +216,7 @@ if ($canSeeHistory) {

+ Founded
@@ -246,6 +239,34 @@ if ($canSeeHistory) {

+ +
+

Equity Structure

+

+
+ + + +
+

+ Expected Investor Returns +

+
+
+
Platform Recommendation
+
%
+
Based on financial analysis & industry benchmarks
+
+
+
Founder's Proposal
+
+ +
+
Target annual dividend yield set by founder
+
+
+
+
@@ -359,7 +380,7 @@ if ($canSeeHistory) {
Total Raised All-Time
-
+
Investments
@@ -373,6 +394,12 @@ if ($canSeeHistory) {
Stage
+ + + + View Financial Docs + + @@ -434,11 +461,11 @@ if ($canSeeHistory) { ?>
- +
-
+
Send Message @@ -459,4 +486,4 @@ if ($canSeeHistory) { - \ No newline at end of file +