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

develop
This commit is contained in:
Laurent Destailleur 2026-03-20 16:43:40 +01:00
commit f7f9b201c1
8 changed files with 101 additions and 13 deletions

View file

@ -111,6 +111,7 @@ div.divsearchfield {
}
.updatedApp{
background-color: #25a580;
line-height: 1em;
}
.notcompatible {
color: red;

View file

@ -236,7 +236,7 @@ print '<tr class="liste_titre"><th class="titlefieldcreate wordbreak">'.$langs->
// Name of Accountant Company
print '<tr class="oddeven"><td><label for="name">'.$langs->trans("CompanyName").'</label></td><td>';
print '<input name="itprovider_nom" id="itprovider_name" class="minwidth200" value="'.dol_escape_htmltag(GETPOSTISSET('itprovider_nom') ? GETPOST('itprovider_nom', 'alphanohtml') : getDolGlobalString('MAIN_INFO_ITPROVIDER_NAME')).'"'.(!getDolGlobalString('MAIN_INFO_ITPROVIDER_NAME') ? ' autofocus="autofocus"' : '').'></td></tr>'."\n";
print '<input name="itprovider_nom" id="itprovider_name" class="minwidth200" value="'.dol_escape_htmltag(GETPOSTISSET('itprovider_nom') ? GETPOST('itprovider_nom', 'alphanohtml') : getDolGlobalString('MAIN_INFO_ITPROVIDER_NAME')).'"></td></tr>'."\n";
// Address
print '<tr class="oddeven"><td><label for="address">'.$langs->trans("CompanyAddress").'</label></td><td>';

View file

@ -699,9 +699,7 @@ abstract class CommonInvoice extends CommonObject
* 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)
@ -713,9 +711,95 @@ abstract class CommonInvoice extends CommonObject
*/
public function isEditable()
{
$test = $this->is_erasable();
// phpcs:enable
global $hookmanager, $action;
return $test;
// We check if invoice is a temporary number (PROVxxxx)
$tmppart = substr($this->ref, 1, 4);
if ($this->status == self::STATUS_DRAFT && $tmppart === 'PROV') { // If draft invoice and ref not yet defined
return 1;
}
/*
if (getDolGlobalInt('INVOICE_CAN_NEVER_BE_REMOVED')) {
return 0;
}
*/
// If not a draft invoice and not temporary invoice
if ($tmppart !== 'PROV') {
if ($this instanceOf Facture) {
/* @var Facture $this */
// If sent by email, we refuse
if ((int) $this->email_sent_counter > 0) {
return -5;
}
// If printed, we refuse
if ((int) $this->pos_print_counter > 0) {
return -6;
}
include_once DOL_DOCUMENT_ROOT.'/blockedlog/lib/blockedlog.lib.php';
if (isALNERunningVersion()) {
$this->error = 'Action not allowed on the certified version';
return -7;
}
}
// If in accountancy, we refuse
$ventilExportCompta = $this->getVentilExportCompta();
if ($ventilExportCompta != 0) {
return -1;
}
// Get last number of validated invoice
if ($this->element != 'invoice_supplier') {
/*
if (empty($this->thirdparty)) {
$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) {
return -2;
}
*/
// TODO If there is payment in bookkeeping, check the payment is not dispatched in accounting and return -2.
// ...
// If invoice is situation type, we refuse if it is not the last in situation cycle
if (!getDolGlobalString('INVOICE_SITUATION_CAN_BE_REMOVED_EVEN_IF_NOT_LAST') && $this->situation_cycle_ref && method_exists($this, 'is_last_in_cycle')) {
$last = $this->is_last_in_cycle();
if (!$last) {
return -3;
}
}
}
// Test if there is at least one payment. If yes, we refuse.
if ($this->getSommePaiement() > 0) {
return -4;
}
$parameters = array();
$reshook = $hookmanager->executeHooks('isEditable', $parameters, $this, $action);
if (!empty($hookmanager->resArray['result'])) {
$this->error = $hookmanager->resArray['error'];
if (!empty($hookmanager->resArray['errors'])) {
$this->errors[] = array_merge($this->errors, $this->error, $hookmanager->resArray['errors']);
} else {
$this->errors[] = array_merge($this->errors, $this->error);
}
return $hookmanager->resArray['result'];
}
}
return 2;
}
/**
@ -866,13 +950,13 @@ abstract class CommonInvoice extends CommonObject
}
}
// Test if there is at least one payment. If yes, we refuse to delete.
// Test if there is at least one payment. If yes, we refuse.
if ($this->getSommePaiement() > 0) {
return -4;
}
$parameters = array();
$reshook = $hookmanager->executeHooks('isEditable', $parameters, $this, $action);
$reshook = $hookmanager->executeHooks('isErasable', $parameters, $this, $action);
if (!empty($hookmanager->resArray['result'])) {
$this->error = $hookmanager->resArray['error'];
if (!in_array($this->error, $this->errors)) {

View file

@ -111,7 +111,7 @@ class modPrinting extends DolibarrModules
'url'=>'/printing/index.php?mainmenu=home&leftmenu=admintools',
'langs'=>'printing', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
'position'=>300,
'enabled'=>'isModEnabled("printing") && isStringVarMatching("leftmenu", "/^(admintools|all)/")',
'enabled'=>'isModEnabled("printing") && isStringVarMatching("leftmenu", "(admintools|all)")',
'perms'=>'$user->hasRight("printing", "read")', // Use 'perms'=>'1' if you want your menu with no permission rules
'target'=>'',
'user'=>0); // 0=Menu for internal users, 1=external users, 2=both

View file

@ -98,7 +98,6 @@ SkillsExtraFields=Complementary attributes (Skills)
JobsExtraFields=Complementary attributes (Job profiles)
EvaluationsExtraFields=Complementary attributes (Competency assessments)
NeedBusinessTravels=Business travels
NoDescription=No description
TheJobProfileHasNoSkillsDefinedFixBefore=The evaluated job profile of this employee has no skill defined on it. Please add skill(s), then delete and restart the evaluation.
PDFStandardHrmEvaluation=Standard template to generate a PDF document for a competency assessment
SkillNotRequired=Skill not required

View file

@ -261,6 +261,7 @@ RefOrLabel=Ref. or label
Info=Log
Family=Family
Description=Description
NoDescription=No description
Designation=Description
DescriptionOfLine=Description of line
DateOfLine=Date of line

View file

@ -181,16 +181,17 @@ if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
$societeName = getDolGlobalString('MAIN_APPLICATION_TITLE');
}
// Add a delay to be sure that any Stripe action from webhooks are executed after interactive actions that also trigger a webhook
sleep(2);
top_httphead();
dol_syslog("***** Stripe IPN was called with event->type=".$event->type." service=".$service);
dol_syslog("***** Stripe IPN was called with event->type=".$event->type." service=".$service, LOG_DEBUG, 0, '_payment');
// Add a delay to be sure that any Stripe action from webhooks are executed after interactive actions
sleep(2);
// Hook to allow external modules to handle Stripe webhook events
$hookmanager = new HookManager($db);
$hookmanager->initHooks(array('stripeipn'));

View file

@ -5480,9 +5480,11 @@ if ($mode == 'replacesite' || $massaction == 'replace') {
$arrayofmassactions['replace'] = img_picto('', 'replacement', 'class="pictofixedwidth"').$langs->trans("Replace");
}
if ($user->hasRight('website', 'write')) {
$langs->load("categories");
$arrayofmassactions['setcategory'] = img_picto('', 'category', 'class="pictofixedwidth"').$langs->trans("ClassifyInCategory");
}
if ($user->hasRight('website', 'write')) {
$langs->load("categories");
$arrayofmassactions['delcategory'] = img_picto('', 'category', 'class="pictofixedwidth"').$langs->trans("RemoveCategory");
}
if ($permissiontodelete) {