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

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', 'accounting_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 authenticateUser() {
    $headers = getallheaders();
    $token = isset($headers['Authorization']) ? str_replace('Bearer ', '', $headers['Authorization']) : '';
    
    if (empty($token)) {
        sendResponse(false, null, 'Access token required', 401);
    }
    
    // در اینجا منطق اعتبارسنجی توکن را پیاده‌سازی کنید
    $userId = verifyToken($token);
    if (!$userId) {
        sendResponse(false, null, 'Invalid token', 401);
    }
    
    return $userId;
}

function verifyToken($token) {
    // پیاده‌سازی منطق اعتبارسنجی JWT
    return 1; // نمونه
}

function checkPermission($userId, $module, $action) {
    // پیاده‌سازی بررسی دسترسی کاربر
    return true; // نمونه
}

function logAudit($userId, $companyId, $action, $table, $recordId, $description = '') {
    global $conn;
    
    $query = "
        INSERT INTO AuditLog (CompanyID, UserID, ActionType, TableName, RecordID, Description, IPAddress)
        VALUES (?, ?, ?, ?, ?, ?, ?)
    ";
    
    $stmt = $conn->prepare($query);
    $ip = $_SERVER['REMOTE_ADDR'];
    $stmt->bind_param("iississ", $companyId, $userId, $action, $table, $recordId, $description, $ip);
    $stmt->execute();
}
?>

2. API مدیریت حساب‌های کل (accounts_api.php)

php
<?php
include 'config.php';

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

switch ($method) {
    case 'GET':
        getChartOfAccounts();
        break;
    case 'POST':
        createAccount();
        break;
    case 'PUT':
        updateAccount();
        break;
    case 'DELETE':
        deleteAccount();
        break;
}

function getChartOfAccounts() {
    global $conn, $userId;
    
    $companyId = $_GET['company_id'] ?? 1;
    $accountId = $_GET['account_id'] ?? null;
    $accountCode = $_GET['account_code'] ?? null;
    $accountType = $_GET['account_type'] ?? null;
    $isActive = $_GET['is_active'] ?? 1;
    
    if (!checkPermission($userId, 'accounts', 'view')) {
        sendResponse(false, null, 'Permission denied', 403);
    }
    
    $query = "
        SELECT 
            a.*,
            g.GroupName,
            g.AccountType as GroupAccountType,
            p.AccountCode as ParentAccountCode,
            p.AccountName as ParentAccountName,
            c.CurrencyCode,
            (a.CurrentBalanceDebit - a.CurrentBalanceCredit) as Balance,
            CASE a.NormalBalance
                WHEN 'Debit' THEN (a.CurrentBalanceDebit - a.CurrentBalanceCredit)
                ELSE (a.CurrentBalanceCredit - a.CurrentBalanceDebit)
            END as SignedBalance
        FROM ChartOfAccounts a
        LEFT JOIN AccountGroups g ON a.GroupID = g.GroupID
        LEFT JOIN ChartOfAccounts p ON a.ParentAccountID = p.AccountID
        LEFT JOIN Currencies c ON a.CurrencyID = c.CurrencyID
        WHERE a.CompanyID = ? AND a.IsActive = ?
    ";
    
    $params = [$companyId, $isActive];
    $types = "ii";
    
    if ($accountId) {
        $query .= " AND a.AccountID = ?";
        $params[] = $accountId;
        $types .= "i";
    }
    
    if ($accountCode) {
        $query .= " AND a.AccountCode = ?";
        $params[] = $accountCode;
        $types .= "s";
    }
    
    if ($accountType) {
        $query .= " AND a.AccountType = ?";
        $params[] = $accountType;
        $types .= "s";
    }
    
    $query .= " ORDER BY a.AccountCode";
    
    $stmt = $conn->prepare($query);
    $stmt->bind_param($types, ...$params);
    $stmt->execute();
    $result = $stmt->get_result();
    
    $accounts = [];
    while ($row = $result->fetch_assoc()) {
        $accounts[] = $row;
    }
    
    // ساختار درختی حساب‌ها
    if (!$accountId && !$accountCode) {
        $accounts = buildAccountTree($accounts);
    }
    
    sendResponse(true, $accounts, 'Chart of accounts retrieved successfully');
}

