Hapa kuna mwongozo wa kitaalamu lakini rahisi wa kutengeneza mfumo wa mauzo (Sales Management System) kwa kutumia PHP + MySQL. Nitakupa: muundo wa database, faili za PHP muhimu (connection, kuingiza bidhaa, kuuza, ripoti), vidokezo vya usalama, na mtazamo wa vipengele vingine unavyoweza kuongeza.
FUNGUA ACCOUNT HAPA UANZE KUFANYA MAUZO https://www.faulink.com/mauzologin.php

Unaweza kumnakili & kubandika moja kwa moja kwenye mfumo wako na kurekebisha kwa mahitaji yako.

1. Mahitaji

PHP 7.4+ (au mpya)

MySQL / MariaDB

Web server (Apache/Nginx) au XAMPP/WAMP/LAMP

Bootstrap (kwa UI ikiwa ungependa)

2. Muundo wa Database (SQL)

Tengeneza database (mfano: mauzo_db) kisha run SQL hizi:

CREATE DATABASE mauzo_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE mauzo_db;

-- Table: products
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
sku VARCHAR(50) UNIQUE,
name VARCHAR(255) NOT NULL,
price DECIMAL(10,2) NOT NULL,
stock INT NOT NULL DEFAULT 0,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Table: customers
CREATE TABLE customers (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
phone VARCHAR(50),
email VARCHAR(150),
address TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Table: sales (invoices)
CREATE TABLE sales (
id INT AUTO_INCREMENT PRIMARY KEY,
customer_id INT,
total DECIMAL(12,2) NOT NULL,
paid DECIMAL(12,2) DEFAULT 0,
sale_date DATETIME DEFAULT CURRENT_TIMESTAMP,
note TEXT,
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE SET NULL
);

-- Table: sale_items (line items)
CREATE TABLE sale_items (
id INT AUTO_INCREMENT PRIMARY KEY,
sale_id INT NOT NULL,
product_id INT NOT NULL,
qty INT NOT NULL,
unit_price DECIMAL(10,2) NOT NULL,
subtotal DECIMAL(12,2) NOT NULL,
FOREIGN KEY (sale_id) REFERENCES sales(id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(id)
);

3. db.php — Muunganisho wa Database (Reusable)

FUNGUA ACCOUNT HAPA UANZE KUFANYA MAUZO https://www.faulink.com/mauzologin.php

Tengeneza fayl db.php ili kuunganisha na DB (tumia prepared statements kwa usalama):

<?php
// db.php
$host = 'localhost';
$db = 'mauzo_db';
$user = 'root';
$pass = ''; // badilisha kama una password
$charset = 'utf8mb4';

$mysqli = new mysqli($host, $user, $pass, $db);
if ($mysqli->connect_errno) {
die("Connection failed: " . $mysqli->connect_error);
}
$mysqli->set_charset($charset);

4. Ongeza Bidhaa (Add Product) — add_product.php

HTML form + PHP insert.

<?php
// add_product.php
require 'db.php';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$sku = $mysqli->real_escape_string($_POST['sku']);
$name = $mysqli->real_escape_string($_POST['name']);
$price = floatval($_POST['price']);
$stock = intval($_POST['stock']);
$desc = $mysqli->real_escape_string($_POST['description']);

$stmt = $mysqli->prepare("INSERT INTO products (sku,name,price,stock,description) VALUES (?,?,?,?,?)");
$stmt->bind_param('ssdiss', $sku, $name, $price, $stock, $desc);
if ($stmt->execute()) {
$msg = "Product added successfully.";
} else {
$msg = "Error: " . $stmt->error;
}
$stmt->close();
}
?>
<!-- Simple form -->
<form method="post">
<input name="sku" placeholder="SKU (unique)" required>
<input name="name" placeholder="Product name" required>
<input name="price" type="number" step="0.01" placeholder="Price" required>
<input name="stock" type="number" placeholder="Stock" required>
<textarea name="description" placeholder="Description">
<button type="submit">Add Product</button>
</form>
<?php if (!empty($msg)) echo "<p>$msg</p>"; ?>
Kumbuka: kwa production, tumia validation za upande wa server & client, na usiweke real_escape_string peke yake — tumia prepared statements kwa kila insert/update.

5. Fanya Mauzo (Create Sale) — create_sale.php
Hii ni sehemu muhimu: kuunda sale record, kuingiza sale_items, na kupunguza stock. Tumia transaction ili kuhakikisha atomicity.

php
Copy code
<?php
// create_sale.php
require 'db.php';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$customer_id = !empty($_POST['customer_id']) ? intval($_POST['customer_id']) : null;
$items = $_POST['items']; // expect array of ['product_id'=>..,'qty'=>..]
$note = $mysqli->real_escape_string($_POST['note']);
$total = 0;

// calculate total
foreach ($items as $it) {
$pid = intval($it['product_id']);
$qty = intval($it['qty']);
// fetch price
$res = $mysqli->query("SELECT price,stock FROM products WHERE id = $pid");
$row = $res->fetch_assoc();
$price = $row['price'];
if ($qty > $row['stock']) {
die("Insufficient stock for product id $pid");
}
$total += $price * $qty;
}

// start transaction
$mysqli->begin_transaction();

try {
// insert into sales
$stmt = $mysqli->prepare("INSERT INTO sales (customer_id,total,paid,note) VALUES (?,?,0,?)");
$stmt->bind_param('ids', $customer_id, $total, $note);
$stmt->execute();
$sale_id = $stmt->insert_id;
$stmt->close();

// insert sale_items and update stock
$stmtItem = $mysqli->prepare("INSERT INTO sale_items (sale_id,product_id,qty,unit_price,subtotal) VALUES (?,?,?,?,?)");
$stmtUpd = $mysqli->prepare("UPDATE products SET stock = stock - ? WHERE id = ?");
foreach ($items as $it) {
$pid = intval($it['product_id']);
$qty = intval($it['qty']);
$res = $mysqli->query("SELECT price FROM products WHERE id = $pid");
$row = $res->fetch_assoc();
$price = $row['price'];
$subtotal = $price * $qty;

$stmtItem->bind_param('iiidd', $sale_id, $pid, $qty, $price, $subtotal);
$stmtItem->execute();

$stmtUpd->bind_param('ii', $qty, $pid);
$stmtUpd->execute();
}
$stmtItem->close();
$stmtUpd->close();

$mysqli->commit();
echo "Sale created. Invoice ID: $sale_id";
} catch (Exception $e) {
$mysqli->rollback();
echo "Error: " . $e->getMessage();
}
}
?>
<!-- A simple example form structure (use JS to add multiple items) -->
<form method="post">
<input name="customer_id" placeholder="Customer ID (optional)">
<div id="items">
<div class="item">
<input name="items[0][product_id]" placeholder="Product ID" required>
<input name="items[0][qty]" type="number" placeholder="Qty" required>
</div>
</div>
<button type="button" onclick="addItem()">Add another item</button>
<textarea name="note" placeholder="Note"></textarea>
<button type="submit">Create Sale</button>
</form>

<script>
let idx = 1;
function addItem(){
const div = document.createElement('div');
div.className = 'item';
div.innerHTML = `<input name="items[${idx}][product_id]" placeholder="Product ID" required>
<input name="items[${idx}][qty]" type="number" placeholder="Qty" required>`;
document.getElementById('items').appendChild(div);
idx++;
}
</script>
6. Orodha ya Mauzo (List Sales) — list_sales.php
Ripoti rahisi ya mauzo:

php
Copy code
<?php
// list_sales.php
require 'db.php';

$result = $mysqli->query("SELECT s.*, c.name as customer_name FROM sales s LEFT JOIN customers c ON s.customer_id = c.id ORDER BY sale_date DESC");
echo "<table border='1'>
<tr><th>ID</th><th>Date</th><th>Customer</th><th>Total</th><th>Paid</th><th>Actions</th></tr>";
while ($row = $result->fetch_assoc()) {
echo "<tr>
<td>{$row['id']}</td>
<td>{$row['sale_date']}</td>
<td>".htmlspecialchars($row['customer_name'])."</td>
<td>{$row['total']}</td>
<td>{$row['paid']}</td>
<td><a href='view_invoice.php?id={$row['id']}'>View</a></td>
</tr>";
}
echo "</table>";
view_invoice.php utaonyesha line items kwa kutumia sale_items table.

7. Ripoti za Kuonyesha (Reports)
Mfano: Mauzo kwa tarehe (date range).

php
Copy code
<?php
// report_sales_by_date.php
require 'db.php';
$from = $_GET['from'] ?? date('Y-m-01');
$to = $_GET['to'] ?? date('Y-m-d');

$stmt = $mysqli->prepare("SELECT SUM(total) as total_sales, COUNT(*) as invoices FROM sales WHERE DATE(sale_date) BETWEEN ? AND ?");
$stmt->bind_param('ss', $from, $to);
$stmt->execute();
$res = $stmt->get_result()->fetch_assoc();

echo "From: $from To: $to <br>";
echo "Total Sales: " . ($res['total_sales'] ?? 0) . "<br>";
echo "Num Invoices: " . ($res['invoices'] ?? 0) . "<br>";
8. Vipengele Zaidi (Optional / Zaidi ya Kumbuka)
Authentication: ongeza login na user roles (admin, cashier).

POS Interface: UI ya kugusa kwa cashier.

Payments: link kwa payments (mpesa, card).

Reports: daily, monthly, product performance, low stock alerts.

Export: CSV/Excel export (use fputcsv() au PhpSpreadsheet).

Invoices/Receipts: PDF generation (use TCPDF au DomPDF).

Audit Logs: rekodi user actions.

Security: Prepared statements, CSRF tokens, XSS escaping (htmlspecialchars), input validation, proper session management (regenerate session id).

9. Usalama & Best Practices
Tumia prepared statements kila mahali (imeonyeshwa kwa mfano).

Usihifadhi password bila hashing — kwa user accounts tumia password_hash() na password_verify().

Tumia HTTPS kwenye server.

Sanitize & validate inputs.

Tumia transactions unapobadilisha inventory & sales.

Add indexes kwenye columns zinazotumika mara kwa mara (product_id, sale_date).

10. UI & UX (Mfano wa HTML + Bootstrap)
Kwa UI nzuri tumia Bootstrap — navbar ya blog yako tayari inaonekana pro; tumia style hiyo kwenye pages zako za dashboard.

11. Mfano wa Flow (Summary ya Kod)
Admin anaingiza bidhaa (add_product.php).

Cashier anaunda sale (create_sale.php) — system itahifadhi sales na sale_items, na kupunguza stock.

Msimamizi anaangalia ripoti (report_sales_by_date.php) au list_sales.

Mfumo una alerts kwa low stock (SELECT COUNT WHERE stock <= threshold).

12. Links Za Kujifunza Zaidi
🌐 Faulink Official Website: https://www.faulink.com/
📘 Jifunze Web Design & Programming: https://www.faulink.com/excel_mifumo.php
📲 Piga / WhatsApp kwa msaada wa haraka: https://wa.me/255693118509