*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*/
/**
* \file htdocs/custom/buchaltungswidget/gewinn_detail.php
* \ingroup buchaltungswidget
* \brief Detail page for Profit/Loss with full charts and year selection
*/
// Load Dolibarr environment
$res = 0;
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
$tmp2 = realpath(__FILE__);
$i = strlen($tmp) - 1;
$j = strlen($tmp2) - 1;
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
$i--;
$j--;
}
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
$res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
}
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
}
if (!$res && file_exists("../main.inc.php")) {
$res = @include "../main.inc.php";
}
if (!$res && file_exists("../../main.inc.php")) {
$res = @include "../../main.inc.php";
}
if (!$res && file_exists("../../../main.inc.php")) {
$res = @include "../../../main.inc.php";
}
if (!$res) {
die("Include of main fails");
}
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
// Load translation files
$langs->loadLangs(array("buchaltungswidget@buchaltungswidget", "bills", "compta"));
// Access control
if (!$user->hasRight('facture', 'lire') && !$user->hasRight('fournisseur', 'facture', 'lire')) {
accessforbidden();
}
// Get parameters
$selectedYear = GETPOST('year', 'int');
if (empty($selectedYear)) {
$selectedYear = date('Y');
}
$currentYear = date('Y');
$years = range($currentYear - 5, $currentYear + 1);
/*
* View
*/
$title = $langs->trans("GewinnVerlust");
llxHeader('', $title, '', '', 0, 0, array('/includes/nnnick/chartjs/dist/Chart.min.js'), array('/buchaltungswidget/css/buchaltungswidget.css'));
print load_fiche_titre($title, '', 'accountancy');
// Year selector
print '
';
// Get data
$currentData = getIncomeExpenseByMonth($db, $selectedYear);
$lastYearData = getIncomeExpenseByMonth($db, $selectedYear - 1);
// Main chart - Cumulative profit/loss
print '';
print '
';
print '
';
print '
'.$langs->trans("CumulativeProfitLoss").'
';
print '
';
print '';
print '
';
print '
';
print '
';
print '
';
print '
';
print '
'.$langs->trans("MonthlyIncomeExpenses").'
';
print '
';
print '';
print '
';
print '
';
print '
';
print '
';
print '';
// Data table
print '';
print '
';
// Header
print '';
print '| '.$langs->trans("Month").' | ';
print ''.$langs->trans("Income").' | ';
print ''.$langs->trans("CustomerRelatedCosts").' | ';
print ''.$langs->trans("ProfitLoss").' | ';
print ''.$langs->trans("CumulativeProfit").' | ';
print ''.($selectedYear - 1).' '.$langs->trans("CumulativeProfit").' | ';
print '
';
$months = array(1 => 'Januar', 2 => 'Februar', 3 => 'Maerz', 4 => 'April', 5 => 'Mai', 6 => 'Juni',
7 => 'Juli', 8 => 'August', 9 => 'September', 10 => 'Oktober', 11 => 'November', 12 => 'Dezember');
$monthsShort = array(1 => 'Jan', 2 => 'Feb', 3 => 'Mar', 4 => 'Apr', 5 => 'Mai', 6 => 'Jun',
7 => 'Jul', 8 => 'Aug', 9 => 'Sep', 10 => 'Okt', 11 => 'Nov', 12 => 'Dez');
$totalIncome = 0;
$totalExpenses = 0;
$cumulative = 0;
$cumulativeLast = 0;
$labels = array();
$incomeData = array();
$expensesData = array();
$cumulativeData = array();
$cumulativeLastData = array();
$monthlyProfit = array();
foreach ($months as $m => $name) {
$income = isset($currentData['income'][$m]) ? $currentData['income'][$m] : 0;
$expenses = isset($currentData['customer_expenses'][$m]) ? $currentData['customer_expenses'][$m] : 0;
$profit = $income - $expenses;
$cumulative += $profit;
$incomeLast = isset($lastYearData['income'][$m]) ? $lastYearData['income'][$m] : 0;
$expensesLast = isset($lastYearData['customer_expenses'][$m]) ? $lastYearData['customer_expenses'][$m] : 0;
$cumulativeLast += ($incomeLast - $expensesLast);
$totalIncome += $income;
$totalExpenses += $expenses;
$colorClass = $profit >= 0 ? 'buchaltung-positive' : 'buchaltung-negative';
$colorCumulative = $cumulative >= 0 ? 'buchaltung-positive' : 'buchaltung-negative';
$colorCumulativeLast = $cumulativeLast >= 0 ? 'buchaltung-positive' : 'buchaltung-negative';
print '';
print '| '.$name.' | ';
print ''.price($income, 0, $langs, 1, 2, 2, $conf->currency).' | ';
print ''.price($expenses, 0, $langs, 1, 2, 2, $conf->currency).' | ';
print ''.price($profit, 0, $langs, 1, 2, 2, $conf->currency).' | ';
print ''.price($cumulative, 0, $langs, 1, 2, 2, $conf->currency).' | ';
print ''.price($cumulativeLast, 0, $langs, 1, 2, 2, $conf->currency).' | ';
print '
';
// Chart data
$labels[] = $monthsShort[$m];
$incomeData[] = round($income, 2);
$expensesData[] = round($expenses, 2);
$cumulativeData[] = round($cumulative, 2);
$cumulativeLastData[] = round($cumulativeLast, 2);
$monthlyProfit[] = round($profit, 2);
}
// Total row
$totalProfit = $totalIncome - $totalExpenses;
$colorClass = $totalProfit >= 0 ? 'buchaltung-positive' : 'buchaltung-negative';
print '';
print '| '.$langs->trans("Total").' | ';
print ''.price($totalIncome, 0, $langs, 1, 2, 2, $conf->currency).' | ';
print ''.price($totalExpenses, 0, $langs, 1, 2, 2, $conf->currency).' | ';
print ''.price($totalProfit, 0, $langs, 1, 2, 2, $conf->currency).' | ';
print ' | ';
print '
';
print '
';
print '
';
// Estimated income tax
if ($totalProfit > 0) {
$estimatedTax = calculateIncomeTax($totalProfit);
print '';
print ''.$langs->trans("EstimatedIncomeTax").': ';
print '~'.price($estimatedTax, 0, $langs, 1, 2, 2, $conf->currency).'';
print ' ('.$langs->trans("NetAfterTax").': '.price($totalProfit - $estimatedTax, 0, $langs, 1, 2, 2, $conf->currency).')';
print '
';
}
// Info box
print '';
print ''.$langs->trans("Note").': '.$langs->trans("CustomerRelatedCostsNote");
print '
';
// Charts JavaScript
print '';
llxFooter();
$db->close();
/**
* Get income and customer-related expenses by month
*/
function getIncomeExpenseByMonth($db, $year)
{
global $conf;
$result = array(
'income' => array_fill(1, 12, 0),
'customer_expenses' => array_fill(1, 12, 0),
);
// Income from customer invoices
$sql = "SELECT MONTH(f.datef) as month, SUM(f.total_ht) as total";
$sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
$sql .= " WHERE f.fk_statut > 0 AND f.entity = ".((int) $conf->entity);
$sql .= " AND YEAR(f.datef) = ".((int) $year);
$sql .= " GROUP BY MONTH(f.datef)";
$resql = $db->query($sql);
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
$result['income'][$obj->month] = (float) $obj->total;
}
$db->free($resql);
}
// Customer-related expenses only (materials for customers)
$sql = "SELECT MONTH(f.datef) as month, SUM(fd.total_ht) as total";
$sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."facture_fourn_det as fd ON fd.fk_facture_fourn = f.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON p.rowid = fd.fk_product";
$sql .= " WHERE f.fk_statut > 0 AND f.entity = ".((int) $conf->entity);
$sql .= " AND YEAR(f.datef) = ".((int) $year);
$sql .= " AND (fd.fk_product IS NOT NULL AND fd.fk_product > 0)";
$sql .= " AND (p.fk_product_type = 0 OR fd.product_type = 0)";
$sql .= " GROUP BY MONTH(f.datef)";
$resql = $db->query($sql);
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
$result['customer_expenses'][$obj->month] = (float) $obj->total;
}
$db->free($resql);
}
return $result;
}
/**
* Calculate estimated income tax
*/
function calculateIncomeTax($profit)
{
$taxableIncome = max(0, $profit - 11604);
if ($taxableIncome <= 0) {
return 0;
} elseif ($taxableIncome <= 17005) {
return $taxableIncome * 0.18;
} elseif ($taxableIncome <= 66760) {
return $taxableIncome * 0.30;
} else {
return $taxableIncome * 0.42;
}
}