کانال نوحه و مداحی ناب

api های ساماتنه جامع انبارداری و مدیریت کالا

در اینجا API های کامل برای مدیریت سیستم انبارداری ارائه می‌دهم:

1. فایل پیکربندی (config.php)

php
<?php
header("Content-Type: application/json; charset=utf-8");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");

if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
    exit(0);
}

// تنظیمات دیتابیس
define('DB_HOST', 'localhost');
define('DB_USER', 'username');
define('DB_PASS', 'password');
define('DB_NAME', 'warehouse_system');
define('DB_CHARSET', 'utf8mb4');

// تابع اتصال به دیتابیس
function getDBConnection() {
    $conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
    if ($conn->connect_error) {
        http_response_code(500);
        echo json_encode(['success' => false, 'message' => 'Database connection failed']);
        exit;
    }
    $conn->set_charset(DB_CHARSET);
    return $conn;
}

// تابع پاسخ استاندارد
function sendResponse($success, $data = null, $message = '', $statusCode = 200) {
    http_response_code($statusCode);
    echo json_encode([
        'success' => $success,
        'message' => $message,
        'data' => $data,
        'timestamp' => date('Y-m-d H:i:s')
    ], JSON_UNESCAPED_UNICODE);
    exit;
}

// تابع اعتبارسنجی
function validateToken() {
    $headers = getallheaders();
    $token = isset($headers['Authorization']) ? str_replace('Bearer ', '', $headers['Authorization']) : '';
    
    if (empty($token)) {
        sendResponse(false, null, 'Access token required', 401);
    }
    
    return true;
}
?>

2. API مدیریت محصولات (products_api.php)

php
<?php
include 'config.php';

$method = $_SERVER['REQUEST_METHOD'];
$conn = getDBConnection();

switch ($method) {
    case 'GET':
        getProducts();
        break;
    case 'POST':
        addProduct();
        break;
    case 'PUT':
        updateProduct();
        break;
    case 'DELETE':
        deleteProduct();
        break;
}

function getProducts() {
    global $conn;
    
    $productId = $_GET['product_id'] ?? null;
    $categoryId = $_GET['category_id'] ?? null;
    $barcode = $_GET['barcode'] ?? null;
    $isActive = $_GET['is_active'] ?? 1;
    $page = $_GET['page'] ?? 1;
    $limit = $_GET['limit'] ?? 20;
    $offset = ($page - 1) * $limit;
    
    $query = "
        SELECT 
            p.*,
            c.CategoryName,
            u.UnitName,
            SUM(i.AvailableQuantity) as TotalStock,
            COUNT(i.InventoryID) as StockLocations
        FROM Products p
        LEFT JOIN ProductCategories c ON p.CategoryID = c.CategoryID
        LEFT JOIN Units u ON p.UnitID = u.UnitID
        LEFT JOIN Inventory i ON p.ProductID = i.ProductID
        WHERE p.IsActive = ?
    ";
    
    $params = [$isActive];
    $types = "i";
    
    if ($productId) {
        $query .= " AND p.ProductID = ?";
        $params[] = $productId;
        $types .= "i";
    }
    
    if ($categoryId) {
        $query .= " AND p.CategoryID = ?";
        $params[] = $categoryId;
        $types .= "i";
    }
    
    if ($barcode) {
        $query .= " AND p.Barcode = ?";
        $params[] = $barcode;
        $types .= "s";
    }
    
    $query .= " GROUP BY p.ProductID";
    
    // گرفتن تعداد کل
    $countQuery = "SELECT COUNT(*) as total FROM Products WHERE IsActive = ?";
    $countStmt = $conn->prepare($countQuery);
    $countStmt->bind_param("i", $isActive);
    $countStmt->execute();
    $totalResult = $countStmt->get_result();
    $total = $totalResult->fetch_assoc()['total'];
    
    $query .= " LIMIT ? OFFSET ?";
    $params[] = $limit;
    $params[] = $offset;
    $types .= "ii";
    
    $stmt = $conn->prepare($query);
    $stmt->bind_param($types, ...$params);
    $stmt->execute();
    $result = $stmt->get_result();
    
    $products = [];
    while ($row = $result->fetch_assoc()) {
        $products[] = $row;
    }
    
    sendResponse(true, [
        'products' => $products,
        'pagination' => [
            'page' => intval($page),
            'limit' => intval($limit),
            'total' => $total,
            'pages' => ceil($total / $limit)
        ]
    ], 'Products retrieved successfully');
}

