Compare commits

...

21 Commits
23.0.0 ... 22.0

Author SHA1 Message Date
Laurent Destailleur
d165a8a557 Automated merge from 21.0 to 22.0 by tool pullmerge.sh 2026-03-06 00:18:38 +01:00
Laurent Destailleur
c723aec696 Automated merge from 20.0 to 21.0 by tool pullmerge.sh 2026-03-06 00:18:35 +01:00
Laurent Destailleur
f23d590749 Merge branch '20.0' of git@github.com:Dolibarr/dolibarr.git into 20.0 2026-03-06 00:18:13 +01:00
Laurent Destailleur
a3d5c0b30b Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into
develop
2026-03-06 00:12:01 +01:00
Laurent Destailleur
a7afc55fde CI 2026-03-05 23:57:07 +01:00
Laurent Destailleur
dea8c0cf0e FIX #37412 Better fix 2026-03-05 23:36:54 +01:00
Henry
ba9f70dc92 Fix: Sales order add line shows 0 when only multicurrency unit price is filled (#37412)
When adding a product line to a sales order in multicurrency mode, if the user
fills only the 'UP currency' (multicurrency_price_ht) and not the local unit
price, the line was saved with price 0. The form values for multicurrency
price were never applied to pu_ht_devise, and pu_ht was not derived from
pu_ht_devise using the order rate.

- Set pu_ht_devise from multicurrency_price_ht when user entered it
- When local price is empty/zero, derive pu_ht from pu_ht_devise / multicurrency_tx
  (same convention as core/lib/price.lib.php calcul_price_total)
- Same for multicurrency_price_ttc -> pu_ttc_devise and pu_ttc

Made-with: Cursor
2026-03-05 22:37:29 +01:00
sonikf
015c9859cc fix broken label and its tooltip in Social or fiscal taxes table (#37401)
* fix label tooltip

* fix broken label and tooltip

* Update chargesociales.class.php

* Update index.php
2026-03-05 22:31:39 +01:00
Anthony Berton
0eb3c9e68d FIX - Reload page after check holiday for save param (#37410)
Co-authored-by: Anthony Berton <anthony.berton@bb2a.fr>
2026-03-05 13:46:02 +01:00
Eric Seigne
e049222877 github.event_name is pull_request_target not pull_request 2026-03-05 09:55:51 +01:00
lvessiller-opendsi
c428e079e3 Merge pull request #37057 from ATM-Consulting/FIX/docPreviewInCommCard
FIX - Fix doc preview in comm card
2026-03-05 09:52:24 +01:00
Anthony Berton
418f0c2e30 FIX - Added user filtering for displaying leave in the calendar (#37385)
* FIX - Added user filtering for displaying leave in the calendar

* Add restric

* Save param check_holiday

* Copy

---------

Co-authored-by: Anthony Berton <anthony.berton@bb2a.fr>
2026-03-05 01:16:38 +01:00
Laurent Destailleur
3a15740c73 Automated merge from 21.0 to 22.0 by tool pullmerge.sh 2026-03-04 19:50:16 +01:00
Laurent Destailleur
7bb2713bd9 Merge branch '21.0' of git@github.com:Dolibarr/dolibarr.git into 21.0 2026-03-04 19:49:33 +01:00
Laurent Destailleur
a4e077a0f7 Merge branch '20.0' of git@github.com:Dolibarr/dolibarr.git into 20.0 2026-03-03 14:24:43 +01:00
Laurent Destailleur
749b45a16d Fix from may be empty 2026-03-03 14:24:04 +01:00
Günter Lukas
293b5a0778 Fix #37388 Change GETPOSTINT to GETPOST for form question (#37390)
Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
2026-03-02 20:10:33 +01:00
Laurent Destailleur
5077058df5 Fix CI 2026-03-02 15:23:26 +01:00
ATM-Lucas
c5b4d149b5 delete more & 2026-02-26 14:11:00 +01:00
ATM-Lucas
ba8ab407fe delete & 2026-02-26 10:10:09 +01:00
ATM-Lucas
eaee0a952d Fix doc preview in comm card 2026-02-02 12:05:11 +01:00
8 changed files with 128 additions and 79 deletions

View File

@@ -97,7 +97,7 @@
$sql .= " AND cs.periode >= '".$db->idate($search_date_limit_start)."'";
$sql .= " OR (cs.periode IS NULL AND cs.date_ech between '".$db->idate(dol_get_first_day($year))."' AND '".$db->idate(dol_get_last_day($year))."')";
$sql .= " SET reponses = '".$db->escape($nouveauchoix)."'";
$sql .= " cs.rowid, cs.libelle, cs.fk_type as type, cs.periode as period, cs.date_ech, cs.amount as total,";
$sql .= " cs.rowid, cs.libelle as label, cs.fk_type as type, cs.periode as period, cs.date_ech, cs.amount as total,";
$sql.= " ".MAIN_DB_PREFIX."notify_def as nd,";
$sql.= " AND nd.fk_action = ad.rowid";
$sql.= " WHERE u.rowid = nd.fk_user";

View File

@@ -7,8 +7,9 @@
* Copyright (C) 2014 Cedric GROSS <c.gross@kreiz-it.fr>
* Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
* Copyright (C) 2017 Open-DSI <support@open-dsi.fr>
* Copyright (C) 2021-2025 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2021-2025 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2026 Anthony Berton <anthony.berton@bb2a.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
@@ -456,6 +457,9 @@ if ($mode == 'show_day' || $mode == 'show_week' || $mode == 'show_month') {
if ($search_categ_cus != 0) {
$param .= '&search_categ_cus='.urlencode((string) ($search_categ_cus));
}
if ($check_holiday) {
$param .= '&check_holiday=1';
}
// Show navigation bar
$nav = '';
@@ -625,7 +629,7 @@ if (!empty($conf->use_javascript_ajax)) { // If javascript on
$s .= '<script type="text/javascript">'."\n";
$s .= 'jQuery(document).ready(function () {'."\n";
$s .= 'jQuery(".check_birthday").click(function() { console.log("Toggle class .family_birthday"); jQuery(".family_birthday").toggle(); });'."\n";
$s .= 'jQuery(".check_holiday").click(function() { console.log("Toggle class .family_holiday"); jQuery(".family_holiday").toggle(); });'."\n";
$s .= 'jQuery(".check_holiday").click(function() { console.log("Toggle class .family_holiday"); jQuery(".family_holiday").toggle(); jQuery(this).closest("form").submit(); });'."\n";
if (isModEnabled("bookcal") && !empty($bookcalcalendars["calendars"])) {
foreach ($bookcalcalendars["calendars"] as $key => $value) {
$s .= 'jQuery(".check_bookcal_calendar_'.$value['id'].'").click(function() { console.log("Toggle Bookcal Calendar '.$value['id'].'"); jQuery(".family_bookcal_calendar_'.$value['id'].'").toggle(); });'."\n";
@@ -1163,9 +1167,14 @@ if ($user->hasRight("holiday", "read")) {
$sql .= " AND x.date_debut <= '".$db->idate(dol_get_last_day($year, $month))."'";
$sql .= " AND x.date_fin >= '".$db->idate(dol_get_first_day($year, $month))."'";
}
if (!$user->hasRight('holiday', 'readall')) {
if (!$user->hasRight('holiday', 'readall') || $filtert == '-3') {
// Restrict on users of current user and his children
$sql .= " AND x.fk_user IN(".$db->sanitize(implode(", ", $user->getAllChildIds(1))).") ";
}
if ($filtert > 0) {
// Restrict on user
$sql .= " AND x.fk_user = ".((int) $filtert);
}
$resql = $db->query($sql);
if ($resql) {

View File

@@ -960,7 +960,7 @@ if ($object->id > 0) {
}
}
$relativepath = dol_sanitizeFileName($objp->ref).'/'.dol_sanitizeFileName($objp->ref).'.pdf';
print $formfile->showPreview($file_list, $propal_static->element, $relativepath, 0);
print $formfile->showPreview($file_list, $propal_static->element, $relativepath, 0, 'entity=' . $objp->entity);
}
print '</td><td class="tdoverflowmax125">';
if ($propal_static->fk_project > 0) {
@@ -1079,7 +1079,7 @@ if ($object->id > 0) {
}
}
$relativepath = dol_sanitizeFileName($objp->ref).'/'.dol_sanitizeFileName($objp->ref).'.pdf';
print $formfile->showPreview($file_list, $commande_static->element, $relativepath, 0, $param);
print $formfile->showPreview($file_list, $commande_static->element, $relativepath, 0, 'entity=' . $objp->entity);
}
print '</td><td class="tdoverflowmax125">';
if ($commande_static->fk_project > 0) {
@@ -1112,6 +1112,8 @@ if ($object->id > 0) {
* Latest shipments
*/
if (isModEnabled("shipping") && $user->hasRight('expedition', 'lire')) {
$param = 'entity=' . ((int) $objp->entity);
$sql = 'SELECT e.rowid as id';
$sql .= ', e.ref, e.entity, e.fk_projet';
$sql .= ', e.date_creation';
@@ -1180,7 +1182,8 @@ if ($object->id > 0) {
}
}
$relativepath = dol_sanitizeFileName($objp->ref).'/'.dol_sanitizeFileName($objp->ref).'.pdf';
print $formfile->showPreview($file_list, $sendingstatic->table_element, $relativepath, 0, $param);
print $formfile->showPreview($file_list, $sendingstatic->element, $relativepath, 0, $param);
}
print '</td><td class="tdoverflowmax125">';
if ($sendingstatic->fk_project > 0) {
@@ -1294,7 +1297,7 @@ if ($object->id > 0) {
}
}
$relativepath = dol_sanitizeFileName($objp->ref).'/'.dol_sanitizeFileName($objp->ref).'.pdf';
print $formfile->showPreview($file_list, $contrat->element, $relativepath, 0);
print $formfile->showPreview($file_list, $contrat->element, $relativepath, 0, 'entity=' . $objp->entity);
}
}
// $filename = dol_sanitizeFileName($objp->ref);
@@ -1395,7 +1398,7 @@ if ($object->id > 0) {
}
}
$relativepath = dol_sanitizeFileName($objp->ref).'/'.dol_sanitizeFileName($objp->ref).'.pdf';
print $formfile->showPreview($file_list, $fichinter_static->element, $relativepath, 0);
print $formfile->showPreview($file_list, $fichinter_static->element, $relativepath, 0, 'entity=' . $objp->entity);
}
print '</td><td class="tdoverflowmax125">';
if ($fichinter_static->fk_project > 0) {
@@ -1624,7 +1627,7 @@ if ($object->id > 0) {
}
}
$relativepath = dol_sanitizeFileName($objp->ref).'/'.dol_sanitizeFileName($objp->ref).'.pdf';
print $formfile->showPreview($file_list, $facturestatic->element, $relativepath, 0);
print $formfile->showPreview($file_list, $facturestatic->element, $relativepath, 0, 'entity=' . $objp->entity);
}
print '</td><td class="tdoverflowmax125">';
if ($facturestatic->fk_project > 0) {

View File

@@ -1332,7 +1332,7 @@ if (empty($reshook)) {
// If a price per customer exist
$pricebycustomerexist = false;
$result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
if ($result) {
if ($result >= 0) {
// If there is some prices specific to the customer
if (count($prodcustprice->lines) > 0) {
$date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours
@@ -1356,9 +1356,11 @@ if (empty($reshook)) {
}
}
}
} else {
setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
}
if (!$pricebycustomerexist && $object->thirdparty->price_level) { // If price per segment
if (!$pricebycustomerexist && !empty($object->thirdparty->price_level)) { // If price per segment
$pu_ht = $prod->multiprices[$object->thirdparty->price_level];
$pu_ttc = $prod->multiprices_ttc[$object->thirdparty->price_level];
$price_min = $prod->multiprices_min[$object->thirdparty->price_level];
@@ -1373,7 +1375,7 @@ if (empty($reshook)) {
}
}
}
} elseif (getDolGlobalString('PRODUIT_MULTIPRICES') && $object->thirdparty->price_level) { // If price per segment
} elseif (getDolGlobalString('PRODUIT_MULTIPRICES') && !empty($object->thirdparty->price_level)) { // If price per segment
$pu_ht = $prod->multiprices[$object->thirdparty->price_level];
$pu_ttc = $prod->multiprices_ttc[$object->thirdparty->price_level];
$price_min = $prod->multiprices_min[$object->thirdparty->price_level];
@@ -1396,7 +1398,7 @@ if (empty($reshook)) {
$filter = array('t.fk_product' => (string) $prod->id, 't.fk_soc' => (string) $object->thirdparty->id);
$result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
if ($result) {
if ($result >= 0) {
// If there is some prices specific to the customer
if (count($prodcustprice->lines) > 0) {
$date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours
@@ -1419,6 +1421,8 @@ if (empty($reshook)) {
}
}
}
} else {
setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
}
} elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY')) {
// If price per quantity
@@ -1464,26 +1468,26 @@ if (empty($reshook)) {
}
}
$tmpvat = price2num(preg_replace('/\s*\(.*\)/', '', $tva_tx));
$tmpprodvat = price2num(preg_replace('/\s*\(.*\)/', '', (string) $prod->tva_tx));
$tmpvat = (float) price2num(preg_replace('/\s*\(.*\)/', '', $tva_tx));
$tmpprodvat = (float) price2num(preg_replace('/\s*\(.*\)/', '', (string) $prod->tva_tx));
// Set unit price to use
if (!empty($price_ht) || (string) $price_ht === '0') {
$pu_ht = price2num($price_ht, 'MU');
$pu_ttc = price2num((float) $pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
$pu_ht = (float) price2num($price_ht, 'MU');
$pu_ttc = (float) price2num((float) $pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
} elseif (!empty($price_ht_devise) || (string) $price_ht_devise === '0') {
$pu_ht_devise = price2num($price_ht_devise, 'MU');
$pu_ht = '';
$pu_ttc = '';
} elseif (!empty($price_ttc) || (string) $price_ttc === '0') {
$pu_ttc = price2num($price_ttc, 'MU');
$pu_ht = price2num((float) $pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
$pu_ttc = (float) price2num($price_ttc, 'MU');
$pu_ht = (float) price2num((float) $pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
} elseif ($tmpvat != $tmpprodvat) {
// Is this still used ?
if ($price_base_type != 'HT') {
$pu_ht = price2num((float) $pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
$pu_ht = (float) price2num((float) $pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
} else {
$pu_ttc = price2num((float) $pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
$pu_ttc = (float) price2num((float) $pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
}
}
@@ -1565,10 +1569,10 @@ if (empty($reshook)) {
$pu_ht = price2num($price_ht, 'MU');
$pu_ttc = price2num($price_ttc, 'MU');
$tva_npr = (preg_match('/\*/', $tva_tx) ? 1 : 0);
$tva_tx = str_replace('*', '', $tva_tx);
if (empty($tva_tx)) {
$tva_npr = 0;
}
$tva_tx = str_replace('*', '', $tva_tx);
$label = (GETPOST('product_label') ? GETPOST('product_label') : '');
$desc = $line_desc;
$type = GETPOST('type');
@@ -1591,7 +1595,7 @@ if (empty($reshook)) {
$localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $mysoc, $tva_npr);
// Margin
$fournprice = (int) (GETPOST('fournprice'.$predef) ? GETPOST('fournprice'.$predef) : ''); // This can be id of supplier price, or 'pmpprice' or 'costprice', or 'inputprice', we force to keep ID only
$fournprice = (int) (GETPOST('fournprice'.$predef) ? GETPOST('fournprice'.$predef) : 0); // This can be id of supplier price, or 'pmpprice' or 'costprice', or 'inputprice', we force to keep ID only
$buyingprice = price2num((GETPOST('buying_price'.$predef) != '' ? GETPOST('buying_price'.$predef) : ''), '', 2); // If buying_price is '0', we must keep this value
$date_start = dol_mktime(GETPOSTINT('date_start'.$predef.'hour'), GETPOSTINT('date_start'.$predef.'min'), GETPOSTINT('date_start'.$predef.'sec'), GETPOSTINT('date_start'.$predef.'month'), GETPOSTINT('date_start'.$predef.'day'), GETPOSTINT('date_start'.$predef.'year'));
@@ -1625,13 +1629,15 @@ if (empty($reshook)) {
//var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
//var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
//$desc = dol_htmlcleanlastbr($desc);
// Check price is not lower than minimum
if ($usermustrespectpricemin) {
if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - $remise_percent / 100)) < price2num($price_min)) && $price_base_type == 'HT') {
if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
$mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
setEventMessages($mesg, null, 'errors');
$error++;
} elseif ($pu_equivalent_ttc && $price_min_ttc && (((float) price2num($pu_equivalent_ttc) * (1 - $remise_percent / 100)) < price2num($price_min_ttc)) && $price_base_type == 'TTC') {
} elseif ($pu_equivalent_ttc && $price_min_ttc && (((float) price2num($pu_equivalent_ttc) * (1 - $remise_percent / 100)) < (float) price2num($price_min_ttc)) && $price_base_type == 'TTC') {
$mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
setEventMessages($mesg, null, 'errors');
$error++;
@@ -1640,12 +1646,12 @@ if (empty($reshook)) {
if (!$error) {
// Insert line
$result = $object->addline($desc, $pu_ht, (float) $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $price_base_type, $pu_ttc, $info_bits, $type, min($rank, count($object->lines) + 1), 0, GETPOSTINT('fk_parent_line'), (int) $fournprice, $buyingprice, $label, $date_start, $date_end, $array_options, $fk_unit, '', 0, $pu_ht_devise);
$result = $object->addline($desc, $pu_ht, (float) $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $price_base_type, $pu_ttc, $info_bits, $type, min($rank, count($object->lines) + 1), 0, GETPOSTINT('fk_parent_line'), (int) $fournprice, $buyingprice, $label, $date_start, $date_end, $array_options, $fk_unit, '', 0, (float) $pu_ht_devise);
if ($result > 0) {
$db->commit();
$ret = $object->fetch($id); // Reload to get new records
$ret = $object->fetch($object->id); // Reload to get new records
if ($ret > 0) {
$object->fetch_thirdparty();
}
@@ -1653,9 +1659,12 @@ if (empty($reshook)) {
if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
// Define output language
$outputlangs = $langs;
if (getDolGlobalInt('MAIN_MULTILANGS')) {
$newlang = GETPOST('lang_id', 'alpha');
if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
$newlang = $object->thirdparty->default_lang;
}
if (!empty($newlang)) {
$outputlangs = new Translate("", $conf);
$newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
$outputlangs->setDefaultLang($newlang);
}
$object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
@@ -1844,7 +1853,7 @@ if (empty($reshook)) {
setEventMessages($object->error, $object->errors, 'errors');
}
} elseif ($action == 'updateline' && $usercancreate && GETPOST('save')) {
// Update a line within proposal
// Update a line
// Clean parameters
$description = dol_htmlcleanlastbr(GETPOST('product_desc', 'restricthtml'));
@@ -1856,7 +1865,7 @@ if (empty($reshook)) {
}
// Define vat_rate
$vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
$vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx', 'alpha') : 0);
$vat_rate = str_replace('*', '', $vat_rate);
$localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
$localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
@@ -1935,7 +1944,6 @@ if (empty($reshook)) {
$res = $product->fetch($productid);
$type = $product->type;
$price_base_type = $product->price_base_type;
// If base type TTc, we change pu value to define the TTC one
if ($price_base_type == 'TTC' && !empty($pu_ttc)) {

View File

@@ -965,10 +965,6 @@ if (empty($reshook)) {
$price_ht_devise = '';
$price_ttc = '';
$price_ttc_devise = '';
$pu_ht = '';
$pu_ttc = '';
$pu_ht_devise = '';
$pu_ttc_devise = '';
if (GETPOST('price_ht') !== '') {
$price_ht = price2num(GETPOST('price_ht'), 'MU', 2);
@@ -1055,13 +1051,20 @@ if (empty($reshook)) {
}
if (!$error && ($qty >= 0) && (!empty($line_desc) || (!empty($idprod) && $idprod > 0))) {
$pu_ht = 0;
$pu_ttc = 0;
$pu_ht_devise = 0;
$pu_ttc_devise = 0;
$price_min = 0;
$price_min_ttc = 0;
$tva_npr = 0;
$price_base_type = (GETPOST('price_base_type', 'alpha') ? GETPOST('price_base_type', 'alpha') : 'HT');
// Clean parameters
$date_start = dol_mktime(GETPOSTINT('date_start'.$predef.'hour'), GETPOSTINT('date_start'.$predef.'min'), GETPOSTINT('date_start'.$predef.'sec'), GETPOSTINT('date_start'.$predef.'month'), GETPOSTINT('date_start'.$predef.'day'), GETPOSTINT('date_start'.$predef.'year'));
$date_end = dol_mktime(GETPOSTINT('date_end'.$predef.'hour'), GETPOSTINT('date_end'.$predef.'min'), GETPOSTINT('date_end'.$predef.'sec'), GETPOSTINT('date_end'.$predef.'month'), GETPOSTINT('date_end'.$predef.'day'), GETPOSTINT('date_end'.$predef.'year'));
$price_base_type = (GETPOST('price_base_type', 'alpha') ? GETPOST('price_base_type', 'alpha') : 'HT');
$price_min = $price_min_ttc = 0;
$tva_npr = 0;
$db->begin();
// Ecrase $pu par celui du produit
// Ecrase $desc par celui du produit
@@ -1079,6 +1082,7 @@ if (empty($reshook)) {
$tva_npr = 0;
}*/
// Price unique per product
$pu_ht = $prod->price;
$pu_ttc = $prod->price_ttc;
$price_min = $prod->price_min;
@@ -1097,6 +1101,7 @@ if (empty($reshook)) {
$pricebycustomerexist = false;
$result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
if ($result >= 0) {
// If there is some prices specific to the customer
if (count($prodcustprice->lines) > 0) {
$date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours
foreach ($prodcustprice->lines as $k => $custprice_line) {
@@ -1107,14 +1112,14 @@ if (empty($reshook)) {
$price_min = price($custprice_line->price_min);
$price_min_ttc = price($custprice_line->price_min_ttc);
$price_base_type = $custprice_line->price_base_type;
$tva_tx = $custprice_line->tva_tx;
/*$tva_tx = $custprice_line->tva_tx;
if ($custprice_line->default_vat_code && !preg_match('/\(.*\)/', (string) $tva_tx)) {
$tva_tx .= ' (' . $custprice_line->default_vat_code . ')';
}
$tva_npr = $custprice_line->recuperableonly;
if (empty($tva_tx)) {
$tva_npr = 0;
}
}*/
break;
}
}
@@ -1123,7 +1128,7 @@ if (empty($reshook)) {
setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
}
if (!$pricebycustomerexist && !empty($object->thirdparty->price_level)) { //// If price per segment
if (!$pricebycustomerexist && !empty($object->thirdparty->price_level)) { // If price per segment
$pu_ht = $prod->multiprices[$object->thirdparty->price_level];
$pu_ttc = $prod->multiprices_ttc[$object->thirdparty->price_level];
$price_min = $prod->multiprices_min[$object->thirdparty->price_level];
@@ -1138,9 +1143,7 @@ if (empty($reshook)) {
}
}
}
}
// If price per segment
if (getDolGlobalString('PRODUIT_MULTIPRICES') && !empty($object->thirdparty->price_level)) {
} elseif (getDolGlobalString('PRODUIT_MULTIPRICES') && !empty($object->thirdparty->price_level)) { // If price per segment
$pu_ht = $prod->multiprices[$object->thirdparty->price_level];
$pu_ttc = $prod->multiprices_ttc[$object->thirdparty->price_level];
$price_min = $prod->multiprices_min[$object->thirdparty->price_level];
@@ -1164,6 +1167,7 @@ if (empty($reshook)) {
$result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
if ($result >= 0) {
// If there is some prices specific to the customer
if (count($prodcustprice->lines) > 0) {
$date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours
foreach ($prodcustprice->lines as $k => $custprice_line) {
@@ -1173,14 +1177,14 @@ if (empty($reshook)) {
$price_min = price($custprice_line->price_min);
$price_min_ttc = price($custprice_line->price_min_ttc);
$price_base_type = $custprice_line->price_base_type;
$tva_tx = $custprice_line->tva_tx;
/*$tva_tx = $custprice_line->tva_tx;
if ($custprice_line->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) {
$tva_tx .= ' (' . $custprice_line->default_vat_code . ')';
}
$tva_npr = $custprice_line->recuperableonly;
if (empty($tva_tx)) {
$tva_npr = 0;
}
}*/
break;
}
}
@@ -1235,18 +1239,22 @@ if (empty($reshook)) {
$tmpprodvat = (float) price2num(preg_replace('/\s*\(.*\)/', '', (string) $prod->tva_tx));
// Set unit price to use
if (!empty($price_ht) || $price_ht === '0') {
if (!empty($price_ht) || (string) $price_ht === '0') {
$pu_ht = (float) price2num($price_ht, 'MU');
$pu_ttc = (float) price2num((float) $pu_ht * (1 + ($tmpvat / 100)), 'MU');
} elseif (!empty($price_ttc) || $price_ttc === '0') {
$pu_ttc = (float) price2num((float) $pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
} elseif (!empty($price_ht_devise) || (string) $price_ht_devise === '0') {
$pu_ht_devise = price2num($price_ht_devise, 'MU');
$pu_ht = '';
$pu_ttc = '';
} elseif (!empty($price_ttc) || (string) $price_ttc === '0') {
$pu_ttc = (float) price2num($price_ttc, 'MU');
$pu_ht = (float) price2num((float) $pu_ttc / (1 + ($tmpvat / 100)), 'MU');
$pu_ht = (float) price2num((float) $pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
} elseif ($tmpvat != $tmpprodvat) {
// Is this still used ?
if ($price_base_type != 'HT') {
$pu_ht = (float) price2num($pu_ttc / (1 + ($tmpvat / 100)), 'MU');
$pu_ht = (float) price2num((float) $pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
} else {
$pu_ttc = (float) price2num($pu_ht * (1 + ($tmpvat / 100)), 'MU');
$pu_ttc = (float) price2num((float) $pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
}
}
@@ -1350,12 +1358,12 @@ if (empty($reshook)) {
}
// Local Taxes
$localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty);
$localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty);
$localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $mysoc, $tva_npr);
$localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $mysoc, $tva_npr);
// Margin
$fournprice = (int) (GETPOST('fournprice'.$predef) ? GETPOSTINT('fournprice'.$predef) : 0); // This can be id of supplier price, or 'pmpprice' or 'costprice', or 'inputprice', we force to keep ID only
$buyingprice = price2num(GETPOST('buying_price'.$predef) != '' ? GETPOST('buying_price'.$predef) : ''); // If buying_price is '0', we must keep this value
$fournprice = (int) (GETPOST('fournprice'.$predef) ? GETPOST('fournprice'.$predef) : 0); // This can be id of supplier price, or 'pmpprice' or 'costprice', or 'inputprice', we force to keep ID only
$buyingprice = price2num((GETPOST('buying_price'.$predef) != '' ? GETPOST('buying_price'.$predef) : ''), '', 2); // If buying_price is '0', we must keep this value
// Prepare a price equivalent for minimum price check
$pu_equivalent = $pu_ht;
@@ -1372,7 +1380,7 @@ if (empty($reshook)) {
$pu_equivalent_ttc = (float) $pu_ttc_devise * (float) $currency_tx;
}
// TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one defined
// TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
/*
if ($pu_equivalent) {
$tmp = calcul_price_total(1, $pu_equivalent, 0, $tva_tx, -1, -1, 0, 'HT', $info_bits, $type);
@@ -1383,6 +1391,9 @@ if (empty($reshook)) {
}
*/
//var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
//var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
$desc = dol_htmlcleanlastbr($desc);
// Check price is not lower than minimum
@@ -1403,8 +1414,12 @@ if (empty($reshook)) {
$result = $object->addline($desc, $pu_ht, (float) $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $info_bits, 0, $price_base_type, $pu_ttc, $date_start, $date_end, $type, min($rank, count($object->lines) + 1), 0, GETPOSTINT('fk_parent_line'), (int) $fournprice, $buyingprice, $label, $array_options, $fk_unit, '', 0, (float) $pu_ht_devise);
if ($result > 0) {
$db->commit();
$ret = $object->fetch($object->id); // Reload to get new records
$object->fetch_thirdparty();
if ($ret > 0) {
$object->fetch_thirdparty();
}
if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
// Define output language
@@ -1454,6 +1469,8 @@ if (empty($reshook)) {
unset($_POST['date_endmonth']);
unset($_POST['date_endyear']);
} else {
$db->rollback();
setEventMessages($object->error, $object->errors, 'errors');
}
}
@@ -1545,6 +1562,7 @@ if (empty($reshook)) {
}
} elseif ($action == 'updateline' && $usercancreate && GETPOST('save')) {
// Update a line
// Clean parameters
$date_start = '';
$date_end = '';
@@ -1613,15 +1631,15 @@ if (empty($reshook)) {
}
// Define special_code for special lines
$special_code = GETPOST('special_code');
$special_code = GETPOSTINT('special_code');
if (!GETPOST('qty')) {
$special_code = 3;
}
$remise_percent = GETPOST('remise_percent') != '' ? price2num(GETPOST('remise_percent'), '', 2) : 0;
$price_base_type = 'HT';
$pu = $pu_ht;
$price_base_type = 'HT';
if (empty($pu) && !empty($pu_ttc)) {
$pu = $pu_ttc;
$price_base_type = 'TTC';
@@ -1648,12 +1666,12 @@ if (empty($reshook)) {
// Check price is not lower than minimum
if ($usermustrespectpricemin) {
if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - (float) $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
$mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
setEventMessages($mesg, null, 'errors');
$error++;
$action = 'editline';
} elseif ($pu_equivalent_ttc && $price_min_ttc && (((float) price2num($pu_equivalent_ttc) * (1 - $remise_percent / 100)) < (float) price2num($price_min_ttc)) && $price_base_type == 'TTC') {
} elseif ($pu_equivalent_ttc && $price_min_ttc && (((float) price2num($pu_equivalent_ttc) * (1 - (float) $remise_percent / 100)) < (float) price2num($price_min_ttc)) && $price_base_type == 'TTC') {
$mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
setEventMessages($mesg, null, 'errors');
$error++;
@@ -1688,6 +1706,8 @@ if (empty($reshook)) {
}
if (!$error) {
$db->begin();
if (!$user->hasRight('margins', 'creer')) {
foreach ($object->lines as &$line) {
if ($line->id == GETPOSTINT('lineid')) {
@@ -1698,9 +1718,13 @@ if (empty($reshook)) {
}
}
$qty = price2num(GETPOST('qty', 'alpha'), 'MS');
$result = $object->updateline(GETPOSTINT('lineid'), $description, (float) $pu, (float) $qty, $remise_percent, $vat_rate, $localtax1_rate, $localtax2_rate, $price_base_type, $info_bits, $date_start, $date_end, $type, GETPOSTINT('fk_parent_line'), 0, (int) $fournprice, $buyingprice, $label, $special_code, $array_options, GETPOSTINT('units'), (float) $pu_ht_devise);
if ($result >= 0) {
$db->commit();
if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
// Define output language
$outputlangs = $langs;
@@ -1747,6 +1771,8 @@ if (empty($reshook)) {
unset($_POST['date_endmonth']);
unset($_POST['date_endyear']);
} else {
$db->rollback();
setEventMessages($object->error, $object->errors, 'errors');
}
}

View File

@@ -9,6 +9,7 @@
* Copyright (C) 2021 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
* Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2026 Nick Fragoulis
*
* 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
@@ -145,8 +146,8 @@ print '<span class="opacitymedium">'.$langs->trans("DescTaxAndDividendsArea").'<
print "<br>";
if (isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) {
$sql = "SELECT c.id, c.libelle as label,";
$sql .= " cs.rowid, cs.libelle, cs.fk_type as type, cs.periode as period, cs.date_ech, cs.amount as total,";
$sql = "SELECT c.id, c.libelle as type_label,";
$sql .= " cs.rowid, cs.libelle as label, cs.fk_type as type, cs.periode as period, cs.date_ech, cs.amount as total,";
$sql .= " pc.rowid as pid, pc.datep, pc.amount as totalpaid, pc.num_paiement as num_payment, pc.fk_bank,";
$sql .= " pct.code as payment_code,";
$sql .= " ba.rowid as bid, ba.ref as bref, ba.number as bnumber, ba.account_number, ba.fk_accountancy_journal, ba.label as blabel";
@@ -160,7 +161,7 @@ if (isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) {
$sql .= " AND cs.entity IN (".getEntity("tax").")";
if ($year > 0) {
$sql .= " AND (";
// If period defined, we use it as dat criteria, if not we use date echeance,
// If period defined, we use it as date criteria, if not we use date echeance,
// so we are compatible when period is not mandatory
$sql .= " (cs.periode IS NOT NULL AND cs.periode between '".$db->idate(dol_get_first_day($year))."' AND '".$db->idate(dol_get_last_day($year))."')";
$sql .= " OR (cs.periode IS NULL AND cs.date_ech between '".$db->idate(dol_get_first_day($year))."' AND '".$db->idate(dol_get_last_day($year))."')";
@@ -184,8 +185,8 @@ if (isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) {
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print_liste_field_titre("PeriodEndDate", $_SERVER["PHP_SELF"], "cs.date_ech", "", $param, 'width="120"', $sortfield, $sortorder, 'nowraponall ');
print_liste_field_titre("Label", $_SERVER["PHP_SELF"], "c.libelle", "", $param, '', $sortfield, $sortorder);
print_liste_field_titre("Type", $_SERVER["PHP_SELF"], "cs.fk_type", "", $param, '', $sortfield, $sortorder);
print_liste_field_titre("Label", $_SERVER["PHP_SELF"], "cs.libelle", "", $param, '', $sortfield, $sortorder);
print_liste_field_titre("Type", $_SERVER["PHP_SELF"], "c.libelle", "", $param, '', $sortfield, $sortorder);
print_liste_field_titre("ExpectedToPay", $_SERVER["PHP_SELF"], "cs.amount", "", $param, 'class="right"', $sortfield, $sortorder);
print_liste_field_titre("RefPayment", $_SERVER["PHP_SELF"], "pc.rowid", "", $param, '', $sortfield, $sortorder);
print_liste_field_titre("DatePayment", $_SERVER["PHP_SELF"], "pc.datep", "", $param, 'align="center"', $sortfield, $sortorder);
@@ -216,12 +217,11 @@ if (isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) {
// Label
print '<td>';
$socialcontrib->id = $obj->rowid;
$socialcontrib->ref = $obj->label;
$socialcontrib->label = $obj->label;
print $socialcontrib->getNomUrl(1, '20');
print '</td>';
// Type
print '<td class="tdoverflowmax200"><a href="'.DOL_URL_ROOT.'/compta/sociales/list.php?filtre=cs.fk_type:'.$obj->type.'">'.$obj->label.'</a></td>';
print '<td class="tdoverflowmax200"><a href="'.DOL_URL_ROOT.'/compta/sociales/list.php?filtre=cs.fk_type:'.$obj->type.'">'.$obj->type_label.'</a></td>';
// Expected to pay
print '<td class="right"><span class="amount">'.price($obj->total).'</span></td>';
// Ref payment
@@ -275,7 +275,7 @@ if (isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) {
print '<td colspan="3" class="liste_total">'.$langs->trans("Total").'</td>';
// Total here has no sens because we can have several time the same line
//Total here makes no sense because we can have the same line several times.
//print '<td class="liste_total right">'.price($total).'</td>';
print '<td class="liste_total right"></td>';
@@ -306,7 +306,7 @@ if (isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) {
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as pct ON ptva.fk_typepaiement = pct.id";
$sql .= " WHERE pv.entity IN (".getEntity("tax").")";
if ($year > 0) {
// If period defined, we use it as dat criteria, if not we use date echeance,
// If period defined, we use it as date criteria, if not we use date echeance,
// so we are compatible when period is not mandatory
$sql .= " AND pv.datev between '".$db->idate(dol_get_first_day($year, 1, false))."' AND '".$db->idate(dol_get_last_day($year, 12, false))."'";
}
@@ -410,7 +410,7 @@ if (isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) {
print '<td class="liste_total" colspan="2">'.$langs->trans("Total").'</td>';
// Total here has no sens because we can have several time the same line
// Total here makes no sense because we can have the same line several times.
//print '<td class="right">'.price($totaltopay).'</td>';
print '<td class="liste_total">&nbsp;</td>';
@@ -461,7 +461,7 @@ while ($j < $numlt) {
$sql .= " FROM ".MAIN_DB_PREFIX."localtax as pv";
$sql .= " WHERE pv.entity = ".$conf->entity." AND localtaxtype = ".((int) $j);
if ($year > 0) {
// If period defined, we use it as dat criteria, if not we use date echeance,
// If period defined, we use it as date criteria, if not we use date echeance,
// so we are compatible when period is not mandatory
$sql .= " AND pv.datev between '".$db->idate(dol_get_first_day($year, 1, false))."' AND '".$db->idate(dol_get_last_day($year, 12, false))."'";
}

View File

@@ -672,8 +672,8 @@ class ChargeSociales extends CommonObject
if (isset($this->paye)) {
$label .= ' '.$this->getLibStatut(5);
}
if (!empty($this->ref)) {
$label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
if (!empty($this->id)) {
$label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->id;
}
if (!empty($this->label)) {
$label .= '<br><b>'.$langs->trans('Label').':</b> '.$this->label;

View File

@@ -668,7 +668,10 @@ class Notify
$application = (preg_match('/^\+/', $applicationcustom) ? $application : '').$applicationcustom;
}
$from = getDolGlobalString('NOTIFICATION_EMAIL_FROM', getDolGlobalString('MAIN_MAIL_EMAIL_FROM'));
$from = getDolGlobalString('NOTIFICATION_EMAIL_FROM');
if (empty($from)) {
$from = getDolGlobalString('MAIN_MAIL_EMAIL_FROM');
}
$object_type = '';
$link = '';