finish invoice per product per line

This commit is contained in:
Florian HENRY 2022-04-13 09:31:30 +02:00
parent c951e681c2
commit 902301659b
4 changed files with 99 additions and 29 deletions

View File

@ -3500,6 +3500,7 @@ class Facture extends CommonInvoice
return -2; return -2;
} }
} else { } else {
$this->errors[]='status of invoice must be Draft to allow use of ->addline()';
dol_syslog(get_class($this)."::addline status of invoice must be Draft to allow use of ->addline()", LOG_ERR); dol_syslog(get_class($this)."::addline status of invoice must be Draft to allow use of ->addline()", LOG_ERR);
return -3; return -3;
} }

View File

@ -259,7 +259,7 @@ TimeSpentInvoiced=Time spent billed
TimeSpentForIntervention=Time spent TimeSpentForIntervention=Time spent
TimeSpentForInvoice=Time spent TimeSpentForInvoice=Time spent
OneLinePerUser=One line per user OneLinePerUser=One line per user
ServiceToUseOnLines=Service to use on lines ServiceToUseOnLines=Service to use on lines by default
InvoiceGeneratedFromTimeSpent=Invoice %s has been generated from time spent on project InvoiceGeneratedFromTimeSpent=Invoice %s has been generated from time spent on project
InterventionGeneratedFromTimeSpent=Intervention %s has been generated from time spent on project InterventionGeneratedFromTimeSpent=Intervention %s has been generated from time spent on project
ProjectBillTimeDescription=Check if you enter timesheet on tasks of project AND you plan to generate invoice(s) from the timesheet to bill the customer of the project (do not check if you plan to create invoice that is not based on entered timesheets). Note: To generate invoice, go on tab 'Time spent' of the project and select lines to include. ProjectBillTimeDescription=Check if you enter timesheet on tasks of project AND you plan to generate invoice(s) from the timesheet to bill the customer of the project (do not check if you plan to create invoice that is not based on entered timesheets). Note: To generate invoice, go on tab 'Time spent' of the project and select lines to include.
@ -276,6 +276,7 @@ NewInter=New intervention
OneLinePerTask=One line per task OneLinePerTask=One line per task
OneLinePerPeriod=One line per period OneLinePerPeriod=One line per period
OneLinePerTimeSpentLine=One line for each time spent declaration OneLinePerTimeSpentLine=One line for each time spent declaration
OneLinePerTimeSpentLineProduct=One line for each time spent declaration with product defined
AddDetailDateAndDuration=With date and duration into line description AddDetailDateAndDuration=With date and duration into line description
RefTaskParent=Ref. Parent Task RefTaskParent=Ref. Parent Task
ProfitIsCalculatedWith=Profit is calculated using ProfitIsCalculatedWith=Profit is calculated using

View File

@ -6058,6 +6058,43 @@ class Product extends CommonObject
dol_print_error($this->db); dol_print_error($this->db);
} }
} }
/**
* Return the duration in Hours of a service base on duration fields
* @return int -1 KO, >= 0 is the duration in hours
*/
public function getProductDurationHours()
{
global $langs;
if (empty($this->duration_value)) {
$this->errors[]='ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
return -1;
}
if ($this->duration_unit == 'i') {
$prodDurationHours = 1. / 60;
}
if ($this->duration_unit == 'h') {
$prodDurationHours = 1.;
}
if ($this->duration_unit == 'd') {
$prodDurationHours = 24.;
}
if ($this->duration_unit == 'w') {
$prodDurationHours = 24. * 7;
}
if ($this->duration_unit == 'm') {
$prodDurationHours = 24. * 30;
}
if ($this->duration_unit == 'y') {
$prodDurationHours = 24. * 365;
}
$prodDurationHours *= $this->duration_value;
return $prodDurationHours;
}
} }

View File

