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 های کامل تمام نیازهای اصلی یک سیستم مدیریت انبار را پوشش میدهند و میتوانند بر اساس نیازهای خاص توسعه داده شوند.
نظرات (۰)
هیچ نظری هنوز ثبت نشده است