Merge branch '23.0' of git@github.com:Dolibarr/dolibarr.git into develop

This commit is contained in:
Laurent Destailleur
2026-01-02 18:16:47 +01:00
44 changed files with 769 additions and 472 deletions

View File

@@ -226,7 +226,7 @@ print dol_get_fiche_head($head, (string) $tab, '', -1, '');
// Print title
if ($mode && !count($data)) {
print $langs->trans("NoValidatedMemberYet").'<br>';
print '<span class="opacitymedium">'.$langs->trans("NoValidatedMemberYet").'</span><br>';
print '<br>';
} else {
if (empty($mode) || $mode == 'memberbycountry') {

View File

@@ -32,6 +32,14 @@
// Load Dolibarr environment
require '../main.inc.php';
/**
* @var Conf $conf
* @var DoliDB $db
* @var HookManager $hookmanager
* @var Societe $mysoc
* @var Translate $langs
* @var User $user
*/
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
@@ -46,15 +54,6 @@ $action = GETPOST('action', 'aZ09');
$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'admincompany'; // To manage different context of search
$page_y = GETPOSTINT('page_y');
/**
* @var Conf $conf
* @var DoliDB $db
* @var HookManager $hookmanager
* @var Societe $mysoc
* @var Translate $langs
* @var User $user
*/
// Load translation files required by the page
$langs->loadLangs(array('admin', 'companies', 'bills'));
@@ -604,15 +603,6 @@ print '<input name="MAIN_INFO_GDPR" id="infodirector" class="minwidth300" value=
print '<tr class="oddeven"><td><label for="capital">'.$langs->trans("Capital").'</label></td><td>';
print '<input name="capital" id="capital" class="maxwidth100" value="'.dolPrintHTMLForAttribute((GETPOSTISSET('capital') ? GETPOST('capital', 'alphanohtml') : getDolGlobalString('MAIN_INFO_CAPITAL'))).'"></td></tr>';
// Juridical Status
print '<tr class="oddeven"><td><label for="forme_juridique_code">'.$langs->trans("JuridicalStatus").'</label></td><td>';
if ($mysoc->country_code) {
print $formcompany->select_juridicalstatus(getDolGlobalInt('MAIN_INFO_SOCIETE_FORME_JURIDIQUE'), $mysoc->country_code, '', 'forme_juridique_code');
} else {
print $countrynotdefined;
}
print '</td></tr>';
// Object of the company
print '<tr class="oddeven"><td><label for="socialobject">'.$langs->trans("CompanyObject").'</label></td><td>';
print '<textarea class="flat quatrevingtpercent" name="socialobject" id="socialobject" rows="'.ROWS_3.'">'.getDolGlobalString('MAIN_INFO_SOCIETE_OBJECT').'</textarea></td></tr>';
@@ -623,6 +613,15 @@ print '<tr class="oddeven"><td><label for="intra_vat">'.$langs->trans("VATIntra"
print '<input name="tva" id="intra_vat" class="minwidth200" value="'.dolPrintHTMLForAttribute(getDolGlobalString('MAIN_INFO_TVAINTRA')).'">';
print '</td></tr>';
// Juridical Status
print '<tr class="oddeven"><td><label for="forme_juridique_code">'.$langs->trans("JuridicalStatus").'</label></td><td>';
if ($mysoc->country_code) {
print $formcompany->select_juridicalstatus(getDolGlobalInt('MAIN_INFO_SOCIETE_FORME_JURIDIQUE'), $mysoc->country_code, '', 'forme_juridique_code');
} else {
print $countrynotdefined;
}
print '</td></tr>';
// ProfId1
if ($langs->transcountry("ProfId1", $mysoc->country_code) != '-') {
print '<tr class="oddeven"><td><label for="profid1">'.$langs->transcountry("ProfId1", $mysoc->country_code).'</label></td><td>';

View File

@@ -690,7 +690,6 @@ if ($mode == 'login') {
print '<tr class="liste_titre"><td class="titlefieldmax45">';
print $langs->trans("Parameter");
print '</td><td>';
print $langs->trans("Value");
print '</td></tr>';
// Hide helpcenter link on login page

View File

@@ -216,12 +216,12 @@ print '</tr>';
print '</table>';
print '</div>';
print dol_get_fiche_end();
print '<div class="center">';
print '<input class="button button-save" type="submit" name="save" value="'.$langs->trans("Save").'">';
print '</div>';
print dol_get_fiche_end();
print '</form>';
// End of page

View File

@@ -118,7 +118,7 @@ if ($withtab) {
print '<span class="opacitymedium">'.$langs->trans("BlockedLogDesc")."</span><br>\n";
if ($mysoc->country_code == 'FR') {
if (in_array($mysoc->country_code, array('FR'))) {
$htmltext = $langs->trans("UnalterableLogTool1FR").'<br>';
print info_admin($htmltext, 0, 0, 'warning');
}

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,88 +223,75 @@ 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) {
// We record the export as a new line into the unalterable logs
require_once DOL_DOCUMENT_ROOT.'/blockedlog/class/blockedlog.class.php';
$b = new BlockedLog($db);
$object = new stdClass();
$object->id = 0;
$object->element = 'module';
$object->ref = 'systemevent';
$object->entity = $conf->entity;
$object->date = dol_now();
$object->label = 'Export unalterable logs - Period: year='.GETPOSTINT('yeartoexport').(GETPOSTINT('monthtoexport') ? ' month='.GETPOSTINT('monthtoexport') : '');
$action = 'BLOCKEDLOG_EXPORT';
$result = $b->setObjectData($object, $action, 0, $user);
//var_dump($b); exit;
if ($result < 0) {
setEventMessages('Failed to insert the export int the unalterable log', null, 'errors');
$error++;
}
$res = $b->create($user);
if ($res < 0) {
setEventMessages('Failed to insert the export int the unalterable log', null, 'errors');
$error++;
}
$fh = fopen($tmpfile, 'w');
}
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,";
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_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');
// Print line with title
fwrite($fh, "BEGIN - date=".$yearmonthdateofexport." - period=".$yearmonthtoexport." - format=V1 - user=".$user->getFullName($langs)
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;
$i = 0;
$totalhtamount = array();
$totalvatamount = array();
$totalamount = array();
while ($obj = $db->fetch_object($resql)) {
// We set here all data used into signature calculation (see checkSignature method) and more
// IMPORTANT: We must have here, the same rule for transformation of data than into the fetch method (db->jdate for date, ...)
@@ -310,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
@@ -366,47 +356,297 @@ if (GETPOST('action') == 'export' && $user->hasRight('blockedlog', 'read')) { /
$signatureexport = dol_hash($previoushash.$concatenateddata, 'sha256'); // SHA256
//$signatureexporthmac = 'TODO';
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");
// Define $totalhtamount, $totalvatamount, $totalamount for $block->action event code
$total_ht = $total_vat = $total_ttc = 0;
sumAmountsForUnalterableEvent($block_static, $totalhtamount, $totalvatamount, $totalamount, $total_ht, $total_vat, $total_ttc);
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++;
}
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');
}
// 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);
}
$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;
}
}
} 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) {
// We record the export as a new line into the unalterable logs
require_once DOL_DOCUMENT_ROOT.'/blockedlog/class/blockedlog.class.php';
$b = new BlockedLog($db);
$object = new stdClass();
$object->id = 0;
$object->element = 'module';
$object->ref = 'systemevent';
$object->entity = $conf->entity;
$object->date = dol_now();
$object->label = 'Export unalterable logs - Period: year='.GETPOSTINT('yeartoexport').(GETPOSTINT('monthtoexport') ? ' month='.GETPOSTINT('monthtoexport') : '');
$action = 'BLOCKEDLOG_EXPORT';
$result = $b->setObjectData($object, $action, 0, $user, null);
//var_dump($b); exit;
if ($result < 0) {
setEventMessages('Failed to insert the export int the unalterable log', null, 'errors');
$error++;
}
$res = $b->create($user);
if ($res < 0) {
setEventMessages('Failed to insert the export int the unalterable log', null, 'errors');
$error++;
}
}
}

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 ?
@@ -442,6 +452,9 @@ if ($limit > 0 && $limit != $conf->liste_limit) {
if ($search_id != '') {
$param .= '&search_id='.urlencode($search_id);
}
if ($search_ref != '') {
$param .= '&search_ref='.urlencode($search_ref);
}
if ($search_fk_user > 0) {
$param .= '&search_fk_user='.urlencode($search_fk_user);
}
@@ -630,12 +643,14 @@ if (is_array($blocks)) {
if (empty($search_showonlyerrors) || !$checkresult[$block->id]) {
$nbshown++;
if ($nbshown < $MAXFORSHOWNLINKS) { // For performance and memory purpose, we get/show the link of objects only for the 100 first output
$object_link = $block->getObjectLink();
$object_link_title = '';
} else {
$object_link = $block->element.'/'.$block->fk_object;
$object_link_title = $langs->trans('LinkHasBeenDisabledForPerformancePurpose');
if (getDolGlobalString("BLOCKEDLOG_DEBUG")) {
if ($nbshown < $MAXFORSHOWNLINKS) { // For performance and memory purpose, we get/show the debug info link of objects only for the 100 first output
$object_link = $block->getObjectLink();
$object_link_title = '';
} else {
$object_link = $block->element.'/'.$block->fk_object;
$object_link_title = $langs->trans('LinkHasBeenDisabledForPerformancePurpose');
}
}
print '<tr class="oddeven">';
@@ -666,6 +681,14 @@ if (is_array($blocks)) {
print '<td class="nowraponall">';
if (!empty($block->ref_object)) {
print dol_escape_htmltag($block->ref_object);
if ($block->linktype && $block->linktoref) {
if ($block->linktype == 'paymentof') {
print '<br><span class="opacitymedium small">'.$langs->trans("PaymentOf").' '.$block->linktoref.'</span>';
}
if ($block->linktype == 'replacedby') {
print '<br><span class="opacitymedium small">'.$langs->trans("ReplacedBy").' '.$block->linktoref.'</span>';
}
}
} else {
// Ref not stored
}
@@ -673,44 +696,13 @@ if (is_array($blocks)) {
//$tmpobj = json_decode($block->object_data);
// Define $totalhtamount, $totalvatamount, $totalamount for $block->action event code
$total_ht = $total_vat = $total_ttc = 0;
sumAmountsForUnalterableEvent($block, $totalhtamount, $totalvatamount, $totalamount, $total_ht, $total_vat, $total_ttc);
// Amount
print '<td class="right nowraponall">';
// Define $totalhtamount, $totalvatamount, $totalamount
if (empty($totalamount[$block->action])) {
$totalamount[$block->action] = array();
}
if ($block->action == 'BILL_VALIDATE') {
$total_ht = $block->object_data->total_ht;
$total_vat = $block->object_data->total_tva;
$total_ttc = $block->object_data->total_ttc;
if (empty($totalamount[$block->action][$block->ref_object])) { // If not, we already met the event for this object, we keep only first one.
$totalhtamount[$block->action][$block->ref_object] = $total_ht;
$totalvatamount[$block->action][$block->ref_object] = $total_vat;
$totalamount[$block->action][$block->ref_object] = $total_ttc;
}
} elseif ($block->action == 'PAYMENT_CUSTOMER_CREATE') {
$total_ht = $block->object_data->amount;
$total_vat = 0;
$total_ttc = $block->object_data->amount;
if (empty($totalhtamount[$block->action][$block->ref_object])) {
$totalhtamount[$block->action][$block->ref_object] = 0;
}
if (empty($totalvatamount[$block->action][$block->ref_object])) {
$totalvatamount[$block->action][$block->ref_object] = 0;
}
if (empty($totalamount[$block->action][$block->ref_object])) {
$totalamount[$block->action][$block->ref_object] = 0;
}
$totalhtamount[$block->action][$block->ref_object] = $total_ht;
$totalvatamount[$block->action][$block->ref_object] = $total_vat;
$totalamount[$block->action][$block->ref_object] = $total_ttc;
} else {
$total_ttc = $block->amounts;
}
if (empty($total_ttc)) {
print '<span class="opacitymedium">';
}

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') {
@@ -1049,7 +1056,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) {
@@ -1066,6 +1073,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;
@@ -1240,6 +1248,7 @@ class BlockedLog
$sql = "INSERT INTO ".MAIN_DB_PREFIX."blockedlog (";
$sql .= " date_creation,";
$sql .= " action,";
$sql .= " amounts_taxexcl,";
$sql .= " amounts,";
$sql .= " signature,";
$sql .= " element,";
@@ -1257,7 +1266,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.",";
@@ -1374,7 +1384,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;
@@ -1547,7 +1557,8 @@ class BlockedLog
$sql .= " AND date_creation <= '".$this->db->idate($search_end)."'";
}
if ($search_ref != '') {
$sql .= natural_search("ref_object", $search_ref);
$sql .= " AND (".natural_search("ref_object", $search_ref, 0, 1);
$sql .= " OR ".natural_search("linktoref", $search_ref, 0, 1).")";
}
if ($search_amount != '') {
$sql .= natural_search("amounts", $search_amount, 1);
@@ -1637,6 +1648,6 @@ class BlockedLog
public function alreadyUsed($ignoresystem = 0)
{
include_once DOL_DOCUMENT_ROOT.'/blockedlog/lib/blockedlog.lib.php';
return isBlockedLogused($ignoresystem);
return isBlockedLogUsed($ignoresystem);
}
}

View File

@@ -169,7 +169,7 @@ function isALNERunningVersion()
if (defined('CERTIF_LNE') && (int) constant('CERTIF_LNE') === 2) {
return true;
}
if (isModEnabled('blockedlog') && isBlockedLogused()) {
if (isModEnabled('blockedlog') && isBlockedLogUsed()) {
return true;
}
@@ -182,17 +182,21 @@ function isALNERunningVersion()
* @param int<0,1> $ignoresystem Ignore system events for the test
* @return boolean True if blocked log was already used, false if not
*/
function isBlockedLogused($ignoresystem = 0)
function isBlockedLogUsed($ignoresystem = 0)
{
global $conf, $db;
$result = true; // by default restrictions are on, so we can't disable them
// For the moment, we don't need this. We already have a feature that does not allow to disable the LNE rstriction by
// adding an inalterable event in the log.
// Note: if module on, we suppose it is used, if not, we check in case of it was disabled.
if (!isModEnabled('blockedlog')) {
// Test the cache key
if (array_key_exists('isblockedlogused', $conf->cache)) {
return $conf->cache['isblockedlogused'.$ignoresystem];
}
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog";
$sql .= " WHERE entity = ".((int) $conf->entity); // Sharing entity in blocked is disallowed
$sql .= " WHERE entity = ".((int) $conf->entity); // Sharing entity in blocked log is disallowed
if ($ignoresystem) {
$sql .= " AND action NOT IN ('MODULE_SET', 'MODULE_RESET')";
}
@@ -207,9 +211,11 @@ function isBlockedLogused($ignoresystem = 0)
} else {
dol_print_error($db);
}
$conf->cache['isblockedlogused'.$ignoresystem] = $result;
}
dol_syslog("isBlockedLogused: ignoresystem=".$ignoresystem." returns ".(string) $result);
dol_syslog("isBlockedLogUsed: ignoresystem=".$ignoresystem." returns ".(string) $result);
return $result;
}
@@ -244,3 +250,57 @@ function pdfCertifMentionblockedLog(&$pdf, $outputlangs, $seller, $default_font_
return $result;
}
/**
* sumAmountsForUnalterableEvent
*
* @param BlockedLog $block Object BlockedLog
* @param array<string,float> $totalhtamount Array of total per code event
* @param array<string,float> $totalvatamount Array of total per code event
* @param array<string,float> $totalamount Array of total per code event
* @param float $total_ht Total HT
* @param float $total_vat Total VAT
* @param float $total_ttc Total TTC
* @return int Return > 0
*/
function sumAmountsForUnalterableEvent($block, &$totalhtamount, &$totalvatamount, &$totalamount, &$total_ht, &$total_vat, &$total_ttc)
{
if (empty($totalamount[$block->action])) {
$totalamount[$block->action] = array();
}
if ($block->action == 'BILL_VALIDATE') {
$total_ht = $block->object_data->total_ht;
$total_vat = $block->object_data->total_tva;
$total_ttc = $block->object_data->total_ttc;
// We add total for the invoice if "invoice validate event" not yet met.
// If we already met the event for this object, we keep only first one but this should not happen because edition of validated invoice is not allowed on secured versions.
if (empty($totalamount[$block->action][$block->ref_object])) {
$totalhtamount[$block->action][$block->ref_object] = $total_ht;
$totalvatamount[$block->action][$block->ref_object] = $total_vat;
$totalamount[$block->action][$block->ref_object] = $total_ttc;
}
} elseif ($block->action == 'PAYMENT_CUSTOMER_CREATE') {
$total_ht = $block->object_data->amount;
$total_vat = 0;
$total_ttc = $block->object_data->amount;
if (empty($totalhtamount[$block->action][$block->ref_object])) {
$totalhtamount[$block->action][$block->ref_object] = 0;
}
if (empty($totalvatamount[$block->action][$block->ref_object])) {
$totalvatamount[$block->action][$block->ref_object] = 0;
}
if (empty($totalamount[$block->action][$block->ref_object])) {
$totalamount[$block->action][$block->ref_object] = 0;
}
$totalhtamount[$block->action][$block->ref_object] = $total_ht;
$totalvatamount[$block->action][$block->ref_object] = $total_vat;
$totalamount[$block->action][$block->ref_object] = $total_ttc;
} else {
$total_ttc = $block->amounts;
}
return 1;
}

View File

@@ -4994,42 +4994,86 @@ if ($action == 'create') {
// Confirm back to draft status
if ($action == 'modif') {
$text = $langs->trans('ConfirmUnvalidateBill', $object->ref);
$formquestion = array();
$oktomodif = 1; // Assume we can modify by default
if ($object->type != Facture::TYPE_DEPOSIT && getDolGlobalString('STOCK_CALCULATE_ON_BILL')) {
$qualified_for_stock_change = 0;
if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
$qualified_for_stock_change = $object->hasProductsOrServices(2);
} else {
$qualified_for_stock_change = $object->hasProductsOrServices(1);
}
if ($qualified_for_stock_change) {
$langs->load("stocks");
require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
$formproduct = new FormProduct($db);
$warehouse = new Entrepot($db);
$warehouse_array = $warehouse->list_array();
if (count($warehouse_array) == 1) {
$label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("WarehouseForStockDecrease", current($warehouse_array)) : $langs->trans("WarehouseForStockIncrease", current($warehouse_array));
$value = '<input type="hidden" id="idwarehouse" name="idwarehouse" value="'.key($warehouse_array).'">';
} else {
$label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("SelectWarehouseForStockDecrease") : $langs->trans("SelectWarehouseForStockIncrease");
$value = $formproduct->selectWarehouses(GETPOST('idwarehouse') ? GETPOST('idwarehouse') : 'ifone', 'idwarehouse', '', 1);
}
$formquestion = array(
// 'text' => $langs->trans("ConfirmClone"),
// array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' =>
// 1),
// array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value'
// => 1),
array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $value));
$testvalue = $object->isEditable();
if ($testvalue < 0) {
switch ($testvalue) {
case -1:
// Dispatched in bookkeeping
setEventMessages($langs->trans("DisabledBecauseDispatchedInBookkeeping"), null, 'errors');
break;
case -2:
// Not last invoice
setEventMessages($langs->trans("DisabledBecauseNotLastInvoice"), null, 'errors');
break;
case -3:
// Not last situation invoice
setEventMessages($langs->trans("DisabledBecauseNotLastSituationInvoice"), null, 'errors');
break;
case -4:
// At least one payment made
setEventMessages($langs->trans("DisabledBecauseThereIsAPayment"), null, 'errors');
break;
case -5:
// Already sent by email
setEventMessages($langs->trans("DisabledBecauseAlreadySentByEmail"), null, 'errors');
break;
case -6:
// Already printed once
setEventMessages($langs->trans("DisabledBecauseAlreadyPrintedOnce"), null, 'errors');
break;
case -7:
// Already validated
setEventMessages($langs->trans("DisabledBecauseVersionProtected"), null, 'errors');
break;
default:
// Other error
setEventMessages($langs->trans("DisabledBecauseNotErasable"), null, 'errors');
break;
}
$oktomodif = 0;
$action = '';
}
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('UnvalidateBill'), $text, 'confirm_modif', $formquestion, "yes", 1);
if ($oktomodif) {
$text = $langs->trans('ConfirmUnvalidateBill', $object->ref);
$formquestion = array();
if ($object->type != Facture::TYPE_DEPOSIT && getDolGlobalString('STOCK_CALCULATE_ON_BILL')) {
$qualified_for_stock_change = 0;
if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
$qualified_for_stock_change = $object->hasProductsOrServices(2);
} else {
$qualified_for_stock_change = $object->hasProductsOrServices(1);
}
if ($qualified_for_stock_change) {
$langs->load("stocks");
require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
$formproduct = new FormProduct($db);
$warehouse = new Entrepot($db);
$warehouse_array = $warehouse->list_array();
if (count($warehouse_array) == 1) {
$label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("WarehouseForStockDecrease", current($warehouse_array)) : $langs->trans("WarehouseForStockIncrease", current($warehouse_array));
$value = '<input type="hidden" id="idwarehouse" name="idwarehouse" value="'.key($warehouse_array).'">';
} else {
$label = $object->type == Facture::TYPE_CREDIT_NOTE ? $langs->trans("SelectWarehouseForStockDecrease") : $langs->trans("SelectWarehouseForStockIncrease");
$value = $formproduct->selectWarehouses(GETPOST('idwarehouse') ? GETPOST('idwarehouse') : 'ifone', 'idwarehouse', '', 1);
}
$formquestion = array(
// 'text' => $langs->trans("ConfirmClone"),
// array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' =>
// 1),
// array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value'
// => 1),
array('type' => 'other', 'name' => 'idwarehouse', 'label' => $label, 'value' => $value));
}
}
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('UnvalidateBill'), $text, 'confirm_modif', $formquestion, "yes", 1);
}
}
// Confirmation of payment classification

View File

@@ -1466,10 +1466,8 @@ if (isModEnabled('prelevement') && $user->hasRight('prelevement', 'bons', 'creer
$arrayofmassactions['withdrawrequest'] = img_picto('', 'payment', 'class="pictofixedwidth"').$langs->trans("MakeWithdrawRequest");
}
if ($user->hasRight('facture', 'supprimer')) {
if (getDolGlobalString('INVOICE_CAN_REMOVE_DRAFT_ONLY')) {
if (!getDolGlobalString('INVOICE_DIABLE_MASS_DELETION_ON_DRAFT_INVOICES')) {
$arrayofmassactions['predeletedraft'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Deletedraft");
} elseif (getDolGlobalString('INVOICE_CAN_ALWAYS_BE_REMOVED')) { // mass deletion never possible on invoices on such situation
$arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete");
}
}
if (in_array($massaction, array('presend', 'predelete', 'makepayment'))) {

View File

@@ -1150,7 +1150,7 @@ if (!$error && ($massaction == 'delete' || ($action == 'delete' && $confirm == '
$result = $objecttmp->fetch($toselectid);
if ($result > 0) {
// Refuse deletion for some objects/status
if ($objectclass == 'Facture' && !getDolGlobalString('INVOICE_CAN_ALWAYS_BE_REMOVED') && $objecttmp->status != Facture::STATUS_DRAFT) {
if ($objectclass == 'Facture' && $objecttmp->status != Facture::STATUS_DRAFT) {
$langs->load("errors");
$nbignored++;
$TMsg[] = '<div class="error">'.$langs->trans('ErrorOnlyDraftStatusCanBeDeletedInMassAction', $objecttmp->ref).'</div><br>';

View File

@@ -689,6 +689,29 @@ abstract class CommonInvoice extends CommonObject
return $retarray;
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Return if an invoice can be set back to draft.
* Rule is:
* If invoice is draft and has a temporary ref -> yes (1)
* If hidden option INVOICE_CAN_NEVER_BE_REMOVED is 1 -> no (0)
* If invoice is transferred in bookkeeping -> no (-1)
* If invoice has a definitive ref, is not last in ref -> no (-2)
* If invoice has a definitive ref, is not last in a situation cycle -> no (-3)
* If there is one payment -> no (-4)
* If already sent by email -> no (-5)
* If already printed -> no (-6)
* If running a LNE version and customer invoice was validated -> no (-7)
* Otherwise -> yes (2)
*
* @return int Return integer <=0 if no, >0 if yes
*/
public function isEditable()
{
$test = $this->is_erasable();
return $test;
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
@@ -702,6 +725,7 @@ abstract class CommonInvoice extends CommonObject
* If there is one payment -> no (-4)
* If already sent by email -> no (-5)
* If already printed -> no (-6)
* If running a LNE version and customer invoice was validated -> no (-7)
* Otherwise -> yes (2)
*
* @return int Return integer <=0 if no, >0 if yes
@@ -734,6 +758,11 @@ abstract class CommonInvoice extends CommonObject
if ((int) $this->pos_print_counter > 0) {
return -6;
}
include_once DOL_DOCUMENT_ROOT.'/blockedlog/lib/blockedlog.lib.php';
if (isALNERunningVersion()) {
return -7;
}
}
// If in accountancy, we refuse
@@ -748,6 +777,7 @@ abstract class CommonInvoice extends CommonObject
$this->fetch_thirdparty(); // We need to have this->thirdparty defined, in case of the numbering rule uses tags that depend on thirdparty (like {t} tag).
}
$maxref = $this->getNextNumRef($this->thirdparty, 'last');
// $maxref can be '' (means not found) if there is no invoice yet, but also if there is no invoice for the new period when there is a reset at each period
// If invoice to delete is not the last one, we refuse
if ($maxref != '' && $maxref != $this->ref) {

View File

@@ -987,6 +987,12 @@ class Conf extends stdClass
if (!isset($this->global->MAIN_ENABLE_AJAX_TOOLTIP)) {
$this->global->MAIN_ENABLE_AJAX_TOOLTIP = 1; // Try to have it enabled by default with v21+
}
if (!isset($this->global->THEME_SHOW_BORDER_ON_INPUT)) {
$this->global->THEME_SHOW_BORDER_ON_INPUT = 1;
}
if (!isset($this->global->THEME_ELDY_BORDER_RADIUS)) {
$this->global->THEME_ELDY_BORDER_RADIUS = 6;
}
// By default, suppliers objects can be linked to all projects
if (!isset($this->global->PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS)) {

View File

@@ -938,10 +938,10 @@ class FormOther
);
});
</script>';
$out .= '<input id="colorpicker'.$prefix.'" name="'.$prefix.'" size="6" maxlength="7" class="flat valignmiddle'.($morecss ? ' '.$morecss : '').'" type="text" value="'.dol_escape_htmltag($set_color).'" />';
$out .= '<input id="colorpicker'.$prefix.'" name="'.$prefix.'" size="6" maxlength="7" class="colorpicker flat valignmiddle'.($morecss ? ' '.$morecss : '').'" type="text" value="'.dol_escape_htmltag($set_color).'" />';
} else {
$color = ($set_color !== '' ? $set_color : ($default !== '' ? $default : 'FFFFFF'));
$out .= '<input id="colorpicker'.$prefix.'" name="'.$prefix.'" size="6" maxlength="7" class="flat input-nobottom colorselector valignmiddle '.($morecss ? ' '.$morecss : '').'" type="color" data-default="'.$default.'" value="'.dol_escape_htmltag(preg_match('/^#/', $color) ? $color : '#'.$color).'" />';
$out .= '<input id="colorpicker'.$prefix.'" name="'.$prefix.'" size="6" maxlength="7" class="colorpicker flat input-nobottom colorselector valignmiddle '.($morecss ? ' '.$morecss : '').'" type="color" data-default="'.$default.'" value="'.dol_escape_htmltag(preg_match('/^#/', $color) ? $color : '#'.$color).'" />';
$out .= '<script nonce="'.getNonce().'" type="text/javascript">
jQuery(document).ready(function(){
var originalhex = null;
@@ -977,7 +977,7 @@ class FormOther
});
</script>';
}
$out .= '<select id="colorpicker'.$prefix.'" class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$prefix.'">';
$out .= '<select id="colorpicker'.$prefix.'" class="colorpicker flat'.($morecss ? ' '.$morecss : '').'" name="'.$prefix.'">';
//print '<option value="-1">&nbsp;</option>';
foreach ($arrayofcolors as $val) {
$out .= '<option value="'.$val.'"';

View File

@@ -1188,7 +1188,7 @@ function purgeSessions($mysessionid)
/**
* Enable a module
*
* @param string $value Name of module to activate
* @param string $value Name of module to activate (modModuleName)
* @param int $withdeps Activate/Disable also all dependencies
* @param int $noconfverification Remove verification of $conf variable for module
* @return array{nbmodules?:int,errors:string[],nbperms?:int} array('nbmodules'=>nb modules activated with success, 'errors=>array of error messages, 'nbperms'=>Nb permission added);
@@ -1249,7 +1249,6 @@ function activateModule($value, $withdeps = 1, $noconfverification = 0)
$ret['errors'][] = $langs->trans("ErrorModuleRequireJavascript");
return $ret;
}
$const_name = $objMod->const_name;
if ($noconfverification == 0) {
if (getDolGlobalString($const_name)) {

View File

@@ -63,10 +63,12 @@ function takepos_admin_prepare_head()
$h++;
}
/*
$head[$h][0] = DOL_URL_ROOT.'/takepos/admin/other.php';
$head[$h][1] = $langs->trans("About");
$head[$h][2] = 'other';
$h++;
*/
complete_head_from_modules($conf, $langs, null, $head, $h, 'takepos_admin');

View File

@@ -2518,7 +2518,9 @@ function get_left_menu_hrm($mainmenu, &$newmenu, $usemenuhider = 1, $leftmenu =
$newmenu->add(dolBuildUrl('/expensereport/list.php', ['search_status' => 4, 'leftmenu' => 'expensereport', 'mainmenu' => 'hrm']), $langs->trans("Canceled"), 2, $user->hasRight('expensereport', 'lire'));
$newmenu->add(dolBuildUrl('/expensereport/list.php', ['search_status' => 99, 'leftmenu' => 'expensereport', 'mainmenu' => 'hrm']), $langs->trans("Refused"), 2, $user->hasRight('expensereport', 'lire'));
}
$newmenu->add(dolBuildUrl('/expensereport/payment/list.php', ['leftmenu' => 'expensereport_payments', 'mainmenu' => 'hrm']), $langs->trans("Payments"), 1, (int) (int) ($user->hasRight('expensereport', 'lire') && isModEnabled('bank')));
if (isModEnabled('bank')) {
$newmenu->add(dolBuildUrl('/expensereport/payment/list.php', ['leftmenu' => 'expensereport_payments', 'mainmenu' => 'hrm']), $langs->trans("Payments"), 1, (int) ($user->hasRight('expensereport', 'read')));
}
$newmenu->add(dolBuildUrl('/expensereport/stats/index.php', ['leftmenu' => 'expensereport', 'mainmenu' => 'hrm']), $langs->trans("Statistics"), 1, $user->hasRight('expensereport', 'lire'));
}

View File

@@ -188,6 +188,7 @@ class mod_facture_mercure extends ModeleNumRefFactures
// Get entities
$entity = getEntity('invoicenumber', 1, $invoice);
$numFinal = get_next_value($db, $mask, 'facture', 'ref', $where, $objsoc, (empty($invoice) ? dol_now() : $invoice->date), $mode, false, null, $entity);
if (!preg_match('/([0-9])+/', $numFinal)) {
$this->error = $numFinal;

View File

@@ -153,7 +153,7 @@ class modBlockedLog extends DolibarrModules
{
require_once DOL_DOCUMENT_ROOT.'/blockedlog/lib/blockedlog.lib.php';
return isBlockedLogused();
return isBlockedLogUsed();
}
@@ -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

@@ -41,7 +41,7 @@ class modExpenseReport extends DolibarrModules
*/
public function __construct($db)
{
global $conf, $user; // Required by some include code
global $conf, $user; // Required by the extrafieldsinexport.inc.php
$this->db = $db;
$this->numero = 770;

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

@@ -1994,6 +1994,7 @@ if ($action == 'create') {
$nbcols++;
}
print '<div class="div-table-responsive-no-min">';
print '<table class="noborder paymenttable centpercent">';
print '<tr class="liste_titre">';
@@ -2003,8 +2004,8 @@ if ($action == 'create') {
if ($canSeeBankAccount) {
print '<td class="liste_titre right">'.$langs->trans('BankAccount').'</td>';
}
print '<td class="liste_titre right">'.$langs->trans('Amount').'</td>';
print '<td class="liste_titre" width="18">&nbsp;</td>';
print '<td class="liste_titre right">'.$langs->trans('Amount').'</td>';
print '</tr>';
// Payments already done (from payment on this expensereport)
@@ -2063,8 +2064,8 @@ if ($action == 'create') {
}
print '</td>';
}
print '<td class="right">'.price($objp->amount)."</td>";
print '<td></td>';
print '<td class="right">'.price($objp->amount)."</td>";
print "</tr>";
$totalpaid += $objp->amount;
$i++;
@@ -2085,17 +2086,24 @@ if ($action == 'create') {
} elseif ($object->paid == 1 && $remaintopay > 0) {
$cssforamountpaymentcomplete = 'amountpaymentneutral strikefordisabled';
}
print '<tr><td colspan="'.$nbcols.'" class="right">'.$langs->trans("AlreadyPaid").':</td><td class="right">'.price($totalpaid).'</td><td></td></tr>';
print '<tr><td colspan="'.$nbcols.'" class="right">'.$langs->trans("AmountExpected").':</td><td class="right">'.price($object->total_ttc).'</td><td></td></tr>';
print '<tr><td colspan="'.$nbcols.'" class="right">'.$langs->trans("AlreadyPaid").':</td>';
print '<td></td>';
print '<td class="right">'.price($totalpaid).'</td></tr>';
print '<tr><td colspan="'.$nbcols.'" class="right">'.$langs->trans("AmountExpected").':</td>';
print '<td></td>';
print '<td class="right">'.price($object->total_ttc).'</td></tr>';
print '<tr><td colspan="'.$nbcols.'" class="right">'.$langs->trans("RemainderToPay").':</td>';
print '<td class="right'.($resteapayeraffiche ? ' amountremaintopay' : (' '.$cssforamountpaymentcomplete)).'">'.price($resteapayeraffiche).'</td><td></td></tr>';
print '<td></td>';
print '<td class="right'.($resteapayeraffiche ? ' amountremaintopay' : (' '.$cssforamountpaymentcomplete)).'">'.price($resteapayeraffiche).'</td></tr>';
$db->free($resql);
} else {
dol_print_error($db);
}
print "</table>";
print '</div>';
print '</div>';
print '</div>';
@@ -2214,7 +2222,7 @@ if ($action == 'create') {
}
// Comment
print '<td class="left linecolcomment">'.dol_nl2br($line->comments).'</td>';
print '<td class="left linecolcomment minwidth100">'.dol_nl2br($line->comments).'</td>';
// VAT rate
$senderissupplier = 0;
@@ -2347,7 +2355,7 @@ if ($action == 'create') {
print '</td>';
print '<td class="nowrap right linecolwarning">';
print !empty($line->rule_warning_message) ? img_warning(html_entity_decode($line->rule_warning_message)) : '&nbsp;';
print !empty($line->rule_warning_message) ? img_warning(html_entity_decode($line->rule_warning_message)) : '';
print '</td>';
// Ajout des boutons de modification/suppression

View File

@@ -607,8 +607,8 @@ if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
print '</td>';
}
if (!empty($arrayfields['d.ref']['checked'])) {
print '<td class="liste_titre" align="left">';
print '<input class="flat" size="15" type="text" name="search_ref" value="'.$search_ref.'">';
print '<td class="liste_titre">';
print '<input class="flat width100" type="text" name="search_ref" value="'.dolPrintHTMLForAttribute($search_ref).'">';
print '</td>';
}
// User
@@ -862,13 +862,9 @@ if ($num > 0) {
}
// Ref
if (!empty($arrayfields['d.ref']['checked'])) {
print '<td>';
print '<table class="nobordernopadding"><tr class="nocellnopadd">';
print '<td class="nobordernopadding nowrap">';
print '<td class="tdoverflowmax150">';
print $expensereportstatic->getNomUrl(1);
print '</td>';
// Warning late icon and note
print '<td class="nobordernopadding nowrap">';
if ($expensereportstatic->status == 2 && $expensereportstatic->hasDelay('toapprove')) {
print img_warning($langs->trans("Late"));
}
@@ -880,15 +876,11 @@ if ($num > 0) {
print '<a href="'.DOL_URL_ROOT.'/expensereport/note.php?id='.$obj->rowid.'">'.img_picto($langs->trans("ViewPrivateNote"), 'object_generic').'</a>';
print '</span>';
}
print '</td>';
print '<td width="16" class="nobordernopadding hideonsmartphone right">';
$filename = dol_sanitizeFileName($obj->ref);
$filedir = $conf->expensereport->dir_output.'/'.dol_sanitizeFileName($obj->ref);
$urlsource = $_SERVER['PHP_SELF'].'?id='.$obj->rowid;
print $formfile->getDocumentsLink($expensereportstatic->element, $filename, $filedir);
print '</td>';
print '</tr></table>';
print '</td>';
if (!$i) {
$totalarray['nbfield']++;
}

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

@@ -14,8 +14,11 @@ BillsStatisticsSuppliers=Vendors invoices statistics
DisabledBecauseDispatchedInBookkeeping=Disabled because invoice was dispatched into bookkeeping
DisabledBecauseNotLastInvoice=Disabled because invoice is not erasable. Some invoices were recorded after this one and it will create holes in the counter.
DisabledBecauseNotLastSituationInvoice=Disabled because invoice is not erasable. This invoice is not the last one in situation invoice cycle.
DisabledBecauseAlreadyPrintedOnce=Disabled because invoice has already been printed at least once
DisabledBecauseThereIsAPayment=Disabled because invoice has already some payments.
DisabledBecauseAlreadyPrintedOnce=Disabled because invoice has already been downloaded or printed at least once
DisabledBecauseAlreadySentByEmail=Disabled because invoice has already been sent by email at least once
DisabledBecauseVersionProtected=Disabled because invoice has already been validated and you are using version secured against deletion of invoices
DisabledBecauseNotDraft=Disabled because invoice is not in draft status
DisabledBecauseNotErasable=Disabled because cannot be erased (unknown reason)
InvoiceStandard=Standard invoice
InvoiceStandardAsk=Standard invoice

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,4 +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

View File

@@ -173,3 +173,6 @@ SentToPrinter=Sent to printer
FailedToSendToPrinter=Failed to send to printer
TemporaryReceipt=Temporary
SignatureID=Signature ID
CashRegisterAlertFR=Warning: According to French law, when using a Point Of Sale system, you must make a cash control every day, every month and every year. Cash controls are done manually from the menu %s - %s.
CashRegisterAlertFR2=Every cash control is recorded into the Unalterable Log.
KitchenPrinter=Kitchen printer

View File

@@ -374,6 +374,7 @@ ErrorBlockLogNeedElement=The unalterbale log object needs element type to be set
ErrorBlockLogNeedObject=The unalterbale log object needs object to be set
ErrorBadParameterWhenCallingCreateOfBlockedLog=Bad parameter when calling create of blocked log
ErrorMaxDecimalsShownTooLowComparedToUnitOrTotal=Value for 'Max. decimals for prices shown on screen' (%s) must be equal to or greater than both 'Max. decimals for unit prices' (%s) and 'Max. decimals for total prices' (%s). This is required to prevent rounding inconsistencies on documents.
ErrorOnlyDraftStatusCanBeDeletedInMassAction=Only elements in draft status can be deleted in mass action
# Warnings
WarningParamUploadMaxFileSizeHigherThanPostMaxSize=Your PHP parameter upload_max_filesize (%s) is higher than PHP parameter post_max_size (%s). This is not a consistent setup.

View File

@@ -121,7 +121,6 @@ ValideTrip=Approve expense report
ExpenseReportPayments=Expense report payments
TaxUndefinedForThisCategory = Tax is undefined for this category
errorComputeTtcOnMileageExpense=Error on computing mileage expense
ErrorOnlyDraftStatusCanBeDeletedInMassAction=Only elements in draft status can be deleted in mass action
## Dictionary
EX_BRE=Breakfast

View File

@@ -2370,8 +2370,9 @@ function top_menu_user($hideloginname = 0, $urllogout = '')
$nophoto = '/public/theme/common/user_woman.png';
}
$userImage = '<img class="photo photouserphoto userphoto" alt="" src="'.DOL_URL_ROOT.$nophoto.'" aria-hidden="true">';
$userDropDownImage = '<img class="photo dropdown-user-image" alt="" src="'.DOL_URL_ROOT.$nophoto.'">';
$userImage = img_picto('', 'user', 'class="photo photouserphoto userphoto"');
//$userImage = '<img class="photo photouserphoto userphoto" alt="" src="'.DOL_URL_ROOT.$nophoto.'" aria-hidden="true">';
$userDropDownImage = '<img class="photo dropdown-user-image" alt="" src="'.DOL_URL_ROOT.$nophoto.'" aria-hidden="true">';
}
$dropdownBody = '';
@@ -2404,7 +2405,8 @@ function top_menu_user($hideloginname = 0, $urllogout = '')
}
}
$dropdownBody .= '<br><b>'.$langs->trans("VATIntraShort").'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_TVAINTRA"), 'VAT').'</span>';
$dropdownBody .= '<br><b>'.$langs->trans("Country").'</b>: <span>'.($mysoc->country_code ? $langs->trans("Country".$mysoc->country_code) : '').'</span>';
$langFlag = picto_from_langcode($langs->getDefaultLang(), 'class="none"');
$dropdownBody .= '<br><b>'.$langs->trans("Country").'</b>: <span>'.($mysoc->country_code ? $langs->trans("Country".$mysoc->country_code).' '.$langFlag : '').'</span>';
if (isModEnabled('multicurrency')) {
$dropdownBody .= '<br><b>'.$langs->trans("Currency").'</b>: <span>'.getDolCurrency().'</span>';
}
@@ -2416,7 +2418,7 @@ function top_menu_user($hideloginname = 0, $urllogout = '')
// login infos
if (!empty($user->admin)) {
$dropdownBody .= '<br><b>'.$langs->trans("Administrator").'</b>: '.yn($user->admin);
$dropdownBody .= '<br><b>'.$langs->trans("Administrator").'</b>: '.yn($user->admin).($user->admin ? ' '.img_picto('', 'admin') : '');
}
$company = '';
if (!empty($user->socid)) { // Add third party for external users
@@ -2441,8 +2443,8 @@ function top_menu_user($hideloginname = 0, $urllogout = '')
$dropdownBody .= '<br><b>'.$langs->trans("CurrentTheme").':</b> '.$conf->theme;
// @phan-suppress-next-line PhanRedefinedClassReference
$dropdownBody .= '<br><b>'.$langs->trans("CurrentMenuManager").':</b> '.(isset($menumanager) ? $menumanager->name : 'unknown');
$langFlag = picto_from_langcode($langs->getDefaultLang());
$dropdownBody .= '<br><b>'.$langs->trans("CurrentUserLanguage").':</b> '.($langFlag ? $langFlag.' ' : '').$langs->getDefaultLang();
$langFlag = picto_from_langcode($langs->getDefaultLang(), 'class="none"');
$dropdownBody .= '<br><b>'.$langs->trans("CurrentUserLanguage").':</b> '.$langs->getDefaultLang().($langFlag ? ' '.$langFlag : '');;
$tz = (int) $_SESSION['dol_tz'] + (int) $_SESSION['dol_dst'];
$dropdownBody .= '<br><b>'.$langs->trans("ClientTZ").':</b> '.($tz ? ($tz >= 0 ? '+' : '').$tz : '');
@@ -2487,7 +2489,7 @@ function top_menu_user($hideloginname = 0, $urllogout = '')
$profilName = $user->getFullName($langs).' ('.$user->login.')';
if (!empty($user->admin)) {
$profilName = '<i class="far fa-star classfortooltip" title="'.$langs->trans("Administrator").'" ></i> '.$profilName;
$profilName = img_picto($langs->trans("Administrator"), 'admin').' '.$profilName;
}
// Define version to show

View File

@@ -85,7 +85,8 @@ $formproduct = new FormProduct($db);
llxHeader('', $langs->trans("CashDeskSetup"), '', '', 0, 0, '', '', '', 'mod-takepos page-admin_appearance');
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToModuleList").'</a>';
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/system/database.php?restore_lastsearch_values=1">'.img_picto($langs->trans("GoBack"), 'back', 'class="pictofixedwidth"').'<span class="hideonsmartphone">'.$langs->trans("GoBack").'</span></a>';
print load_fiche_titre($langs->trans("CashDeskSetup").' (TakePOS)', $linkback, 'title_setup');
$head = takepos_admin_prepare_head();
print dol_get_fiche_head($head, 'appearance', 'TakePOS', -1, 'cash-register');

View File

@@ -96,7 +96,8 @@ $arrayofcss = array("/takepos/css/colorbox.css");
llxHeader('', $langs->trans("CashDeskSetup"), '', '', 0, 0, $arrayofjs, $arrayofcss, '', 'mod-takepos page-admin_bar');
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToModuleList").'</a>';
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/system/database.php?restore_lastsearch_values=1">'.img_picto($langs->trans("GoBack"), 'back', 'class="pictofixedwidth"').'<span class="hideonsmartphone">'.$langs->trans("GoBack").'</span></a>';
print load_fiche_titre($langs->trans("CashDeskSetup").' (TakePOS)', $linkback, 'title_setup');
$head = takepos_admin_prepare_head();
print dol_get_fiche_head($head, 'bar', 'TakePOS', -1, 'cash-register');

View File

@@ -30,11 +30,6 @@
// Load Dolibarr environment
require '../../main.inc.php'; // Load $user and permissions
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/treeview.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
/**
* @var Conf $conf
* @var DoliDB $db
@@ -42,6 +37,10 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
* @var Translate $langs
* @var User $user
*/
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/treeview.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
$langs->loadLangs(array("main", "categories", "takepos", "printing"));

View File

@@ -1,159 +0,0 @@
<?php
/* Copyright (C) 2008-2011 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2011-2017 Juanjo Menent <jmenent@2byte.es>
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* \file htdocs/takepos/admin/other.php
* \ingroup takepos
* \brief Setup page for TakePos module
*/
require '../../main.inc.php'; // Load $user and permissions
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
require_once DOL_DOCUMENT_ROOT."/core/lib/takepos.lib.php";
// If socid provided by ajax company selector
if (GETPOST('CASHDESK_ID_THIRDPARTY_id', 'alpha')) {
$_GET['CASHDESK_ID_THIRDPARTY'] = GETPOST('CASHDESK_ID_THIRDPARTY_id', 'alpha'); // Keep this ?
$_POST['CASHDESK_ID_THIRDPARTY'] = GETPOST('CASHDESK_ID_THIRDPARTY_id', 'alpha'); // Keep this ?
$_REQUEST['CASHDESK_ID_THIRDPARTY'] = GETPOST('CASHDESK_ID_THIRDPARTY_id', 'alpha'); // Keep this ?
}
/**
* @var Conf $conf
* @var DoliDB $db
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
*/
// Security check
if (!$user->admin) {
accessforbidden();
}
$langs->loadLangs(array("admin", "cashdesk"));
global $db;
$sql = "SELECT code, libelle FROM ".MAIN_DB_PREFIX."c_paiement";
$sql .= " WHERE entity IN (".getEntity('c_paiement').")";
$sql .= " AND active = 1";
$sql .= " ORDER BY libelle";
$resql = $db->query($sql);
$paiements = array();
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
array_push($paiements, $obj);
}
}
/*
* Actions
*/
// Nothing
/*
* View
*/
llxHeader('', $langs->trans("CashDeskSetup"), '', '', 0, 0, '', '', '', 'mod-takepos page-admin_other');
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToModuleList").'</a>';
print load_fiche_titre($langs->trans("CashDeskSetup").' (TakePOS)', $linkback, 'title_setup');
$head = takepos_admin_prepare_head();
print dol_get_fiche_head($head, 'other', 'TakePOS', -1, 'cash-register');
print '<br>';
// Mode
print '<form action="'.$_SERVER["PHP_SELF"].'" method="post">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="set">';
print '<div class="div-table-responsive-no-min">';
// Marketplace
print "<table summary=\"list_of_modules\" class=\"noborder\" width=\"100%\">\n";
print '<tr class="liste_titre">'."\n";
print '<td class="titlefield" colspan="2">'.$langs->trans("WebSiteDesc").'</td>';
print '<td>'.$langs->trans("URL").'</td>';
print '</tr>';
$url = 'https://www.dolistore.com/45-pos';
print '<tr class="oddeven">'."\n";
print '<td class="titlefield">';
print '<a href="'.$url.'" target="_blank" rel="noopener noreferrer external">';
print '<img border="0" class="imgautosize imgmaxwidth180" src="'.DOL_URL_ROOT.'/theme/dolistore_logo.png">';
print '</a>';
print '</td>';
print '<td>'.$langs->trans("DolistorePosCategory").'</td>';
print '<td>';
print '<a href="'.$url.'" target="_blank" rel="noopener noreferrer external">';
print img_picto('', 'url', 'class="pictofixedwidth"');
print $url.'</a></td>';
print '</tr>';
print "</table>\n";
print '</div>';
print '<br>';
print '<div class="div-table-responsive-no-min">';
// Support
print "<table summary=\"list_of_modules\" class=\"noborder centpercent\">\n";
print '<tr class="liste_titre">'."\n";
print '<td colspan="2">TakePOS Support</td>';
print '<td>'.$langs->trans("URL").'</td>';
print '</tr>';
$url = 'https://partners.dolibarr.org';
print '<tr class="oddeven">'."\n";
print '<td class="titlefield">';
print '<a href="'.$url.'" target="_blank" rel="noopener noreferrer external">';
print '<img border="0" class="imgautosize imgmaxwidth180" src="'.DOL_URL_ROOT.'/theme/dolibarr_preferred_partner.png">';
print '</a></td>';
print '<td>Dolibarr Preferred Partners</td>';
print '<td>';
print '<a href="'.$url.'" target="_blank" rel="noopener noreferrer external">';
print img_picto('', 'url', 'class="pictofixedwidth"');
print $url.'</a></td>';
print '</tr>';
print "</table>\n";
print '</div>';
print '</form>';
print dol_get_fiche_end();
llxFooter();
$db->close();

View File

@@ -28,11 +28,6 @@
// Load Dolibarr environment
require '../../main.inc.php'; // Load $user and permissions
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
require_once DOL_DOCUMENT_ROOT."/core/lib/takepos.lib.php";
/**
* @var Conf $conf
* @var DoliDB $db
@@ -40,6 +35,10 @@ require_once DOL_DOCUMENT_ROOT."/core/lib/takepos.lib.php";
* @var Translate $langs
* @var User $user
*/
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
require_once DOL_DOCUMENT_ROOT."/core/lib/takepos.lib.php";
// Security check
if (!$user->admin) {
@@ -90,16 +89,17 @@ if (GETPOST('action', 'alpha') == 'set') {
*/
$form = new Form($db);
$formproduct = new FormProduct($db);
llxHeader('', $langs->trans("CashDeskSetup"), '', '', 0, 0, '', '', '', 'mod-takepos page-admin_receipt');
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToModuleList").'</a>';
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/system/database.php?restore_lastsearch_values=1">'.img_picto($langs->trans("GoBack"), 'back', 'class="pictofixedwidth"').'<span class="hideonsmartphone">'.$langs->trans("GoBack").'</span></a>';
print load_fiche_titre($langs->trans("CashDeskSetup").' (TakePOS)', $linkback, 'title_setup');
$head = takepos_admin_prepare_head();
print dol_get_fiche_head($head, 'receipt', 'TakePOS', -1, 'cash-register');
print '<form action="'.$_SERVER["PHP_SELF"].'?terminal='.(empty($terminal) ? 1 : $terminal).'" method="post">';
print '<form action="'.$_SERVER["PHP_SELF"].'" method="post">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="set">';

View File

@@ -28,6 +28,13 @@
// Load Dolibarr environment
require '../../main.inc.php'; // Load $user and permissions
/**
* @var Conf $conf
* @var DoliDB $db
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
*/
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
@@ -42,14 +49,6 @@ if (GETPOST('CASHDESK_ID_THIRDPARTY_id', 'alpha')) {
$_REQUEST['CASHDESK_ID_THIRDPARTY'] = GETPOST('CASHDESK_ID_THIRDPARTY_id', 'alpha');
}
/**
* @var Conf $conf
* @var DoliDB $db
* @var HookManager $hookmanager
* @var Translate $langs
* @var User $user
*/
// Security check
if (!$user->admin) {
accessforbidden();
@@ -137,14 +136,23 @@ if ($action != '') {
*/
$form = new Form($db);
$formproduct = new FormProduct($db);
$help_url = 'EN:Module_Point_of_sale_(TakePOS)';
llxHeader('', $langs->trans("CashDeskSetup"), $help_url, '', 0, 0, '', '', '', 'mod-takepos page-admin_setup');
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToModuleList").'</a>';
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/system/database.php?restore_lastsearch_values=1">'.img_picto($langs->trans("GoBack"), 'back', 'class="pictofixedwidth"').'<span class="hideonsmartphone">'.$langs->trans("GoBack").'</span></a>';
print load_fiche_titre($langs->trans("CashDeskSetup").' (TakePOS)', $linkback, 'title_setup');
if (in_array($mysoc->country_code, array('FR'))) {
$htmltext = $langs->trans("CashRegisterAlertFR", $langs->transnoentitiesnoconv("Bank"), $langs->transnoentitiesnoconv("CashControl")).' ';
$htmltext .= $langs->trans("CashRegisterAlertFR2").'<br>';
print info_admin($htmltext, 0, 0, 'warning');
}
$head = takepos_admin_prepare_head();
print dol_get_fiche_head($head, 'setup', 'TakePOS', -1, 'cash-register');
@@ -172,8 +180,6 @@ foreach ($dirmodels as $reldir) {
if (is_dir($dir)) {
$handle = opendir($dir);
if (is_resource($handle)) {
$var = true;
while (($file = readdir($handle)) !== false) {
if (substr($file, 0, 16) == 'mod_takepos_ref_' && substr($file, dol_strlen($file) - 3, 3) == 'php') {
$file = substr($file, 0, dol_strlen($file) - 4);
@@ -304,7 +310,6 @@ print "</td></tr>\n";
print '<tr class="oddeven"><td>';
print $langs->trans("SortProductField");
print '<td>';
$prod = new Product($db);
$array = array('rowid' => 'ID', 'ref' => 'Ref', 'label' => 'Label', 'datec' => 'DateCreation', 'tms' => 'DateModification');
print $form->selectarray('TAKEPOS_SORTPRODUCTFIELD', $array, getDolGlobalString('TAKEPOS_SORTPRODUCTFIELD', 'rowid'), 0, 0, 0, '', 1);
print "</td></tr>\n";
@@ -361,8 +366,7 @@ print $langs->trans('EmailTemplate');
print '<td>';
include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
$formmail = new FormMail($db);
$nboftemplates = $formmail->fetchAllEMailTemplate('facture_send', $user, null, -1); // We set lang=null to get in priority record with no lang
//$arraydefaultmessage = $formmail->getEMailTemplate($db, $tmp[1], $user, null, 0, 1, '');
$formmail->fetchAllEMailTemplate('facture_send', $user, null, -1); // We set lang=null to get in priority record with no lang
$arrayofmessagename = array();
if (is_array($formmail->lines_model)) {
foreach ($formmail->lines_model as $modelmail) {

View File

@@ -180,7 +180,8 @@ $formproduct = new FormProduct($db);
llxHeader('', $langs->trans("CashDeskSetup"), '', '', 0, 0, '', '', '', 'mod-takepos page-admin_terminal');
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToModuleList").'</a>';
$linkback = '<a href="'.DOL_URL_ROOT.'/admin/system/database.php?restore_lastsearch_values=1">'.img_picto($langs->trans("GoBack"), 'back', 'class="pictofixedwidth"').'<span class="hideonsmartphone">'.$langs->trans("GoBack").'</span></a>';
print load_fiche_titre($langs->trans("CashDeskSetup").' (TakePOS)', $linkback, 'title_setup');
$head = takepos_admin_prepare_head();
print dol_get_fiche_head($head, 'terminal'.$terminal, 'TakePOS', -1, 'cash-register');
@@ -464,15 +465,15 @@ if (isModEnabled('receiptprinter')) {
print '</td></tr>';
if (getDolGlobalString('TAKEPOS_BAR_RESTAURANT') && getDolGlobalInt('TAKEPOS_ORDER_PRINTERS') && $orderprinterallowed) {
print '<tr class="oddeven"><td>'.$langs->trans("OrderPrinterToUse").' - '.$langs->trans("Printer").' 1</td>';
print '<tr class="oddeven"><td>'.$langs->trans("OrderPrinterToUse").' - '.$langs->trans("KitchenPrinter").' 1</td>';
print '<td>';
print $form->selectarray('TAKEPOS_ORDER_PRINTER1_TO_USE'.$terminal, $printers, getDolGlobalInt('TAKEPOS_ORDER_PRINTER1_TO_USE'.$terminal), 1);
print '</td></tr>';
print '<tr class="oddeven"><td>'.$langs->trans("OrderPrinterToUse").' - '.$langs->trans("Printer").' 2</td>';
print '<tr class="oddeven"><td>'.$langs->trans("OrderPrinterToUse").' - '.$langs->trans("KitchenPrinter").' 2</td>';
print '<td>';
print $form->selectarray('TAKEPOS_ORDER_PRINTER2_TO_USE'.$terminal, $printers, getDolGlobalInt('TAKEPOS_ORDER_PRINTER2_TO_USE'.$terminal), 1);
print '</td></tr>';
print '<tr class="oddeven"><td>'.$langs->trans("OrderPrinterToUse").' - '.$langs->trans("Printer").' 3</td>';
print '<tr class="oddeven"><td>'.$langs->trans("OrderPrinterToUse").' - '.$langs->trans("KitchenPrinter").' 3</td>';
print '<td>';
print $form->selectarray('TAKEPOS_ORDER_PRINTER3_TO_USE'.$terminal, $printers, getDolGlobalInt('TAKEPOS_ORDER_PRINTER3_TO_USE'.$terminal), 1);
print '</td></tr>';

View File

@@ -3733,7 +3733,8 @@ img.login, img.printer, img.entity {
}
.userimg.atoplogin img.userphoto, .userimgatoplogin img.userphoto { /* size for user photo in login bar */
.userimg.atoplogin img.userphoto, .userimgatoplogin img.userphoto,
.userimg.atoplogin span.userphoto, .userimgatoplogin span.userphoto { /* size for user photo in login bar */
width: <?php echo $disableimages ? '26' : '30'; ?>px;
height: <?php echo $disableimages ? '26' : '30'; ?>px;
border-radius: 50%;
@@ -3748,6 +3749,16 @@ img.userphoto { /* size for user photo in lists */
background-size: contain;
vertical-align: middle;
}
.userimg.atoplogin span.userphoto, .userimgatoplogin span.userphoto {
vertical-align: middle;
color: unset;
}
.userimg.atoplogin span.userphoto::before, .userimgatoplogin span.userphoto::before {
margin-top: 7px;
display: inline-block;
margin-right: 8px;
}
span.userimg div.userphoto {
background-color: #eee;
border-radius: 0.72em;
@@ -5070,9 +5081,9 @@ tr.liste_titre_topborder td {
border-top-color: var(--colortopbordertitle1);
border-top-style: solid;
}
.liste_titre td a {
.liste_titre td a, .liste_titre td a span {
text-shadow: none !important;
color: var(--colortexttitle);
color: var(--colortexttitle) !important;
}
.liste_titre td a.notasortlink {
color: var(--colortextlink);
@@ -6771,6 +6782,10 @@ A.none, A.none:active, A.none:visited, A.none:hover {
.colorselector {
border: solid 1px #ddd !important;
}
input.colorpicker {
color: unset !important;
background-color: unset !important;
}
/* ============================================================================== */

View File

@@ -253,7 +253,7 @@ div#topmenu-login-dropdown {
<?php if ($disableimages) { ?>
line-height: 35px;
<?php } else { ?>
line-height: 50px;
line-height: 49px;
<?php } ?>
}
a.top-menu-dropdown-link {

View File

@@ -1629,7 +1629,7 @@ div.divsearchfield {
.divsearchfieldfilter {
text-overflow: clip;
overflow: auto;
white-space: nowrap;
/* white-space: nowrap; */
padding-bottom: 5px;
opacity: 0.6;
font-size: small;
@@ -3808,7 +3808,8 @@ img.login, img.printer, img.entity {
color: white;
font-weight: bold;
}
.userimg.atoplogin img.userphoto, .userimgatoplogin img.userphoto { /* size for user photo in login bar */
.userimg.atoplogin img.userphoto, .userimgatoplogin img.userphoto,
.userimg.atoplogin span.userphoto, .userimgatoplogin span.userphoto { /* size for user photo in login bar */
/* border-radius: 8px; */
width: <?php echo $disableimages ? '26' : '30'; ?>px;
height: <?php echo $disableimages ? '26' : '30'; ?>px;
@@ -3823,6 +3824,16 @@ img.userphoto { /* size for user photo in lists */
background-size: contain;
vertical-align: middle;
}
.userimg.atoplogin span.userphoto, .userimgatoplogin span.userphoto {
vertical-align: middle;
color: unset;
}
.userimg.atoplogin span.userphoto::before, .userimgatoplogin span.userphoto::before {
margin-top: 7px;
display: inline-block;
margin-right: 1px;
}
span.userimg div.userphoto {
background-color: #eee;
border-radius: 0.72em;
@@ -5564,12 +5575,19 @@ div.fiche div.info, div.fiche div.warning, div.fiche div.neutral {
margin: 1em 0em 1.2em 0em;
}
/* Info message */
/* Neutral message */
div.neutral {
border-<?php print $left; ?>: solid 5px #aaa;
background: #f8f8f8;
}
/* Info message */
div.info {
border-<?php print $left; ?>: solid 5px #87cfd2;
background: #eff8fc;
color: #558;
}
/* Ok message */
div.green div.greenborder, section.green, section.greenborder {
border-<?php print $left; ?>: solid 5px #118822;
@@ -6655,6 +6673,10 @@ A.none, A.none:active, A.none:visited, A.none:hover {
.colorselector {
border: solid 1px #ddd !important;
}
input.colorpicker {
color: unset !important;
background-color: unset !important;
}
/* ============================================================================== */

View File

@@ -29,6 +29,7 @@ global $conf,$user,$langs,$db;
//define('TEST_DB_FORCE_TYPE','mysql'); // This is to force using mysql driver
//require_once 'PHPUnit/Autoload.php';
require_once dirname(__FILE__).'/../../htdocs/master.inc.php';
require_once dirname(__FILE__).'/../../htdocs/core/lib/admin.lib.php';
require_once dirname(__FILE__).'/CommonClassTest.class.php';
if (empty($user->id)) {
@@ -71,7 +72,7 @@ class NumberingModulesTest extends CommonClassTest
$conf->global->FACTURE_MERCURE_MASK_CREDIT = '{yyyy}-{0000}';
$conf->global->FACTURE_MERCURE_MASK_DEPOSIT = '{yyyy}-{0000}';
$conf->global->FACTURE_MERCURE_MASK_REPLACEMENT = '{yyyy}-{0000}';
$conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED = 0;
$conf->global->FAC_FORCE_DATE_VALIDATION = 0; // We disable option "Force date on validation", so we can make test on old dates
$localobject = new Facture($db);
$localobject->initAsSpecimen();
@@ -87,16 +88,26 @@ class NumberingModulesTest extends CommonClassTest
$result3 = $localobject->validate($user, $result); // create invoice by forcing ref
print __METHOD__." result3=".$result."\n";
$this->assertEquals(1, $result3, 'Test validation of invoice with forced ref is ok'); // counter must start to 1
// Force enable of BlockedLog (not possible from application, but required to allow the test with sample data))
activateModule('modBlockedLog', 1, 1);
$result = $localobject->is_erasable();
print __METHOD__." is_erasable=".$result."\n";
$this->assertGreaterThanOrEqual(1, $result, 'Test for is_erasable, 1st invoice'); // Can be deleted
$this->assertEquals(-7, $result, 'Test for is_erasable, 1st invoice without other invoice'); // Can be deleted
// Disable module BlockedLog (not possible from application, but required to allow the test with sample data))
unActivateModule('modBlockedLog');
$result = $localobject->is_erasable();
print __METHOD__." is_erasable=".$result."\n";
$this->assertGreaterThanOrEqual(1, $result, 'Test for is_erasable, 1st invoice without other invoice'); // Can be deleted
// We emulate print on invoice 3 times
$localobject->pos_print_counter = 3;
$result = $localobject->is_erasable();
print __METHOD__." is_erasable=".$result."\n";
$this->assertGreaterThanOrEqual(-6, $result, 'Test for is_erasable, 1st invoice already printed'); // Can be deleted
$this->assertGreaterThanOrEqual(-6, $result, 'Test for is_erasable, 1st invoice already printed'); // Can be deleted
$localobject2 = new Facture($db);
$localobject2->initAsSpecimen();
@@ -220,6 +231,7 @@ class NumberingModulesTest extends CommonClassTest
$result = $numbering->getNextValue($mysoc, $localobject2);
$result2 = $localobject2->create($user, 1);
$result3 = $localobject2->validate($user, $result);
print __METHOD__." result=".$result."\n";
$this->assertEquals('0125-0002', $result, 'Test for {mm}{yy}-{0000@1} 2nd invoice'); // counter must be now 2
$result = $localobject2->is_erasable();
@@ -227,7 +239,7 @@ class NumberingModulesTest extends CommonClassTest
$this->assertGreaterThanOrEqual(1, $result); // Can be deleted
$result = $localobject->is_erasable();
print __METHOD__." is_erasable=".$result."\n";
$this->assertLessThanOrEqual(0, $result); // Case 1 can not be deleted (because there is an invoice 2)
$this->assertLessThanOrEqual(0, $result, 'Test that invoice '.$localobject->ref.' is not erasable failed'); // Invoice 1 can not be deleted (because there is an invoice 2)
$localobject3 = new Facture($db);
$localobject3->initAsSpecimen();
@@ -609,11 +621,11 @@ class NumberingModulesTest extends CommonClassTest
$localobject->initAsSpecimen();
$localobject->fetch_thirdparty();
$localobject->date_creation = dol_mktime(12, 0, 0, 1, 1, 1980); // we use year 1915 to be sure to not have existing invoice for this year (useful only if numbering is {0000@1}
$localobject->date_creation = dol_mktime(12, 0, 0, 1, 1, 1980); // we use year 1980 to be sure to not have existing invoice for this year (useful only if numbering is {0000@1}
$numbering = new mod_expedition_safor();
$result = $numbering->getNextValue($mysoc, $localobject);
print __METHOD__." result=".$result."\n";
$this->assertEquals('SH8001-0003', $result); // counter must start to 1
$this->assertEquals('SH8001-0003', $result); // SH8001-0003 is valid with dataset demo
}
}