Files
kulakpos_web/public/assets/plugins/custom/branch-overview.js

375 lines
12 KiB
JavaScript
Raw Normal View History

2026-03-15 17:08:23 +07:00
"use strict";
function currencyFormat(amount, type = "icon", decimals = 2) {
let symbol = $("#currency_symbol").val();
let position = $("#currency_position").val();
let code = $("#currency_code").val();
let formattedAmount = formatNumber(amount, decimals); // Abbreviate number
// Apply currency format based on the position and type
if (type == "icon" || type == "symbol") {
return position == "right"
? formattedAmount + symbol
: symbol + formattedAmount;
} else {
return position == "right"
? formattedAmount + " " + code
: code + " " + formattedAmount;
}
}
function formatNumber(number, decimals = 2) {
if (number >= 1e9) {
return removeTrailingZeros((number / 1e9).toFixed(decimals)) + "B";
} else if (number >= 1e6) {
return removeTrailingZeros((number / 1e6).toFixed(decimals)) + "M";
} else if (number >= 1e3) {
return removeTrailingZeros((number / 1e3).toFixed(decimals)) + "K";
} else {
return removeTrailingZeros(number.toFixed(decimals));
}
}
function removeTrailingZeros(value) {
return parseFloat(value).toString();
}
let branchRevenueChart;
$(document).ready(function () {
const ctxBranchRevenue = document
.getElementById("branchRevenueChart")
.getContext("2d");
function totalEarningExpenseChart(months, incomeData, expenseData) {
if (branchRevenueChart) {
branchRevenueChart.destroy();
}
const allData = [...incomeData, ...expenseData];
const maxValue = Math.max(...allData);
// Gradient Backgrounds
const incomeBgGradient = ctxBranchRevenue.createLinearGradient(0, 0, 0, 400);
incomeBgGradient.addColorStop(0, "rgba(42, 180, 249, 0.17)");
incomeBgGradient.addColorStop(1, "rgba(34, 201, 177, 0)");
const expenseBgGradient = ctxBranchRevenue.createLinearGradient(0, 0, 0, 400);
expenseBgGradient.addColorStop(0, "rgba(248, 107, 35, 0.12)");
expenseBgGradient.addColorStop(1, "rgba(249, 190, 16, 0)");
// Solid Gradients for border lines
const incomeLine = ctxBranchRevenue.createLinearGradient(0, 0, 400, 0);
incomeLine.addColorStop(0, "#019934");
incomeLine.addColorStop(1, "#019934");
const expenseLine = ctxBranchRevenue.createLinearGradient(0, 0, 400, 0);
expenseLine.addColorStop(0, "#FF9500");
expenseLine.addColorStop(1, "#FF9500");
branchRevenueChart = new Chart(ctxBranchRevenue, {
type: "line",
data: {
labels: months,
datasets: [
{
label: "Profit",
data: incomeData,
borderColor: incomeLine,
backgroundColor: incomeBgGradient,
fill: true,
tension: 0.4,
pointBackgroundColor: "#019934",
pointRadius: 0,
pointHoverRadius: 5,
},
{
label: "Loss",
data: expenseData,
borderColor: expenseLine,
backgroundColor: expenseBgGradient,
fill: true,
tension: 0.4,
pointBackgroundColor: "#FF9500",
pointRadius: 0,
pointHoverRadius: 5,
},
],
},
options: {
responsive: true,
maintainAspectRatio: false,
interaction: { mode: "index", intersect: false },
plugins: {
tooltip: {
backgroundColor: "#ffffff",
titleColor: "#000000",
bodyColor: "#000000",
borderColor: "#e5e7eb",
borderWidth: 1,
callbacks: {
label: function (context) {
const value = parseFloat(context.raw);
return `${context.dataset.label} : ${(value)}`;
},
},
},
legend: { display: false },
},
scales: {
y: {
beginAtZero: true,
grid: { drawBorder: false, color: "#C2C6CE", borderDash: [4, 4] },
ticks: {
callback: function (value) {
if (maxValue < 1000) return value;
else if (maxValue < 100000) return (value / 1000) + 'k';
else return (value / 100000).toFixed(1) + 'M';
},
},
},
x: { grid: { display: false } },
},
},
});
}
function fetchIncomeExpense(year) {
const route = $("#incomeExpenseRoute").val();
$.ajax({
url: route,
type: "GET",
data: { year: year },
success: function (data) {
const months = [
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
];
const incomeData = Array(12).fill(0);
const expenseData = Array(12).fill(0);
data.incomes.forEach((item) => {
const monthIndex = item.month_number - 1;
incomeData[monthIndex] = parseFloat(item.total);
});
data.expenses.forEach((item) => {
const monthIndex = item.month_number - 1;
expenseData[monthIndex] = parseFloat(item.total);
});
const totalIncome = incomeData.reduce((a, b) => a + b, 0);
const totalExpense = expenseData.reduce((a, b) => a + b, 0);
$(".profit-value").text(currencyFormat(totalIncome));
$(".loss-value").text(currencyFormat(totalExpense));
totalEarningExpenseChart(months, incomeData, expenseData);
},
error: function (err) {
console.error("Error fetching income/expense data:", err);
},
});
}
// Initial load
const selectedYear = $(".overview-year").val();
fetchIncomeExpense(selectedYear);
// On year change
$(".overview-year").on("change", function () {
const year = $(this).val();
fetchIncomeExpense(year);
});
});
// Profit Loss Reports ----------------------->
const profitLossCanvas = document.getElementById("profitLossChart");
const ctxProfitLoss = profitLossCanvas.getContext("2d");
const gradientProfit = ctxProfitLoss.createLinearGradient(0, 0, 0, profitLossCanvas.height);
gradientProfit.addColorStop(0, "#05C535");
gradientProfit.addColorStop(1, "#36F165");
const gradientLoss = ctxProfitLoss.createLinearGradient(0, 0, 0, profitLossCanvas.height);
gradientLoss.addColorStop(0, "#FF8983");
gradientLoss.addColorStop(1, "#FF3B30");
// Initial static values (will be updated dynamically)
let profit = 0;
let loss = 0;
const profitLossData = {
labels: ["Income", "Expense"],
datasets: [
{
data: [profit, loss],
backgroundColor: [gradientProfit, gradientLoss],
hoverOffset: 5,
},
],
};
const profitLossConfig = {
type: "pie",
data: profitLossData,
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: false },
tooltip: {
enabled: true,
backgroundColor: "#FFFFFF",
titleColor: "#000000",
bodyColor: "#000000",
borderWidth: 1,
displayColors: false,
callbacks: {
label: function (context) {
const label = context.label || '';
const value = parseFloat(context.parsed || 0);
const formattedValue = value.toFixed(2);
return `${label}: ${formattedValue}`;
},
},
},
},
},
};
const profitLossChart = new Chart(ctxProfitLoss, profitLossConfig);
// Dynamic update function
const chartRoute = document.getElementById("salePurchaseChartRoute").value;
const yearSelector = document.querySelector(".overview-loss-profit-year");
function updateProfitLossChart(year) {
fetch(`${chartRoute}?year=${year}`)
.then(res => res.json())
.then(data => {
profit = data.profit ?? 0;
loss = data.loss ?? 0;
// Update chart dataset
profitLossChart.data.datasets[0].data = [profit, loss];
profitLossChart.update();
// ✅ Use your currencyFormat for displayed values too
document.querySelector(".profit").textContent = currencyFormat(profit);
document.querySelector(".loss").textContent = currencyFormat(loss);
})
.catch(err => {
console.error("Error fetching profit/loss data:", err);
});
}
// Initial load
updateProfitLossChart(yearSelector.value);
// On year change
yearSelector.addEventListener("change", function () {
updateProfitLossChart(this.value);
});
// Responsive resize
window.addEventListener("resize", function () {
profitLossChart.resize();
});
// for sale data
$(document).ready(function() {
var route = $('#branchWiseSaleRoute').val();
// Load current year sales on page load
var currentYear = $('.branch-wise-sales-year').val();
fetchBranchWiseSales(currentYear);
// Listen for year change
$('.branch-wise-sales-year').on('change', function() {
var year = $(this).val();
fetchBranchWiseSales(year);
});
function fetchBranchWiseSales(year) {
$.ajax({
url: route,
type: 'GET',
data: { year: year },
dataType: 'json',
success: function(data) {
var tbody = $('#sale-data');
tbody.empty(); // clear existing table rows
$.each(data, function(index, branch) {
var row = `
<tr>
<td>${index + 1}</td>
<td>${branch.name}</td>
<td>${branch.sales_sum_total_amount_formatted}</td>
<td>${branch.sales_sum_paid_amount_formatted}</td>
<td>${branch.sales_sum_due_amount_formatted}</td>
</tr>
`;
tbody.append(row);
});
},
error: function(xhr, status, error) {
console.error('Error fetching branch sales:', error);
}
});
}
});
// for purchase data
$(document).ready(function() {
function fetchBranchPurchases(year) {
let url = $('#branchWisePurchaseRoute').val();
$.ajax({
url: url,
method: 'GET',
data: { year: year },
dataType: 'json',
success: function(response) {
let tbody = $('#purchase-data');
tbody.empty();
$.each(response, function(index, branch) {
let row = `
<tr>
<td>${index + 1}</td>
<td>${branch.name}</td>
<td>${branch.purchases_sum_total_amount_formatted}</td>
<td>${branch.purchases_sum_paid_amount_formatted}</td>
<td>${branch.purchases_sum_due_amount_formatted}</td>
</tr>
`;
tbody.append(row);
});
},
error: function(xhr, status, error) {
console.error('Error fetching branch purchases:', error);
}
});
}
// Initial load for current year
let currentYear = $('.batch-wise-purchases-year').val();
fetchBranchPurchases(currentYear);
// Fetch data on year change
$('.batch-wise-purchases-year').on('change', function() {
let selectedYear = $(this).val();
fetchBranchPurchases(selectedYear);
});
});