Debug v23

This commit is contained in:
Laurent Destailleur
2026-01-01 16:43:14 +01:00
parent 3da7cceb81
commit ada7bd2fd8
9 changed files with 346 additions and 191 deletions

View File

@@ -42,6 +42,7 @@ require_once DOL_DOCUMENT_ROOT.'/blockedlog/class/blockedlog.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
// Load translation files required by the page
@@ -196,16 +197,18 @@ if (GETPOST('action') == 'export' && $user->hasRight('blockedlog', 'read')) { /
if (!$error) {
// Get the ID of the first line qualified
$sql = "SELECT rowid,date_creation,tms,user_fullname,action,amounts,element,fk_object,date_object,ref_object,signature,fk_user,object_data";
$sql = "SELECT rowid";
$sql .= " FROM ".MAIN_DB_PREFIX."blockedlog";
$sql .= " WHERE entity = ".((int) $conf->entity);
// For unalterable log, we are using the date of creation of the log. Note that a bookkeeper may decide to dispatch an invoice
// on different periods for example to manage depreciation.
$sql .= " AND date_creation BETWEEN '".$db->idate($dates)."' AND '".$db->idate($datee)."'";
$sql .= " ORDER BY rowid ASC"; // Required so we get the first one
$sql .= " ORDER BY date_creation ASC, rowid ASC"; // Required so we get the first one
$sql .= $db->plimit(1);
$res = $db->query($sql);
if ($res) {
// Make the first fetch to get first line
// Make the first fetch to get first line and then get the previous hash.
$obj = $db->fetch_object($res);
if ($obj) {
$firstid = $obj->rowid;
@@ -220,54 +223,66 @@ if (GETPOST('action') == 'export' && $user->hasRight('blockedlog', 'read')) { /
}
}
// Define file name
$registrationnumber = getHashUniqueIdOfRegistration();
$secretkey = $registrationnumber;
$yearmonthtoexport = GETPOSTINT('yeartoexport').'-'.(GETPOSTINT('monthtoexport') > 0 ? sprintf("%02d", GETPOSTINT('monthtoexport')) : '');
$yearmonthdateofexport = dol_print_date(dol_now(), 'dayhourrfc', 'gmt');
$yearmonthdateofexportstandard = dol_print_date(dol_now(), 'dayhourlog', 'gmt');
$nameofdownoadedfile = "unalterable-log-archive-".$dolibarr_main_db_name."-".str_replace('-', '', $yearmonthtoexport).'-'.$yearmonthdateofexportstandard.'UTC-DONOTMODIFY.csv';
//$tmpfile = $conf->admin->dir_temp.'/unalterable-log-archive-tmp-'.$user->id.'.csv';
$tmpfile = getMultidirOutput($block_static, 'blockedlog').'/archives/'.$nameofdownoadedfile;
$formatexport = 'VE1';
// Init var for totals
$totalhtamountalllines = array('BILL_VALIDATE' => 0, 'PAYMENT_CUSTOMER_CREATE' => 0);
$totalvatamountalllines = array('BILL_VALIDATE' => 0, 'PAYMENT_CUSTOMER_CREATE' => 0);
$totalamountalllines = array('BILL_VALIDATE' => 0, 'PAYMENT_CUSTOMER_CREATE' => 0);
$totalhtamountlifetime = array('BILL_VALIDATE' => 0, 'PAYMENT_CUSTOMER_CREATE' => 0);
$totalvatamountlifetime = array('BILL_VALIDATE' => 0, 'PAYMENT_CUSTOMER_CREATE' => 0);
$totalamountlifetime = array('BILL_VALIDATE' => 0, 'PAYMENT_CUSTOMER_CREATE' => 0);
if (!$error) {
$fh = fopen($tmpfile, 'w');
}
if (!$error && $fh) {
// Now restart request with all data, so without the limit(1) in sql request
$sql = "SELECT rowid, date_creation, tms, user_fullname, action, amounts, element, fk_object, date_object, ref_object,";
$sql = "SELECT rowid, date_creation, tms, user_fullname, action, amounts_taxexcl, amounts, element, fk_object, date_object, ref_object,";
$sql .= " signature, fk_user, object_data, object_version, object_format, debuginfo";
$sql .= " FROM ".MAIN_DB_PREFIX."blockedlog";
$sql .= " WHERE entity = ".((int) $conf->entity);
if (GETPOSTINT('monthtoexport') > 0 || GETPOSTINT('yeartoexport') > 0) {
$dates = dol_get_first_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') > 0 ? GETPOSTINT('monthtoexport') : 1);
$datee = dol_get_last_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') > 0 ? GETPOSTINT('monthtoexport') : 12);
$sql .= " AND date_creation BETWEEN '".$db->idate($dates)."' AND '".$db->idate($datee)."'";
}
$sql .= " ORDER BY rowid ASC"; // Required so later we can use the parameter $previoushash of checkSignature()
// For unalterable log, we are using the date of creation of the log. Note that a bookkeeper may decide to dispatch an invoice
// on different periods for example to manage depreciation.
$sql .= " AND date_creation BETWEEN '".$db->idate($dates)."' AND '".$db->idate($datee)."'";
$sql .= " ORDER BY date_creation ASC, rowid ASC"; // Required so later we can use the parameter $previoushash of checkSignature()
$resql = $db->query($sql);
if ($resql) {
$registrationnumber = getHashUniqueIdOfRegistration();
$secretkey = $registrationnumber;
$yearmonthtoexport = GETPOSTINT('yeartoexport').(GETPOSTINT('monthtoexport') > 0 ? sprintf("%02d", GETPOSTINT('monthtoexport')) : '');
$yearmonthdateofexport = dol_print_date(dol_now(), 'dayhourlog', 'gmt');
$nameofdownoadedfile = "unalterable-log-archive-".$dolibarr_main_db_name."-".$yearmonthtoexport.'-'.$yearmonthdateofexport.'UTC-DONOTMODIFY.csv';
//$tmpfile = $conf->admin->dir_temp.'/unalterable-log-archive-tmp-'.$user->id.'.csv';
$tmpfile = getMultidirOutput($block_static, 'blockedlog').'/archives/'.$nameofdownoadedfile;
$fh = fopen($tmpfile, 'w');
$formatexport = 'V1';
// Print line with title
fwrite($fh, "BEGIN - date=".$yearmonthdateofexport." - period=".$yearmonthtoexport." - formatexport=".$formatexport." - user=".$user->getFullName($langs)
.';'.$langs->transnoentities('Id')
.';'.$langs->transnoentities('DateCreation')
.';'.$langs->transnoentities('Action')
.';'.$langs->transnoentities('Amounts')
.';'.$langs->transnoentities('AmountHT')
.';'.$langs->transnoentities('AmountTTC')
.';'.$langs->transnoentities('Ref')
.';'.$langs->transnoentities('Date')
.';'.$langs->transnoentities('User')
.';'.$langs->transnoentities('LinkTo')
.';'.$langs->transnoentities('LinkType')
.';'.$langs->transnoentities('FullData')
.';'.$langs->transnoentities('Version')
.';'.$langs->transnoentities('Fingerprint')
.';'.$langs->transnoentities('Version') // Version Dolibarr, example 22.0.0
.';'.$langs->transnoentities('VersionSignature') // Rule used for fingerprint calculation
.';'.$langs->transnoentities('FingerprintDatabase') // Signature
.';'.$langs->transnoentities('Status')
.';'.$langs->transnoentities('FingerprintExport')
.';'.$langs->transnoentities('FingerprintFormat')
//.';'.$langs->transnoentities('FingerprintExportHMAC')
."\n");
$loweridinerror = 0;
@@ -285,8 +300,8 @@ if (GETPOST('action') == 'export' && $user->hasRight('blockedlog', 'read')) { /
$block_static->date_creation = $db->jdate($obj->date_creation); // jdate(date_creation) is UTC
$block_static->amounts_excl = (float) $obj->amounts_excl; // Database store value with 8 digits, we cut ending 0 them with (flow)
$block_static->amounts = (float) $obj->amounts; // Database store value with 8 digits, we cut ending 0 them with (flow)
$block_static->vat = $obj->vat;
$block_static->action = $obj->action;
$block_static->date_object = $db->jdate($obj->date_object); // jdate(date_object) is UTC
@@ -347,148 +362,260 @@ if (GETPOST('action') == 'export' && $user->hasRight('blockedlog', 'read')) { /
sumAmountsForUnalterableEvent($block_static, $totalhtamount, $totalvatamount, $totalamount, $total_ht, $total_vat, $total_ttc);
fwrite($fh,
';'.$block_static->id
.';'.$block_static->date_creation
.';'.$block_static->action
.';'.$block_static->amounts // Can be 1.20000000 with 8 digits. TODO Clean to have 8 digits in V1
.';"'.str_replace('"', '""', $block_static->ref_object).'";'
.$block_static->date_object
.';"'.str_replace('"', '""', $block_static->user_fullname).'";"'
.str_replace('"', '""', $block_static->linktoref).'";"'
.str_replace('"', '""', $block_static->linktype).'";"'
.str_replace('"', '""', $obj->object_data).'"' // We must the string to decode into object with dolDecodeBlockedData
.';"'.str_replace('"', '""', $block_static->object_version).'";"'
.str_replace('"', '""', $block_static->signature).'";"'
.str_replace('"', '""', $statusofrecord).'";"'
.str_replace('"', '""', $signatureexport).'";"'
.str_replace('"', '""', $block_static->object_format).'";'
//.str_replace('"', '""', $signatureexporthmac).'"'
//.';'.$statusofrecordnote
."\n");
fwrite($fh, ";"
.csvClean($block_static->id).';'
.csvClean($block_static->date_creation).';'
.csvClean($block_static->action).';'
.csvClean($block_static->amounts_taxexcl).';' // Can be 1.20000000 with 8 digits. TODO Clean to have 8 digits in V1
.csvClean($block_static->amounts).';' // Can be 1.20000000 with 8 digits. TODO Clean to have 8 digits in V1
.csvClean($block_static->ref_object).';'
.csvClean($block_static->date_object).';'
.csvClean($block_static->user_fullname).';'
.csvClean($block_static->linktoref).';'
.csvClean($block_static->linktype).';'
.csvClean($obj->object_data).';' // We must the string to decode into object with dolDecodeBlockedData
.csvClean($block_static->object_version).';'
.csvClean($block_static->object_format).';'
.csvClean($block_static->signature).';'
.csvClean($statusofrecord).';'
.csvClean($signatureexport).';'."\n");
// Set new previous hash for next fetch
$previoushash = $obj->signature;
$i++;
}
} else {
$error++;
setEventMessages($db->lasterror, null, 'errors');
}
$totalhtamountallines = array('BILL_VALIDATE' => 0);
$totalvatamountallines = array('BILL_VALIDATE' => 0);
$totalamountalllines = array('BILL_VALIDATE' => 0);
if (array_key_exists('BILL_VALIDATE', $totalhtamount)) {
foreach ($totalhtamount['BILL_VALIDATE'] as $key => $val) {
$totalhtamountalllines['BILL_VALIDATE'] += $val;
// Now calculate cumulative total of all invoices validated
if (array_key_exists('BILL_VALIDATE', $totalhtamount)) {
foreach ($totalhtamount['BILL_VALIDATE'] as $key => $val) {
$totalhtamountalllines['BILL_VALIDATE'] += $val;
}
foreach ($totalvatamount['BILL_VALIDATE'] as $key => $val) {
$totalvatamountalllines['BILL_VALIDATE'] += $val;
}
foreach ($totalamount['BILL_VALIDATE'] as $key => $val) {
$totalamountalllines['BILL_VALIDATE'] += $val;
}
}
if (array_key_exists('PAYMENT_CUSTOMER_CREATE', $totalhtamount)) {
foreach ($totalhtamount['PAYMENT_CUSTOMER_CREATE'] as $key => $val) {
$totalhtamountalllines['PAYMENT_CUSTOMER_CREATE'] += $val;
}
foreach ($totalvatamount['PAYMENT_CUSTOMER_CREATE'] as $key => $val) {
$totalvatamountalllines['PAYMENT_CUSTOMER_CREATE'] += $val;
}
foreach ($totalamount['PAYMENT_CUSTOMER_CREATE'] as $key => $val) {
$totalamountalllines['PAYMENT_CUSTOMER_CREATE'] += $val;
}
}
// Add a final line with cumulative total of invoices validated (BILL_VALIDATE)
$block_static->id = '';
$block_static->date_creation = '';
$block_static->action = 'BILL_VALIDATE';
$block_static->amounts_taxexcl = $totalhtamountalllines['BILL_VALIDATE'];
$block_static->amounts = $totalamountalllines['BILL_VALIDATE'];
$block_static->ref_object = $langs->transnoentitiesnoconv("VAT").': '.$totalvatamountalllines['BILL_VALIDATE'];
$block_static->date_object = '';
$block_static->user_fullname = '';
$block_static->linktoref = '';
$block_static->linktype = '';
$block_static->object_data = '';
$block_static->object_version = '';
$block_static->signature = '';
$statusofrecord = '';
$signatureexport = '';
$block_static->object_format = '';
fwrite($fh, 'Cumulative total - Invoice validations;'
.csvClean($block_static->id).';'
.csvClean($block_static->date_creation).';'
.csvClean($block_static->action).';'
.csvClean($block_static->amounts_taxexcl).';' // Can be 1.20000000 with 8 digits. TODO Clean to have 8 digits in V1
.csvClean($block_static->amounts).';' // Can be 1.20000000 with 8 digits. TODO Clean to have 8 digits in V1
.csvClean($block_static->ref_object).';'
.csvClean($block_static->date_object).';'
.csvClean($block_static->user_fullname).';'
.csvClean($block_static->linktoref).';'
.csvClean($block_static->linktype).';'
.csvClean($obj->object_data).';' // We must the string to decode into object with dolDecodeBlockedData
.csvClean($block_static->object_version).';'
.csvClean($block_static->object_format).';'
.csvClean($block_static->signature).';'
.csvClean($statusofrecord).';'
.csvClean($signatureexport).';'."\n");
// Add a final line with cumulative total of invoices validated (PAYMENT_CUSTOMER_CREATE)
$block_static->id = '';
$block_static->date_creation = '';
$block_static->action = 'PAYMENT_CUSTOMER_CREATE';
$block_static->amounts_taxexcl = '';
$block_static->amounts = $totalamountalllines['PAYMENT_CUSTOMER_CREATE'];
$block_static->ref_object = '';
$block_static->date_object = '';
$block_static->user_fullname = '';
$block_static->linktoref = '';
$block_static->linktype = '';
$block_static->object_data = '';
$block_static->object_version = '';
$block_static->signature = '';
$statusofrecord = '';
$signatureexport = '';
$block_static->object_format = '';
fwrite($fh, 'Cumulative total - Invoice payments;'
.csvClean($block_static->id).';'
.csvClean($block_static->date_creation).';'
.csvClean($block_static->action).';'
.csvClean($block_static->amounts_taxexcl).';' // Can be 1.20000000 with 8 digits. TODO Clean to have 8 digits in V1
.csvClean($block_static->amounts).';' // Can be 1.20000000 with 8 digits. TODO Clean to have 8 digits in V1
.csvClean($block_static->ref_object).';'
.csvClean($block_static->date_object).';'
.csvClean($block_static->user_fullname).';'
.csvClean($block_static->linktoref).';'
.csvClean($block_static->linktype).';'
.csvClean($obj->object_data).';' // We must the string to decode into object with dolDecodeBlockedData
.csvClean($block_static->object_version).';'
.csvClean($block_static->object_format).';'
.csvClean($block_static->signature).';'
.csvClean($statusofrecord).';'
.csvClean($signatureexport).';'."\n");
// Calculate perpetual totals
$sql = "SELECT action, object_format, MIN(date_creation) as datemin, SUM(amounts_taxexcl) as sumamounts_taxexcl, SUM(amounts) as sumamounts";
$sql .= " FROM ".MAIN_DB_PREFIX."blockedlog";
$sql .= " WHERE entity = ".((int) $conf->entity);
$sql .= " AND action IN ('BILL_VALIDATE', 'PAYMENT_CUSTOMER_CREATE')";
$sql .= " GROUP BY action, object_format";
$foundoldformat = 0;
$firstrecorddate = array();
$resql = $db->query($sql);
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
if (!empty($firstrecorddate[$obj->action])) {
$firstrecorddate[$obj->action] = min($firstrecorddate[$obj->action], $db->jdate($obj->datemin));
} else {
$firstrecorddate[$obj->action] = $db->jdate($obj->datemin);
}
foreach ($totalvatamount['BILL_VALIDATE'] as $key => $val) {
$totalvatamountalllines['BILL_VALIDATE'] += $val;
}
foreach ($totalamount['BILL_VALIDATE'] as $key => $val) {
$totalamountalllines['BILL_VALIDATE'] += $val;
$totalamountlifetime[$obj->action] += $obj->sumamounts;
// If format of line is old, the sumamounts_taxexcl was not recorded. So we flag this case.
if (empty($obj->object_format) || $obj->object_format == 'V1') {
$foundoldformat = 1;
} else {
$totalhtamountlifetime[$obj->action] += $obj->sumamounts_taxexcl;
}
}
// Add a final line with cumulative total of invoices validated
$block_static->id = '';
$block_static->date_creation = '';
$block_static->action = '';
$block_static->amounts = $langs->transnoentitiesnoconv("HT").': '.$totalhtamountalllines['BILL_VALIDATE'].' | '.$langs->transnoentitiesnoconv("VAT").': '.$totalvatamountalllines['BILL_VALIDATE'].' | '.$langs->transnoentitiesnoconv("TTC").': '.$totalamountalllines['BILL_VALIDATE'];
$block_static->ref_object = '';
$block_static->date_object = '';
$block_static->user_fullname = '';
$block_static->linktoref = '';
$block_static->linktype = '';
$block_static->object_data = '';
$block_static->object_version = '';
$block_static->signature = '';
$statusofrecord = '';
$signatureexport = '';
$block_static->object_format = '';
fwrite($fh, 'Cumulative total Invoice Validation;'
.$block_static->id
.';'.$block_static->date_creation
.';'.$block_static->action
.';'.$block_static->amounts // Can be 1.20000000 with 8 digits. TODO Clean to have 8 digits in V1
.';"'.str_replace('"', '""', $block_static->ref_object).'";'
.$block_static->date_object
.';"'.str_replace('"', '""', $block_static->user_fullname).'";"'
.str_replace('"', '""', $block_static->linktoref).'";"'
.str_replace('"', '""', $block_static->linktype).'";"'
.str_replace('"', '""', $obj->object_data).'"' // We must the string to decode into object with dolDecodeBlockedData
.';"'.str_replace('"', '""', $block_static->object_version).'";"'
.str_replace('"', '""', $block_static->signature).'";"'
.str_replace('"', '""', $statusofrecord).'";"'
.str_replace('"', '""', $signatureexport).'";"'
.str_replace('"', '""', $block_static->object_format).'";'
//.str_replace('"', '""', $signatureexporthmac).'"'
//.';'.$statusofrecordnote
."\n");
// Add a final line with perpetual total
$totalhtamountlifetime = array();
$totalvatamountlifetime = array();
$totalamountlifetime = array();
$block_static->id = '';
$block_static->date_creation = '';
$block_static->action = '';
$block_static->amounts = $totalamountlifetime['BILL_VALIDATE'];
$block_static->ref_object = '';
$block_static->date_object = '';
$block_static->user_fullname = '';
$block_static->linktoref = '';
$block_static->linktype = '';
$block_static->object_data = '';
$block_static->object_version = '';
$block_static->signature = '';
$statusofrecord = '';
$signatureexport = '';
$block_static->object_format = '';
fwrite($fh, 'Perpetual total Invoice Validation;'
.$block_static->id
.';'.$block_static->date_creation
.';'.$block_static->action
.';'.$block_static->amounts // Can be 1.20000000 with 8 digits. TODO Clean to have 8 digits in V1
.';"'.str_replace('"', '""', $block_static->ref_object).'";'
.$block_static->date_object
.';"'.str_replace('"', '""', $block_static->user_fullname).'";"'
.str_replace('"', '""', $block_static->linktoref).'";"'
.str_replace('"', '""', $block_static->linktype).'";"'
.str_replace('"', '""', $obj->object_data).'"' // We must the string to decode into object with dolDecodeBlockedData
.';"'.str_replace('"', '""', $block_static->object_version).'";"'
.str_replace('"', '""', $block_static->signature).'";"'
.str_replace('"', '""', $statusofrecord).'";"'
.str_replace('"', '""', $signatureexport).'";"'
.str_replace('"', '""', $block_static->object_format).'";'
//.str_replace('"', '""', $signatureexporthmac).'"'
//.';'.$statusofrecordnote
."\n");
fclose($fh);
// Calculate the md5 of the file (the last line has a return line)
$algo = 'sha256';
$sha256 = hash_file($algo, $tmpfile);
$hmacsha256 = hash_hmac_file($algo, $tmpfile, $secretkey);
// Now add a signature to check integrity at end of file
file_put_contents($tmpfile, 'END - sha256='.$sha256.' - hmac_sha256='.$hmacsha256, FILE_APPEND);
dolChmod($tmpfile);
setEventMessages($langs->trans("FileGenerated"), null);
} else {
$error++;
setEventMessages($db->lasterror, null, 'errors');
}
// Add a final line with perpetual total for invoice validations
$block_static->id = '';
$block_static->date_creation = '';
$block_static->action = 'BILL_VALIDATE';
// if an old format was found, we do not have reliable amount excluding tax for lifetime value, we do not show it
$block_static->amounts_taxexcl = ($foundoldformat ? '' : $totalhtamountlifetime['BILL_VALIDATE']);
$block_static->amounts = $totalamountlifetime['BILL_VALIDATE'];
// if an old format was found, we do not have reliable VAT amount for lifetime value, we do not show it
$block_static->ref_object = ($foundoldformat ? '' : $langs->transnoentitiesnoconv("VAT").': '.($block_static->amounts - $totalhtamountlifetime['BILL_VALIDATE']));
$block_static->date_object = '';
$block_static->user_fullname = '';
$block_static->linktoref = '';
$block_static->linktype = '';
$block_static->object_data = '';
$block_static->object_version = '';
$block_static->signature = '';
$statusofrecord = '';
$signatureexport = '';
$block_static->object_format = '';
fwrite($fh, 'Lifetime total (>= '.dol_print_date($firstrecorddate['BILL_VALIDATE'], 'standard').') - Invoice validations;'
.csvClean($block_static->id).';'
.csvClean($block_static->date_creation).';'
.csvClean($block_static->action).';'
.csvClean($block_static->amounts_taxexcl).';' // Can be 1.20000000 with 8 digits. TODO Clean to have 8 digits in V1
.csvClean($block_static->amounts).';' // Can be 1.20000000 with 8 digits. TODO Clean to have 8 digits in V1
.csvClean($block_static->ref_object).';'
.csvClean($block_static->date_object).';'
.csvClean($block_static->user_fullname).';'
.csvClean($block_static->linktoref).';'
.csvClean($block_static->linktype).';'
.csvClean($obj->object_data).';' // We must the string to decode into object with dolDecodeBlockedData
.csvClean($block_static->object_version).';'
.csvClean($block_static->object_format).';'
.csvClean($block_static->signature).';'
.csvClean($statusofrecord).';'
.csvClean($signatureexport).';'."\n");
// Add a final line with perpetual total for customer payments
$block_static->id = '';
$block_static->date_creation = '';
$block_static->action = 'PAYMENT_CUSTOMER_CREATE';
$block_static->amounts_taxtecl = '';
$block_static->amounts = $totalamountlifetime['PAYMENT_CUSTOMER_CREATE'];
$block_static->ref_object = '';
$block_static->date_object = '';
$block_static->user_fullname = '';
$block_static->linktoref = '';
$block_static->linktype = '';
$block_static->object_data = '';
$block_static->object_version = '';
$block_static->signature = '';
$statusofrecord = '';
$signatureexport = '';
$block_static->object_format = '';
fwrite($fh, 'Lifetime total (>= '.dol_print_date($firstrecorddate['PAYMENT_CUSTOMER_CREATE'], 'standard').') - Invoice payments;'
.csvClean($block_static->id).';'
.csvClean($block_static->date_creation).';'
.csvClean($block_static->action).';'
.csvClean($block_static->amounts_taxexcl).';' // Can be 1.20000000 with 8 digits. TODO Clean to have 8 digits in V1
.csvClean($block_static->amounts).';' // Can be 1.20000000 with 8 digits. TODO Clean to have 8 digits in V1
.csvClean($block_static->ref_object).';'
.csvClean($block_static->date_object).';'
.csvClean($block_static->user_fullname).';'
.csvClean($block_static->linktoref).';'
.csvClean($block_static->linktype).';'
.csvClean($obj->object_data).';' // We must the string to decode into object with dolDecodeBlockedData
.csvClean($block_static->object_version).';'
.csvClean($block_static->object_format).';'
.csvClean($block_static->signature).';'
.csvClean($statusofrecord).';'
.csvClean($signatureexport).';'."\n");
fclose($fh);
// Calculate the md5 of the file (the last line has a return line)
$algo = 'sha256';
$sha256 = hash_file($algo, $tmpfile);
$hmacsha256 = hash_hmac_file($algo, $tmpfile, $secretkey);
// Now add a signature to check integrity at end of file
file_put_contents($tmpfile, 'END - sha256='.$sha256.' - hmac_sha256='.$hmacsha256, FILE_APPEND);
dolChmod($tmpfile);
if (!$error) {
setEventMessages($langs->trans("FileGenerated"), null);
}
}
if (!$error) {
@@ -506,7 +633,7 @@ if (GETPOST('action') == 'export' && $user->hasRight('blockedlog', 'read')) { /
$object->label = 'Export unalterable logs - Period: year='.GETPOSTINT('yeartoexport').(GETPOSTINT('monthtoexport') ? ' month='.GETPOSTINT('monthtoexport') : '');
$action = 'BLOCKEDLOG_EXPORT';
$result = $b->setObjectData($object, $action, 0, $user);
$result = $b->setObjectData($object, $action, 0, $user, null);
//var_dump($b); exit;
if ($result < 0) {

View File

@@ -163,10 +163,20 @@ if (GETPOST('downloadcsv', 'alpha')) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Year")), null, "errors");
$error++;
} else {
$dates = dol_get_first_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') > 0 ? GETPOSTINT('monthtoexport') : 1);
$datee = dol_get_last_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') > 0 ? GETPOSTINT('monthtoexport') : 12);
if ($datee >= dol_now()) {
setEventMessages($langs->trans("ErrorPeriodMustBePastToAllowExport"), null, "errors");
$error++;
}
// Get the ID of the first line qualified
$sql = "SELECT rowid,date_creation,tms,user_fullname,action,amounts,element,fk_object,date_object,ref_object,signature,fk_user,object_data";
$sql = "SELECT rowid, date_creation, tms, user_fullname, action, amounts, amounts_taxexcl, element, fk_object, date_object, ref_object, signature, fk_user, object_data";
$sql .= " FROM ".MAIN_DB_PREFIX."blockedlog";
$sql .= " WHERE entity = ".((int) $conf->entity);
// For unalterable log, we are using the date of creation of the log. Note that a bookkeeper may decide to dispatch an invoice
// on different periods for example to manage depreciation.
if (GETPOSTINT('monthtoexport') > 0 || GETPOSTINT('yeartoexport') > 0) {
$dates = dol_get_first_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') ? GETPOSTINT('monthtoexport') : 1);
$datee = dol_get_last_day(GETPOSTINT('yeartoexport'), GETPOSTINT('monthtoexport') ? GETPOSTINT('monthtoexport') : 12);
@@ -207,7 +217,7 @@ if (GETPOST('downloadcsv', 'alpha')) {
$object->label = 'Export unalterable logs - Period: year='.GETPOSTINT('yeartoexport').(GETPOSTINT('monthtoexport') ? ' month='.GETPOSTINT('monthtoexport') : '');
$action = 'BLOCKEDLOG_EXPORT';
$result = $b->setObjectData($object, $action, 0, $user);
$result = $b->setObjectData($object, $action, 0, $user, null);
//var_dump($b); exit;
if ($result < 0) {
@@ -225,7 +235,7 @@ if (GETPOST('downloadcsv', 'alpha')) {
if (!$error) {
// Now restart request with all data, si without the limit(1) in sql request
$sql = "SELECT rowid, date_creation, tms, user_fullname, action, amounts, element, fk_object, date_object, ref_object,";
$sql = "SELECT rowid, date_creation, tms, user_fullname, action, amounts, amounts_taxexcl, element, fk_object, date_object, ref_object,";
$sql .= " signature, fk_user, object_data, object_version, object_format, debuginfo";
$sql .= " FROM ".MAIN_DB_PREFIX."blockedlog";
$sql .= " WHERE entity = ".((int) $conf->entity);
@@ -274,8 +284,8 @@ if (GETPOST('downloadcsv', 'alpha')) {
$block_static->date_creation = $db->jdate($obj->date_creation); // TODO Use gmt
$block_static->amounts = (float) $obj->amounts; // Database store value with 8 digits, we cut ending 0 them with (flow)
$block_static->vat = $obj->vat;
$block_static->amounts_taxexcl = (float) $obj->amounts_taxexcl; // Database store value with 8 digits, we cut ending 0 them with (float)
$block_static->amounts = (float) $obj->amounts; // Database store value with 8 digits, we cut ending 0 them with (float)
$block_static->action = $obj->action;
$block_static->date_object = $db->jdate($obj->date_object); // TODO Use gmt ?

View File

@@ -71,6 +71,11 @@ class BlockedLog
*/
public $amounts = null;
/**
* @var float|string|null
*/
public $amounts_taxexcl = null;
/**
* @var float|string|null
*/
@@ -457,16 +462,17 @@ class BlockedLog
/**
* Populate properties of an unalterable log entry from object data.
* This populates ->object_data but also other fields like ->action, ->amounts and ->linktoref and ->linktype
* This populates ->object_data but also other fields like ->action, ->amounts_taxexcl, ->amounts and ->linktoref and ->linktype
* It also populates some debug info like ->element and ->fk_object
*
* @param CommonObject|stdClass $object object to store
* @param string $action action
* @param float|int $amounts amounts
* @param ?User $fuser User object (forced)
* @return int<-1,-1>|int<1,1> >0 if OK, <0 if KO
* @param CommonObject|stdClass $object Object to store
* @param string $action Action code
* @param float|int $amounts amounts (incl tax)
* @param ?User $fuser User object (forced)
* @param float|int|null $amounts_taxexcl amounts (excl tax or null if not relevant)
* @return int<-1,-1>|int<1,1> >0 if OK, <0 if KO
*/
public function setObjectData(&$object, $action, $amounts, $fuser = null)
public function setObjectData(&$object, $action, $amounts, $fuser = null, $amounts_taxexcl = null)
{
global $langs, $user, $mysoc;
@@ -479,6 +485,7 @@ class BlockedLog
// action
$this->action = $action;
// amount
$this->amounts_taxexcl = $amounts_taxexcl;
$this->amounts = $amounts;
// date
if ($object->element == 'payment' || $object->element == 'payment_supplier') {
@@ -1014,7 +1021,7 @@ class BlockedLog
return -1;
}
$sql = "SELECT b.rowid, b.date_creation, b.signature, b.amounts, b.action, b.element, b.fk_object, b.entity,";
$sql = "SELECT b.rowid, b.date_creation, b.signature, b.amounts_taxexcl, b.amounts, b.action, b.element, b.fk_object, b.entity,";
$sql .= " b.certified, b.tms, b.fk_user, b.user_fullname, b.date_object, b.ref_object, b.object_data, b.object_version, b.object_format";
$sql .= " FROM ".MAIN_DB_PREFIX."blockedlog as b";
if ($id) {
@@ -1031,6 +1038,7 @@ class BlockedLog
$this->date_creation = $this->db->jdate($obj->date_creation); // jdate(date_creation)is UTC
$this->date_modification = $this->db->jdate($obj->tms); // jdate(tms) is UTC
$this->amounts_taxecl = (is_null($obj->amounts_taxexcl) ? null : (float) $obj->amounts);
$this->amounts = (float) $obj->amounts;
$this->action = $obj->action;
$this->element = $obj->element;
@@ -1205,6 +1213,7 @@ class BlockedLog
$sql = "INSERT INTO ".MAIN_DB_PREFIX."blockedlog (";
$sql .= " date_creation,";
$sql .= " action,";
$sql .= " amounts_taxexcl,";
$sql .= " amounts,";
$sql .= " signature,";
$sql .= " element,";
@@ -1222,7 +1231,8 @@ class BlockedLog
$sql .= ") VALUES (";
$sql .= "'".$this->db->idate($this->date_creation)."',";
$sql .= "'".$this->db->escape($this->action)."',";
$sql .= $this->amounts.",";
$sql .= (is_null($this->amounts_taxexcl) ? "null" : (float) $this->amounts_taxexcl).",";
$sql .= (float) $this->amounts.",";
$sql .= "'".$this->db->escape($this->signature)."',";
$sql .= "'".$this->db->escape($this->element)."',";
$sql .= (int) $this->fk_object.",";
@@ -1339,7 +1349,7 @@ class BlockedLog
return $this->date_creation.'|'.$this->action.'|'.$this->amounts.'|'.$this->ref_object.'|'.$this->date_object.'|'.$this->user_fullname;
} elseif ($this->object_format == 'V2') {
$s = $this->entity;
$s .= '|'.$this->date_creation.'|'.$this->action.'|'.$this->amounts.'|'.$this->ref_object.'|'.$this->date_object.'|'.$this->user_fullname;
$s .= '|'.$this->date_creation.'|'.$this->action.'|'.$this->amounts_taxexcl.'|'.$this->amounts.'|'.$this->ref_object.'|'.$this->date_object.'|'.$this->user_fullname;
$s .= '|'.(string) $this->linktoref;
$s .= '|'.(string) $this->linktype;
return $s;

View File

@@ -230,7 +230,7 @@ class modBlockedLog extends DolibarrModules
// Add first entry in unalterable Log to track that module was activated
$action = 'MODULE_SET';
$result = $b->setObjectData($object, $action, 0);
$result = $b->setObjectData($object, $action, 0, $user, null);
if ($result < 0) {
$this->error = $b->error;
@@ -274,7 +274,7 @@ class modBlockedLog extends DolibarrModules
$object->label = 'Module disabled';
$b = new BlockedLog($this->db);
$result = $b->setObjectData($object, 'MODULE_RESET', 0);
$result = $b->setObjectData($object, 'MODULE_RESET', 0, $user, null);
if ($result < 0) {
$this->error = $b->error;
$this->errors = $b->errors;

View File

@@ -90,6 +90,7 @@ class InterfaceActionsBlockedLog extends DolibarrTriggers
// Event/record is qualified
$qualified = 0;
$amounts_taxexcl = null;
$amounts = 0;
if ($action === 'BILL_VALIDATE' || (($action === 'BILL_DELETE' || $action === 'BILL_SENTBYMAIL') && ($object->statut != 0 || $object->status != 0))
|| $action === 'BILL_SUPPLIER_VALIDATE' || (($action === 'BILL_SUPPLIER_DELETE' || $action === 'BILL_SUPPLIER_SENTBYMAIL') && ($object->statut != 0 || $object->status != 0))
@@ -105,13 +106,18 @@ class InterfaceActionsBlockedLog extends DolibarrTriggers
if (in_array($action, array(
'MEMBER_SUBSCRIPTION_CREATE', 'MEMBER_SUBSCRIPTION_MODIFY', 'MEMBER_SUBSCRIPTION_DELETE',
'DON_VALIDATE', 'DON_MODIFY', 'DON_DELETE'))) {
/** @var Don|Subscription $object */
/** @var Don|Subscription $object */
$amounts = (float) $object->amount;
} elseif ($action == 'CASHCONTROL_VALIDATE') {
/** @var CashControl $object */
$amounts = (float) $object->cash + (float) $object->cheque + (float) $object->card;
} elseif (property_exists($object, 'total_ttc')) {
$amounts = (float) $object->total_ttc;
} else {
if (property_exists($object, 'total_ht')) {
$amounts_taxexcl = (float) $object->total_ht;
}
if (property_exists($object, 'total_ttc')) {
$amounts = (float) $object->total_ttc;
}
}
}
/*if ($action === 'BILL_PAYED' || $action==='BILL_UNPAYED'
@@ -123,7 +129,6 @@ class InterfaceActionsBlockedLog extends DolibarrTriggers
if ($action === 'PAYMENT_CUSTOMER_CREATE' || $action === 'PAYMENT_SUPPLIER_CREATE' || $action === 'DONATION_PAYMENT_CREATE'
|| $action === 'PAYMENT_CUSTOMER_DELETE' || $action === 'PAYMENT_SUPPLIER_DELETE' || $action === 'DONATION_PAYMENT_DELETE') {
$qualified++;
$amounts = 0;
if (!empty($object->amounts)) {
foreach ($object->amounts as $amount) {
$amounts += (float) $amount;
@@ -143,7 +148,7 @@ class InterfaceActionsBlockedLog extends DolibarrTriggers
}
// Set field date_object, ref_object, fk_object, element, object_data
$result = $b->setObjectData($object, $action, $amounts, $user);
$result = $b->setObjectData($object, $action, $amounts, $user, $amounts_taxexcl);
if ($result < 0) {
$this->setErrorsFromObject($b);

View File

@@ -320,7 +320,7 @@ ALTER TABLE llx_oauth_token ADD COLUMN expire_at datetime NULL AFTER lastaccess;
ALTER TABLE llx_blockedlog ADD COLUMN linktoref varchar(255);
ALTER TABLE llx_blockedlog ADD COLUMN linktype varchar(16);
ALTER TABLE llx_blockedlog ADD COLUMN vat double(24,8) DEFAULT NULL;
ALTER TABLE llx_blockedlog ADD COLUMN amounts_taxexcl double(24,8) DEFAULT NULL AFTER amounts;
-- Incoterms 2025 and specific terms

View File

@@ -24,6 +24,7 @@ CREATE TABLE llx_blockedlog
date_creation datetime, -- field included into line signature
action varchar(50), -- The type of event. field included into line signature
amounts double(24,8) NOT NULL, -- field included into line signature (denormalized data from object_data)
amounts_taxexcl double(24,8) NULL, -- field included into line signature (denormalized data from object_data)
ref_object varchar(255), -- field included into line signature (denormalized data from object_data)
date_object datetime, -- field included into line signature (denormalized data from object_data)
user_fullname varchar(255), -- field included into line signature (denormalized data from object_data)
@@ -37,6 +38,7 @@ CREATE TABLE llx_blockedlog
fk_user integer,
fk_object integer,
object_version varchar(32) DEFAULT '', -- in which version did the line was recorded
object_format varchar(16) DEFAULT 'V1', -- format of data stored in object_data
certified integer, -- not used, reserved for future use
tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
debuginfo mediumtext

View File

@@ -3864,7 +3864,7 @@ function migrate_reset_blocked_log($db, $langs, $conf)
$object->date = dol_now();
$b = new BlockedLog($db);
$b->setObjectData($object, 'MODULE_SET', 0);
$b->setObjectData($object, 'MODULE_SET', 0, $user, null);
$res = $b->create($user);
if ($res <= 0) {

View File

@@ -12,7 +12,7 @@ CompanyInitialKey=Company initial key (hash of genesis block)
BrowseBlockedLog=Unalterable logs
ShowAllFingerPrintsMightBeTooLong=Show all archived unlaterable logs (might be long)
ShowAllFingerPrintsErrorsMightBeTooLong=Show all non-valid unalterable logs (might be long)
DownloadBlockChain=Download fingerprints
DownloadBlockChain=Download blockchain
KoCheckFingerprintValidity=Archived log entry is not valid. It means someone (a hacker?) has modified some data of this record after it was recorded, OR has erased the previous archived record (check that the line with previous # exists) OR has modified the checksum of the previous record.
OkCheckFingerprintValidity=Archived log record is valid. The data on this line was not modified and the entry follows the previous one.
OkCheckFingerprintValidityButChainIsKo=Archived log seems valid compared to previous one but the chain was corrupted previously.
@@ -22,10 +22,10 @@ BlockedLogBillDownload=Customer invoice download
BlockedLogBillPreview=Customer invoice preview
BlockedlogInfoDialog=Log Details
ListOfTrackedEvents=List of tracked events
Fingerprint=Fingerprint
FingerprintExport=Fingerprint export
FingerprintExportHMAC=Fingerprint export HMAC
FingerprintFormat=Fingerprint format
Fingerprint=Signature
FingerprintDatabase=Signature in database
FingerprintExport=Signature export
FingerprintExportHMAC=Signature export HMAC
DownloadLogCSV=Export unalterable logs (CSV)
DataOfArchivedEvent=Complete data of archived event
DataOfArchivedEventHelp=This field contains the complementary data that was archived on real time. Even if some parent business event could have been canceled or modified, the data stored here is the original data, and it can't be modified.
@@ -83,6 +83,7 @@ logPAYMENT_VARIOUS_DELETE=Payment (not assigned to an invoice) logical deletion
logPAYMENT_VARIOUS_MODIFY=Payment (not assigned to an invoice) modified
logBLOCKEDLOG_EXPORT=Export of unalterable logs into a file
DebugInfo=Debug info
PreviousFingerprint=Previous fingerprint
PreviousFingerprint=Previous signature
PaymentOf=Payment of
ReplacedBy=Replaced by
VersionSignature=Version signature