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

This commit is contained in:
Laurent Destailleur
2025-11-20 11:51:51 +01:00
16 changed files with 140 additions and 83 deletions

View File

@@ -999,7 +999,7 @@ class Categorie extends CommonObject
$obj->fetch($rec['fk_object']); $obj->fetch($rec['fk_object']);
// @phpstan-ignore-next-line // @phpstan-ignore-next-line
if ($obj->id > 0) { // Failing fetch may happen for example when a category supplier was set and third party was moved as customer only. The object supplier can't be loaded. if ($obj->id > 0) { // Failing fetch may happen for example when a category supplier was set and third party was moved as customer only. The object supplier can't be loaded.
$objs[] = $obj; $objs[] = clone $obj;
} }
} }
} }

View File

@@ -233,7 +233,7 @@ if ($resql) {
$transactionspertype = array(); $transactionspertype = array();
$amountpertype = array(); $amountpertype = array();
$totalarray = array('nbfield' => 0, 'pos' => array()); $totalarray = array('nbfield' => 0, 'pos' => array(), 'val' => array('totaldebfield' => 0, 'totalcredfield' => 0));
while ($i < $num) { while ($i < $num) {
$objp = $db->fetch_object($resql); $objp = $db->fetch_object($resql);

View File

@@ -5246,6 +5246,7 @@ if ($action == 'create') {
print '<td>'.$langs->trans('ListOfSituationInvoices').'</td>'; print '<td>'.$langs->trans('ListOfSituationInvoices').'</td>';
print '<td></td>'; print '<td></td>';
print '<td class="center">'.$langs->trans('Situation').'</td>'; print '<td class="center">'.$langs->trans('Situation').'</td>';
if (isModEnabled("bank")) { if (isModEnabled("bank")) {
print '<td class="right"></td>'; print '<td class="right"></td>';
} }
@@ -5346,7 +5347,6 @@ if ($action == 'create') {
$totalpaid = $next_invoice->getSommePaiement(0); $totalpaid = $next_invoice->getSommePaiement(0);
$totalcreditnotes = $next_invoice->getSumCreditNotesUsed(0); $totalcreditnotes = $next_invoice->getSumCreditNotesUsed(0);
$totaldeposits = $next_invoice->getSumDepositsUsed(0); $totaldeposits = $next_invoice->getSumDepositsUsed(0);
$total_next_ht += $next_invoice->total_ht; $total_next_ht += $next_invoice->total_ht;
$total_next_ttc += $next_invoice->total_ttc; $total_next_ttc += $next_invoice->total_ttc;

View File

@@ -76,9 +76,9 @@ if (!$sortfield) {
} }
$object = new Facture($db); $object = new Facture($db);
if ($object->fetch($id, $ref)) { if ($object->fetch($id, $ref) > 0) {
$object->fetch_thirdparty(); $object->fetch_thirdparty();
$upload_dir = $conf->facture->dir_output."/".dol_sanitizeFileName($object->ref); $upload_dir = $conf->facture->multidir_output[$object->entity].'/'.dol_sanitizeFileName($object->ref);
} }
$permissiontoadd = $user->hasRight('facture', 'creer'); $permissiontoadd = $user->hasRight('facture', 'creer');
@@ -127,7 +127,6 @@ if ($id > 0 || !empty($ref)) {
if ($object->fetch($id, $ref) > 0) { if ($object->fetch($id, $ref) > 0) {
$object->fetch_thirdparty(); $object->fetch_thirdparty();
$upload_dir = $conf->facture->multidir_output[$object->entity].'/'.dol_sanitizeFileName($object->ref);
$head = facture_prepare_head($object); $head = facture_prepare_head($object);
print dol_get_fiche_head($head, 'documents', $langs->trans('InvoiceCustomer'), -1, 'bill'); print dol_get_fiche_head($head, 'documents', $langs->trans('InvoiceCustomer'), -1, 'bill');

View File

@@ -1816,8 +1816,17 @@ abstract class CommonInvoice extends CommonObject
{ {
global $mysoc; global $mysoc;
// Convert total_ttc to a string with 2 decimal places // Get the amount to pay
$totalTTCString = number_format($this->total_ttc, 2, '.', ''); if (method_exists($this, 'getRemainToPay')) {
// Get remaining amount to pay
$amount_to_pay = $this->getRemainToPay();
} else {
// Use Total amount with taxes
$amount_to_pay = $this->total_ttc;
}
// Ensure numeric formatting for EPC QR code
$amount_to_pay = price2num($amount_to_pay, 'MT');
// Initialize an array to hold the lines of the QR code // Initialize an array to hold the lines of the QR code
$lines = array(); $lines = array();
@@ -1849,7 +1858,7 @@ abstract class CommonInvoice extends CommonObject
} }
// Add the amount and reference // Add the amount and reference
$lines[] = 'EUR' . $totalTTCString; // Amount (optional) $lines[] = 'EUR' . $amount_to_pay; // Amount (optional)
$lines[] = ''; // Purpose (optional) $lines[] = ''; // Purpose (optional)
$lines[] = ''; // Payment reference (optional) $lines[] = ''; // Payment reference (optional)
$lines[] = $this->ref; // Remittance Information (optional) $lines[] = $this->ref; // Remittance Information (optional)

View File

@@ -110,6 +110,9 @@ function facture_prepare_head($object)
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
$upload_dir = $conf->facture->dir_output."/".dol_sanitizeFileName($object->ref); $upload_dir = $conf->facture->dir_output."/".dol_sanitizeFileName($object->ref);
if (!empty($conf->facture->multidir_output[$object->entity])) {
$upload_dir = $conf->facture->multidir_output[$object->entity]."/".dol_sanitizeFileName($object->ref);
}
$nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$')); $nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$'));
$nbLinks = Link::count($db, $object->element, $object->id); $nbLinks = Link::count($db, $object->element, $object->id);
$head[$h][0] = DOL_URL_ROOT.'/compta/facture/document.php?id='.$object->id; $head[$h][0] = DOL_URL_ROOT.'/compta/facture/document.php?id='.$object->id;

View File

@@ -509,6 +509,7 @@ function restrictedArea(User $user, $features, $object = 0, $tableandshare = '',
$tableandshare = 'paiementcharge'; $tableandshare = 'paiementcharge';
$parentfortableentity = 'fk_charge@chargesociales'; $parentfortableentity = 'fk_charge@chargesociales';
} }
// if commonObjectLine : Using many2one related commonObject // if commonObjectLine : Using many2one related commonObject
// @see commonObjectLine::parentElement // @see commonObjectLine::parentElement
if (in_array($features, ['commandedet', 'propaldet', 'facturedet', 'supplier_proposaldet', 'evaluationdet', 'skilldet', 'deliverydet', 'contratdet'])) { if (in_array($features, ['commandedet', 'propaldet', 'facturedet', 'supplier_proposaldet', 'evaluationdet', 'skilldet', 'deliverydet', 'contratdet'])) {
@@ -520,6 +521,11 @@ function restrictedArea(User $user, $features, $object = 0, $tableandshare = '',
} elseif ($features == 'invoice_supplier_det_rec') { } elseif ($features == 'invoice_supplier_det_rec') {
$features = 'invoice_supplier_rec'; $features = 'invoice_supplier_rec';
} }
if ($features == 'evaluation') {
$features = 'hrm';
$feature2 = 'evaluation';
}
// @todo check : project_task // @todo check : project_task
// @todo possible ? // @todo possible ?
// elseif (substr($features, -3, 3) == 'det') { // elseif (substr($features, -3, 3) == 'det') {
@@ -965,8 +971,11 @@ function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tabl
if ($feature == 'project') { if ($feature == 'project') {
$feature = 'projet'; $feature = 'projet';
} }
if ($feature == 'task') { if ($feature == 'projet' && !empty($feature2) && is_array($feature2) && !empty(array_intersect(array('project_task', 'projet_task'), $feature2))) {
$feature = 'projet_task'; $feature = 'project_task';
}
if ($feature == 'task' || $feature == 'projet_task') {
$feature = 'project_task';
} }
if ($feature == 'eventorganization') { if ($feature == 'eventorganization') {
$feature = 'agenda'; $feature = 'agenda';
@@ -987,8 +996,8 @@ function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tabl
$checksoc = array('societe'); // Test for object Societe $checksoc = array('societe'); // Test for object Societe
$checkparentsoc = array('agenda', 'contact', 'contrat'); // Test on entity + link to third party on field $dbt_keyfield. Allowed if link is empty (Ex: contacts...). $checkparentsoc = array('agenda', 'contact', 'contrat'); // Test on entity + link to third party on field $dbt_keyfield. Allowed if link is empty (Ex: contacts...).
$checkproject = array('projet', 'project'); // Test for project object $checkproject = array('projet', 'project'); // Test for project object
$checktask = array('projet_task'); // Test for task object $checktask = array('projet_task', 'project_task'); // Test for task object
$checkhierarchy = array('expensereport', 'holiday'); // check permission among the hierarchy of user $checkhierarchy = array('expensereport', 'holiday', 'hrm'); // check permission among the hierarchy of user
$checkuser = array('bookmark'); // check permission among the fk_user (must be myself or null) $checkuser = array('bookmark'); // check permission among the fk_user (must be myself or null)
$nocheck = array('barcode', 'stock'); // No test $nocheck = array('barcode', 'stock'); // No test
@@ -1127,6 +1136,7 @@ function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tabl
return false; return false;
} }
} else { } else {
$sharedelement = 'project'; // for multicompany compatibility
$sql = "SELECT COUNT(dbt.".$dbt_select.") as nb"; $sql = "SELECT COUNT(dbt.".$dbt_select.") as nb";
$sql .= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt"; $sql .= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
$sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")"; $sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
@@ -1215,6 +1225,20 @@ function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tabl
} }
} }
} }
if ($feature == 'hrm' && in_array('evaluation', $feature2)) {
$useridtocheck = $object->fk_user;
if ($user->hasRight('hrm', 'evaluation', 'readall')) {
// the user can view evaluations for anyone
return true;
}
if (!$user->hasRight('hrm', 'evaluation', 'read')) {
// the user can't view any evaluations
return false;
}
// the user can only their own evaluations or their subordinates'
return in_array($useridtocheck, $childids);
}
} }
// For some object, we also have to check it is public or owned by user // For some object, we also have to check it is public or owned by user

View File

@@ -81,7 +81,7 @@ if (isset($totalarray['pos'])) {
printTotalValCell($totalarray['type'][$i] ?? '', empty($totalarray['val'][$totalarray['pos'][$i]]) ? 0 : $totalarray['val'][$totalarray['pos'][$i]]); printTotalValCell($totalarray['type'][$i] ?? '', empty($totalarray['val'][$totalarray['pos'][$i]]) ? 0 : $totalarray['val'][$totalarray['pos'][$i]]);
} else { } else {
if ($i == 1) { if ($i == 1) {
if ((is_null($limit) || $num < $limit) && empty($offset)) { if ((!isset($limit) || is_null($limit) || $num < $limit) && empty($offset)) {
print '<td>'.$langs->trans("Total").'</td>'; print '<td>'.$langs->trans("Total").'</td>';
} else { } else {
print '<td>'; print '<td>';

View File

@@ -558,7 +558,7 @@ class InterfaceWorkflowManager extends DolibarrTriggers
if (isModEnabled('contract') && isModEnabled('ticket') && isModEnabled('workflow') && getDolGlobalString('WORKFLOW_TICKET_LINK_CONTRACT') && getDolGlobalString('TICKET_PRODUCT_CATEGORY') && !empty($object->fk_soc)) { if (isModEnabled('contract') && isModEnabled('ticket') && isModEnabled('workflow') && getDolGlobalString('WORKFLOW_TICKET_LINK_CONTRACT') && getDolGlobalString('TICKET_PRODUCT_CATEGORY') && !empty($object->fk_soc)) {
$societe = new Societe($this->db); $societe = new Societe($this->db);
$company_ids = (!getDolGlobalString('WORKFLOW_TICKET_USE_PARENT_COMPANY_CONTRACTS')) ? [$object->fk_soc] : $societe->getParentsForCompany($object->fk_soc, [$object->fk_soc]); $company_ids = (!getDolGlobalString('WORKFLOW_TICKET_USE_PARENT_COMPANY_CONTRACTS')) ? [$object->fk_soc] : $societe->getParentsForCompany($object->fk_soc, [$object->fk_soc]);
require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
$contrat = new Contrat($this->db); $contrat = new Contrat($this->db);
$number_contracts_found = 0; $number_contracts_found = 0;
foreach ($company_ids as $company_id) { foreach ($company_ids as $company_id) {

View File

@@ -900,10 +900,9 @@ class EmailCollector extends CommonObject
{ {
global $user; global $user;
$nberror = 0; $nbErrors = 0;
$arrayofcollectors = $this->fetchAll($user, 1); $arrayofcollectors = $this->fetchAll($user, 1);
// Loop on each collector // Loop on each collector
foreach ($arrayofcollectors as $emailcollector) { foreach ($arrayofcollectors as $emailcollector) {
$result = $emailcollector->doCollectOneCollector(0); $result = $emailcollector->doCollectOneCollector(0);
@@ -912,11 +911,12 @@ class EmailCollector extends CommonObject
$this->error .= 'EmailCollector ID '.$emailcollector->id.':'.$emailcollector->error.'<br>'; $this->error .= 'EmailCollector ID '.$emailcollector->id.':'.$emailcollector->error.'<br>';
if (!empty($emailcollector->errors)) { if (!empty($emailcollector->errors)) {
$this->error .= implode('<br>', $emailcollector->errors); $this->error .= implode('<br>', $emailcollector->errors);
$nbErrors++;
} }
$this->output .= 'EmailCollector ID '.$emailcollector->id.': '.$emailcollector->lastresult.'<br>'; $this->output .= 'EmailCollector ID '.$emailcollector->id.': '.$emailcollector->lastresult.'<br>';
} }
return $nberror; return $nbErrors;
} }
/** /**
@@ -1976,7 +1976,11 @@ class EmailCollector extends CommonObject
$attachments = []; $attachments = [];
} }
} else { } else {
$this->getmsg($connection, $imapemail); // This set global var $charset, $htmlmsg, $plainmsg, $attachments $getMsg = $this->getmsg($connection, $imapemail); // This set global var $charset, $htmlmsg, $plainmsg, $attachments
if ($getMsg < 0) {
$this->errors = array_merge($this->errors, [$this->error]);
return $getMsg;
}
} }
'@phan-var-force Webklex\PHPIMAP\Attachment[] $attachments'; '@phan-var-force Webklex\PHPIMAP\Attachment[] $attachments';
@@ -3288,7 +3292,11 @@ class EmailCollector extends CommonObject
$this->saveAttachment($destdir, $filename, $content); $this->saveAttachment($destdir, $filename, $content);
} }
} else { } else {
$this->getmsg($connection, $imapemail, $destdir); $getMsg = $this->getmsg($connection, $imapemail, $destdir);
if ($getMsg < 0) {
$this->errors = array_merge($this->errors, [$this->error]);
return $getMsg;
}
} }
$operationslog .= '<br>Project created with attachments -> id='.dol_escape_htmltag($projecttocreate->id); $operationslog .= '<br>Project created with attachments -> id='.dol_escape_htmltag($projecttocreate->id);
@@ -3445,7 +3453,11 @@ class EmailCollector extends CommonObject
$this->saveAttachment($destdir, $filename, $content); $this->saveAttachment($destdir, $filename, $content);
} }
} else { } else {
$this->getmsg($connection, $imapemail, $destdir); $getMsg = $this->getmsg($connection, $imapemail, $destdir);
if ($getMsg < 0) {
$this->errors = array_merge($this->errors, [$this->error]);
return $getMsg;
}
} }
$operationslog .= '<br>Ticket created with attachments -> id='.dol_escape_htmltag($tickettocreate->id); $operationslog .= '<br>Ticket created with attachments -> id='.dol_escape_htmltag($tickettocreate->id);
@@ -3775,9 +3787,9 @@ class EmailCollector extends CommonObject
* @param Object $mbox Structure * @param Object $mbox Structure
* @param string $mid UID email * @param string $mid UID email
* @param string $destdir Target dir for attachments. Leave blank to parse without writing to disk. * @param string $destdir Target dir for attachments. Leave blank to parse without writing to disk.
* @return void * @return int
*/ */
private function getmsg($mbox, $mid, $destdir = '') private function getmsg($mbox, $mid, $destdir = ''): int
{ {
// input $mbox = IMAP stream, $mid = message id // input $mbox = IMAP stream, $mid = message id
// output all the following: // output all the following:
@@ -3791,9 +3803,12 @@ class EmailCollector extends CommonObject
// BODY @phan-suppress-next-line PhanTypeMismatchArgumentInternal // BODY @phan-suppress-next-line PhanTypeMismatchArgumentInternal
$s = imap_fetchstructure($mbox, $mid, FT_UID); $s = imap_fetchstructure($mbox, $mid, FT_UID);
if ($s === false) {
$this->errors = array_merge($this->errors, [imap_last_error()]);
return -1;
}
if (empty($s->parts)) {
if (!$s->parts) {
// simple // simple
$this->getpart($mbox, $mid, $s, '0'); // pass '0' as part-number $this->getpart($mbox, $mid, $s, '0'); // pass '0' as part-number
} else { } else {
@@ -3802,6 +3817,8 @@ class EmailCollector extends CommonObject
$this->getpart($mbox, $mid, $p, $partno0 + 1, $destdir); $this->getpart($mbox, $mid, $p, $partno0 + 1, $destdir);
} }
} }
return 1;
} }
/* partno string /* partno string

View File

@@ -122,8 +122,10 @@ function getAttachments($jk, $mbox)
$fpos = 2; $fpos = 2;
$attachments = array(); $attachments = array();
$nb = count($parts);
if ($nb && !empty($parts)) { if (!empty($parts)) {
$nb = count($parts);
for ($i = 1; $i < $nb; $i++) { for ($i = 1; $i < $nb; $i++) {
$part = $parts[$i]; $part = $parts[$i];
@@ -140,6 +142,7 @@ function getAttachments($jk, $mbox)
$fpos++; $fpos++;
} }
} }
return $attachments; return $attachments;
} }

View File

@@ -1967,9 +1967,10 @@ if ($action == 'create') {
print '</tr>'; print '</tr>';
// List of payments already done // List of payments already done
$canSeeBankAccount = isModEnabled('bank') && $user->hasRight('banque', 'lire');
$nbcols = 3; $nbcols = 3;
$nbrows = 0; $nbrows = 0;
if (isModEnabled("bank")) { if ($canSeeBankAccount) {
$nbrows++; $nbrows++;
$nbcols++; $nbcols++;
} }
@@ -1980,7 +1981,7 @@ if ($action == 'create') {
print '<td class="liste_titre">'.$langs->trans('Payments').'</td>'; print '<td class="liste_titre">'.$langs->trans('Payments').'</td>';
print '<td class="liste_titre">'.$langs->trans('Date').'</td>'; print '<td class="liste_titre">'.$langs->trans('Date').'</td>';
print '<td class="liste_titre">'.$langs->trans('Type').'</td>'; print '<td class="liste_titre">'.$langs->trans('Type').'</td>';
if (isModEnabled("bank")) { if ($canSeeBankAccount) {
print '<td class="liste_titre right">'.$langs->trans('BankAccount').'</td>'; 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 right">'.$langs->trans('Amount').'</td>';
@@ -2023,7 +2024,7 @@ if ($action == 'create') {
$labeltype = $langs->trans("PaymentType".$objp->payment_code) != "PaymentType".$objp->payment_code ? $langs->trans("PaymentType".$objp->payment_code) : $objp->payment_type; $labeltype = $langs->trans("PaymentType".$objp->payment_code) != "PaymentType".$objp->payment_code ? $langs->trans("PaymentType".$objp->payment_code) : $objp->payment_type;
print "<td>".$labeltype.' '.$objp->num_payment."</td>\n"; print "<td>".$labeltype.' '.$objp->num_payment."</td>\n";
// Bank account // Bank account
if (isModEnabled("bank")) { if ($canSeeBankAccount) {
$bankaccountstatic->id = $objp->baid; $bankaccountstatic->id = $objp->baid;
$bankaccountstatic->ref = $objp->baref; $bankaccountstatic->ref = $objp->baref;
$bankaccountstatic->label = $objp->baref; $bankaccountstatic->label = $objp->baref;

View File

@@ -103,8 +103,8 @@ $upload_dir = $conf->hrm->multidir_output[isset($object->entity) ? $object->enti
// Security check (enable the most restrictive one) // Security check (enable the most restrictive one)
//if ($user->socid > 0) accessforbidden(); //if ($user->socid > 0) accessforbidden();
//if ($user->socid > 0) $socid = $user->socid; //if ($user->socid > 0) $socid = $user->socid;
//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0); $isdraft = ($object->status == Evaluation::STATUS_DRAFT) ? 1 : 0;
//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft); restrictedArea($user, $object->element, $object, $object->table_element, '', 'fk_soc', 'rowid', $isdraft);
if (!isModEnabled("hrm")) { if (!isModEnabled("hrm")) {
accessforbidden(); accessforbidden();
} }

View File

@@ -3,6 +3,7 @@
* Copyright (C) 2020 Lenin Rivas <lenin@leninrivas.com> * Copyright (C) 2020 Lenin Rivas <lenin@leninrivas.com>
* Copyright (C) 2023-2024 Frédéric France <frederic.france@free.fr> * Copyright (C) 2023-2024 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com> * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2025 Noé Cendrier <noe.cendrier@altairis.fr>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -948,75 +949,74 @@ class Mo extends CommonObject
$this->db->begin(); $this->db->begin();
if (!empty($arrayoflines)) { if (!empty($fk_movement) || !empty($arrayoflines)) {
// If there is child lines
$stockmove = new MouvementStock($this->db); $stockmove = new MouvementStock($this->db);
$stockmove->setOrigin($this->element, $this->id); $stockmove->setOrigin($this->element, $this->id);
}
if (!empty($fk_movement)) { if (!empty($fk_movement)) {
// The fk_movement was not recorded so we try to guess the product and quantity to restore. // The fk_movement was not recorded so we try to guess the product and quantity to restore.
$moline = new MoLine($this->db); $moline = new MoLine($this->db);
$TArrayMoLine = $moline->fetchAll('', '', 1, 0, '(fk_stock_movement:=:'.((int) $fk_movement).')'); $TArrayMoLine = $moline->fetchAll('', '', 1, 0, '(fk_stock_movement:=:'.((int) $fk_movement).')');
$moline = array_shift($TArrayMoLine); $moline = array_shift($TArrayMoLine);
$movement = new MouvementStock($this->db); $movement = new MouvementStock($this->db);
$movement->fetch($fk_movement); $movement->fetch($fk_movement);
$productstatic->fetch($movement->product_id); $productstatic->fetch($movement->product_id);
$qtytoprocess = $movement->qty; $qtytoprocess = $movement->qty;
// Reverse stock movement
$labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
$codemovementCancel = $langs->trans("StockIncrease");
if (($qtytoprocess >= 0)) {
$idstockmove = $stockmove->reception($user, $movement->product_id, $movement->warehouse_id, $qtytoprocess, 0, $labelmovementCancel, '', '', $movement->batch, dol_now(), 0, $codemovementCancel);
} else {
$idstockmove = $stockmove->livraison($user, $movement->product_id, $movement->warehouse_id, $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $movement->batch, 0, $codemovementCancel);
}
if ($idstockmove < 0) {
$this->error++;
setEventMessages($stockmove->error, $stockmove->errors, 'errors');
} else {
$result = $moline->delete($user, $notrigger);
}
} elseif (!empty($arrayoflines)) {
// Loop on each child lines
foreach ($arrayoflines as $key => $arrayofline) {
$lineDetails = $arrayoflines[$key];
$productstatic->fetch($lineDetails['fk_product']);
$qtytoprocess = $lineDetails['qty'];
// Reverse stock movement // Reverse stock movement
$labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref); $labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref);
$codemovementCancel = $langs->trans("StockIncrease"); $codemovementCancel = $langs->trans("StockIncrease");
if (($qtytoprocess >= 0)) {
$idstockmove = $stockmove->reception($user, $movement->product_id, $movement->warehouse_id, $qtytoprocess, 0, $labelmovementCancel, '', '', $movement->batch, dol_now(), 0, $codemovementCancel); if ($qtytoprocess >= 0) {
$idstockmove = $stockmove->reception($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, '', '', $lineDetails['batch'], dol_now(), 0, $codemovementCancel);
} else { } else {
$idstockmove = $stockmove->livraison($user, $movement->product_id, $movement->warehouse_id, $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $movement->batch, 0, $codemovementCancel); $idstockmove = $stockmove->livraison($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $lineDetails['batch'], 0, $codemovementCancel);
} }
if ($idstockmove < 0) { if ($idstockmove < 0) {
$this->error++; $this->error++;
setEventMessages($stockmove->error, $stockmove->errors, 'errors'); setEventMessages($stockmove->error, $stockmove->errors, 'errors');
} else { } else {
$result = $moline->delete($user, $notrigger); $moline = new MoLine($this->db);
} $moline->fetch($lineDetails['rowid']);
} else {
// Loop on each child lines
foreach ($arrayoflines as $key => $arrayofline) {
$lineDetails = $arrayoflines[$key];
$productstatic->fetch($lineDetails['fk_product']);
$qtytoprocess = $lineDetails['qty'];
// Reverse stock movement $resdel = $moline->delete($user, $notrigger);
$labelmovementCancel = $langs->trans("CancelProductionForRef", $productstatic->ref); if ($resdel < 0) {
$codemovementCancel = $langs->trans("StockIncrease");
if ($qtytoprocess >= 0) {
$idstockmove = $stockmove->reception($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, '', '', $lineDetails['batch'], dol_now(), 0, $codemovementCancel);
} else {
$idstockmove = $stockmove->livraison($user, $lineDetails['fk_product'], $lineDetails['fk_warehouse'], $qtytoprocess, 0, $labelmovementCancel, dol_now(), '', '', $lineDetails['batch'], 0, $codemovementCancel);
}
if ($idstockmove < 0) {
$this->error++; $this->error++;
setEventMessages($stockmove->error, $stockmove->errors, 'errors'); setEventMessages($moline->error, $moline->errors, 'errors');
} else {
$moline = new MoLine($this->db);
$moline->fetch($lineDetails['rowid']);
$resdel = $moline->delete($user, $notrigger);
if ($resdel < 0) {
$this->error++;
setEventMessages($moline->error, $moline->errors, 'errors');
}
} }
} }
}
if (empty($this->error)) {
$result = $this->deleteLineCommon($user, $idline, $notrigger); if (empty($this->error)) {
} $result = $this->deleteLineCommon($user, $idline, $notrigger);
} }
} else { } else {
// No child lines // No child lines and no associated movement
$result = $this->deleteLineCommon($user, $idline, $notrigger); $result = $this->deleteLineCommon($user, $idline, $notrigger);
} }

View File

@@ -5,6 +5,7 @@
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr> * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com> * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2024 Alexandre Spangaro <alexandre@inovea-conseil.com> * Copyright (C) 2024 Alexandre Spangaro <alexandre@inovea-conseil.com>
* Copyright (C) 2025 Noé Cendrier <noe.cendrier@altairis.fr>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -1292,8 +1293,8 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
print '</td>'; print '</td>';
} }
// Action delete line // Action delete line, if no consumption has occurred for this product
if ($permissiontodelete) { if ($permissiontodelete && empty($arrayoflines)) {
$href = $_SERVER["PHP_SELF"] . '?id=' . ((int) $object->id) . '&action=deleteline&token=' . newToken() . '&lineid=' . ((int) $line->id); $href = $_SERVER["PHP_SELF"] . '?id=' . ((int) $object->id) . '&action=deleteline&token=' . newToken() . '&lineid=' . ((int) $line->id);
print '<td class="center">'; print '<td class="center">';
print '<a class="reposition" href="' . $href . '">'; print '<a class="reposition" href="' . $href . '">';

View File

@@ -482,7 +482,7 @@ function MoreProducts(moreorless) {
var nb_cat_shown = $('.div5 div.wrapper2[data-iscat=1]').length; var nb_cat_shown = $('.div5 div.wrapper2[data-iscat=1]').length;
var offset = <?php echo($MAXPRODUCT - 2); ?> * pageproducts - nb_cat_shown; var offset = <?php echo($MAXPRODUCT - 2); ?> * pageproducts - nb_cat_shown;
// Only show products for sale (tosell=1) // Only show products for sale (tosell=1)
$.getJSON('<?php echo DOL_URL_ROOT ?>/takepos/ajax/ajax.php?action=getProducts&token=<?php echo newToken();?>&category='+currentcat+'&tosell=1&limit='+limit+'&offset='+offset, function(data) { $.getJSON('<?php echo DOL_URL_ROOT ?>/takepos/ajax/ajax.php?action=getProducts&token=<?php echo newToken();?>&thirdpartyid=' + jQuery('#thirdpartyid').val() + '&category='+currentcat+'&tosell=1&limit='+limit+'&offset='+offset, function(data) {
console.log("Call ajax.php (in MoreProducts) to get Products of category "+currentcat); console.log("Call ajax.php (in MoreProducts) to get Products of category "+currentcat);
if (typeof (data[0]) == "undefined" && moreorless=="more"){ // Return if no more pages if (typeof (data[0]) == "undefined" && moreorless=="more"){ // Return if no more pages