function buildAccountTree($accounts, $parentId = null) {
    $branch = [];
    foreach ($accounts as $account) {
        if ($account['ParentAccountID'] == $parentId) {
            $children = buildAccountTree($accounts, $account['AccountID']);
            if ($children) {
                $account['children'] = $children;
            }
            $branch[] = $account;
        }
    }
    return $branch;
}

function createAccount() {
    global $conn, $userId;
    
    $data = json_decode(file_get_contents("php://input"), true);
    
    if (!checkPermission($userId, 'accounts', 'create')) {
        sendResponse(false, null, 'Permission denied', 403);
    }
    
    $required = ['CompanyID', 'AccountCode', 'AccountName', 'GroupID', 'AccountType', 'NormalBalance'];
    foreach ($required as $field) {
        if (!isset($data[$field]) || empty($data[$field])) {
            sendResponse(false, null, "Field $field is required", 400);
        }
    }
    
    // بررسی تکراری نبودن کد حساب
    $checkQuery = "SELECT AccountID FROM ChartOfAccounts WHERE CompanyID = ? AND AccountCode = ?";
    $checkStmt = $conn->prepare($checkQuery);
    $checkStmt->bind_param("is", $data['CompanyID'], $data['AccountCode']);
    $checkStmt->execute();
    
    if ($checkStmt->get_result()->num_rows > 0) {
        sendResponse(false, null, 'Account code already exists', 400);
    }
    
    $query = "
        INSERT INTO ChartOfAccounts (
            CompanyID, AccountCode, AccountName, AccountNameEnglish, GroupID, ParentAccountID,
            AccountLevel, AccountType, NormalBalance, IsDetailAccount, IsCashAccount, IsBankAccount,
            IsReceivableAccount, IsPayableAccount, CurrencyID, OpeningBalanceDebit, OpeningBalanceCredit,
            Notes
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    ";
    
    $stmt = $conn->prepare($query);
    $stmt->bind_param(
        "issssiissssssiidds",
        $data['CompanyID'], $data['AccountCode'], $data['AccountName'],
        $data['AccountNameEnglish'] ?? null, $data['GroupID'], $data['ParentAccountID'] ?? null,
        $data['AccountLevel'] ?? 1, $data['AccountType'], $data['NormalBalance'],
        $data['IsDetailAccount'] ?? false, $data['IsCashAccount'] ?? false,
        $data['IsBankAccount'] ?? false, $data['IsReceivableAccount'] ?? false,
        $data['IsPayableAccount'] ?? false, $data['CurrencyID'] ?? null,
        $data['OpeningBalanceDebit'] ?? 0, $data['OpeningBalanceCredit'] ?? 0,
        $data['Notes'] ?? null
    );
    
    if ($stmt->execute()) {
        $accountId = $stmt->insert_id;
        logAudit($userId, $data['CompanyID'], 'CREATE', 'ChartOfAccounts', $accountId, 'Account created: ' . $data['AccountCode']);
        sendResponse(true, ['account_id' => $accountId], 'Account created successfully', 201);
    } else {
        sendResponse(false, null, 'Failed to create account: ' . $stmt->error, 500);
    }
}

function updateAccount() {
    global $conn, $userId;
    
    $data = json_decode(file_get_contents("php://input"), true);
    $accountId = $_GET['account_id'] ?? $data['account_id'];
    
    if (!$accountId) {
        sendResponse(false, null, 'Account ID is required', 400);
    }
    
    if (!checkPermission($userId, 'accounts', 'edit')) {
        sendResponse(false, null, 'Permission denied', 403);
    }
    
    // گرفتن اطلاعات فعلی حساب
    $currentQuery = "SELECT CompanyID, AccountCode FROM ChartOfAccounts WHERE AccountID = ?";
    $currentStmt = $conn->prepare($currentQuery);
    $currentStmt->bind_param("i", $accountId);
    $currentStmt->execute();
    $currentResult = $currentStmt->get_result();
    
    if ($currentResult->num_rows === 0) {
        sendResponse(false, null, 'Account not found', 404);
    }
    
    $currentAccount = $currentResult->fetch_assoc();
    $companyId = $currentAccount['CompanyID'];
    
    $fields = [];
    $params = [];
    $types = "";
    
    $updatableFields = [
        'AccountName', 'AccountNameEnglish', 'GroupID', 'ParentAccountID',
        'AccountType', 'NormalBalance', 'IsDetailAccount', 'IsCashAccount',
        'IsBankAccount', 'IsReceivableAccount', 'IsPayableAccount',
        'CurrencyID', 'Notes', 'IsActive'
    ];
    
    foreach ($updatableFields as $field) {
        if (isset($data[$field])) {
            $fields[] = "$field = ?";
            $params[] = $data[$field];
            $types .= "s";
        }
    }
    
    if (empty($fields)) {
        sendResponse(false, null, 'No fields to update', 400);
    }
    
    $params[] = $accountId;
    $types .= "i";
    
    $query = "UPDATE ChartOfAccounts SET " . implode(", ", $fields) . " WHERE AccountID = ?";
    $stmt = $conn->prepare($query);
    $stmt->bind_param($types, ...$params);
    
    if ($stmt->execute()) {
        logAudit($userId, $companyId, 'UPDATE', 'ChartOfAccounts', $accountId, 'Account updated');
        sendResponse(true, null, 'Account updated successfully');
    } else {
        sendResponse(false, null, 'Failed to update account: ' . $stmt->error, 500);
    }
}
?>

3. API مدیریت اسناد حسابداری (vouchers_api.php)

php
<?php
include 'config.php';

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

switch ($method) {
    case 'GET':
        getVouchers();
        break;
    case 'POST':
        createVoucher();
        break;
    case 'PUT':
        updateVoucher();
        break;
    case 'DELETE':
        deleteVoucher();
        break;
}

function getVouchers() {
    global $conn, $userId;
    
    $companyId = $_GET['company_id'] ?? 1;
    $voucherId = $_GET['voucher_id'] ?? null;
    $periodId = $_GET['period_id'] ?? null;
    $voucherType = $_GET['voucher_type'] ?? null;
    $status = $_GET['status'] ?? null;
    $startDate = $_GET['start_date'] ?? null;
    $endDate = $_GET['end_date'] ?? null;
    $page = $_GET['page'] ?? 1;
    $limit = $_GET['limit'] ?? 20;
    $offset = ($page - 1) * $limit;
    
    if (!checkPermission($userId, 'vouchers', 'view')) {
        sendResponse(false, null, 'Permission denied', 403);
    }
    
    $query = "
        SELECT 
            v.*,
            p.PeriodName,
            c.CurrencyCode,
            prep.FirstName as PreparedByFirstName,
            prep.LastName as PreparedByLastName,
            app.FirstName as ApprovedByFirstName,
            app.LastName as ApprovedByLastName
        FROM AccountingVouchers v
        INNER JOIN FiscalPeriods p ON v.PeriodID = p.PeriodID
        INNER JOIN Currencies c ON v.CurrencyID = c.CurrencyID
        LEFT JOIN Users prep ON v.PreparedBy = prep.UserID
        LEFT JOIN Users app ON v.ApprovedBy = app.UserID
        WHERE v.CompanyID = ?
    ";
    
    $params = [$companyId];
    $types = "i";
    
    if ($voucherId) {
        $query .= " AND v.VoucherID = ?";
        $params[] = $voucherId;
        $types .= "i";
    }
    
    if ($periodId) {
        $query .= " AND v.PeriodID = ?";
        $params[] = $periodId;
        $types .= "i";
    }
    
    if ($voucherType) {
        $query .= " AND v.VoucherType = ?";
        $params[] = $voucherType;
        $types .= "s";
    }
    
    if ($status) {
        $query .= " AND v.Status = ?";
        $params[] = $status;
        $types .= "s";
    }
    
    if ($startDate) {
        $query .= " AND v.VoucherDate >= ?";
        $params[] = $startDate;
        $types .= "s";
    }
    
    if ($endDate) {
        $query .= " AND v.VoucherDate <= ?";
        $params[] = $endDate;
        $types .= "s";
    }
    
    // گرفتن تعداد کل
    $countQuery = str_replace(
        "SELECT v.*, p.PeriodName, c.CurrencyCode, prep.FirstName as PreparedByFirstName, prep.LastName as PreparedByLastName, app.FirstName as ApprovedByFirstName, app.LastName as ApprovedByLastName",
        "SELECT COUNT(*) as total",
        $query
    );
    $countStmt = $conn->prepare($countQuery);
    $countStmt->bind_param($types, ...$params);
    $countStmt->execute();
    $totalResult = $countStmt->get_result();
    $total = $totalResult->fetch_assoc()['total'];
    
    $query .= " ORDER BY v.VoucherDate DESC, v.VoucherID DESC LIMIT ? OFFSET ?";
    $params[] = $limit;
    $params[] = $offset;
    $types .= "ii";
    
    $stmt = $conn->prepare($query);
    $stmt->bind_param($types, ...$params);
    $stmt->execute();
    $result = $stmt->get_result();
    
    $vouchers = [];
    while ($row = $result->fetch_assoc()) {
        // گرفتن سطرهای سند
        $itemsQuery = "
            SELECT 
                vi.*,
                a.AccountCode, a.AccountName,
                cc.CostCenterCode, cc.CostCenterName,
                proj.ProjectCode, proj.ProjectName,
                cust.CustomerCode, cust.CustomerName,
                supp.SupplierCode, supp.SupplierName
            FROM VoucherItems vi
            INNER JOIN ChartOfAccounts a ON vi.AccountID = a.AccountID
            LEFT JOIN CostCenters cc ON vi.CostCenterID = cc.CostCenterID
            LEFT JOIN Projects proj ON vi.ProjectID = proj.ProjectID
            LEFT JOIN Customers cust ON vi.CustomerID = cust.CustomerID
            LEFT JOIN Suppliers supp ON vi.SupplierID = supp.SupplierID
            WHERE vi.VoucherID = ?
            ORDER BY vi.LineNumber
        ";
        $itemsStmt = $conn->prepare($itemsQuery);
        $itemsStmt->bind_param("i", $row['VoucherID']);
        $itemsStmt->execute();
        $itemsResult = $itemsStmt->get_result();
        
        $row['items'] = [];
        while ($item = $itemsResult->fetch_assoc()) {
            $row['items'][] = $item;
        }
        
        $vouchers[] = $row;
    }
    
    sendResponse(true, [
        'vouchers' => $vouchers,
        'pagination' => [
            'page' => intval($page),
            'limit' => intval($limit),
            'total' => $total,
            'pages' => ceil($total / $limit)
        ]
    ], 'Vouchers retrieved successfully');
}

function createVoucher() {
    global $conn, $userId;
    
    $data = json_decode(file_get_contents("php://input"), true);
    
    if (!checkPermission($userId, 'vouchers', 'create')) {
        sendResponse(false, null, 'Permission denied', 403);
    }
    
    $required = ['CompanyID', 'VoucherDate', 'VoucherType', 'PeriodID', 'CurrencyID', 'items'];
    foreach ($required as $field) {
        if (!isset($data[$field]) || empty($data[$field])) {
            sendResponse(false, null, "Field $field is required", 400);
        }
    }
    
    // اعتبارسنجی دوره مالی
    $periodQuery = "SELECT Status FROM FiscalPeriods WHERE PeriodID = ? AND CompanyID = ?";
    $periodStmt = $conn->prepare($periodQuery);
    $periodStmt->bind_param("ii", $data['PeriodID'], $data['CompanyID']);
    $periodStmt->execute();
    $periodResult = $periodStmt->get_result();
    
    if ($periodResult->num_rows === 0) {
        sendResponse(false, null, 'Invalid fiscal period', 400);
    }
    
    $period = $periodResult->fetch_assoc();
    if ($period['Status'] !== 'Open') {
        sendResponse(false, null, 'Fiscal period is not open', 400);
    }
    
    // محاسبه جمع بدهکار و بستانکار
    $totalDebit = 0;
    $totalCredit = 0;
    
    foreach ($data['items'] as $item) {
        $totalDebit += $item['DebitAmount'] ?? 0;
        $totalCredit += $item['CreditAmount'] ?? 0;
    }
    
    if (abs($totalDebit - $totalCredit) > 0.01) { // تحمل خطای اعشاری
        sendResponse(false, null, 'Debit and credit totals must be equal', 400);
    }
    
    $conn->begin_transaction();
    
    try {
        // تولید شماره سند
        $voucherNumber = generateVoucherNumber($data['CompanyID'], $data['VoucherType']);
        
        // ایجاد سند
        $voucherQuery = "
            INSERT INTO AccountingVouchers (
                CompanyID, VoucherNumber, VoucherDate, VoucherType, PeriodID,
                ReferenceNumber, ReferenceDate, Description, TotalDebit, TotalCredit,
                CurrencyID, ExchangeRate, PreparedBy
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        ";
        
        $voucherStmt = $conn->prepare($voucherQuery);
        $voucherStmt->bind_param(
            "isssisssdddsi",
            $data['CompanyID'], $voucherNumber, $data['VoucherDate'], $data['VoucherType'],
            $data['PeriodID'], $data['ReferenceNumber'] ?? null, $data['ReferenceDate'] ?? null,
            $data['Description'] ?? null, $totalDebit, $totalCredit,
            $data['CurrencyID'], $data['ExchangeRate'] ?? 1, $userId
        );
        $voucherStmt->execute();
        $voucherId = $voucherStmt->insert_id;
        
        // ایجاد سطرهای سند
        $lineNumber = 1;
        foreach ($data['items'] as $item) {
            $itemQuery = "
                INSERT INTO VoucherItems (
                    VoucherID, AccountID, Description, DebitAmount, CreditAmount,
                    CurrencyID, ExchangeRate, CostCenterID, ProjectID,
                    CustomerID, SupplierID, EmployeeID, ReferenceType, ReferenceID, LineNumber
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ";
            
            $itemStmt = $conn->prepare($itemQuery);
            $itemStmt->bind_param(
                "iisdddsiiiiisii",
                $voucherId, $item['AccountID'], $item['Description'] ?? null,
                $item['DebitAmount'] ?? 0, $item['CreditAmount'] ?? 0,
                $data['CurrencyID'], $data['ExchangeRate'] ?? 1,
                $item['CostCenterID'] ?? null, $item['ProjectID'] ?? null,
                $item['CustomerID'] ?? null, $item['SupplierID'] ?? null,
                $item['EmployeeID'] ?? null, $item['ReferenceType'] ?? 'None',
                $item['ReferenceID'] ?? null, $lineNumber
            );
            $itemStmt->execute();
            
            $lineNumber++;
        }
        
        $conn->commit();
        
        logAudit($userId, $data['CompanyID'], 'CREATE', 'AccountingVouchers', $voucherId, 'Voucher created: ' . $voucherNumber);
        
        sendResponse(true, [
            'voucher_id' => $voucherId,
            'voucher_number' => $voucherNumber
        ], 'Voucher created successfully', 201);
        
    } catch (Exception $e) {
        $conn->rollback();
        sendResponse(false, null, 'Failed to create voucher: ' . $e->getMessage(), 500);
    }
}

function generateVoucherNumber($companyId, $voucherType) {
    global $conn;
    
    $prefix = '';
    switch ($voucherType) {
        case 'General': $prefix = 'GV'; break;
        case 'Receipt': $prefix = 'RC'; break;
        case 'Payment': $prefix = 'PY'; break;
        case 'Sales': $prefix = 'SL'; break;
        case 'Purchase': $prefix = 'PR'; break;
        case 'Journal': $prefix = 'JV'; break;
        default: $prefix = 'GV';
    }
    
    $year = date('Y');
    $month = date('m');
    
    $query = "
        SELECT COUNT(*) as count 
        FROM AccountingVouchers 
        WHERE CompanyID = ? AND VoucherType = ? 
        AND YEAR(VoucherDate) = ? AND MONTH(VoucherDate) = ?
    ";
    $stmt = $conn->prepare($query);
    $stmt->bind_param("isii", $companyId, $voucherType, $year, $month);
    $stmt->execute();
    $result = $stmt->get_result();
    $count = $result->fetch_assoc()['count'] + 1;
    
    return $prefix . $year . $month . str_pad($count, 4, '0', STR_PAD_LEFT);
}

function updateVoucher() {
    global $conn, $userId;
    
    $data = json_decode(file_get_contents("php://input"), true);
    $voucherId = $_GET['voucher_id'] ?? $data['voucher_id'];
    
    if (!$voucherId) {
        sendResponse(false, null, 'Voucher ID is required', 400);
    }
    
    if (!checkPermission($userId, 'vouchers', 'edit')) {
        sendResponse(false, null, 'Permission denied', 403);
    }
    
    // بررسی وضعیت سند
    $statusQuery = "SELECT Status, CompanyID FROM AccountingVouchers WHERE VoucherID = ?";
    $statusStmt = $conn->prepare($statusQuery);
    $statusStmt->bind_param("i", $voucherId);
    $statusStmt->execute();
    $statusResult = $statusStmt->get_result();
    
    if ($statusResult->num_rows === 0) {
        sendResponse(false, null, 'Voucher not found', 404);
    }
    
    $voucher = $statusResult->fetch_assoc();
    if ($voucher['Status'] !== 'Draft') {
        sendResponse(false, null, 'Only draft vouchers can be modified', 400);
    }
    
    // به‌روزرسانی سند
    $conn->begin_transaction();
    
    try {
        // حذف سطرهای قبلی
        $deleteItemsQuery = "DELETE FROM VoucherItems WHERE VoucherID = ?";
        $deleteStmt = $conn->prepare($deleteItemsQuery);
        $deleteStmt->bind_param("i", $voucherId);
        $deleteStmt->execute();
        
        // درج سطرهای جدید
        $lineNumber = 1;
        foreach ($data['items'] as $item) {
            $itemQuery = "
                INSERT INTO VoucherItems (
                    VoucherID, AccountID, Description, DebitAmount, CreditAmount,
                    CurrencyID, ExchangeRate, CostCenterID, ProjectID,
                    CustomerID, SupplierID, EmployeeID, ReferenceType, ReferenceID, LineNumber
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ";
            
            $itemStmt = $conn->prepare($itemQuery);
            $itemStmt->bind_param(
                "iisdddsiiiiisii",
                $voucherId, $item['AccountID'], $item['Description'] ?? null,
                $item['DebitAmount'] ?? 0, $item['CreditAmount'] ?? 0,
                $data['CurrencyID'], $data['ExchangeRate'] ?? 1,
                $item['CostCenterID'] ?? null, $item['ProjectID'] ?? null,
                $item['CustomerID'] ?? null, $item['SupplierID'] ?? null,
                $item['EmployeeID'] ?? null, $item['ReferenceType'] ?? 'None',
                $item['ReferenceID'] ?? null, $lineNumber
            );
            $itemStmt->execute();
            
            $lineNumber++;
        }
        
        // محاسبه جمع جدید
        $totalQuery = "
            SELECT SUM(DebitAmount) as TotalDebit, SUM(CreditAmount) as TotalCredit
            FROM VoucherItems WHERE VoucherID = ?
        ";
        $totalStmt = $conn->prepare($totalQuery);
        $totalStmt->bind_param("i", $voucherId);
        $totalStmt->execute();
        $totals = $totalStmt->get_result()->fetch_assoc();
        
        // به‌روزرسانی سند اصلی
        $updateQuery = "
            UPDATE AccountingVouchers 
            SET Description = ?, ReferenceNumber = ?, ReferenceDate = ?,
                TotalDebit = ?, TotalCredit = ?, ExchangeRate = ?
            WHERE VoucherID = ?
        ";
        $updateStmt = $conn->prepare($updateQuery);
        $updateStmt->bind_param(
            "sssdddi",
            $data['Description'] ?? null, $data['ReferenceNumber'] ?? null,
            $data['ReferenceDate'] ?? null, $totals['TotalDebit'], $totals['TotalCredit'],
            $data['ExchangeRate'] ?? 1, $voucherId
        );
        $updateStmt->execute();
        
        $conn->commit();
        
        logAudit($userId, $voucher['CompanyID'], 'UPDATE', 'AccountingVouchers', $voucherId, 'Voucher updated');
        
        sendResponse(true, null, 'Voucher updated successfully');
        
    } catch (Exception $e) {
        $conn->rollback();
        sendResponse(false, null, 'Failed to update voucher: ' . $e->getMessage(), 500);
    }
}
?>

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

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

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

ارسال نظر

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