@ -392,36 +392,21 @@ if ($action == 'confirm_generateinvoice') {
$generateinvoicemode = GETPOST('generateinvoicemode', 'string'); $generateinvoicemode = GETPOST('generateinvoicemode', 'string');
$invoiceToUse = GETPOST('invoiceid', 'int'); $invoiceToUse = GETPOST('invoiceid', 'int');
$prodDurationHours = 1.0; $prodDurationHoursBase = 1.0;
if ($idprod > 0) { if ($idprod > 0) {
$tmpproduct->fetch($idprod); $tmpproduct->fetch($idprod);
if ($result<0) {
$error++;
setEventMessages($tmpproduct->error, $tmpproduct->errors, 'errors');
}
if (empty($tmpproduct->duration_value)) { $prodDurationHoursBase=$tmpproduct->getProductDurationHours();
if ($prodDurationHoursBase<0) {
$error++; $error++;
$langs->load("errors"); $langs->load("errors");
setEventMessages($langs->trans("ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice"), null, 'errors'); setEventMessages(null, $tmpproduct->errors, 'errors');
} }
if ($tmpproduct->duration_unit == 'i') {
$prodDurationHours = 1. / 60;
}
if ($tmpproduct->duration_unit == 'h') {
$prodDurationHours = 1.;
}
if ($tmpproduct->duration_unit == 'd') {
$prodDurationHours = 24.;
}
if ($tmpproduct->duration_unit == 'w') {
$prodDurationHours = 24. * 7;
}
if ($tmpproduct->duration_unit == 'm') {
$prodDurationHours = 24. * 30;
}
if ($tmpproduct->duration_unit == 'y') {
$prodDurationHours = 24. * 365;
}
$prodDurationHours *= $tmpproduct->duration_value;
$dataforprice = $tmpproduct->getSellPrice($mysoc, $projectstatic->thirdparty, 0); $dataforprice = $tmpproduct->getSellPrice($mysoc, $projectstatic->thirdparty, 0);
$pu_ht = empty($dataforprice['pu_ht']) ? 0 : $dataforprice['pu_ht']; $pu_ht = empty($dataforprice['pu_ht']) ? 0 : $dataforprice['pu_ht'];
@ -429,7 +414,7 @@ if ($action == 'confirm_generateinvoice') {
$localtax1 = $dataforprice['localtax1']; $localtax1 = $dataforprice['localtax1'];
$localtax2 = $dataforprice['localtax2']; $localtax2 = $dataforprice['localtax2'];
} else { } else {
$prodDurationHours = 1; $prodDurationHoursBase = 1;
$pu_ht = 0; $pu_ht = 0;
$txtva = get_default_tva($mysoc, $projectstatic->thirdparty); $txtva = get_default_tva($mysoc, $projectstatic->thirdparty);
@ -476,7 +461,7 @@ if ($action == 'confirm_generateinvoice') {
} }
// Add lines // Add lines
$lineid = $tmpinvoice->addline($langs->trans("TimeSpentForInvoice", $username).' : '.$qtyhourtext, $pu_ht, round($qtyhour / $prodDurationHours, 2), $txtva, $localtax1, $localtax2, ($idprod > 0 ? $idprod : 0)); $lineid = $tmpinvoice->addline($langs->trans("TimeSpentForInvoice", $username).' : '.$qtyhourtext, $pu_ht, round($qtyhour / $prodDurationHoursBase, 2), $txtva, $localtax1, $localtax2, ($idprod > 0 ? $idprod : 0));
// Update lineid into line of timespent // 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 = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id);
@ -488,8 +473,9 @@ if ($action == 'confirm_generateinvoice') {
break; break;
} }
} }
} elseif ($generateinvoicemode == 'onelineperperiod') { // One line for each time spent line } elseif ($generateinvoicemode == 'onelineperperiod' || $generateinvoicemode == 'onelineperperiodproduct') { // One line for each time spent line
$arrayoftasks = array(); $arrayoftasks = array();
$product_data_cache = array();
$withdetail=GETPOST('detail_time_duration', 'alpha'); $withdetail=GETPOST('detail_time_duration', 'alpha');
foreach ($toselect as $key => $value) { foreach ($toselect as $key => $value) {
// Get userid, timepent // Get userid, timepent
@ -519,6 +505,7 @@ if ($action == 'confirm_generateinvoice') {
$arrayoftasks[$object->timespent_id]['note'] .= ' - '.$langs->trans("Duration").': '.convertSecondToTime($object->timespent_duration, 'all', $conf->global->MAIN_DURATION_OF_WORKDAY); $arrayoftasks[$object->timespent_id]['note'] .= ' - '.$langs->trans("Duration").': '.convertSecondToTime($object->timespent_duration, 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
} }
$arrayoftasks[$object->timespent_id]['user'] = $object->timespent_fk_user; $arrayoftasks[$object->timespent_id]['user'] = $object->timespent_fk_user;
$arrayoftasks[$object->timespent_id]['fk_product'] = $object->timespent_fk_product;
} }
foreach ($arrayoftasks as $timespent_id => $value) { foreach ($arrayoftasks as $timespent_id => $value) {
@ -534,7 +521,50 @@ if ($action == 'confirm_generateinvoice') {
} }
// Add lines // Add lines
$lineid = $tmpinvoice->addline($value['note'], $pu_ht, round($qtyhour / $prodDurationHours, 2), $txtva, $localtax1, $localtax2, ($idprod > 0 ? $idprod : 0)); $prodDurationHours = $prodDurationHoursBase;
$idprodline=$idprod;
$pu_htline = $pu_ht;
$txtvaline = $txtva;
$localtax1line = $localtax1;
$localtax2line = $localtax2;
if ($generateinvoicemode == 'onelineperperiodproduct' && !empty($value['fk_product']) && $value['fk_product']!==$idprod) {
if (!array_key_exists($value['fk_product'], $product_data_cache)) {
$result = $tmpproduct->fetch($value['fk_product']);
if ($result < 0) {
$error++;
setEventMessages($tmpproduct->error, $tmpproduct->errors, 'errors');
}
$prodDurationHours = $tmpproduct->getProductDurationHours();
if ($prodDurationHours < 0) {
$error++;
$langs->load("errors");
setEventMessages(null, $tmpproduct->errors, 'errors');
}
$dataforprice = $tmpproduct->getSellPrice($mysoc, $projectstatic->thirdparty, 0);
$pu_htline = empty($dataforprice['pu_ht']) ? 0 : $dataforprice['pu_ht'];
$txtvaline = $dataforprice['tva_tx'];
$localtax1line = $dataforprice['localtax1'];
$localtax2line = $dataforprice['localtax2'];
$product_data_cache[$value['fk_product']] = array('duration'=>$prodDurationHours,'dataforprice'=>$dataforprice);
} else {
$prodDurationHours = $product_data_cache[$value['fk_product']]['duration'];
$pu_htline = empty($product_data_cache[$value['fk_product']]['dataforprice']['pu_ht']) ? 0 : $product_data_cache[$value['fk_product']]['dataforprice']['pu_ht'];
$txtvaline = $product_data_cache[$value['fk_product']]['dataforprice']['tva_tx'];
$localtax1line = $product_data_cache[$value['fk_product']]['dataforprice']['localtax1'];
$localtax2line = $product_data_cache[$value['fk_product']]['dataforprice']['localtax2'];
}
$idprodline=$value['fk_product'];
}
$lineid = $tmpinvoice->addline($value['note'], $pu_htline, round($qtyhour / $prodDurationHours, 2), $txtvaline, $localtax1line, $localtax2line, ($idprodline > 0 ? $idprodline : 0));
if ($lineid<0) {
$error++;
setEventMessages(null, $tmpinvoice->errors, 'errors');
}
//var_dump($lineid);exit; //var_dump($lineid);exit;
// Update lineid into line of timespent // Update lineid into line of timespent
@ -1178,6 +1208,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
'onelineperuser'=>'OneLinePerUser', 'onelineperuser'=>'OneLinePerUser',
'onelinepertask'=>'OneLinePerTask', 'onelinepertask'=>'OneLinePerTask',
'onelineperperiod'=>'OneLinePerTimeSpentLine', 'onelineperperiod'=>'OneLinePerTimeSpentLine',
'onelineperperiodproduct'=>'OneLinePerTimeSpentLineProduct',
); );
print $form->selectarray('generateinvoicemode', $tmparray, 'onelineperuser', 0, 0, 0, '', 1); print $form->selectarray('generateinvoicemode', $tmparray, 'onelineperuser', 0, 0, 0, '', 1);
print "\n".'<script type="text/javascript">'; print "\n".'<script type="text/javascript">';
@ -1834,7 +1865,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
//Product //Product
if (!empty($arrayfields['t.fk_product']['checked'])) { if (!empty($arrayfields['t.fk_product']['checked'])) {
print '<td class="nowraponall right">'; print '<td class="nowraponall">';
if ($action == 'editline' && $_GET['lineid'] == $task_time->rowid) { if ($action == 'editline' && $_GET['lineid'] == $task_time->rowid) {
$form->select_produits($task_time->fk_product, 'fk_product', '1', 0, $projectstatic->thirdparty->price_level, 1, 2, '', 0, array(), $projectstatic->thirdparty->id, 'None', 0, 'maxwidth500'); $form->select_produits($task_time->fk_product, 'fk_product', '1', 0, $projectstatic->thirdparty->price_level, 1, 2, '', 0, array(), $projectstatic->thirdparty->id, 'None', 0, 'maxwidth500');
} elseif (!empty($task_time->fk_product)) { } elseif (!empty($task_time->fk_product)) {