v1.2: Bugfixes USt-Widget, Statusfilter und Kategoriestatistik
- USt-Widget: Spalte fd.total_tva -> fd.tva fuer Lieferantenrechnungen (facture_fourn_det nutzt 'tva' statt 'total_tva' wie facturedet) - Stornierte Rechnungen (Status 3) aus allen Berechnungen ausgeschlossen (fk_statut > 0 -> fk_statut IN (1, 2) in 10 SQL-Queries) - Kategoriestatistik: Jahresvergleich berechnet jetzt korrekt zum Vorjahr - invoice_category_stats.php: Robuste Pfaderkennung statt hartem require - Fehlende en_US Uebersetzungen fuer Kategoriestatistik ergaenzt - Version 1.1 -> 1.2 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
67776723a3
commit
00c4792c17
11 changed files with 106 additions and 42 deletions
10
ChangeLog.md
10
ChangeLog.md
|
|
@ -1,5 +1,15 @@
|
|||
# CHANGELOG MODULE BUCHALTUNGSWIDGET FOR [DOLIBARR ERP CRM](https://www.dolibarr.org)
|
||||
|
||||
## 1.2
|
||||
|
||||
- Bugfix: USt-Widget zeigte bezahlte USt (Vorsteuer) immer als 0 an
|
||||
- Ursache: Falsche Spalte `total_tva` statt `tva` in Tabelle `facture_fourn_det`
|
||||
- Bugfix: Stornierte Rechnungen (Status 3) wurden in allen Berechnungen mitgezaehlt
|
||||
- Betrifft: USt, Gewinn/Verlust, Rentabilitaet (Widgets + Detailseiten)
|
||||
- Bugfix: Jahresvergleich in Kategoriestatistik berechnete Prozente in falscher Richtung
|
||||
- Bugfix: Robuste Pfaderkennung fuer invoice_category_stats.php
|
||||
- Fehlende englische Uebersetzungen fuer Kategoriestatistik ergaenzt
|
||||
|
||||
## 1.1
|
||||
|
||||
- Neue Statistikseite: Rechnungsstatistik nach Kategorie
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# BUCHHALTUNGS-WIDGET / ACCOUNTING WIDGETS FOR [DOLIBARR ERP & CRM](https://www.dolibarr.org)
|
||||
|
||||
**Version:** 1.1
|
||||
**Version:** 1.2
|
||||
**Compatibility:** Dolibarr 19.0+
|
||||
**Author:** Eduard Wisch - Data IT Solution
|
||||
**License:** GPL v3+
|
||||
|
|
@ -157,6 +157,13 @@ The following options can be configured in the admin area:
|
|||
|
||||
## Changelog
|
||||
|
||||
### Version 1.2
|
||||
- Fix: VAT widget showed paid VAT (input tax) always as 0 (wrong column name in supplier invoice detail table)
|
||||
- Fix: Cancelled invoices (status 3) were included in all financial calculations
|
||||
- Fix: Year comparison percentages in category statistics were calculated in wrong direction
|
||||
- Fix: Robust path detection for invoice_category_stats.php
|
||||
- Added missing English translations for category statistics
|
||||
|
||||
### Version 1.1
|
||||
- New: Invoice Category Statistics page
|
||||
- Filter invoices by category/tag
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ class box_gewinn_verlust extends ModeleBoxes
|
|||
// 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 .= " WHERE f.fk_statut IN (1, 2) AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " AND YEAR(f.datef) = ".((int) $year);
|
||||
$sql .= " GROUP BY MONTH(f.datef)";
|
||||
|
||||
|
|
@ -309,7 +309,7 @@ class box_gewinn_verlust extends ModeleBoxes
|
|||
$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 .= " WHERE f.fk_statut IN (1, 2) AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " AND YEAR(f.datef) = ".((int) $year);
|
||||
// Only include products (materials) - product_type 0 = product, 1 = service
|
||||
// Also include invoice lines with product linked
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@ class box_rentabilitaet extends ModeleBoxes
|
|||
$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 .= " INNER 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 .= " WHERE f.fk_statut IN (1, 2) AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " AND YEAR(f.datef) = ".((int) $year);
|
||||
// Only products (type 0), not services (type 1)
|
||||
// And only products that are meant for resale or customer projects
|
||||
|
|
@ -322,7 +322,7 @@ class box_rentabilitaet extends ModeleBoxes
|
|||
$sql = "SELECT MONTH(f.datef) as month, SUM(fd.total_ht) as total";
|
||||
$sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
|
||||
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."facturedet as fd ON fd.fk_facture = f.rowid";
|
||||
$sql .= " WHERE f.fk_statut > 0 AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " WHERE f.fk_statut IN (1, 2) AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " AND YEAR(f.datef) = ".((int) $year);
|
||||
$sql .= " GROUP BY MONTH(f.datef)";
|
||||
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ class box_ust_uebersicht extends ModeleBoxes
|
|||
$sql = "SELECT QUARTER(f.datef) as quarter, SUM(fd.total_tva) as tva_amount";
|
||||
$sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
|
||||
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."facturedet as fd ON fd.fk_facture = f.rowid";
|
||||
$sql .= " WHERE f.fk_statut > 0 AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " WHERE f.fk_statut IN (1, 2) AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " AND YEAR(f.datef) = ".((int) $year);
|
||||
$sql .= " GROUP BY QUARTER(f.datef)";
|
||||
|
||||
|
|
@ -265,10 +265,11 @@ class box_ust_uebersicht extends ModeleBoxes
|
|||
}
|
||||
|
||||
// VAT paid from supplier invoices
|
||||
$sql = "SELECT QUARTER(f.datef) as quarter, SUM(fd.total_tva) as tva_amount";
|
||||
// Hinweis: In facture_fourn_det heißt die USt-Spalte 'tva', nicht 'total_tva' wie bei facturedet
|
||||
$sql = "SELECT QUARTER(f.datef) as quarter, SUM(fd.tva) as tva_amount";
|
||||
$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 .= " WHERE f.fk_statut > 0 AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " WHERE f.fk_statut IN (1, 2) AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " AND YEAR(f.datef) = ".((int) $year);
|
||||
$sql .= " GROUP BY QUARTER(f.datef)";
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ class modBuchaltungsWidget extends DolibarrModules
|
|||
$this->editor_squarred_logo = ''; // Must be image filename into the module/img directory followed with @modulename. Example: 'myimage.png@buchaltungswidget'
|
||||
|
||||
// Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z'
|
||||
$this->version = '1.1';
|
||||
$this->version = '1.2';
|
||||
// Url to the file with your last numberversion of this module
|
||||
//$this->url_last_version = 'http://www.example.com/versionmodule.txt';
|
||||
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ function getIncomeExpenseByMonth($db, $year)
|
|||
// 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 .= " WHERE f.fk_statut IN (1, 2) AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " AND YEAR(f.datef) = ".((int) $year);
|
||||
$sql .= " GROUP BY MONTH(f.datef)";
|
||||
|
||||
|
|
@ -337,7 +337,7 @@ function getIncomeExpenseByMonth($db, $year)
|
|||
$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 .= " WHERE f.fk_statut IN (1, 2) 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)";
|
||||
|
|
|
|||
83
invoice_category_stats.php
Normal file → Executable file
83
invoice_category_stats.php
Normal file → Executable file
|
|
@ -14,7 +14,37 @@
|
|||
*/
|
||||
|
||||
// Load Dolibarr environment
|
||||
require '../../main.inc.php';
|
||||
$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/class/dolgraph.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
|
||||
|
|
@ -382,39 +412,40 @@ function getInvoiceStatsByYear($db, $conf, $socid, $userid, $object_status, $sql
|
|||
|
||||
$resql = $db->query($sql);
|
||||
if ($resql) {
|
||||
$prevnb = 0;
|
||||
$prevtotal = 0;
|
||||
$prevavg = 0;
|
||||
|
||||
// Zuerst alle Zeilen einlesen (absteigend sortiert)
|
||||
$rows = array();
|
||||
while ($obj = $db->fetch_object($resql)) {
|
||||
$row = array(
|
||||
$rows[] = array(
|
||||
'year' => $obj->year,
|
||||
'nb' => (int) $obj->nb,
|
||||
'total' => (float) $obj->total,
|
||||
'avg' => (float) $obj->avg,
|
||||
'nb_diff' => 0,
|
||||
'total_diff' => 0,
|
||||
'avg_diff' => 0,
|
||||
);
|
||||
|
||||
// Calculate percentage differences
|
||||
if ($prevnb > 0) {
|
||||
$row['nb_diff'] = (($obj->nb - $prevnb) / $prevnb) * 100;
|
||||
}
|
||||
if ($prevtotal > 0) {
|
||||
$row['total_diff'] = (($obj->total - $prevtotal) / $prevtotal) * 100;
|
||||
}
|
||||
if ($prevavg > 0) {
|
||||
$row['avg_diff'] = (($obj->avg - $prevavg) / $prevavg) * 100;
|
||||
}
|
||||
|
||||
$data[] = $row;
|
||||
|
||||
$prevnb = $obj->nb;
|
||||
$prevtotal = $obj->total;
|
||||
$prevavg = $obj->avg;
|
||||
}
|
||||
$db->free($resql);
|
||||
|
||||
// Prozentuale Veraenderung zum Vorjahr berechnen (jedes Jahr mit dem aelteren vergleichen)
|
||||
for ($i = 0; $i < count($rows); $i++) {
|
||||
$rows[$i]['nb_diff'] = 0;
|
||||
$rows[$i]['total_diff'] = 0;
|
||||
$rows[$i]['avg_diff'] = 0;
|
||||
|
||||
// Das naechste Element im Array ist das aeltere Jahr (DESC-Sortierung)
|
||||
if (isset($rows[$i + 1])) {
|
||||
$prev = $rows[$i + 1];
|
||||
if ($prev['nb'] > 0) {
|
||||
$rows[$i]['nb_diff'] = (($rows[$i]['nb'] - $prev['nb']) / $prev['nb']) * 100;
|
||||
}
|
||||
if ($prev['total'] > 0) {
|
||||
$rows[$i]['total_diff'] = (($rows[$i]['total'] - $prev['total']) / $prev['total']) * 100;
|
||||
}
|
||||
if ($prev['avg'] > 0) {
|
||||
$rows[$i]['avg_diff'] = (($rows[$i]['avg'] - $prev['avg']) / $prev['avg']) * 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$data = $rows;
|
||||
}
|
||||
|
||||
return $data;
|
||||
|
|
|
|||
|
|
@ -122,6 +122,20 @@ PaymentWarning = Slow Payer
|
|||
PaymentLate = Late
|
||||
PaymentCritical = Critical
|
||||
|
||||
#
|
||||
# Invoice Category Statistics
|
||||
#
|
||||
StatistikenNachKategorie = Statistics by Category
|
||||
NachRechnungskategorie = By Invoice Category
|
||||
Statistik = Statistics
|
||||
InvoiceCategoryStatistics = Invoice Statistics by Category
|
||||
SelectInvoiceCategory = Select Invoice Category
|
||||
NoInvoiceCategoriesFound = No invoice categories found
|
||||
AllCategories = All Categories
|
||||
CategoryFilter = Category Filter
|
||||
InvoicesInCategory = Invoices in this Category
|
||||
AmountInCategory = Amount in this Category
|
||||
|
||||
#
|
||||
# Months
|
||||
#
|
||||
|
|
|
|||
|
|
@ -340,7 +340,7 @@ function getProfitabilityByMonth($db, $year)
|
|||
$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 .= " INNER 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 .= " WHERE f.fk_statut IN (1, 2) AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " AND YEAR(f.datef) = ".((int) $year);
|
||||
$sql .= " AND p.fk_product_type = 0";
|
||||
$sql .= " AND (p.tobuy = 1 OR p.tosell = 1)";
|
||||
|
|
@ -358,7 +358,7 @@ function getProfitabilityByMonth($db, $year)
|
|||
$sql = "SELECT MONTH(f.datef) as month, SUM(fd.total_ht) as total";
|
||||
$sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
|
||||
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."facturedet as fd ON fd.fk_facture = f.rowid";
|
||||
$sql .= " WHERE f.fk_statut > 0 AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " WHERE f.fk_statut IN (1, 2) AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " AND YEAR(f.datef) = ".((int) $year);
|
||||
$sql .= " GROUP BY MONTH(f.datef)";
|
||||
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ function getVatData($db, $year, $mode = 'quarterly')
|
|||
$sql = "SELECT ".$groupBy." as period, SUM(fd.total_tva) as tva_amount";
|
||||
$sql .= " FROM ".MAIN_DB_PREFIX."facture as f";
|
||||
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."facturedet as fd ON fd.fk_facture = f.rowid";
|
||||
$sql .= " WHERE f.fk_statut > 0 AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " WHERE f.fk_statut IN (1, 2) AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " AND YEAR(f.datef) = ".((int) $year);
|
||||
$sql .= " GROUP BY ".$groupBy;
|
||||
|
||||
|
|
@ -320,10 +320,11 @@ function getVatData($db, $year, $mode = 'quarterly')
|
|||
}
|
||||
|
||||
// VAT paid
|
||||
$sql = "SELECT ".$groupBy." as period, SUM(fd.total_tva) as tva_amount";
|
||||
// Hinweis: In facture_fourn_det heißt die USt-Spalte 'tva', nicht 'total_tva' wie bei facturedet
|
||||
$sql = "SELECT ".$groupBy." as period, SUM(fd.tva) as tva_amount";
|
||||
$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 .= " WHERE f.fk_statut > 0 AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " WHERE f.fk_statut IN (1, 2) AND f.entity = ".((int) $conf->entity);
|
||||
$sql .= " AND YEAR(f.datef) = ".((int) $year);
|
||||
$sql .= " GROUP BY ".$groupBy;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue