diff --git a/htdocs/compta/facture.php b/htdocs/compta/facture.php index 95ddde4719f3739060f40711feff45046263ce31..55f259aa2fe1c5462a73879aef525daf8b19bc39 100644 --- a/htdocs/compta/facture.php +++ b/htdocs/compta/facture.php @@ -126,8 +126,8 @@ if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'e if (empty($reshook)) { if ($cancel) $action=''; - - include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not includ_once + + include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not include_once include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be include, not include_once @@ -672,7 +672,7 @@ if (empty($reshook)) /* * Insert new invoice in database - */ + */ else if ($action == 'add' && $user->rights->facture->creer) { if ($socid > 0) $object->socid = GETPOST('socid', 'int'); @@ -722,7 +722,7 @@ if (empty($reshook)) $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); $object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int'); - + // Proprietes particulieres a facture de remplacement $object->fk_facture_source = $_POST['fac_replacement']; $object->type = Facture::TYPE_REPLACEMENT; @@ -868,6 +868,15 @@ if (empty($reshook)) $object->ref_client = $_POST['ref_client']; $object->ref_int = $_POST['ref_int']; $object->modelpdf = $_POST['model']; + $object->fk_project = $_POST['projectid']; + $object->cond_reglement_id = ($_POST['type'] == 3?1:$_POST['cond_reglement_id']); + $object->mode_reglement_id = $_POST['mode_reglement_id']; + $object->fk_account = GETPOST('fk_account', 'int'); + $object->amount = $_POST['amount']; + $object->remise_absolue = $_POST['remise_absolue']; + $object->remise_percent = $_POST['remise_percent']; + $object->fk_incoterms = GETPOST('incoterm_id', 'int'); + $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); $object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int'); diff --git a/htdocs/compta/facture/class/facture-rec.class.php b/htdocs/compta/facture/class/facture-rec.class.php index 8e4e05037a8cc9e7eb9611237f3edcb92e05c573..0acd58f0202dc21fda28ab57d65ee555e204eee6 100644 --- a/htdocs/compta/facture/class/facture-rec.class.php +++ b/htdocs/compta/facture/class/facture-rec.class.php @@ -348,7 +348,7 @@ class FactureRec extends CommonInvoice */ function fetch_lines() { - $sql = 'SELECT l.rowid, l.fk_product, l.product_type, l.label as custom_label, l.description, l.price, l.qty, l.tva_tx, '; + $sql = 'SELECT l.rowid, l.fk_product, l.product_type, l.label as custom_label, l.description, l.product_type, l.price, l.qty, l.tva_tx, '; $sql.= ' l.remise, l.remise_percent, l.subprice,'; $sql.= ' l.total_ht, l.total_tva, l.total_ttc,'; $sql.= ' l.rang, l.special_code,'; @@ -358,7 +358,7 @@ class FactureRec extends CommonInvoice $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid'; $sql.= ' WHERE l.fk_facture = '.$this->id; - dol_syslog('Facture::fetch_lines', LOG_DEBUG); + dol_syslog('FactureRec::fetch_lines', LOG_DEBUG); $result = $this->db->query($sql); if ($result) { @@ -369,10 +369,13 @@ class FactureRec extends CommonInvoice $objp = $this->db->fetch_object($result); $line = new FactureLigne($this->db); + $line->id = $objp->rowid; $line->rowid = $objp->rowid; $line->label = $objp->custom_label; // Label line $line->desc = $objp->description; // Description line + $line->description = $objp->description; // Description line $line->product_type = $objp->product_type; // Type of line + $line->ref = $objp->product_ref; // Ref product $line->product_ref = $objp->product_ref; // Ref product $line->libelle = $objp->product_label; // deprecated $line->product_label = $objp->product_label; // Label product @@ -904,3 +907,52 @@ class FactureRec extends CommonInvoice } } } + + + +/** + * Class to manage invoice lines of templates. + * Saved into database table llx_facturedet_rec + */ +class FactureLigneRec extends CommonInvoiceLine +{ + + /** + * Delete line in database + * + * @return int <0 if KO, >0 if OK + */ + function delete() + { + global $conf,$langs,$user; + + $error=0; + + $this->db->begin(); + + // Call trigger + /*$result=$this->call_trigger('LINEBILLREC_DELETE',$user); + if ($result < 0) + { + $this->db->rollback(); + return -1; + }*/ + // End call triggers + + + $sql = "DELETE FROM ".MAIN_DB_PREFIX."facturedet_rec WHERE rowid = ".($this->rowid > 0 ? $this->rowid : $this->id); + dol_syslog(get_class($this)."::delete", LOG_DEBUG); + if ($this->db->query($sql) ) + { + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->error()." sql=".$sql; + $this->db->rollback(); + return -1; + } + } + +} \ No newline at end of file diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index b7531719646f9f59291194da303c586ef47cabc4..4dbf4b9020a89d953eb26474b453497825cb0cf5 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -280,7 +280,7 @@ class Facture extends CommonInvoice $this->socid = $_facrec->socid; - $this->fk_project = $_facrec->fk_project; + $this->fk_project = GETPOST('projectid','int') > 0 ? GETPOST('projectid','int') : $_facrec->fk_project; $this->fk_account = $_facrec->fk_account; $this->cond_reglement_id = $_facrec->cond_reglement_id; $this->mode_reglement_id = $_facrec->mode_reglement_id; diff --git a/htdocs/compta/facture/fiche-rec.php b/htdocs/compta/facture/fiche-rec.php index 7f4c5282098125f3d18274bc1bfecb7a09779230..ad9626718c643e75787ae85d61ed3dfcdf05d02e 100644 --- a/htdocs/compta/facture/fiche-rec.php +++ b/htdocs/compta/facture/fiche-rec.php @@ -32,18 +32,23 @@ require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php'; require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; $langs->load('bills'); $langs->load('compta'); // Security check $id=(GETPOST('facid','int')?GETPOST('facid','int'):GETPOST('id','int')); +$confirm = GETPOST('confirm', 'alpha'); +$cancel = GETPOST('cancel', 'alpha'); +$lineid=GETPOST('lineid','int'); $ref=GETPOST('ref','alpha'); $action=GETPOST('action', 'alpha'); if ($user->societe_id) $socid=$user->societe_id; $objecttype = 'facture_rec'; if ($action == "create" || $action == "add") $objecttype = ''; $result = restrictedArea($user, 'facture', $id, $objecttype); +$projectid = GETPOST('projectid','int'); if ($page == -1) { @@ -68,10 +73,16 @@ if (($id > 0 || $ref) && $action != 'create' && $action != 'add') } } + /* * Actions */ +// Set note +$permissionnote=$user->rights->facture->creer; // Used by the include of actions_setnotes.inc.php +include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not include_once + +include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; // Must be include, not include_once // Create predefined invoice if ($action == 'add') @@ -119,6 +130,8 @@ if ($action == 'add') $object->nb_gen_max = $nb_gen_max; $object->auto_validate = GETPOST('auto_validate', 'int'); + $object->fk_project = $projectid; + $date_next_execution = dol_mktime($rehour, $remin, 0, $remonth, $reday, $reyear); $object->date_when = $date_next_execution; @@ -233,9 +246,329 @@ elseif ($action == 'setauto_validate' && $user->rights->facture->creer) { $object->setAutoValidate(GETPOST('auto_validate', 'int')); } -// Set note -$permissionnote=$user->rights->facture->creer; // Used by the include of actions_setnotes.inc.php -include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not includ_once + +// Delete line +if ($action == 'confirm_deleteline' && $confirm == 'yes' && $user->rights->facture->creer) +{ + $object->fetch($id); + $object->fetch_thirdparty(); + + $db->begin(); + + $line=new FactureLigneRec($db); + + // For triggers + $line->id = $lineid; + + if ($line->delete() > 0) + { + $result=$object->update_price(1); + + if ($result > 0) + { + $db->commit(); + $object->fetch($object->id); // Reload lines + } + else + { + $db->rollback(); + setEventMessages($db->lasterror(), null, 'errors'); + } + } + else + { + $db->rollback(); + setEventMessages($line->error, $line->errors, 'errors'); + } +} + +// Add a new line +if ($action == 'addline' && $user->rights->facture->creer) +{ + $langs->load('errors'); + $error = 0; + + // Set if we used free entry or predefined product + $predef=''; + $product_desc=(GETPOST('dp_desc')?GETPOST('dp_desc'):''); + $price_ht = GETPOST('price_ht'); + if (GETPOST('prod_entry_mode') == 'free') + { + $idprod=0; + $tva_tx = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0); + } + else + { + $idprod=GETPOST('idprod', 'int'); + $tva_tx = ''; + } + + $qty = GETPOST('qty' . $predef); + $remise_percent = GETPOST('remise_percent' . $predef); + + // Extrafields + $extrafieldsline = new ExtraFields($db); + $extralabelsline = $extrafieldsline->fetch_name_optionals_label($object->table_element_line); + $array_options = $extrafieldsline->getOptionalsFromPost($extralabelsline, $predef); + // Unset extrafield + if (is_array($extralabelsline)) { + // Get extra fields + foreach ($extralabelsline as $key => $value) { + unset($_POST["options_" . $key . $predef]); + } + } + + if (empty($idprod) && ($price_ht < 0) && ($qty < 0)) { + setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPriceHT'), $langs->transnoentitiesnoconv('Qty')), null, 'errors'); + $error ++; + } + if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && GETPOST('type') < 0) { + setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors'); + $error ++; + } + if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && (! ($price_ht >= 0) || $price_ht == '')) // Unit price can be 0 but not '' + { + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors'); + $error ++; + } + if ($qty == '') { + setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors'); + $error ++; + } + if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && empty($product_desc)) { + setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors'); + $error ++; + } + if ($qty < 0) { + $langs->load("errors"); + setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors'); + $error ++; + } + + if (! $error && ($qty >= 0) && (! empty($product_desc) || ! empty($idprod))) { + $ret = $object->fetch($id); + if ($ret < 0) { + dol_print_error($db, $object->error); + exit(); + } + $ret = $object->fetch_thirdparty(); + + // Clean parameters + $date_start = dol_mktime(GETPOST('date_start' . $predef . 'hour'), GETPOST('date_start' . $predef . 'min'), GETPOST('date_start' . $predef . 'sec'), GETPOST('date_start' . $predef . 'month'), GETPOST('date_start' . $predef . 'day'), GETPOST('date_start' . $predef . 'year')); + $date_end = dol_mktime(GETPOST('date_end' . $predef . 'hour'), GETPOST('date_end' . $predef . 'min'), GETPOST('date_end' . $predef . 'sec'), GETPOST('date_end' . $predef . 'month'), GETPOST('date_end' . $predef . 'day'), GETPOST('date_end' . $predef . 'year')); + $price_base_type = (GETPOST('price_base_type', 'alpha') ? GETPOST('price_base_type', 'alpha') : 'HT'); + + // Define special_code for special lines + $special_code = 0; + // if (empty($_POST['qty'])) $special_code=3; // Options should not exists on invoices + + // Ecrase $pu par celui du produit + // Ecrase $desc par celui du produit + // Ecrase $txtva par celui du produit + // Ecrase $base_price_type par celui du produit + // Replaces $fk_unit with the product's + if (! empty($idprod)) + { + $prod = new Product($db); + $prod->fetch($idprod); + + $label = ((GETPOST('product_label') && GETPOST('product_label') != $prod->label) ? GETPOST('product_label') : ''); + + // Update if prices fields are defined + $tva_tx = get_default_tva($mysoc, $object->thirdparty, $prod->id); + $tva_npr = get_default_npr($mysoc, $object->thirdparty, $prod->id); + if (empty($tva_tx)) $tva_npr=0; + + $pu_ht = $prod->price; + $pu_ttc = $prod->price_ttc; + $price_min = $prod->price_min; + $price_base_type = $prod->price_base_type; + + // We define price for product + if (! empty($conf->global->PRODUIT_MULTIPRICES) && ! empty($object->thirdparty->price_level)) + { + $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]; + $price_base_type = $prod->multiprices_base_type[$object->thirdparty->price_level]; + if (! empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) // using this option is a bug. kept for backward compatibility + { + if (isset($prod->multiprices_tva_tx[$object->thirdparty->price_level])) $tva_tx=$prod->multiprices_tva_tx[$object->thirdparty->price_level]; + if (isset($prod->multiprices_recuperableonly[$object->thirdparty->price_level])) $tva_npr=$prod->multiprices_recuperableonly[$object->thirdparty->price_level]; + if (empty($tva_tx)) $tva_npr=0; + } + } + elseif (! empty($conf->global->PRODUIT_CUSTOMER_PRICES)) + { + require_once DOL_DOCUMENT_ROOT . '/product/class/productcustomerprice.class.php'; + + $prodcustprice = new Productcustomerprice($db); + + $filter = array('t.fk_product' => $prod->id,'t.fk_soc' => $object->thirdparty->id); + + $result = $prodcustprice->fetch_all('', '', 0, 0, $filter); + if ($result) { + if (count($prodcustprice->lines) > 0) { + $pu_ht = price($prodcustprice->lines[0]->price); + $pu_ttc = price($prodcustprice->lines[0]->price_ttc); + $price_base_type = $prodcustprice->lines[0]->price_base_type; + $prod->tva_tx = $prodcustprice->lines[0]->tva_tx; + } + } + } + + // if price ht was forced (ie: from gui when calculated by margin rate and cost price) + if (! empty($price_ht)) + { + $pu_ht = price2num($price_ht, 'MU'); + $pu_ttc = price2num($pu_ht * (1 + ($tva_tx / 100)), 'MU'); + } + // On reevalue prix selon taux tva car taux tva transaction peut etre different + // de ceux du produit par defaut (par exemple si pays different entre vendeur et acheteur). + elseif ($tva_tx != $prod->tva_tx) + { + if ($price_base_type != 'HT') + { + $pu_ht = price2num($pu_ttc / (1 + ($tva_tx / 100)), 'MU'); + } + else + { + $pu_ttc = price2num($pu_ht * (1 + ($tva_tx / 100)), 'MU'); + } + } + + $desc = ''; + + // Define output language + if (! empty($conf->global->MAIN_MULTILANGS) && ! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) { + $outputlangs = $langs; + $newlang = ''; + if (empty($newlang) && GETPOST('lang_id')) + $newlang = GETPOST('lang_id'); + if (empty($newlang)) + $newlang = $object->thirdparty->default_lang; + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + + $desc = (! empty($prod->multilangs [$outputlangs->defaultlang] ["description"])) ? $prod->multilangs [$outputlangs->defaultlang] ["description"] : $prod->description; + } else { + $desc = $prod->description; + } + + $desc = dol_concatdesc($desc, $product_desc); + + // Add custom code and origin country into description + if (empty($conf->global->MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE) && (! empty($prod->customcode) || ! empty($prod->country_code))) { + $tmptxt = '('; + if (! empty($prod->customcode)) + $tmptxt .= $langs->transnoentitiesnoconv("CustomCode") . ': ' . $prod->customcode; + if (! empty($prod->customcode) && ! empty($prod->country_code)) + $tmptxt .= ' - '; + if (! empty($prod->country_code)) + $tmptxt .= $langs->transnoentitiesnoconv("CountryOrigin") . ': ' . getCountry($prod->country_code, 0, $db, $langs, 0); + $tmptxt .= ')'; + $desc = dol_concatdesc($desc, $tmptxt); + } + + $type = $prod->type; + $fk_unit = $prod->fk_unit; + } else { + $pu_ht = price2num($price_ht, 'MU'); + $pu_ttc = price2num(GETPOST('price_ttc'), 'MU'); + $tva_npr = (preg_match('/\*/', $tva_tx) ? 1 : 0); + $tva_tx = str_replace('*', '', $tva_tx); + if (empty($tva_tx)) $tva_npr=0; + $label = (GETPOST('product_label') ? GETPOST('product_label') : ''); + $desc = $product_desc; + $type = GETPOST('type'); + $fk_unit= GETPOST('units', 'alpha'); + } + + // Margin + $fournprice = price2num(GETPOST('fournprice' . $predef) ? GETPOST('fournprice' . $predef) : ''); + $buyingprice = price2num(GETPOST('buying_price' . $predef) != '' ? GETPOST('buying_price' . $predef) : ''); // If buying_price is '0', we must keep this value + + // Local Taxes + $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $mysoc, $tva_npr); + $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $mysoc, $tva_npr); + + $info_bits = 0; + if ($tva_npr) + $info_bits |= 0x01; + + if (! empty($price_min) && (price2num($pu_ht) * (1 - price2num($remise_percent) / 100) < price2num($price_min))) { + $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, - 1, $conf->currency)); + setEventMessages($mesg, null, 'errors'); + } else { + // Insert line + $result = $object->addline($desc, $pu_ht, $qty, $tva_tx, $idprod, $remise_percent, $price_base_type, $info_bits, '', $pu_ttc, $type, - 1, $special_code, $label, $fk_unit); + + if ($result > 0) + { + // Define output language + /*if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id')) $newlang = GETPOST('lang_id','alpha'); + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang = $object->thirdparty->default_lang; + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + $model=$object->modelpdf; + $ret = $object->fetch($id); // Reload to get new records + + $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref); + if ($result < 0) setEventMessages($object->error, $object->errors, 'errors'); + }*/ + $object->fetch($object->id); // Reload lines + + unset($_POST['prod_entry_mode']); + + unset($_POST['qty']); + unset($_POST['type']); + unset($_POST['remise_percent']); + unset($_POST['price_ht']); + unset($_POST['multicurrency_price_ht']); + unset($_POST['price_ttc']); + unset($_POST['tva_tx']); + unset($_POST['product_ref']); + unset($_POST['product_label']); + unset($_POST['product_desc']); + unset($_POST['fournprice']); + unset($_POST['buying_price']); + unset($_POST['np_marginRate']); + unset($_POST['np_markRate']); + unset($_POST['dp_desc']); + unset($_POST['idprod']); + unset($_POST['units']); + + unset($_POST['date_starthour']); + unset($_POST['date_startmin']); + unset($_POST['date_startsec']); + unset($_POST['date_startday']); + unset($_POST['date_startmonth']); + unset($_POST['date_startyear']); + unset($_POST['date_endhour']); + unset($_POST['date_endmin']); + unset($_POST['date_endsec']); + unset($_POST['date_endday']); + unset($_POST['date_endmonth']); + unset($_POST['date_endyear']); + + unset($_POST['situations']); + unset($_POST['progress']); + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } + + $action = ''; + } + } +} @@ -262,7 +595,8 @@ if ($action == 'create') $object = new Facture($db); // Source invoice $product_static = new Product($db); - + $formproject = new FormProjets($db); + if ($object->fetch($id, $ref) > 0) { print '<form action="fiche-rec.php" method="post">'; @@ -281,14 +615,14 @@ if ($action == 'create') $object->fetch_thirdparty(); // Third party - print '<tr><td>'.$langs->trans("Customer").'</td><td>'.$object->thirdparty->getNomUrl(1,'customer').'</td>'; + print '<tr><td class="titlefieldcreate">'.$langs->trans("Customer").'</td><td>'.$object->thirdparty->getNomUrl(1,'customer').'</td>'; print '<td>'; print $langs->trans("Comment"); print '</td></tr>'; // Title print '<tr><td class="fieldrequired">'.$langs->trans("Title").'</td><td>'; - print '<input class="flat" type="text" name="titre" size="24" value="'.$_POST["titre"].'">'; + print '<input class="flat quatrevingtpercent" type="text" name="titre" value="'.$_POST["titre"].'">'; print '</td>'; // Note @@ -310,18 +644,16 @@ if ($action == 'create') print "</td></tr>"; // Project - if (! empty($conf->projet->enabled)) - { - print "<tr><td>".$langs->trans("Project")."</td><td>"; - if ($object->fk_project > 0) - { - $project = new Project($db); - $project->fetch($object->fk_project); - print $project->getNomUrl(1); - } - print "</td></tr>"; - } - + if (! empty($conf->projet->enabled) && is_object($object->thirdparty) && $object->thirdparty->id > 0) + { + $projectid = $object->fk_project; + $langs->load('projects'); + print '<tr><td>' . $langs->trans('Project') . '</td><td colspan="2">'; + $numprojet = $formproject->select_projects($socid, $projectid, 'projectid', 0); + print ' <a href="'.DOL_URL_ROOT.'/projet/card.php?socid=' . $soc->id . '&action=create&status=1&backtopage='.urlencode($_SERVER["PHP_SELF"].'?action=create&socid='.$soc->id).'">' . $langs->trans("AddProject") . '</a>'; + print '</td></tr>'; + } + // Bank account if ($object->fk_account > 0) { @@ -342,7 +674,7 @@ if ($action == 'create') print '<table class="border" width="100%">'; // Frequency - print "<tr><td>".$form->textwithpicto($langs->trans("Frequency"), $langs->transnoentitiesnoconv('toolTipFrequency'))."</td><td>"; + print '<tr><td class="titlefieldcreate">'.$form->textwithpicto($langs->trans("Frequency"), $langs->transnoentitiesnoconv('toolTipFrequency'))."</td><td>"; print "<input type='text' name='frequency' value='".GETPOST('frequency', 'int')."' size='5' /> ".$form->selectarray('unit_frequency', array('d'=>$langs->trans('Day'), 'm'=>$langs->trans('Month'), 'y'=>$langs->trans('Year')), (GETPOST('unit_frequency')?GETPOST('unit_frequency'):'m')); print "</td></tr>"; @@ -375,6 +707,7 @@ if ($action == 'create') print load_fiche_titre($title, '', ''); + /* * Invoice lines */ @@ -580,9 +913,16 @@ else { $object->fetch_thirdparty(); + // Confirmation de la suppression d'une ligne produit + if ($action == 'ask_deleteline') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id . '&lineid=' . $lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 'no', 1); + } + + print $formconfirm; + $author = new User($db); $author->fetch($object->user_author); - + $head=array(); $h=0; $head[$h][0] = $_SERVER["PHP_SELF"].'?id='.$object->id; @@ -851,96 +1191,45 @@ else print '<br>'; } - /* - * Lines - */ - - print '<table class="noborder noshadow" width="100%">'; - print '<tr class="liste_titre">'; - print '<td>'.$langs->trans("Description").'</td>'; - print '<td align="right">'.$langs->trans("VAT").'</td>'; - print '<td align="right">'.$langs->trans("PriceUHT").'</td>'; - print '<td align="center">'.$langs->trans("Qty").'</td>'; - print '<td align="center">'.$langs->trans("ReductionShort").'</td>'; - if ($conf->global->PRODUCT_USE_UNITS) { - print '<td align="left">'.$langs->trans("Unit").'</td>'; + // Lines + print ' <form name="addproduct" id="addproduct" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . (($action != 'editline') ? '#add' : '#line_' . GETPOST('lineid')) . '" method="POST"> + <input type="hidden" name="token" value="' . $_SESSION ['newtoken'] . '"> + <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateligne') . '"> + <input type="hidden" name="mode" value=""> + <input type="hidden" name="id" value="' . $object->id . '"> + '; + + if (! empty($conf->use_javascript_ajax) && $object->statut == 0) { + include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php'; } - print '</tr>'; - - $num = count($object->lines); - $i = 0; - $var=true; - while ($i < $num) + + print '<table id="tablelines" class="noborder noshadow" width="100%">'; + // Show object lines + if (! empty($object->lines)) { - $var=!$var; - - $product_static=new Product($db); - - // Show product and description - $type=(isset($object->lines[$i]->product_type)?$object->lines[$i]->product_type:$object->lines[$i]->fk_product_type); - // Try to enhance type detection using date_start and date_end for free lines when type - // was not saved. - if (! empty($objp->date_start)) $type=1; - if (! empty($objp->date_end)) $type=1; - - // Show line - print "<tr ".$bc[$var].">"; - if ($object->lines[$i]->fk_product > 0) - { - print '<td>'; - print '<a name="'.$object->lines[$i]->id.'"></a>'; // ancre pour retourner sur la ligne - - // Show product and description - $product_static->type=$object->lines[$i]->fk_product_type; - $product_static->id=$object->lines[$i]->fk_product; - $product_static->ref=$object->lines[$i]->product_ref; - $text=$product_static->getNomUrl(1); - $text.= ' - '.(! empty($object->lines[$i]->label)?$object->lines[$i]->label:$object->lines[$i]->product_label); - $description=(! empty($conf->global->PRODUIT_DESC_IN_FORM)?'':dol_htmlentitiesbr($object->lines[$i]->desc)); - print $form->textwithtooltip($text,$description,3,'','',$i); - - // Show range - print_date_range($object->lines[$i]->date_start, $object->lines[$i]->date_end); - - // Add description in form - if (! empty($conf->global->PRODUIT_DESC_IN_FORM)) - print (! empty($object->lines[$i]->desc) && $object->lines[$i]->desc!=$fac->lines[$i]->product_label)?'<br>'.dol_htmlentitiesbr($object->lines[$i]->desc):''; - - print '</td>'; - } - else - { - print '<td>'; - - if ($type==1) $text = img_object($langs->trans('Service'),'service'); - else $text = img_object($langs->trans('Product'),'product'); - - if (! empty($object->lines[$i]->label)) { - - $text.= ' <strong>'.$object->lines[$i]->label.'</strong>'; - print $form->textwithtooltip($text,dol_htmlentitiesbr($object->lines[$i]->desc),3,'','',$i); - - } else { - - print $text.' '.nl2br($object->lines[$i]->desc); - } - - // Show range - print_date_range($object->lines[$i]->date_start, $object->lines[$i]->date_end); - - print '</td>'; - } - print '<td align="right">'.vatrate($object->lines[$i]->tva_tx, 1).'</td>'; - print '<td align="right">'.price($object->lines[$i]->price).'</td>'; - print '<td align="center">'.$object->lines[$i]->qty.'</td>'; - print '<td align="center">'.$object->lines[$i]->remise_percent.' %</td>'; - if ($conf->global->PRODUCT_USE_UNITS) { - print "<td align=\"left\">".$object->lines[$i]->getLabelOfUnit()."</td>"; - } - print "</tr>\n"; - $i++; + $disableedit=1; + $disablemove=1; + $ret = $object->printObjectLines($action, $mysoc, $soc, $lineid, 0); // No date selector for template invoice } - print '</table>'; + + // Form to add new line + if ($object->statut == 0 && $user->rights->facture->creer && $action != 'valid' && $action != 'editline') + { + if ($action != 'editline') + { + $var = true; + + // Add free products/services + $object->formAddObjectLine(0, $mysoc, $soc); // No date selector for template invoice + + $parameters = array(); + $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + } + } + + print "</table>\n"; + + print "</form>\n"; dol_fiche_end(); diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 33c70d57ae6c30c923aac29d2c384f640799f39d..ec02fce3daeb99b52cbe9b12597f4edd69f634ee 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -3236,7 +3236,7 @@ abstract class CommonObject */ function printObjectLines($action, $seller, $buyer, $selected=0, $dateSelector=0) { - global $conf, $hookmanager, $inputalsopricewithtax, $usemargins, $langs, $user; + global $conf, $hookmanager, $inputalsopricewithtax, $usemargins, $disableedit, $disablemove, $langs, $user; // Define usemargins $usemargins=0; @@ -3365,7 +3365,8 @@ abstract class CommonObject function printObjectLine($action,$line,$var,$num,$i,$dateSelector,$seller,$buyer,$selected=0,$extrafieldsline=0) { global $conf,$langs,$user,$object,$hookmanager; - global $form,$bc,$bcdd, $object_rights; + global $form,$bc,$bcdd; + global $object_rights, $disableedit, $disablemove; // TODO We should not use global var for this ! $object_rights = $this->getRights(); @@ -4458,7 +4459,10 @@ abstract class CommonObject { global $user; - return $user->rights->{$this->element}; + $element = $this->element; + if ($element == 'facturerec') $element='facture'; + + return $user->rights->{$element}; } /** diff --git a/htdocs/core/tpl/objectline_create.tpl.php b/htdocs/core/tpl/objectline_create.tpl.php index 77b58bd83cdb3bcf6b6816af6c650195f0dcb922..f89184cedc1d7119a4204b59cf82ad55c023060b 100644 --- a/htdocs/core/tpl/objectline_create.tpl.php +++ b/htdocs/core/tpl/objectline_create.tpl.php @@ -46,7 +46,7 @@ if (empty($inputalsopricewithtax)) $inputalsopricewithtax=0; // Define colspan for button Add $colspan = 3; // Col total ht + col edit + col delete -if (in_array($object->element,array('propal', 'supplier_proposal','facture','invoice','commande','order','order_supplier','invoice_supplier'))) $colspan++; // With this, there is a column move button +if (in_array($object->element,array('propal', 'supplier_proposal','facture','facturerec','invoice','commande','order','order_supplier','invoice_supplier'))) $colspan++; // With this, there is a column move button //print $object->element; ?> @@ -360,6 +360,7 @@ if ((! empty($conf->service->enabled) || ($object->element == 'contrat')) && $da 'propal', 'supplier_proposal', 'facture', + 'facturerec', 'invoice', 'commande', 'order', diff --git a/htdocs/core/tpl/objectline_view.tpl.php b/htdocs/core/tpl/objectline_view.tpl.php index c264bac205d49718933441ba371c517aee9d8e6f..967d9f8197010cb5acf085599bb45bb0c5656269 100644 --- a/htdocs/core/tpl/objectline_view.tpl.php +++ b/htdocs/core/tpl/objectline_view.tpl.php @@ -30,7 +30,9 @@ * $senderissupplier (0 by default, 1 for supplier invoices/orders) * $inputalsopricewithtax (0 by default, 1 to also show column with unit price including tax) * $usemargins (0 to disable all margins columns, 1 to show according to margin setup) - * + * $object_rights->creer initialized from = $object->getRights() + * $disableedit, $disablemove + * * $type, $text, $description, $line */ @@ -201,9 +203,10 @@ if (empty($usemargins)) $usemargins=0; <?php } ?> <?php } ?> - <?php if ($this->statut == 0 && ($object_rights->creer)) { ?> + <?php + if ($this->statut == 0 && ($object_rights->creer)) { ?> <td class="linecoledit" align="center"><?php $coldisplay++; ?> - <?php if (($line->info_bits & 2) == 2) { ?> + <?php if (($line->info_bits & 2) == 2 || ! empty($disableedit)) { ?> <?php } else { ?> <a href="<?php echo $_SERVER["PHP_SELF"].'?id='.$this->id.'&action=editline&lineid='.$line->id.'#line_'.$line->id; ?>"> <?php echo img_edit(); ?> @@ -221,7 +224,8 @@ if (empty($usemargins)) $usemargins=0; ?> </td> - <?php if ($num > 1 && empty($conf->browser->phone) && ($this->situation_counter == 1 || !$this->situation_cycle_ref)) { ?> + <?php + if ($num > 1 && empty($conf->browser->phone) && ($this->situation_counter == 1 || !$this->situation_cycle_ref) && empty($disablemove)) { ?> <td align="center" class="linecolmove tdlineupdown"><?php $coldisplay++; ?> <?php if ($i > 0) { ?> <a class="lineupdown" href="<?php echo $_SERVER["PHP_SELF"].'?id='.$this->id.'&action=up&rowid='.$line->id; ?>"> @@ -235,7 +239,7 @@ if (empty($usemargins)) $usemargins=0; <?php } ?> </td> <?php } else { ?> - <td align="center"<?php echo (empty($conf->browser->phone)?' class="linecolmove tdlineupdown"':' class="linecolmove"'); ?>><?php $coldisplay++; ?></td> + <td align="center"<?php echo ((empty($conf->browser->phone) && empty($disablemove)) ?' class="linecolmove tdlineupdown"':' class="linecolmove"'); ?>><?php $coldisplay++; ?></td> <?php } ?> <?php } else { ?> <td colspan="3"><?php $coldisplay=$coldisplay+3; ?></td>