importzugferd/datanorm_changelog.php

333 lines
13 KiB
PHP

<?php
/* Copyright (C) 2026 ZUGFeRD Import Module
*
* 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 datanorm_changelog.php
* \ingroup importzugferd
* \brief View Datanorm update change log
*/
// 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';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
dol_include_once('/importzugferd/lib/importzugferd.lib.php');
// Load translations
$langs->loadLangs(array("importzugferd@importzugferd", "products", "bills"));
// Security check
if (!$user->hasRight('produit', 'lire')) {
accessforbidden();
}
// Get parameters
$action = GETPOST('action', 'aZ09');
$batch_id = GETPOST('batch_id', 'alphanohtml');
$fk_product = GETPOSTINT('fk_product');
$fk_soc = GETPOSTINT('fk_soc');
$date_start = GETPOST('date_start', 'alpha');
$date_end = GETPOST('date_end', 'alpha');
// Pagination
$sortfield = GETPOST('sortfield', 'aZ09comma');
$sortorder = GETPOST('sortorder', 'aZ09comma');
$page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT('page');
$limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit;
$offset = $limit * $page;
if (!$sortfield) $sortfield = 'l.date_change';
if (!$sortorder) $sortorder = 'DESC';
// Initialize objects
$form = new Form($db);
$formcompany = new FormCompany($db);
/*
* View
*/
$title = $langs->trans('DatanormChangeLog');
llxHeader('', $title, '', '', 0, 0, '', '', '', 'mod-importzugferd page-datanorm-changelog');
print load_fiche_titre($title, '<a href="'.dol_buildpath('/importzugferd/datanorm_update.php', 1).'" class="button">'.$langs->trans('DatanormMassUpdate').'</a>', 'fa-history');
// Filter form
print '<form method="GET" action="'.$_SERVER['PHP_SELF'].'">';
print '<div class="div-table-responsive-no-min">';
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<td colspan="6">'.$langs->trans('Filters').'</td>';
print '</tr>';
print '<tr class="oddeven">';
// Batch ID filter
print '<td class="titlefield">'.$langs->trans('BatchUpdate').'</td>';
print '<td>';
print '<input type="text" name="batch_id" value="'.dol_escape_htmltag($batch_id).'" class="minwidth200" placeholder="batch_...">';
print '</td>';
// Supplier filter
print '<td>'.$langs->trans('Supplier').'</td>';
print '<td>';
$sql = "SELECT DISTINCT s.rowid, s.nom FROM ".MAIN_DB_PREFIX."societe s";
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."importzugferd_datanorm_log l ON l.fk_soc = s.rowid";
$sql .= " ORDER BY s.nom";
$resql = $db->query($sql);
print '<select name="fk_soc" class="flat minwidth200">';
print '<option value="">'.$langs->trans('All').'</option>';
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
$selected = ($obj->rowid == $fk_soc) ? 'selected' : '';
print '<option value="'.$obj->rowid.'" '.$selected.'>'.dol_escape_htmltag($obj->nom).'</option>';
}
}
print '</select>';
print '</td>';
// Date range
print '<td>'.$langs->trans('DateRange').'</td>';
print '<td>';
print '<input type="date" name="date_start" value="'.dol_escape_htmltag($date_start).'" class="minwidth100">';
print ' - ';
print '<input type="date" name="date_end" value="'.dol_escape_htmltag($date_end).'" class="minwidth100">';
print '</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td colspan="6" class="center">';
print '<input type="submit" class="button" value="'.$langs->trans('Search').'">';
print ' &nbsp; <a href="'.$_SERVER['PHP_SELF'].'" class="button">'.$langs->trans('Reset').'</a>';
print '</td>';
print '</tr>';
print '</table>';
print '</div>';
print '</form>';
// Build SQL query
$sql = "SELECT l.*, p.ref as product_ref, p.label as product_label, s.nom as supplier_name, u.login as user_login";
$sql .= " FROM ".MAIN_DB_PREFIX."importzugferd_datanorm_log l";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product p ON p.rowid = l.fk_product";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe s ON s.rowid = l.fk_soc";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user u ON u.rowid = l.fk_user";
$sql .= " WHERE l.entity IN (".getEntity('product').")";
if (!empty($batch_id)) {
$sql .= " AND l.batch_id = '".$db->escape($batch_id)."'";
}
if ($fk_soc > 0) {
$sql .= " AND l.fk_soc = ".((int)$fk_soc);
}
if ($fk_product > 0) {
$sql .= " AND l.fk_product = ".((int)$fk_product);
}
if (!empty($date_start)) {
$sql .= " AND l.date_change >= '".$db->escape($date_start)." 00:00:00'";
}
if (!empty($date_end)) {
$sql .= " AND l.date_change <= '".$db->escape($date_end)." 23:59:59'";
}
// Count total
$sqlcount = preg_replace('/SELECT.*FROM/', 'SELECT COUNT(*) as total FROM', $sql);
$resqlcount = $db->query($sqlcount);
$total = 0;
if ($resqlcount) {
$objcount = $db->fetch_object($resqlcount);
$total = $objcount->total;
}
$sql .= $db->order($sortfield, $sortorder);
$sql .= $db->plimit($limit + 1, $offset);
$resql = $db->query($sql);
print '<br>';
// Batch summary if filtering by batch
if (!empty($batch_id)) {
$sql_batch = "SELECT MIN(date_change) as start_date, MAX(date_change) as end_date, COUNT(DISTINCT fk_product) as product_count, COUNT(*) as change_count";
$sql_batch .= " FROM ".MAIN_DB_PREFIX."importzugferd_datanorm_log";
$sql_batch .= " WHERE batch_id = '".$db->escape($batch_id)."'";
$res_batch = $db->query($sql_batch);
if ($res_batch) {
$batch_info = $db->fetch_object($res_batch);
print '<div class="info">';
print '<strong>'.$langs->trans('BatchUpdate').':</strong> '.$batch_id.'<br>';
print '<strong>'.$langs->trans('DateChange').':</strong> '.dol_print_date($db->jdate($batch_info->start_date), 'dayhour').'<br>';
print '<strong>'.$langs->trans('Products').':</strong> '.$batch_info->product_count.' | ';
print '<strong>'.$langs->trans('Changes').':</strong> '.$batch_info->change_count;
print '</div><br>';
}
}
// Navigation
print_barre_liste($langs->trans('ChangeHistory'), $page, $_SERVER['PHP_SELF'], '&batch_id='.urlencode($batch_id).'&fk_soc='.$fk_soc.'&date_start='.$date_start.'&date_end='.$date_end, $sortfield, $sortorder, '', $resql ? $db->num_rows($resql) : 0, $total, '', 0, '', '', $limit);
if ($resql) {
$num = $db->num_rows($resql);
print '<div class="div-table-responsive">';
print '<table class="noborder centpercent">';
// Header
print '<tr class="liste_titre">';
print_liste_field_titre($langs->trans('DateChange'), $_SERVER['PHP_SELF'], 'l.date_change', '', '&batch_id='.urlencode($batch_id).'&fk_soc='.$fk_soc, '', $sortfield, $sortorder);
print_liste_field_titre($langs->trans('Product'), $_SERVER['PHP_SELF'], 'p.ref', '', '&batch_id='.urlencode($batch_id).'&fk_soc='.$fk_soc, '', $sortfield, $sortorder);
print_liste_field_titre($langs->trans('Supplier'), $_SERVER['PHP_SELF'], 's.nom', '', '&batch_id='.urlencode($batch_id).'&fk_soc='.$fk_soc, '', $sortfield, $sortorder);
print_liste_field_titre($langs->trans('DatanormArticle'), $_SERVER['PHP_SELF'], 'l.datanorm_ref', '', '&batch_id='.urlencode($batch_id).'&fk_soc='.$fk_soc, '', $sortfield, $sortorder);
print_liste_field_titre($langs->trans('FieldChanged'), $_SERVER['PHP_SELF'], 'l.field_changed', '', '&batch_id='.urlencode($batch_id).'&fk_soc='.$fk_soc, '', $sortfield, $sortorder);
print_liste_field_titre($langs->trans('OldValue'), $_SERVER['PHP_SELF'], '', '', '', '');
print_liste_field_titre($langs->trans('NewValue'), $_SERVER['PHP_SELF'], '', '', '', '');
print_liste_field_titre($langs->trans('ChangedBy'), $_SERVER['PHP_SELF'], 'u.login', '', '&batch_id='.urlencode($batch_id).'&fk_soc='.$fk_soc, '', $sortfield, $sortorder);
print '</tr>';
if ($num > 0) {
$i = 0;
while ($i < min($num, $limit)) {
$obj = $db->fetch_object($resql);
print '<tr class="oddeven">';
// Date
print '<td class="nowraponall">'.dol_print_date($db->jdate($obj->date_change), 'dayhour').'</td>';
// Product
print '<td>';
$product = new Product($db);
if ($product->fetch($obj->fk_product) > 0) {
print $product->getNomUrl(1);
print '<br><span class="opacitymedium">'.$obj->product_label.'</span>';
}
print '</td>';
// Supplier
print '<td>'.dol_escape_htmltag($obj->supplier_name).'</td>';
// Datanorm ref
print '<td>'.dol_escape_htmltag($obj->datanorm_ref).'</td>';
// Field changed
print '<td>';
$field_label = '';
switch ($obj->field_changed) {
case 'price':
$field_label = $langs->trans('Price');
print '<i class="fas fa-euro-sign paddingright"></i>';
break;
case 'description':
$field_label = $langs->trans('Description');
print '<i class="fas fa-align-left paddingright"></i>';
break;
case 'label':
$field_label = $langs->trans('Label');
print '<i class="fas fa-tag paddingright"></i>';
break;
default:
$field_label = $obj->field_changed;
}
print $field_label;
print '</td>';
// Old value
print '<td class="tdoverflowmax200" style="background-color: #fff3cd;">';
if ($obj->field_changed == 'price') {
print price($obj->old_value);
} else {
print dol_escape_htmltag(dol_trunc($obj->old_value, 100));
}
print '</td>';
// New value
print '<td class="tdoverflowmax200" style="background-color: #d4edda;">';
if ($obj->field_changed == 'price') {
print price($obj->new_value);
// Show difference
$diff = $obj->new_value - $obj->old_value;
if ($obj->old_value > 0) {
$diff_percent = ($diff / $obj->old_value) * 100;
print '<br>';
if ($diff > 0) {
print '<span style="color: #d9534f;">+'.number_format($diff_percent, 1).'%</span>';
} else {
print '<span style="color: #5cb85c;">'.number_format($diff_percent, 1).'%</span>';
}
}
} else {
print dol_escape_htmltag(dol_trunc($obj->new_value, 100));
}
print '</td>';
// User
print '<td>'.dol_escape_htmltag($obj->user_login).'</td>';
print '</tr>';
$i++;
}
} else {
print '<tr class="oddeven"><td colspan="8" class="opacitymedium center">'.$langs->trans('NoChangesRecorded').'</td></tr>';
}
print '</table>';
print '</div>';
$db->free($resql);
} else {
dol_print_error($db);
}
// Export buttons
if ($total > 0) {
print '<br><div class="center">';
print '<a href="'.$_SERVER['PHP_SELF'].'?action=export&batch_id='.urlencode($batch_id).'&fk_soc='.$fk_soc.'&date_start='.$date_start.'&date_end='.$date_end.'" class="button">';
print '<i class="fas fa-download paddingright"></i>'.$langs->trans('Export');
print '</a>';
print '</div>';
}
llxFooter();
$db->close();