forked from Wavyzz/dolibarr
Merge remote-tracking branch 'Dolibarr/14.0' into 14
This commit is contained in:
21
ChangeLog
21
ChangeLog
@@ -2,6 +2,27 @@
|
||||
English Dolibarr ChangeLog
|
||||
--------------------------------------------------------------
|
||||
|
||||
***** ChangeLog for 13.0.4 compared to 13.0.2 *****
|
||||
|
||||
FIX: Allow disabling of a module (not a dangerous action) even if there is problem with token (due to bugged modules).
|
||||
FIX: 13.0 - fatal - missing inclusion of ajax.lib.php for calling `ajax_autocompleter()`
|
||||
FIX: #17919 pictures in docs.
|
||||
FIX: #18006
|
||||
FIX: Accountancy - if we define a date start, automatic binding try to continue to solve old binding
|
||||
FIX: Accoutancy Limit date payment not registered on purchases operations
|
||||
FIX: Can't edit replacement invoice
|
||||
FIX: deposit can create credit note in payment conf
|
||||
FIX: division by zero on create
|
||||
FIX: holiday: balances not updated correctly with pgsql because of case sensitivity field
|
||||
FIX: holiday: status filter parameter has been renamed but not in links it was used
|
||||
FIX: List and Create Companies Left Menus
|
||||
FIX: method exists
|
||||
FIX: need to add payment sum to getlibstatus function in object linked block
|
||||
FIX: permission to close a proposal when using advanced permissions
|
||||
FIX: Problem of z-index with popup and top menu
|
||||
FIX: same thing on supplier orders
|
||||
FIX: Status of invoice when making a replacement invoice
|
||||
FIX: update contact birthday alert
|
||||
|
||||
***** ChangeLog for 14.0.0 compared to 13.0.0 *****
|
||||
|
||||
|
||||
@@ -549,110 +549,111 @@ class BlockedLog
|
||||
|
||||
$totalamount = 0;
|
||||
|
||||
if (!is_array($object->amounts) && $object->amount) {
|
||||
$object->amounts = array($object->id => $object->amount);
|
||||
}
|
||||
// Loop on each invoice payment amount
|
||||
if (is_array($object->amounts) && !empty($object->amounts)) {
|
||||
$paymentpartnumber = 0;
|
||||
foreach ($object->amounts as $objid => $amount) {
|
||||
if (empty($amount)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$paymentpartnumber = 0;
|
||||
foreach ($object->amounts as $objid => $amount) {
|
||||
if (empty($amount)) {
|
||||
continue;
|
||||
}
|
||||
$totalamount += $amount;
|
||||
|
||||
$totalamount += $amount;
|
||||
$tmpobject = null;
|
||||
if ($this->element == 'payment_supplier') {
|
||||
include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
|
||||
$tmpobject = new FactureFournisseur($this->db);
|
||||
} elseif ($this->element == 'payment') {
|
||||
include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
|
||||
$tmpobject = new Facture($this->db);
|
||||
} elseif ($this->element == 'payment_donation') {
|
||||
include_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
|
||||
$tmpobject = new Don($this->db);
|
||||
} elseif ($this->element == 'payment_various') {
|
||||
include_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
|
||||
$tmpobject = new PaymentVarious($this->db);
|
||||
}
|
||||
|
||||
$tmpobject = null;
|
||||
if ($this->element == 'payment_supplier') {
|
||||
include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
|
||||
$tmpobject = new FactureFournisseur($this->db);
|
||||
} elseif ($this->element == 'payment') {
|
||||
include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
|
||||
$tmpobject = new Facture($this->db);
|
||||
} elseif ($this->element == 'payment_donation') {
|
||||
include_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
|
||||
$tmpobject = new Don($this->db);
|
||||
} elseif ($this->element == 'payment_various') {
|
||||
include_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
|
||||
$tmpobject = new PaymentVarious($this->db);
|
||||
}
|
||||
if (!is_object($tmpobject)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_object($tmpobject)) {
|
||||
continue;
|
||||
}
|
||||
$result = $tmpobject->fetch($objid);
|
||||
|
||||
$result = $tmpobject->fetch($objid);
|
||||
|
||||
if ($result <= 0) {
|
||||
$this->error = $tmpobject->error;
|
||||
$this->errors = $tmpobject->errors;
|
||||
dol_syslog("Failed to fetch object with id ".$objid, LOG_ERR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
$paymentpart = new stdClass();
|
||||
$paymentpart->amount = $amount;
|
||||
|
||||
if (!in_array($this->element, array('payment_donation', 'payment_various'))) {
|
||||
$result = $tmpobject->fetch_thirdparty();
|
||||
if ($result == 0) {
|
||||
$this->error = 'Failed to fetch thirdparty for object with id '.$tmpobject->id;
|
||||
$this->errors[] = $this->error;
|
||||
dol_syslog("Failed to fetch thirdparty for object with id ".$tmpobject->id, LOG_ERR);
|
||||
return -1;
|
||||
} elseif ($result < 0) {
|
||||
if ($result <= 0) {
|
||||
$this->error = $tmpobject->error;
|
||||
$this->errors = $tmpobject->errors;
|
||||
dol_syslog("Failed to fetch object with id ".$objid, LOG_ERR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
$paymentpart->thirdparty = new stdClass();
|
||||
foreach ($tmpobject->thirdparty as $key => $value) {
|
||||
if (in_array($key, $arrayoffieldstoexclude)) {
|
||||
continue; // Discard some properties
|
||||
}
|
||||
if (!in_array($key, array(
|
||||
'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
|
||||
'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
|
||||
))) {
|
||||
continue; // Discard if not into a dedicated list
|
||||
}
|
||||
if (!is_object($value) && !is_null($value) && $value !== '') {
|
||||
$paymentpart->thirdparty->{$key} = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
$paymentpart = new stdClass();
|
||||
$paymentpart->amount = $amount;
|
||||
|
||||
// Init object to avoid warnings
|
||||
if ($this->element == 'payment_donation') {
|
||||
$paymentpart->donation = new stdClass();
|
||||
} else {
|
||||
$paymentpart->invoice = new stdClass();
|
||||
}
|
||||
if (!in_array($this->element, array('payment_donation', 'payment_various'))) {
|
||||
$result = $tmpobject->fetch_thirdparty();
|
||||
if ($result == 0) {
|
||||
$this->error = 'Failed to fetch thirdparty for object with id '.$tmpobject->id;
|
||||
$this->errors[] = $this->error;
|
||||
dol_syslog("Failed to fetch thirdparty for object with id ".$tmpobject->id, LOG_ERR);
|
||||
return -1;
|
||||
} elseif ($result < 0) {
|
||||
$this->error = $tmpobject->error;
|
||||
$this->errors = $tmpobject->errors;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ($this->element != 'payment_various') {
|
||||
foreach ($tmpobject as $key => $value) {
|
||||
if (in_array($key, $arrayoffieldstoexclude)) {
|
||||
continue; // Discard some properties
|
||||
}
|
||||
if (!in_array($key, array(
|
||||
'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public'
|
||||
))) {
|
||||
continue; // Discard if not into a dedicated list
|
||||
}
|
||||
if (!is_object($value) && !is_null($value) && $value !== '') {
|
||||
if ($this->element == 'payment_donation') {
|
||||
$paymentpart->donation->{$key} = $value;
|
||||
} elseif ($this->element == 'payment_various') {
|
||||
$paymentpart->various->{$key} = $value;
|
||||
} else {
|
||||
$paymentpart->invoice->{$key} = $value;
|
||||
$paymentpart->thirdparty = new stdClass();
|
||||
foreach ($tmpobject->thirdparty as $key => $value) {
|
||||
if (in_array($key, $arrayoffieldstoexclude)) {
|
||||
continue; // Discard some properties
|
||||
}
|
||||
if (!in_array($key, array(
|
||||
'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
|
||||
'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
|
||||
))) {
|
||||
continue; // Discard if not into a dedicated list
|
||||
}
|
||||
if (!is_object($value) && !is_null($value) && $value !== '') {
|
||||
$paymentpart->thirdparty->{$key} = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$paymentpartnumber++; // first payment will be 1
|
||||
$this->object_data->payment_part[$paymentpartnumber] = $paymentpart;
|
||||
// Init object to avoid warnings
|
||||
if ($this->element == 'payment_donation') {
|
||||
$paymentpart->donation = new stdClass();
|
||||
} else {
|
||||
$paymentpart->invoice = new stdClass();
|
||||
}
|
||||
|
||||
if ($this->element != 'payment_various') {
|
||||
foreach ($tmpobject as $key => $value) {
|
||||
if (in_array($key, $arrayoffieldstoexclude)) {
|
||||
continue; // Discard some properties
|
||||
}
|
||||
if (!in_array($key, array(
|
||||
'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public'
|
||||
))) {
|
||||
continue; // Discard if not into a dedicated list
|
||||
}
|
||||
if (!is_object($value) && !is_null($value) && $value !== '') {
|
||||
if ($this->element == 'payment_donation') {
|
||||
$paymentpart->donation->{$key} = $value;
|
||||
} elseif ($this->element == 'payment_various') {
|
||||
$paymentpart->various->{$key} = $value;
|
||||
} else {
|
||||
$paymentpart->invoice->{$key} = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$paymentpartnumber++; // first payment will be 1
|
||||
$this->object_data->payment_part[$paymentpartnumber] = $paymentpart;
|
||||
}
|
||||
}
|
||||
} elseif (!empty($object->amount)) {
|
||||
$totalamount = $object->amount;
|
||||
}
|
||||
|
||||
$this->object_data->amount = $totalamount;
|
||||
|
||||
@@ -226,7 +226,7 @@ if (!empty($conf->facture->enabled) && !empty($user->rights->facture->lire)) {
|
||||
print $thirdpartystatic->getNomUrl(1, 'customer', 44);
|
||||
print '</td>';
|
||||
if (!empty($conf->global->MAIN_SHOW_HT_ON_SUMMARY)) {
|
||||
print '<td class="nowrap right">'.price($obj->total_ht).'</td>';
|
||||
print '<td class="nowrap right"><span class="amount">'.price($obj->total_ht).'</span></td>';
|
||||
}
|
||||
print '<td class="nowrap right"><span class="amount">'.price($obj->total_ttc).'</span></td>';
|
||||
print '<td class="right">'.dol_print_date($db->jdate($obj->tms), 'day').'</td>';
|
||||
|
||||
@@ -180,7 +180,7 @@ class box_factures extends ModeleBoxes
|
||||
);
|
||||
|
||||
$this->info_box_contents[$line][] = array(
|
||||
'td' => 'class="right nowraponall"',
|
||||
'td' => 'class="right nowraponall amount"',
|
||||
'text' => price($objp->total_ht, 0, $langs, 0, -1, -1, $conf->currency),
|
||||
);
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ class box_factures_imp extends ModeleBoxes
|
||||
);
|
||||
|
||||
$this->info_box_contents[$line][] = array(
|
||||
'td' => 'class="nowraponall right"',
|
||||
'td' => 'class="nowraponall right amount"',
|
||||
'text' => price($objp->total_ht, 0, $langs, 0, -1, -1, $conf->currency),
|
||||
);
|
||||
|
||||
|
||||
@@ -272,8 +272,10 @@ class HookManager
|
||||
$parameters['currentcontext'] = $context;
|
||||
// Hooks that must return int (hooks with type 'addreplace')
|
||||
if ($hooktype == 'addreplace') {
|
||||
$resaction += $actionclassinstance->$method($parameters, $object, $action, $this); // $object and $action can be changed by method ($object->id during creation for example or $action to go back to other action for example)
|
||||
if ($resaction < 0 || !empty($actionclassinstance->error) || (!empty($actionclassinstance->errors) && count($actionclassinstance->errors) > 0)) {
|
||||
$resactiontmp = $actionclassinstance->$method($parameters, $object, $action, $this); // $object and $action can be changed by method ($object->id during creation for example or $action to go back to other action for example)
|
||||
$resaction += $resactiontmp;
|
||||
|
||||
if ($resactiontmp < 0 || !empty($actionclassinstance->error) || (!empty($actionclassinstance->errors) && count($actionclassinstance->errors) > 0)) {
|
||||
$error++;
|
||||
$this->error = $actionclassinstance->error;
|
||||
$this->errors = array_merge($this->errors, (array) $actionclassinstance->errors);
|
||||
@@ -281,13 +283,22 @@ class HookManager
|
||||
}
|
||||
|
||||
if (isset($actionclassinstance->results) && is_array($actionclassinstance->results)) {
|
||||
$this->resArray = array_merge($this->resArray, $actionclassinstance->results);
|
||||
if ($resactiontmp > 0) {
|
||||
$this->resArray = $actionclassinstance->results;
|
||||
} else {
|
||||
$this->resArray = array_merge($this->resArray, $actionclassinstance->results);
|
||||
}
|
||||
}
|
||||
if (!empty($actionclassinstance->resprints)) {
|
||||
$this->resPrint .= $actionclassinstance->resprints;
|
||||
if ($resactiontmp > 0) {
|
||||
$this->resPrint = $actionclassinstance->resprints;
|
||||
} else {
|
||||
$this->resPrint .= $actionclassinstance->resprints;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Generic hooks that return a string or array (printLeftBlock, formAddObjectLine, formBuilddocOptions, ...)
|
||||
|
||||
// TODO. this test should be done into the method of hook by returning nothing
|
||||
if (is_array($parameters) && !empty($parameters['special_code']) && $parameters['special_code'] > 3 && $parameters['special_code'] != $actionclassinstance->module_number) {
|
||||
continue;
|
||||
|
||||
@@ -8487,8 +8487,10 @@ function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type,
|
||||
if (!empty($hookmanager)) {
|
||||
$parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head);
|
||||
$reshook = $hookmanager->executeHooks('completeTabsHead', $parameters);
|
||||
if ($reshook > 0) {
|
||||
if ($reshook > 0) { // Hook ask to replace completely the array
|
||||
$head = $hookmanager->resArray;
|
||||
} else { // Hook
|
||||
$head = array_merge($head, $hookmanager->resArray);
|
||||
}
|
||||
$h = count($head);
|
||||
}
|
||||
|
||||
@@ -118,6 +118,8 @@ class InterfaceActionsBlockedLog extends DolibarrTriggers
|
||||
foreach ($object->amounts as $amount) {
|
||||
$amounts += price2num($amount);
|
||||
}
|
||||
} elseif (!empty($object->amount)) {
|
||||
$amounts = $object->amount;
|
||||
}
|
||||
} elseif (strpos($action, 'PAYMENT') !== false && !in_array($action, array('PAYMENT_ADD_TO_BANK'))) {
|
||||
$qualified++;
|
||||
|
||||
@@ -367,7 +367,7 @@ ALTER TABLE llx_actioncomm_reminder ADD UNIQUE uk_actioncomm_reminder_unique (fk
|
||||
|
||||
ALTER TABLE llx_actioncomm_reminder ADD INDEX idx_actioncomm_reminder_status (status);
|
||||
|
||||
|
||||
ALTER TABLE llx_inventorydet ADD COLUMN fk_warehouse integer DEFAULT 0;
|
||||
ALTER TABLE llx_inventorydet ADD UNIQUE uk_inventorydet(fk_inventory, fk_warehouse, fk_product, batch);
|
||||
|
||||
ALTER TABLE llx_commandedet ADD COLUMN ref_ext varchar(255) AFTER label;
|
||||
|
||||
@@ -86,7 +86,7 @@ create table llx_facture
|
||||
fk_incoterms integer, -- for incoterms
|
||||
location_incoterms varchar(255), -- for incoterms
|
||||
|
||||
fk_mode_transport integer, -- for intracomm report
|
||||
fk_transport_mode integer, -- for intracomm report
|
||||
|
||||
situation_cycle_ref smallint, -- situation cycle reference
|
||||
situation_counter smallint, -- situation counter
|
||||
|
||||
@@ -74,7 +74,7 @@ create table llx_facture_fourn
|
||||
fk_incoterms integer, -- for incoterms
|
||||
location_incoterms varchar(255), -- for incoterms
|
||||
|
||||
fk_mode_transport integer, -- for intracomm report
|
||||
fk_transport_mode integer, -- for intracomm report
|
||||
|
||||
model_pdf varchar(255),
|
||||
last_main_doc varchar(255), -- relative filepath+filename of last main generated document
|
||||
|
||||
@@ -264,6 +264,7 @@ ErrorAnAmountWithoutTaxIsRequired=Error, amount is mandatory
|
||||
ErrorAPercentIsRequired=Error, please fill in the percentage correctly
|
||||
ErrorYouMustFirstSetupYourChartOfAccount=You must first setup your chart of account
|
||||
ErrorFailedToFindEmailTemplate=Failed to find template with code name %s
|
||||
ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice=Duration not defined on service. No way to calculate the hourly price.
|
||||
|
||||
# Warnings
|
||||
WarningParamUploadMaxFileSizeHigherThanPostMaxSize=Your PHP parameter upload_max_filesize (%s) is higher than PHP parameter post_max_size (%s). This is not a consistent setup.
|
||||
|
||||
@@ -1234,7 +1234,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
|
||||
if ($type == 1) {
|
||||
print '<tr><td>'.$langs->trans("Duration").'</td><td>';
|
||||
print '<input name="duration_value" size="4" value="'.GETPOST('duration_value', 'int').'">';
|
||||
print $formproduct->selectMeasuringUnits("duration_unit", "time", GETPOST('duration_value', 'alpha'), 0, 1);
|
||||
print $formproduct->selectMeasuringUnits("duration_unit", "time", (GETPOSTISSET('duration_value') ? GETPOSTISSET('duration_value', 'alpha') : 'h'), 0, 1);
|
||||
print '</td></tr>';
|
||||
}
|
||||
|
||||
|
||||
@@ -414,7 +414,7 @@ class FormProduct
|
||||
dol_print_error($db);
|
||||
return -1;
|
||||
} else {
|
||||
$return .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$name.'">';
|
||||
$return .= '<select class="flat'.($morecss ? ' '.$morecss : '').'" name="'.$name.'" id="'.$name.'">';
|
||||
if ($adddefault || $adddefault === '') {
|
||||
$return .= '<option value="0">'.($adddefault ? $langs->trans("Default") : '').'</option>';
|
||||
}
|
||||
@@ -447,6 +447,8 @@ class FormProduct
|
||||
$return .= '</select>';
|
||||
}
|
||||
|
||||
$return .= ajax_combobox($name);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,6 +116,7 @@ class Task extends CommonObject
|
||||
public $timespent_datehour; // More accurate start date (same than timespent_date but includes hours, minutes and seconds)
|
||||
public $timespent_withhour; // 1 = we entered also start hours for timesheet line
|
||||
public $timespent_fk_user;
|
||||
public $timespent_thm;
|
||||
public $timespent_note;
|
||||
|
||||
public $comments = array();
|
||||
@@ -1212,6 +1213,7 @@ class Task extends CommonObject
|
||||
$ret = -2;
|
||||
}
|
||||
|
||||
// Update hourly rate of this time spent entry
|
||||
$sql = "UPDATE ".MAIN_DB_PREFIX."projet_task_time";
|
||||
$sql .= " SET thm = (SELECT thm FROM ".MAIN_DB_PREFIX."user WHERE rowid = ".((int) $this->timespent_fk_user).")"; // set average hour rate of user
|
||||
$sql .= " WHERE rowid = ".((int) $tasktime_id);
|
||||
@@ -1425,6 +1427,7 @@ class Task extends CommonObject
|
||||
$sql .= " ptt.task_duration,";
|
||||
$sql .= " ptt.fk_user,";
|
||||
$sql .= " ptt.note,";
|
||||
$sql .= " ptt.thm,";
|
||||
$sql .= " pt.rowid as task_id,";
|
||||
$sql .= " pt.ref as task_ref,";
|
||||
$sql .= " pt.label as task_label,";
|
||||
@@ -1435,7 +1438,7 @@ class Task extends CommonObject
|
||||
$sql .= " FROM ".MAIN_DB_PREFIX."projet_task_time as ptt, ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."projet as p";
|
||||
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
|
||||
$sql .= " WHERE ptt.fk_task = pt.rowid AND pt.fk_projet = p.rowid";
|
||||
$sql .= " AND ptt.fk_user = ".$userobj->id;
|
||||
$sql .= " AND ptt.fk_user = ".((int) $userobj->id);
|
||||
$sql .= " AND pt.entity IN (".getEntity('project').")";
|
||||
if ($morewherefilter) {
|
||||
$sql .= $morewherefilter;
|
||||
@@ -1471,6 +1474,7 @@ class Task extends CommonObject
|
||||
$newobj->timespent_withhour = $obj->task_date_withhour;
|
||||
$newobj->timespent_duration = $obj->task_duration;
|
||||
$newobj->timespent_fk_user = $obj->fk_user;
|
||||
$newobj->timespent_thm = $obj->thm; // hourly rate
|
||||
$newobj->timespent_note = $obj->note;
|
||||
|
||||
$arrayres[] = $newobj;
|
||||
@@ -1552,10 +1556,12 @@ class Task extends CommonObject
|
||||
}
|
||||
|
||||
if ($ret == 1 && ($this->timespent_old_duration != $this->timespent_duration)) {
|
||||
$newDuration = $this->timespent_duration - $this->timespent_old_duration;
|
||||
|
||||
// Recalculate amount of time spent for task and update denormalized field
|
||||
$sql = "UPDATE ".MAIN_DB_PREFIX."projet_task";
|
||||
$sql .= " SET duration_effective = (SELECT SUM(task_duration) FROM ".MAIN_DB_PREFIX."projet_task_time as ptt where ptt.fk_task = ".((int) $this->id).")";
|
||||
if (isset($this->progress)) {
|
||||
$sql .= ", progress = ".((float) $this->progress); // Do not overwrite value if not provided
|
||||
}
|
||||
$sql .= " WHERE rowid = ".((int) $this->id);
|
||||
|
||||
dol_syslog(get_class($this)."::updateTimeSpent", LOG_DEBUG);
|
||||
@@ -1564,6 +1570,17 @@ class Task extends CommonObject
|
||||
$this->db->rollback();
|
||||
$ret = -2;
|
||||
}
|
||||
|
||||
// Update hourly rate of this time spent entry, but only if it was not set initialy
|
||||
$sql = "UPDATE ".MAIN_DB_PREFIX."projet_task_time";
|
||||
$sql .= " SET thm = (SELECT thm FROM ".MAIN_DB_PREFIX."user WHERE rowid = ".((int) $this->timespent_fk_user).")"; // set average hour rate of user
|
||||
$sql .= " WHERE (thm IS NULL OR thm = 0) AND rowid = ".((int) $this->timespent_id);
|
||||
|
||||
dol_syslog(get_class($this)."::addTimeSpent", LOG_DEBUG);
|
||||
if (!$this->db->query($sql)) {
|
||||
$this->error = $this->db->lasterror();
|
||||
$ret = -2;
|
||||
}
|
||||
}
|
||||
|
||||
if ($ret >= 0) {
|
||||
|
||||
@@ -261,10 +261,10 @@ if (($action == 'updateline' || $action == 'updatesplitline') && !$cancel && $us
|
||||
$object->timespent_duration = GETPOSTINT("new_durationhour") * 60 * 60; // We store duration in seconds
|
||||
$object->timespent_duration += (GETPOSTINT("new_durationmin") ? GETPOSTINT('new_durationmin') : 0) * 60; // We store duration in seconds
|
||||
if (GETPOST("timelinehour") != '' && GETPOST("timelinehour") >= 0) { // If hour was entered
|
||||
$object->timespent_date = dol_mktime(GETPOST("timelinehour"), GETPOST("timelinemin"), 0, GETPOST("timelinemonth"), GETPOST("timelineday"), GETPOST("timelineyear"));
|
||||
$object->timespent_date = dol_mktime(GETPOST("timelinehour", 'int'), GETPOST("timelinemin", 'int'), 0, GETPOST("timelinemonth", 'int'), GETPOST("timelineday", 'int'), GETPOST("timelineyear", 'int'));
|
||||
$object->timespent_withhour = 1;
|
||||
} else {
|
||||
$object->timespent_date = dol_mktime(12, 0, 0, GETPOST("timelinemonth"), GETPOST("timelineday"), GETPOST("timelineyear"));
|
||||
$object->timespent_date = dol_mktime(12, 0, 0, GETPOST("timelinemonth", 'int'), GETPOST("timelineday", 'int'), GETPOST("timelineyear", 'int'));
|
||||
}
|
||||
$object->timespent_fk_user = GETPOST("userid_line", 'int');
|
||||
|
||||
@@ -353,6 +353,13 @@ if ($action == 'confirm_generateinvoice') {
|
||||
$prodDurationHours = 1.0;
|
||||
if ($idprod > 0) {
|
||||
$tmpproduct->fetch($idprod);
|
||||
|
||||
if (empty($tmpproduct->duration_value)) {
|
||||
$error++;
|
||||
$langs->load("errors");
|
||||
setEventMessages($langs->trans("ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice"), null, 'errors');
|
||||
}
|
||||
|
||||
if ($tmpproduct->duration_unit == 'i') {
|
||||
$prodDurationHours = 1. / 60;
|
||||
}
|
||||
@@ -380,6 +387,8 @@ if ($action == 'confirm_generateinvoice') {
|
||||
$localtax1 = $dataforprice['localtax1'];
|
||||
$localtax2 = $dataforprice['localtax2'];
|
||||
} else {
|
||||
$prodDurationHours = 1;
|
||||
|
||||
$pu_ht = 0;
|
||||
$txtva = get_default_tva($mysoc, $projectstatic->thirdparty);
|
||||
$localtax1 = get_default_localtax($mysoc, $projectstatic->thirdparty, 1);
|
||||
@@ -482,14 +491,14 @@ if ($action == 'confirm_generateinvoice') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} elseif ($generateinvoicemode == 'onelinepertask') {
|
||||
} elseif ($generateinvoicemode == 'onelinepertask') { // One line for each different task
|
||||
$arrayoftasks = array();
|
||||
foreach ($toselect as $key => $value) {
|
||||
// Get userid, timepent
|
||||
$object->fetchTimeSpent($value);
|
||||
// $object->id is the task id
|
||||
$object->fetchTimeSpent($value); // Call method to get list of timespent for a timespent line id (We use the utiliy method found into Task object)
|
||||
// $object->id is now the task id
|
||||
$arrayoftasks[$object->id]['timespent'] += $object->timespent_duration;
|
||||
$arrayoftasks[$object->id]['totalvaluetodivideby3600'] += $object->timespent_duration * $object->timespent_thm;
|
||||
$arrayoftasks[$object->id]['totalvaluetodivideby3600'] += ($object->timespent_duration * $object->timespent_thm);
|
||||
}
|
||||
|
||||
foreach ($arrayoftasks as $task_id => $value) {
|
||||
@@ -499,24 +508,46 @@ if ($action == 'confirm_generateinvoice') {
|
||||
$qtyhour = $value['timespent'] / 3600;
|
||||
$qtyhourtext = convertSecondToTime($value['timespent'], 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
|
||||
|
||||
// If no unit price known
|
||||
if (empty($pu_ht)) {
|
||||
$pu_ht = price2num($value['totalvaluetodivideby3600'] / 3600, 'MU');
|
||||
if ($idprod > 0) {
|
||||
// If a product is defined, we msut use the $prodDurationHours and $pu_ht of product (already set previously).
|
||||
$pu_ht_for_task = $pu_ht;
|
||||
// If we want to reuse the value of timespent (so use same price than cost price)
|
||||
if (!empty($conf->global->PROJECT_TIME_SPENT_INTO_INVOICE_USE_VALUE)) {
|
||||
$pu_ht_for_task = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU') * $prodDurationHours;
|
||||
}
|
||||
$pa_ht = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU') * $prodDurationHours;
|
||||
} else {
|
||||
// If not product used, we use the hour unit for duration and unit price.
|
||||
$pu_ht_for_task = 0;
|
||||
// If we want to reuse the value of timespent (so use same price than cost price)
|
||||
if (!empty($conf->global->PROJECT_TIME_SPENT_INTO_INVOICE_USE_VALUE)) {
|
||||
$pu_ht_for_task = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU');
|
||||
}
|
||||
$pa_ht = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU');
|
||||
}
|
||||
|
||||
// Add lines
|
||||
$date_start = '';
|
||||
$date_end = '';
|
||||
$lineName = $ftask->ref.' - '.$ftask->label;
|
||||
$lineid = $tmpinvoice->addline($lineName, $pu_ht, round($qtyhour / $prodDurationHours, 2), $txtva, $localtax1, $localtax2, ($idprod > 0 ? $idprod : 0));
|
||||
|
||||
// Update lineid into line of timespent
|
||||
$sql = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id);
|
||||
$sql .= ' WHERE rowid IN ('.$db->sanitize(join(',', $toselect)).')';
|
||||
$result = $db->query($sql);
|
||||
if (!$result) {
|
||||
$lineid = $tmpinvoice->addline($lineName, $pu_ht_for_task, price2num($qtyhour / $prodDurationHours, 'MS'), $txtva, $localtax1, $localtax2, ($idprod > 0 ? $idprod : 0), 0, $date_start, $date_end, 0, 0, '', 'HT', 0, 1, -1, 0, '', 0, 0, null, $pa_ht);
|
||||
if ($lineid < 0) {
|
||||
$error++;
|
||||
setEventMessages($db->lasterror(), null, 'errors');
|
||||
setEventMessages($tmpinvoice->error, $tmpinvoice->errors, 'errors');
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$error) {
|
||||
// Update lineid into line of timespent
|
||||
$sql = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id);
|
||||
$sql .= ' WHERE rowid IN ('.$db->sanitize(join(',', $toselect)).')';
|
||||
$result = $db->query($sql);
|
||||
if (!$result) {
|
||||
$error++;
|
||||
setEventMessages($db->lasterror(), null, 'errors');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -960,7 +991,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) {
|
||||
print '<input type="hidden" name="massaction" value="confirm_createbills">';
|
||||
|
||||
if ($projectstatic->thirdparty->id > 0) {
|
||||
print '<table class="noborder" width="100%" >';
|
||||
print '<table class="noborder centerpercent">';
|
||||
print '<tr>';
|
||||
print '<td class="titlefield">';
|
||||
print $langs->trans('DateInvoice');
|
||||
@@ -1352,11 +1383,11 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
print '<tr class="oddeven">';
|
||||
|
||||
$date1 = $db->jdate($task_time->task_date);
|
||||
$date2 = $db->jdate($task_time->task_datehour);
|
||||
|
||||
print '<tr class="oddeven">';
|
||||
|
||||
// Date
|
||||
if (!empty($arrayfields['t.task_date']['checked'])) {
|
||||
print '<td class="nowrap">';
|
||||
@@ -1480,9 +1511,13 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) {
|
||||
|
||||
// Value spent
|
||||
if (!empty($arrayfields['value']['checked'])) {
|
||||
$langs->load("salaries");
|
||||
|
||||
print '<td class="nowraponall right">';
|
||||
$value = price2num($task_time->thm * $task_time->task_duration / 3600, 'MT', 1);
|
||||
print '<span class="amount" title="'.$langs->trans("THM").': '.price($task_time->thm).'">';
|
||||
print price($value, 1, $langs, 1, -1, -1, $conf->currency);
|
||||
print '</span>';
|
||||
print '</td>';
|
||||
if (!$i) {
|
||||
$totalarray['nbfield']++;
|
||||
|
||||
@@ -1095,7 +1095,7 @@ $( document ).ready(function() {
|
||||
$max_sale = 0;
|
||||
while ($obj = $db->fetch_object($resql)) {
|
||||
echo '$("#customerandsales").append(\'';
|
||||
echo '<a class="valignmiddle" title="'.dol_escape_js($langs->trans("SaleStartedAt", dol_print_date($db->jdate($obj->datec), '%H:%M', 'tzuser'))).'" onclick="place=\\\'';
|
||||
echo '<a class="valignmiddle" title="'.dol_escape_js($langs->trans("SaleStartedAt", dol_print_date($db->jdate($obj->datec), '%H:%M', 'tzuser')).' - '.$obj->ref).'" onclick="place=\\\'';
|
||||
$num_sale = str_replace(")", "", str_replace("(PROV-POS".$_SESSION["takeposterminal"]."-", "", $obj->ref));
|
||||
echo $num_sale;
|
||||
if (str_replace("-", "", $num_sale) > $max_sale) {
|
||||
|
||||
@@ -258,9 +258,9 @@ function _createStatusBadgeCss($statusName, $statusVarNamePrefix = '', $commentL
|
||||
print $cssPrefix.".badge-status".$statusName." {\n";
|
||||
print " color: ".$thisBadgeTextColor." !important;\n";
|
||||
if (in_array((string) $statusName, $TBadgeBorderOnly)) {
|
||||
print " border-color: ".$thisBadgeBorderColor.";\n";
|
||||
print " border-color: ".$thisBadgeBorderColor." !important;\n";
|
||||
}
|
||||
print " background-color: ".$thisBadgeBackgroundColor.";\n";
|
||||
print " background-color: ".$thisBadgeBackgroundColor." !important;\n";
|
||||
print "}\n";
|
||||
|
||||
print $cssPrefix.".font-status".$statusName." {\n";
|
||||
@@ -269,14 +269,14 @@ function _createStatusBadgeCss($statusName, $statusVarNamePrefix = '', $commentL
|
||||
|
||||
print $cssPrefix.".badge-status".$statusName.".focus, ".$cssPrefix.".badge-status".$statusName.":focus {\n";
|
||||
print " outline: 0;\n";
|
||||
print " box-shadow: 0 0 0 0.2rem ".colorHexToRgb($thisBadgeBackgroundColor, 0.5).";\n";
|
||||
print " box-shadow: 0 0 0 0.2rem ".colorHexToRgb($thisBadgeBackgroundColor, 0.5)." !important;\n";
|
||||
print "}\n";
|
||||
|
||||
print $cssPrefix.".badge-status".$statusName.":focus, ".$cssPrefix.".badge-status".$statusName.":hover {\n";
|
||||
print " color: ".$thisBadgeTextColor." !important;\n";
|
||||
//print " background-color: " . colorDarker($thisBadgeBackgroundColor, 10) . ";\n";
|
||||
if (in_array((string) $statusName, $TBadgeBorderOnly)) {
|
||||
print " border-color: ".colorDarker($thisBadgeBorderColor, 10).";\n";
|
||||
print " border-color: ".colorDarker($thisBadgeBorderColor, 10)." !important;\n";
|
||||
}
|
||||
print "}\n";
|
||||
}
|
||||
|
||||
@@ -261,9 +261,9 @@ function _createStatusBadgeCss($statusName, $statusVarNamePrefix = '', $commentL
|
||||
print $cssPrefix.".badge-status".$statusName." {\n";
|
||||
print " color: ".$thisBadgeTextColor." !important;\n";
|
||||
if (in_array((string) $statusName, $TBadgeBorderOnly)) {
|
||||
print " border-color: ".$thisBadgeBorderColor.";\n";
|
||||
print " border-color: ".$thisBadgeBorderColor." !important;\n";
|
||||
}
|
||||
print " background-color: ".$thisBadgeBackgroundColor.";\n";
|
||||
print " background-color: ".$thisBadgeBackgroundColor." !important;\n";
|
||||
print "}\n";
|
||||
|
||||
print $cssPrefix.".font-status".$statusName." {\n";
|
||||
@@ -272,14 +272,14 @@ function _createStatusBadgeCss($statusName, $statusVarNamePrefix = '', $commentL
|
||||
|
||||
print $cssPrefix.".badge-status".$statusName.".focus, ".$cssPrefix.".badge-status".$statusName.":focus {\n";
|
||||
print " outline: 0;\n";
|
||||
print " box-shadow: 0 0 0 0.2rem ".colorHexToRgb($thisBadgeBackgroundColor, 0.5).";\n";
|
||||
print " box-shadow: 0 0 0 0.2rem ".colorHexToRgb($thisBadgeBackgroundColor, 0.5)." !important;\n";
|
||||
print "}\n";
|
||||
|
||||
print $cssPrefix.".badge-status".$statusName.":focus, ".$cssPrefix.".badge-status".$statusName.":hover {\n";
|
||||
print " color: ".$thisBadgeTextColor." !important;\n";
|
||||
//print " background-color: ".colorDarker($thisBadgeBackgroundColor, 10).";\n";
|
||||
if (in_array((string) $statusName, $TBadgeBorderOnly)) {
|
||||
print " border-color: ".colorDarker($thisBadgeBorderColor, 10).";\n";
|
||||
print " border-color: ".colorDarker($thisBadgeBorderColor, 10)." !important;\n";
|
||||
}
|
||||
print "}\n";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user