function addProduct() {
    global $conn;
    
    $data = json_decode(file_get_contents("php://input"), true);
    
    $required = ['ProductCode', 'ProductName', 'CategoryID', 'UnitID'];
    foreach ($required as $field) {
        if (!isset($data[$field]) || empty($data[$field])) {
            sendResponse(false, null, "Field $field is required", 400);
        }
    }
    
    $query = "
        INSERT INTO Products (
            ProductCode, Barcode, ProductName, ProductDescription, CategoryID, UnitID,
            Brand, Model, Specifications, Weight, Dimensions, Volume,
            MinStockLevel, MaxStockLevel, ReorderPoint, SafetyStock,
            IsBatchTracked, IsSerialTracked, IsExpiryTracked, ShelfLife, StorageConditions
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    ";
    
    $specifications = isset($data['Specifications']) ? json_encode($data['Specifications']) : null;
    
    $stmt = $conn->prepare($query);
    $stmt->bind_param(
        "ssssiisssddddddddiiis",
        $data['ProductCode'], $data['Barcode'] ?? null, $data['ProductName'],
        $data['ProductDescription'] ?? null, $data['CategoryID'], $data['UnitID'],
        $data['Brand'] ?? null, $data['Model'] ?? null, $specifications,
        $data['Weight'] ?? 0, $data['Dimensions'] ?? null, $data['Volume'] ?? 0,
        $data['MinStockLevel'] ?? 0, $data['MaxStockLevel'] ?? 0,
        $data['ReorderPoint'] ?? 0, $data['SafetyStock'] ?? 0,
        $data['IsBatchTracked'] ?? 0, $data['IsSerialTracked'] ?? 0,
        $data['IsExpiryTracked'] ?? 0, $data['ShelfLife'] ?? null,
        $data['StorageConditions'] ?? null
    );
    
    if ($stmt->execute()) {
        sendResponse(true, ['product_id' => $stmt->insert_id], 'Product added successfully', 201);
    } else {
        sendResponse(false, null, 'Failed to add product: ' . $stmt->error, 500);
    }
}

function updateProduct() {
    global $conn;
    
    $data = json_decode(file_get_contents("php://input"), true);
    $productId = $_GET['product_id'] ?? $data['product_id'];
    
    if (!$productId) {
        sendResponse(false, null, 'Product ID is required', 400);
    }
    
    $fields = [];
    $params = [];
    $types = "";
    
    $updatableFields = [
        'ProductName', 'ProductDescription', 'CategoryID', 'UnitID', 'Barcode',
        'Brand', 'Model', 'Weight', 'Dimensions', 'Volume',
        'MinStockLevel', 'MaxStockLevel', 'ReorderPoint', 'SafetyStock',
        'IsBatchTracked', 'IsSerialTracked', 'IsExpiryTracked', 'ShelfLife',
        'StorageConditions', 'IsActive'
    ];
    
    foreach ($updatableFields as $field) {
        if (isset($data[$field])) {
            $fields[] = "$field = ?";
            $params[] = $data[$field];
            $types .= "s";
        }
    }
    
    if (isset($data['Specifications'])) {
        $fields[] = "Specifications = ?";
        $params[] = json_encode($data['Specifications']);
        $types .= "s";
    }
    
    if (empty($fields)) {
        sendResponse(false, null, 'No fields to update', 400);
    }
    
    $params[] = $productId;
    $types .= "i";
    
    $query = "UPDATE Products SET " . implode(", ", $fields) . " WHERE ProductID = ?";
    $stmt = $conn->prepare($query);
    $stmt->bind_param($types, ...$params);
    
    if ($stmt->execute()) {
        sendResponse(true, null, 'Product updated successfully');
    } else {
        sendResponse(false, null, 'Failed to update product: ' . $stmt->error, 500);
    }
}
?>

3. API مدیریت موجودی (inventory_api.php)

php
<?php
include 'config.php';

$method = $_SERVER['REQUEST_METHOD'];
$conn = getDBConnection();

switch ($method) {
    case 'GET':
        getInventory();
        break;
    case 'POST':
        updateInventory();
        break;
}

function getInventory() {
    global $conn;
    
    $productId = $_GET['product_id'] ?? null;
    $warehouseId = $_GET['warehouse_id'] ?? null;
    $zoneId = $_GET['zone_id'] ?? null;
    $showLowStock = $_GET['show_low_stock'] ?? false;
    $showExpired = $_GET['show_expired'] ?? false;
    
    $query = "
        SELECT 
            i.*,
            p.ProductCode, p.ProductName, p.Barcode,
            w.WarehouseName, w.WarehouseCode,
            z.ZoneName, z.ZoneCode,
            DATEDIFF(i.ExpiryDate, CURDATE()) as DaysToExpiry
        FROM Inventory i
        INNER JOIN Products p ON i.ProductID = p.ProductID
        INNER JOIN Warehouses w ON i.WarehouseID = w.WarehouseID
        INNER JOIN WarehouseZones z ON i.ZoneID = z.ZoneID
        WHERE i.Quantity > 0
    ";
    
    $params = [];
    $types = "";
    
    if ($productId) {
        $query .= " AND i.ProductID = ?";
        $params[] = $productId;
        $types .= "i";
    }
    
    if ($warehouseId) {
        $query .= " AND i.WarehouseID = ?";
        $params[] = $warehouseId;
        $types .= "i";
    }
    
    if ($zoneId) {
        $query .= " AND i.ZoneID = ?";
        $params[] = $zoneId;
        $types .= "i";
    }
    
    if ($showLowStock) {
        $query .= " AND p.MinStockLevel > 0 AND i.AvailableQuantity <= p.MinStockLevel";
    }
    
    if ($showExpired) {
        $query .= " AND i.ExpiryDate IS NOT NULL AND i.ExpiryDate < CURDATE()";
    }
    
    $query .= " ORDER BY p.ProductName, i.ExpiryDate";
    
    $stmt = $conn->prepare($query);
    if (!empty($params)) {
        $stmt->bind_param($types, ...$params);
    }
    $stmt->execute();
    $result = $stmt->get_result();
    
    $inventory = [];
    while ($row = $result->fetch_assoc()) {
        $inventory[] = $row;
    }
    
    // محاسبه خلاصه موجودی
    $summaryQuery = "
        SELECT 
            COUNT(DISTINCT i.ProductID) as TotalProducts,
            SUM(i.Quantity) as TotalQuantity,
            SUM(i.TotalValue) as TotalValue,
            COUNT(CASE WHEN i.ExpiryDate < CURDATE() THEN 1 END) as ExpiredItems
        FROM Inventory i
        WHERE i.Quantity > 0
    ";
    
    $summaryResult = $conn->query($summaryQuery);
    $summary = $summaryResult->fetch_assoc();
    
    sendResponse(true, [
        'inventory' => $inventory,
        'summary' => $summary
    ], 'Inventory data retrieved successfully');
}

function updateInventory() {
    global $conn;
    
    $data = json_decode(file_get_contents("php://input"), true);
    $action = $data['action'] ?? 'adjust';
    
    switch ($action) {
        case 'reserve':
            reserveStock($data);
            break;
        case 'release':
            releaseStock($data);
            break;
        case 'transfer':
            transferStock($data);
            break;
        default:
            adjustStock($data);
    }
}

function reserveStock($data) {
    global $conn;
    
    $productId = $data['product_id'];
    $quantity = $data['quantity'];
    $referenceType = $data['reference_type']; // 'order', 'issue', etc.
    $referenceId = $data['reference_id'];
    
    $conn->begin_transaction();
    
    try {
        // پیدا کردن موجودی قابل رزرو (FIFO)
        $findStockQuery = "
            SELECT InventoryID, AvailableQuantity 
            FROM Inventory 
            WHERE ProductID = ? AND AvailableQuantity > 0 
            ORDER BY ExpiryDate ASC, CreatedAt ASC
        ";
        $findStmt = $conn->prepare($findStockQuery);
        $findStmt->bind_param("i", $productId);
        $findStmt->execute();
        $stockResult = $findStmt->get_result();
        
        $remainingQty = $quantity;
        
        while ($stock = $stockResult->fetch_assoc() && $remainingQty > 0) {
            $reserveQty = min($stock['AvailableQuantity'], $remainingQty);
            
            $updateQuery = "
                UPDATE Inventory 
                SET ReservedQuantity = ReservedQuantity + ? 
                WHERE InventoryID = ?
            ";
            $updateStmt = $conn->prepare($updateQuery);
            $updateStmt->bind_param("di", $reserveQty, $stock['InventoryID']);
            $updateStmt->execute();
            
            // ثبت تراکنش
            logTransaction(
                $productId,
                $stock['WarehouseID'],
                $stock['ZoneID'],
                'Reservation',
                $referenceId,
                $referenceType . '_reserve',
                0,
                0,
                $reserveQty,
                $stock['UnitCost'],
                'Stock reserved for ' . $referenceType
            );
            
            $remainingQty -= $reserveQty;
        }
        
        if ($remainingQty > 0) {
            throw new Exception("Insufficient stock available");
        }
        
        $conn->commit();
        sendResponse(true, null, 'Stock reserved successfully');
        
    } catch (Exception $e) {
        $conn->rollback();
        sendResponse(false, null, 'Failed to reserve stock: ' . $e->getMessage(), 500);
    }
}

function logTransaction($productId, $warehouseId, $zoneId, $type, $referenceId, $referenceNumber, $qtyIn, $qtyOut, $unitCost, $remarks) {
    global $conn;
    
    $query = "
        INSERT INTO InventoryTransactions (
            ProductID, WarehouseID, ZoneID, TransactionType, ReferenceID, ReferenceNumber,
            QuantityIn, QuantityOut, UnitCost, Remarks
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    ";
    
    $stmt = $conn->prepare($query);
    $stmt->bind_param(
        "iiisisddds",
        $productId, $warehouseId, $zoneId, $type, $referenceId, $referenceNumber,
        $qtyIn, $qtyOut, $unitCost, $remarks
    );
    $stmt->execute();
}
?>

4. API دریافت کالا (receiving_api.php)

php
<?php
include 'config.php';

$method = $_SERVER['REQUEST_METHOD'];
$conn = getDBConnection();

switch ($method) {
    case 'GET':
        getReceipts();
        break;
    case 'POST':
        receiveGoods();
        break;
    case 'PUT':
        updateReceiptStatus();
        break;
}

function getReceipts() {
    global $conn;
    
    $receiptId = $_GET['receipt_id'] ?? null;
    $orderId = $_GET['order_id'] ?? null;
    $status = $_GET['status'] ?? null;
    
    $query = "
        SELECT 
            gr.*,
            po.OrderNumber,
            s.SupplierName,
            w.WarehouseName,
            e.FirstName as ReceivedByName
        FROM GoodsReceipts gr
        LEFT JOIN PurchaseOrders po ON gr.OrderID = po.OrderID
        LEFT JOIN Suppliers s ON gr.SupplierID = s.SupplierID
        LEFT JOIN Warehouses w ON gr.WarehouseID = w.WarehouseID
        LEFT JOIN Employees e ON gr.ReceivedBy = e.EmployeeID
        WHERE 1=1
    ";
    
    $params = [];
    $types = "";
    
    if ($receiptId) {
        $query .= " AND gr.ReceiptID = ?";
        $params[] = $receiptId;
        $types .= "i";
    }
    
    if ($orderId) {
        $query .= " AND gr.OrderID = ?";
        $params[] = $orderId;
        $types .= "i";
    }
    
    if ($status) {
        $query .= " AND gr.Status = ?";
        $params[] = $status;
        $types .= "s";
    }
    
    $query .= " ORDER BY gr.ReceiptDate DESC";
    
    $stmt = $conn->prepare($query);
    if (!empty($params)) {
        $stmt->bind_param($types, ...$params);
    }
    $stmt->execute();
    $result = $stmt->get_result();
    
    $receipts = [];
    while ($row = $result->fetch_assoc()) {
        // گرفتن اقلام رسید
        $itemsQuery = "
            SELECT gri.*, p.ProductCode, p.ProductName, z.ZoneCode
            FROM GoodsReceiptItems gri
            INNER JOIN Products p ON gri.ProductID = p.ProductID
            INNER JOIN WarehouseZones z ON gri.ZoneID = z.ZoneID
            WHERE gri.ReceiptID = ?
        ";
        $itemsStmt = $conn->prepare($itemsQuery);
        $itemsStmt->bind_param("i", $row['ReceiptID']);
        $itemsStmt->execute();
        $itemsResult = $itemsStmt->get_result();
        
        $row['items'] = [];
        while ($item = $itemsResult->fetch_assoc()) {
            $row['items'][] = $item;
        }
        
        $receipts[] = $row;
    }
    
    sendResponse(true, $receipts, 'Receipts retrieved successfully');
}

function receiveGoods() {
    global $conn;
    
    $data = json_decode(file_get_contents("php://input"), true);
    
    $conn->begin_transaction();
    
    try {
        // ایجاد رسید
        $receiptNumber = 'GR-' . date('Ymd-His');
        
        $receiptQuery = "
            INSERT INTO GoodsReceipts (
                ReceiptNumber, OrderID, ReceiptDate, ReceivedBy, WarehouseID,
                SupplierID, ReceiptType, TotalQuantity, TotalValue
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        ";
        
        $receiptStmt = $conn->prepare($receiptQuery);
        $receiptStmt->bind_param(
            "sisiiisdd",
            $receiptNumber, $data['order_id'], $data['receipt_date'],
            $data['received_by'], $data['warehouse_id'], $data['supplier_id'],
            $data['receipt_type'], $data['total_quantity'], $data['total_value']
        );
        $receiptStmt->execute();
        $receiptId = $receiptStmt->insert_id;
        
        $totalQuantity = 0;
        $totalValue = 0;
        
        // پردازش اقلام
        foreach ($data['items'] as $item) {
            $itemQuery = "
                INSERT INTO GoodsReceiptItems (
                    ReceiptID, OrderItemID, ProductID, ReceivedQuantity,
                    UnitPrice, BatchNumber, SerialNumber, ExpiryDate,
                    ProductionDate, ZoneID, QualityStatus
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ";
            
            $itemStmt = $conn->prepare($itemQuery);
            $itemStmt->bind_param(
                "iiiddssssis",
                $receiptId, $item['order_item_id'], $item['product_id'],
                $item['quantity'], $item['unit_price'], $item['batch_number'] ?? null,
                $item['serial_number'] ?? null, $item['expiry_date'] ?? null,
                $item['production_date'] ?? null, $item['zone_id'],
                $item['quality_status']
            );
            $itemStmt->execute();
            
            // به‌روزرسانی موجودی
            if ($item['quality_status'] === 'Accepted') {
                updateInventoryOnReceipt(
                    $item['product_id'],
                    $data['warehouse_id'],
                    $item['zone_id'],
                    $item['quantity'],
                    $item['unit_price'],
                    $item['batch_number'] ?? null,
                    $item['serial_number'] ?? null,
                    $item['expiry_date'] ?? null,
                    $item['production_date'] ?? null
                );
                
                // ثبت تراکنش
                logTransaction(
                    $item['product_id'],
                    $data['warehouse_id'],
                    $item['zone_id'],
                    'PurchaseReceipt',
                    $receiptId,
                    $receiptNumber,
                    $item['quantity'],
                    0,
                    $item['unit_price'],
                    'Goods receipt: ' . $receiptNumber
                );
            }
            
            $totalQuantity += $item['quantity'];
            $totalValue += ($item['quantity'] * $item['unit_price']);
        }
        
        // به‌روزرسانی مقادیر کل رسید
        $updateReceiptQuery = "
            UPDATE GoodsReceipts 
            SET TotalQuantity = ?, TotalValue = ?, Status = 'Received'
            WHERE ReceiptID = ?
        ";
        $updateStmt = $conn->prepare($updateReceiptQuery);
        $updateStmt->bind_param("ddi", $totalQuantity, $totalValue, $receiptId);
        $updateStmt->execute();
        
        $conn->commit();
        sendResponse(true, ['receipt_id' => $receiptId], 'Goods received successfully', 201);
        
    } catch (Exception $e) {
        $conn->rollback();
        sendResponse(false, null, 'Failed to receive goods: ' . $e->getMessage(), 500);
    }
}

function updateInventoryOnReceipt($productId, $warehouseId, $zoneId, $quantity, $unitCost, $batchNumber, $serialNumber, $expiryDate, $productionDate) {
    global $conn;
    
    $query = "
        INSERT INTO Inventory (
            ProductID, WarehouseID, ZoneID, BatchNumber, SerialNumber,
            ExpiryDate, ProductionDate, Quantity, UnitCost
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        ON DUPLICATE KEY UPDATE
            Quantity = Quantity + VALUES(Quantity),
            UnitCost = (UnitCost * Quantity + VALUES(UnitCost) * VALUES(Quantity)) / (Quantity + VALUES(Quantity))
    ";
    
    $stmt = $conn->prepare($query);
    $stmt->bind_param(
        "iisssssdd",
        $productId, $warehouseId, $zoneId, $batchNumber, $serialNumber,
        $expiryDate, $productionDate, $quantity, $unitCost
    );
    $stmt->execute();
}
?>

5. API حواله خروج (issuing_api.php)

php
<?php
include 'config.php';

$method = $_SERVER['REQUEST_METHOD'];
$conn = getDBConnection();

switch ($method) {
    case 'GET':
        getIssues();
        break;
    case 'POST':
        createIssue();
        break;
    case 'PUT':
        processIssue();
        break;
}

function getIssues() {
    global $conn;
    
    $issueId = $_GET['issue_id'] ?? null;
    $status = $_GET['status'] ?? null;
    
    $query = "
        SELECT 
            ir.*,
            e.FirstName as RequestedByName,
            d.DepartmentName,
            a.FirstName as ApprovedByName
        FROM IssueRequests ir
        LEFT JOIN Employees e ON ir.RequestedBy = e.EmployeeID
        LEFT JOIN Departments d ON ir.DepartmentID = d.DepartmentID
        LEFT JOIN Employees a ON ir.ApprovedBy = a.EmployeeID
        WHERE 1=1
    ";
    
    $params = [];
    $types = "";
    
    if ($issueId) {
        $query .= " AND ir.IssueID = ?";
        $params[] = $issueId;
        $types .= "i";
    }
    
    if ($status) {
        $query .= " AND ir.Status = ?";
        $params[] = $status;
        $types .= "s";
    }
    
    $query .= " ORDER BY ir.IssueDate DESC";
    
    $stmt = $conn->prepare($query);
    if (!empty($params)) {
        $stmt->bind_param($types, ...$params);
    }
    $stmt->execute();
    $result = $stmt->get_result();
    
    $issues = [];
    while ($row = $result->fetch_assoc()) {
        // گرفتن اقلام درخواست
        $itemsQuery = "
            SELECT iri.*, p.ProductCode, p.ProductName
            FROM IssueRequestItems iri
            INNER JOIN Products p ON iri.ProductID = p.ProductID
            WHERE iri.IssueID = ?
        ";
        $itemsStmt = $conn->prepare($itemsQuery);
        $itemsStmt->bind_param("i", $row['IssueID']);
        $itemsStmt->execute();
        $itemsResult = $itemsStmt->get_result();
        
        $row['items'] = [];
        while ($item = $itemsResult->fetch_assoc()) {
            $row['items'][] = $item;
        }
        
        $issues[] = $row;
    }
    
    sendResponse(true, $issues, 'Issue requests retrieved successfully');
}

function createIssue() {
    global $conn;
    
    $data = json_decode(file_get_contents("php://input"), true);
    
    $conn->begin_transaction();
    
    try {
        $issueNumber = 'IR-' . date('Ymd-His');
        
        $issueQuery = "
            INSERT INTO IssueRequests (
                IssueNumber, IssueDate, RequestedBy, DepartmentID, Purpose,
                TotalQuantity, TotalValue
            ) VALUES (?, ?, ?, ?, ?, ?, ?)
        ";
        
        $issueStmt = $conn->prepare($issueQuery);
        $issueStmt->bind_param(
            "ssiisdd",
            $issueNumber, $data['issue_date'], $data['requested_by'],
            $data['department_id'], $data['purpose'], $data['total_quantity'],
            $data['total_value']
        );
        $issueStmt->execute();
        $issueId = $issueStmt->insert_id;
        
        $totalQuantity = 0;
        $totalValue = 0;
        
        foreach ($data['items'] as $item) {
            $itemQuery = "
                INSERT INTO IssueRequestItems (
                    IssueID, ProductID, RequestedQuantity, RequiredDate
                ) VALUES (?, ?, ?, ?)
            ";
            
            $itemStmt = $conn->prepare($itemQuery);
            $itemStmt->bind_param(
                "iids",
                $issueId, $item['product_id'], $item['quantity'],
                $item['required_date']
            );
            $itemStmt->execute();
            
            $totalQuantity += $item['quantity'];
        }
        
        // به‌روزرسانی مقادیر کل
        $updateQuery = "
            UPDATE IssueRequests 
            SET TotalQuantity = ? 
            WHERE IssueID = ?
        ";
        $updateStmt = $conn->prepare($updateQuery);
        $updateStmt->bind_param("di", $totalQuantity, $issueId);
        $updateStmt->execute();
        
        $conn->commit();
        sendResponse(true, ['issue_id' => $issueId], 'Issue request created successfully', 201);
        
    } catch (Exception $e) {
        $conn->rollback();
        sendResponse(false, null, 'Failed to create issue request: ' . $e->getMessage(), 500);
    }
}

function processIssue() {
    global $conn;
    
    $data = json_decode(file_get_contents("php://input"), true);
    $action = $data['action']; // 'approve', 'reject', 'issue'
    
    $conn->begin_transaction();
    
    try {
        if ($action === 'approve') {
            $query = "
                UPDATE IssueRequests 
                SET Status = 'Approved', ApprovedBy = ?, ApprovedAt = NOW()
                WHERE IssueID = ?
            ";
            $stmt = $conn->prepare($query);
            $stmt->bind_param("ii", $data['approved_by'], $data['issue_id']);
            $stmt->execute();
            
        } elseif ($action === 'issue') {
            // ایجاد حواله خروج
            $voucherNumber = 'IV-' . date('Ymd-His');
            
            $voucherQuery = "
                INSERT INTO IssueVouchers (
                    VoucherNumber, IssueID, VoucherDate, IssuedBy,
                    WarehouseID, IssuedTo, DepartmentID, VoucherType
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
            ";
            
            $voucherStmt = $conn->prepare($voucherQuery);
            $voucherStmt->bind_param(
                "sissiiss",
                $voucherNumber, $data['issue_id'], $data['voucher_date'],
                $data['issued_by'], $data['warehouse_id'], $data['issued_to'],
                $data['department_id'], $data['voucher_type']
            );
            $voucherStmt->execute();
            $voucherId = $voucherStmt->insert_id;
            
            $totalQuantity = 0;
            $totalValue = 0;
            
            // پردازش اقلام خروج
            foreach ($data['items'] as $item) {
                // کسر از موجودی (FIFO)
                $issued = issueStockFIFO(
                    $item['product_id'],
                    $data['warehouse_id'],
                    $item['quantity'],
                    $voucherId,
                    $item['issue_item_id']
                );
                
                $totalQuantity += $item['quantity'];
                $totalValue += $issued['total_cost'];
            }
            
            // به‌روزرسانی حواله
            $updateVoucherQuery = "
                UPDATE IssueVouchers 
                SET TotalQuantity = ?, TotalValue = ?, Status = 'Issued'
                WHERE VoucherID = ?
            ";
            $updateStmt = $conn->prepare($updateVoucherQuery);
            $updateStmt->bind_param("ddi", $totalQuantity, $totalValue, $voucherId);
            $updateStmt->execute();
            
            // به‌روزرسانی درخواست
            $updateIssueQuery = "
                UPDATE IssueRequests 
                SET Status = 'Completed'
                WHERE IssueID = ?
            ";
            $updateIssueStmt = $conn->prepare($updateIssueQuery);
            $updateIssueStmt->bind_param("i", $data['issue_id']);
            $updateIssueStmt->execute();
        }
        
        $conn->commit();
        sendResponse(true, null, 'Issue processed successfully');
        
    } catch (Exception $e) {
        $conn->rollback();
        sendResponse(false, null, 'Failed to process issue: ' . $e->getMessage(), 500);
    }
}

function issueStockFIFO($productId, $warehouseId, $quantity, $voucherId, $issueItemId) {
    global $conn;
    
    $findStockQuery = "
        SELECT InventoryID, AvailableQuantity, UnitCost, ZoneID, BatchNumber, SerialNumber
        FROM Inventory 
        WHERE ProductID = ? AND WarehouseID = ? AND AvailableQuantity > 0
        ORDER BY ExpiryDate ASC, CreatedAt ASC
    ";
    
    $findStmt = $conn->prepare($findStockQuery);
    $findStmt->bind_param("ii", $productId, $warehouseId);
    $findStmt->execute();
    $stockResult = $findStmt->get_result();
    
    $remainingQty = $quantity;
    $totalCost = 0;
    
    while ($stock = $stockResult->fetch_assoc() && $remainingQty > 0) {
        $issueQty = min($stock['AvailableQuantity'], $remainingQty);
        
        // کسر از موجودی
        $updateQuery = "
            UPDATE Inventory 
            SET Quantity = Quantity - ? 
            WHERE InventoryID = ?
        ";
        $updateStmt = $conn->prepare($updateQuery);
        $updateStmt->bind_param("di", $issueQty, $stock['InventoryID']);
        $updateStmt->execute();
        
        // ثبت در حواله
        $voucherItemQuery = "
            INSERT INTO IssueVoucherItems (
                VoucherID, IssueItemID, ProductID, IssuedQuantity,
                UnitCost, BatchNumber, SerialNumber, ZoneID
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
        ";
        $voucherItemStmt = $conn->prepare($voucherItemQuery);
        $voucherItemStmt->bind_param(
            "iiiddssi",
            $voucherId, $issueItemId, $productId, $issueQty,
            $stock['UnitCost'], $stock['BatchNumber'], $stock['SerialNumber'],
            $stock['ZoneID']
        );
        $voucherItemStmt->execute();
        
        // ثبت تراکنش
        logTransaction(
            $productId,
            $warehouseId,
            $stock['ZoneID'],
            'Issue',
            $voucherId,
            'IV-' . $voucherId,
            0,
            $issueQty,
            $stock['UnitCost'],
            'Stock issued via voucher'
        );
        
        $totalCost += ($issueQty * $stock['UnitCost']);
        $remainingQty -= $issueQty;
    }
    
    if ($remainingQty > 0) {
        throw new Exception("Insufficient stock available for issue");
    }
    
    return ['total_cost' => $totalCost];
}
?>

6. API گزارشات (reports_api.php)

php
<?php
include 'config.php';

$method = $_SERVER['REQUEST_METHOD'];

if ($method == 'GET') {
    $reportType = $_GET['type'] ?? 'inventory';
    
    switch ($reportType) {
        case 'inventory':
            getInventoryReport();
            break;
        case 'movement':
            getMovementReport();
            break;
        case 'valuation':
            getValuationReport();
            break;
        case 'expiry':
            getExpiryReport();
            break;
        default:
            sendResponse(false, null, 'Invalid report type', 400);
    }
}

function getInventoryReport() {
    global $conn;
    
    $warehouseId = $_GET['warehouse_id'] ?? null;
    $categoryId = $_GET['category_id'] ?? null;
    
    $query = "
        SELECT 
            p.ProductID,
            p.ProductCode,
            p.ProductName,
            c.CategoryName,
            u.UnitName,
            p.MinStockLevel,
            p.MaxStockLevel,
            COALESCE(SUM(i.Quantity), 0) as TotalStock,
            COALESCE(SUM(i.AvailableQuantity), 0) as AvailableStock,
            COALESCE(SUM(i.ReservedQuantity), 0) as ReservedStock,
            COALESCE(SUM(i.TotalValue), 0) as TotalValue,
            CASE 
                WHEN COALESCE(SUM(i.AvailableQuantity), 0) <= p.MinStockLevel THEN 'Low'
                WHEN COALESCE(SUM(i.AvailableQuantity), 0) >= p.MaxStockLevel THEN 'High'
                ELSE 'Normal'
            END as StockStatus
        FROM Products p
        LEFT JOIN ProductCategories c ON p.CategoryID = c.CategoryID
        LEFT JOIN Units u ON p.UnitID = u.UnitID
        LEFT JOIN Inventory i ON p.ProductID = i.ProductID
        WHERE p.IsActive = 1
    ";
    
    $params = [];
    $types = "";
    
    if ($warehouseId) {
        $query .= " AND i.WarehouseID = ?";
        $params[] = $warehouseId;
        $types .= "i";
    }
    
    if ($categoryId) {
        $query .= " AND p.CategoryID = ?";
        $params[] = $categoryId;
        $types .= "i";
    }
    
    $query .= " GROUP BY p.ProductID
                ORDER BY c.CategoryName, p.ProductName";
    
    $stmt = $conn->prepare($query);
    if (!empty($params)) {
        $stmt->bind_param($types, ...$params);
    }
    $stmt->execute();
    $result = $stmt->get_result();
    
    $report = [];
    while ($row = $result->fetch_assoc()) {
        $report[] = $row;
    }
    
    sendResponse(true, $report, 'Inventory report generated successfully');
}

function getMovementReport() {
    global $conn;
    
    $startDate = $_GET['start_date'] ?? date('Y-m-01');
    $endDate = $_GET['end_date'] ?? date('Y-m-d');
    $productId = $_GET['product_id'] ?? null;
    
    $query = "
        SELECT 
            p.ProductCode,
            p.ProductName,
            SUM(CASE WHEN it.TransactionType IN ('PurchaseReceipt', 'TransferIn') THEN it.QuantityIn ELSE 0 END) as TotalIn,
            SUM(CASE WHEN it.TransactionType IN ('Issue', 'TransferOut') THEN it.QuantityOut ELSE 0 END) as TotalOut,
            SUM(it.QuantityIn - it.QuantityOut) as NetMovement,
            SUM(it.TotalCost) as TotalValue
        FROM InventoryTransactions it
        INNER JOIN Products p ON it.ProductID = p.ProductID
        WHERE it.TransactionDate BETWEEN ? AND ?
    ";
    
    $params = [$startDate, $endDate];
    $types = "ss";
    
    if ($productId) {
        $query .= " AND it.ProductID = ?";
        $params[] = $productId;
        $types .= "i";
    }
    
    $query .= " GROUP BY it.ProductID
                ORDER BY NetMovement DESC";
    
    $stmt = $conn->prepare($query);
    $stmt->bind_param($types, ...$params);
    $stmt->execute();
    $result = $stmt->get_result();
    
    $report = [];
    while ($row = $result->fetch_assoc()) {
        $report[] = $row;
    }
    
    sendResponse(true, $report, 'Movement report generated successfully');
}
?>

7. فایل روتر اصلی (router.php)

php
<?php
include 'config.php';

$request_uri = $_SERVER['REQUEST_URI'];
$method = $_SERVER['REQUEST_METHOD'];
$path = parse_url($request_uri, PHP_URL_PATH);

// مسیرهای API
$routes = [
    'GET' => [
        '/api/products' => 'products_api.php',
        '/api/inventory' => 'inventory_api.php',
        '/api/receipts' => 'receiving_api.php',
        '/api/issues' => 'issuing_api.php',
        '/api/reports' => 'reports_api.php',
        '/api/warehouses' => 'warehouses_api.php',
        '/api/suppliers' => 'suppliers_api.php'
    ],
    'POST' => [
        '/api/products' => 'products_api.php',
        '/api/inventory/update' => 'inventory_api.php',
        '/api/receipts' => 'receiving_api.php',
        '/api/issues' => 'issuing_api.php',
        '/api/transfers' => 'transfers_api.php'
    ],
    'PUT' => [
        '/api/products' => 'products_api.php',
        '/api/receipts' => 'receiving_api.php',
        '/api/issues' => 'issuing_api.php'
    ],
    'DELETE' => [
        '/api/products' => 'products_api.php'
    ]
];

// پیدا کردن مسیر منطبق
$matched = false;
foreach ($routes[$method] as $route => $file) {
    if (strpos($path, $route) === 0) {
        include($file);
        $matched = true;
        break;
    }
}

if (!$matched) {
    sendResponse(false, null, 'Endpoint not found', 404);
}
?>

8. مثال استفاده از API ها

javascript
// گرفتن لیست محصولات
fetch('/api/products?page=1&limit=20')
    .then(response => response.json())
    .then(data => console.log(data));

// بررسی موجودی
fetch('/api/inventory?product_id=123')
    .then(response => response.json())
    .then(data => console.log(data));

// ثبت دریافت کالا
fetch('/api/receipts', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({
        order_id: 456,
        receipt_date: '2024-01-15',
        received_by: 1,
        warehouse_id: 1,
        supplier_id: 1,
        receipt_type: 'Purchase',
        items: [
            {
                product_id: 123,
                quantity: 100,
                unit_price: 25.50,
                zone_id: 1,
                quality_status: 'Accepted'
            }
        ]
    })
});

// ایجاد درخواست خروج
fetch('/api/issues', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({
        issue_date: '2024-01-15',
        requested_by: 1,
        department_id: 1,
        purpose: 'Production',
        items: [
            {
                product_id: 123,
                quantity: 50,
                required_date: '2024-01-16'
            }
        ]
    })
});

// گرفتن گزارش موجودی
fetch('/api/reports?type=inventory&warehouse_id=1')
    .then(response => response.json())
    .then(data => console.log(data));

این API های کامل تمام نیازهای اصلی یک سیستم مدیریت انبار را پوشش می‌دهند و می‌توانند بر اساس نیازهای خاص توسعه داده شوند.

 
 
کانال نوحه و مداحی ناب

نظرات (۰)
هیچ نظری هنوز ثبت نشده است

ارسال نظر

ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی