Jinsi ya Kutengeneza Mfumo wa Mauzo kwa PHP | HATUA KWA HATUA
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