ayula-storeee/views/barang/topsis_functions.php

175 lines
6.4 KiB
PHP

<?php
function restockWithTOPSIS($conn, $criteria_weights = null) {
// Bobot default (sesuai manual)
if ($criteria_weights === null) {
$criteria_weights = [
'stock_level' => 0.4,
'price_value' => 0.3,
'turnover_rate' => 0.3,
];
}
// Ambil data produk dan penjualan 30 hari terakhir sesuai struktur DB
$query = "
SELECT
bk.id_barangK AS id_barang,
bk.nama_barang,
bk.stok,
bk.harga,
COALESCE(SUM(dt.jumlah), 0) AS total_penjualan
FROM barang_kasir bk
LEFT JOIN detail_transaksi dt ON bk.id_barangK = dt.id_barangK
LEFT JOIN transaksi t ON dt.id_transaksi = t.id_transaksi
AND t.tanggal BETWEEN DATE_SUB(NOW(), INTERVAL 30 DAY) AND NOW()
GROUP BY bk.id_barangK, bk.nama_barang, bk.stok, bk.harga
";
$result = mysqli_query($conn, $query);
if (!$result) {
return ["error" => "Query failed: " . mysqli_error($conn)];
}
$products = [];
while ($row = mysqli_fetch_assoc($result)) {
// Pastikan harga sudah dalam format numeric (decimal)
$harga = (float)$row['harga'];
// Hitung turnover rate (penjualan/stok), hindari pembagian 0
$turnover_rate = ($row['stok'] > 0) ? ($row['total_penjualan'] / $row['stok']) : 0;
$products[] = [
'id_barang' => $row['id_barang'],
'nama_barang' => $row['nama_barang'],
'stok' => (int)$row['stok'],
'harga' => $harga,
'turnover_rate' => $turnover_rate,
];
}
if (empty($products)) {
return ["message" => "No products found"];
}
// Buat decision matrix dengan reciprocal stok (1/stok)
$decision_matrix = [];
foreach ($products as $product) {
$reciprocal_stock = ($product['stok'] > 0) ? (1 / $product['stok']) : 0;
$decision_matrix[] = [
'id_barang' => $product['id_barang'],
'nama_barang' => $product['nama_barang'],
'stock_level' => $reciprocal_stock,
'price_value' => $product['harga'],
'turnover_rate' => $product['turnover_rate'],
];
}
// Normalisasi
$normalized_matrix = normalizeMatrix($decision_matrix);
// Terapkan bobot
$weighted_matrix = applyWeights($normalized_matrix, $criteria_weights);
// Tentukan solusi ideal positif dan negatif
$ideal_solution = [];
$negative_ideal_solution = [];
foreach (['stock_level', 'price_value', 'turnover_rate'] as $criteria) {
$values = array_column($weighted_matrix, $criteria);
$ideal_solution[$criteria] = max($values);
$negative_ideal_solution[$criteria] = min($values);
}
// Hitung jarak ke solusi ideal positif dan negatif
$separation_ideal = [];
$separation_negative = [];
foreach ($weighted_matrix as $key => $product) {
$separation_ideal[$key] = sqrt(
pow($product['stock_level'] - $ideal_solution['stock_level'], 2) +
pow($product['price_value'] - $ideal_solution['price_value'], 2) +
pow($product['turnover_rate'] - $ideal_solution['turnover_rate'], 2)
);
$separation_negative[$key] = sqrt(
pow($product['stock_level'] - $negative_ideal_solution['stock_level'], 2) +
pow($product['price_value'] - $negative_ideal_solution['price_value'], 2) +
pow($product['turnover_rate'] - $negative_ideal_solution['turnover_rate'], 2)
);
}
// Hitung skor TOPSIS (relative closeness)
$relative_closeness = [];
foreach ($weighted_matrix as $key => $product) {
$denominator = $separation_negative[$key] + $separation_ideal[$key];
$relative_closeness[$key] = ($denominator > 0) ? ($separation_negative[$key] / $denominator) : 0;
}
// Siapkan hasil
$topsis_scores = [];
foreach ($relative_closeness as $key => $score) {
$topsis_scores[] = [
'id_barang' => $decision_matrix[$key]['id_barang'],
'nama_barang' => $decision_matrix[$key]['nama_barang'],
'stok' => $products[$key]['stok'],
'harga' => $products[$key]['harga'],
'topsis_score' => round($score, 4),
'rank' => 0,
];
}
// Urutkan berdasarkan skor TOPSIS descending
usort($topsis_scores, function($a, $b) {
return $b['topsis_score'] <=> $a['topsis_score'];
});
// Beri peringkat
foreach ($topsis_scores as $key => $product) {
$topsis_scores[$key]['rank'] = $key + 1;
}
return $topsis_scores;
}
function normalizeMatrix($matrix) {
$normalized = [];
$sum_squares = [
'stock_level' => 0,
'price_value' => 0,
'turnover_rate' => 0,
];
foreach ($matrix as $product) {
$sum_squares['stock_level'] += pow($product['stock_level'], 2);
$sum_squares['price_value'] += pow($product['price_value'], 2);
$sum_squares['turnover_rate'] += pow($product['turnover_rate'], 2);
}
foreach ($sum_squares as $key => $value) {
$sum_squares[$key] = sqrt($value);
}
foreach ($matrix as $key => $product) {
$normalized[$key] = [
'id_barang' => $product['id_barang'],
'nama_barang' => $product['nama_barang'],
'stock_level' => ($sum_squares['stock_level'] > 0) ? ($product['stock_level'] / $sum_squares['stock_level']) : 0,
'price_value' => ($sum_squares['price_value'] > 0) ? ($product['price_value'] / $sum_squares['price_value']) : 0,
'turnover_rate' => ($sum_squares['turnover_rate'] > 0) ? ($product['turnover_rate'] / $sum_squares['turnover_rate']) : 0,
];
}
return $normalized;
}
function applyWeights($matrix, $weights) {
$weighted = [];
foreach ($matrix as $key => $product) {
$weighted[$key] = [
'id_barang' => $product['id_barang'],
'nama_barang' => $product['nama_barang'],
'stock_level' => $product['stock_level'] * $weights['stock_level'],
'price_value' => $product['price_value'] * $weights['price_value'],
'turnover_rate' => $product['turnover_rate'] * $weights['turnover_rate'],
];
}
return $weighted;
}
?>