diff --git a/htdocs/compta/facture.php b/htdocs/compta/facture.php index 0884fbe1504..56a26abc2ec 100644 --- a/htdocs/compta/facture.php +++ b/htdocs/compta/facture.php @@ -45,7 +45,7 @@ if ($conf->commande->enabled) require_once(DOL_DOCUMENT_ROOT.'/commande/commande $user->getrights('facture'); $user->getrights('banque'); -if (!$user->rights->facture->lire) +if (! $user->rights->facture->lire) accessforbidden(); $langs->load('bills'); @@ -53,9 +53,9 @@ $langs->load('companies'); $langs->load('products'); $langs->load('main'); -$sall=isset($_GET['sall'])?$_GET['sall']:$_POST['sall']; -if (isset($_GET['msg'])) { $msg=urldecode($_GET['msg']); } -if ($_GET['socidp']) { $socidp=$_GET['socidp']; } +$sall=isset($_GET['sall'])?trim($_GET['sall']):trim($_POST['sall']); +$msg=isset($_GET['msg'])?urldecode($_GET['msg']):''; +$socidp=isset($_GET['socidp'])?$_GET['socidp']:$_POST['socidp']; // Sécurité accés client if ($user->societe_id > 0) @@ -273,10 +273,12 @@ if ($_POST['action'] == 'add') $facture = new Facture($db, $_POST['socid']); + $facture->type = $_POST['type']; + if ($facture->type == 1) $facture->fk_facture_source = $_POST['replacement_ref']; $facture->number = $_POST['facnumber']; $facture->date = $datefacture; - $facture->note_public = $_POST['note_public']; - $facture->note = $_POST['note']; + $facture->note_public = trim($_POST['note_public']); + $facture->note = trim($_POST['note']); $facture->ref_client = $_POST['ref_client']; $facture->modelpdf = $_POST['model']; @@ -604,17 +606,24 @@ if ($_POST['action'] == 'updateligne' && $user->rights->facture->creer && $_POST exit; } -if ($_GET['action'] == 'deleteline' && $user->rights->facture->creer && !$conf->global->PRODUIT_CONFIRM_DELETE_LINE) +if ($_GET['action'] == 'deleteline' && $user->rights->facture->creer && ! $conf->global->PRODUIT_CONFIRM_DELETE_LINE) { $fac = new Facture($db,'',$_GET['facid']); $fac->fetch($_GET['facid']); $result = $fac->deleteline($_GET['rowid']); - if ($_REQUEST['lang_id']) + if ($result > 0) { - $outputlangs = new Translate(DOL_DOCUMENT_ROOT ."/langs"); - $outputlangs->setDefaultLang($_REQUEST['lang_id']); + if ($_REQUEST['lang_id']) + { + $outputlangs = new Translate(DOL_DOCUMENT_ROOT ."/langs"); + $outputlangs->setDefaultLang($_REQUEST['lang_id']); + } + // facture_pdf_create($db, $fac->id, '', $fac->modelpdf, $outputlangs); + } + else + { + print $fac->error; } - facture_pdf_create($db, $fac->id, '', $fac->modelpdf, $outputlangs); } if ($_POST['action'] == 'confirm_delete' && $_POST['confirm'] == 'yes') @@ -623,9 +632,15 @@ if ($_POST['action'] == 'confirm_delete' && $_POST['confirm'] == 'yes') { $fac = new Facture($db); $result = $fac->delete($_GET['facid']); - $_GET['facid'] = 0 ; - Header('Location: '.$_SERVER["PHP_SELF"]); - exit; + if ($result > 0) + { + Header('Location: '.$_SERVER["PHP_SELF"]); + exit; + } + else + { + $mesg='
'.$fac->error.'
'; + } } } @@ -888,6 +903,8 @@ $html = new Form($db); **********************************************************************/ if ($_GET['action'] == 'create') { + $facturestatic=new Facture($db); + print_titre($langs->trans('NewBill')); if ($msg) print $msg; @@ -958,14 +975,46 @@ if ($_GET['action'] == 'create') // Ref print ''.$langs->trans('Ref').''.$langs->trans('Draft').''; - // Reference client - $refclient = $ref_client ? $ref_client : ''; - print ''.$langs->trans('RefCustomer').''; - print ''; - print ''; - + // Type de facture + print ''.$langs->trans('Type').''; + print ''; + print ''; + print ''; + print ''; + print '
'; + print ''; + print ''; + $desc=$html->textwithhelp($langs->trans("InvoiceStandardAsk"),$langs->transnoentities("InvoiceStandardDesc"),1); + print $desc; + print '
'; + print ''; + print ''; + $facids=$facturestatic->list_replacable_invoices($soc->id); + $options=""; + foreach ($facids as $key => $value) + { + $options.=''; + } + $text=$langs->trans("InvoiceReplacementAsk").' '; + $text.=''; + $desc=$html->textwithhelp($text,$langs->transnoentities("InvoiceReplacementDesc"),1); + print $desc; + print '
'; + print ''; + print ''; + $desc=$html->textwithhelp($langs->trans("InvoiceAvoirAsk").' ('.$langs->trans("FeatureNotYetAvailable").')',$langs->transnoentities("InvoiceAvoirDesc"),1); + print $desc; + print '
'; + print ''; + // Societe - print ''.$langs->trans('Company').''.$soc->getNomUrl(1).''; + print ''.$langs->trans('Company').''; + print $soc->getNomUrl(1); + print ''; + print ''; print ''; // Ligne info remises tiers @@ -1044,15 +1093,29 @@ if ($_GET['action'] == 'create') print ''; } + // Modele PDF print ''.$langs->trans('Model').''; print ''; - // pdf include_once(DOL_DOCUMENT_ROOT.'/includes/modules/facture/modules_facture.php'); $model=new ModelePDFFactures(); $liste=$model->liste_modeles($db); $html->select_array('model',$liste,$conf->global->FACTURE_ADDON_PDF); print ""; + /* + \todo + L'info "Reference commande client" est une carac de la commande et non de la facture. + Elle devrait donc etre stockée sur l'objet commande lié à la facture et non sur la facture. + Pour ceux qui veulent l'utiliser au niveau de la facture, positionner la + constante FAC_USE_CUSTOMER_ORDER_REF à 1. + */ + if ($conf->global->FAC_USE_CUSTOMER_ORDER_REF) + { + print ''.$langs->trans('RefCustomerOrder').''; + print ''; + print ''; + } + // Note publique print ''; print ''.$langs->trans('NotePublic').''; @@ -1094,19 +1157,6 @@ if ($_GET['action'] == 'create') print ''; } - /* - \todo - L'info "Reference commande client" est une carac de la commande et non de la facture. - Elle devrait donc etre stockée sur l'objet commande lié à la facture et non sur la facture. - Pour ceux qui utilisent ainsi, positionner la constante FAC_USE_CUSTOMER_ORDER_REF à 1. - */ - if ($conf->global->FAC_USE_CUSTOMER_ORDER_REF) - { - print ''.$langs->trans('RefCustomerOrder').''; - print ''; - print ''; - } - if ($_GET['propalid'] > 0) { print ''."\n"; @@ -1156,47 +1206,50 @@ if ($_GET['action'] == 'create') } else { - print ''; - - // Zone de choix des produits prédéfinis à la création - print ''; - print ''; - print ''; - print ''; - print ''; - if ($conf->service->enabled) + if ($conf->global->PRODUCT_SHOW_WHEN_CREATE) { - print ''; - } - print ''; - for ($i = 1 ; $i <= $NBLINES ; $i++) - { - print ''; - print ''; - print ''; - print ''; - print ''; - // Si le module service est actif, on propose des dates de début et fin à la ligne + print ''; } - - print '
'.$langs->trans('ProductsAndServices').''.$langs->trans('Qty').''.$langs->trans('ReductionShort').'     '.$langs->trans('ServiceLimitedDuration').'
'; - // multiprix - if($conf->global->PRODUIT_MULTIPRICES == 1) - $html->select_produits('','idprod'.$i,'',$conf->produit->limit_size,$soc->price_level); - else - $html->select_produits('','idprod'.$i,'',$conf->produit->limit_size); - print '% 
'; + + // Zone de choix des produits prédéfinis à la création + print ''; + print ''; + print ''; + print ''; + print ''; if ($conf->service->enabled) { - print ''; + print ''; } - print "\n"; + print ''; + for ($i = 1 ; $i <= $NBLINES ; $i++) + { + print ''; + print ''; + print ''; + print ''; + print ''; + // Si le module service est actif, on propose des dates de début et fin à la ligne + if ($conf->service->enabled) + { + print ''; + } + print "\n"; + } + + print '
'.$langs->trans('ProductsAndServices').''.$langs->trans('Qty').''.$langs->trans('ReductionShort').'     '; - print $langs->trans('From').' '; - print $html->select_date('','date_start'.$i,0,0,1,"add"); - print '
'.$langs->trans('to').' '; - print $html->select_date('','date_end'.$i,0,0,1,"add"); - print '
'.$langs->trans('ServiceLimitedDuration').'
'; + // multiprix + if($conf->global->PRODUIT_MULTIPRICES == 1) + $html->select_produits('','idprod'.$i,'',$conf->produit->limit_size,$soc->price_level); + else + $html->select_produits('','idprod'.$i,'',$conf->produit->limit_size); + print '% '; + print $langs->trans('From').' '; + print $html->select_date('','date_start'.$i,0,0,1,"add"); + print '
'.$langs->trans('to').' '; + print $html->select_date('','date_end'.$i,0,0,1,"add"); + print '
'; + print '
'; - print ''; } /* @@ -1483,29 +1536,24 @@ else // Reference print ''.$langs->trans('Ref').''.$fac->ref.''; - // Ref client - print ''; - print ''; - if ($_GET['action'] != 'RefCustomerOrder' && $fac->brouillon) print ''; - print '
'; - print $langs->trans('RefCustomer').''; - print ''.img_edit($langs->trans('Edit')).'
'; - print ''; - if ($user->rights->facture->creer && $_GET['action'] == 'RefCustomerOrder') + // Type + print ''.$langs->trans('Type').''; + print $fac->getLibType(); + if ($fac->type == 1) { - print '
'; - print ''; - print ''; - print ' '; - print '
'; + $facreplaced=new Facture($db); + $facreplaced->fetch($fac->fk_facture_source); + print ' ('.$langs->transnoentities("ReplaceInvoice",$facreplaced->getNomUrl(1)).')'; } - else + $facidnext=$fac->getIdNextInvoice(); + if ($facidnext > 0) { - print $fac->ref_client; + $facthatreplace=new Facture($db); + $facthatreplace->fetch($facidnext); + print ' ('.$langs->transnoentities("ReplacedByInvoice",$facthatreplace->getNomUrl(1)).')'; } - print ''; - print ''; - + print ''; + // Société print ''.$langs->trans('Company').''; print ''.$soc->getNomUrl(1,'compta').''; @@ -1706,8 +1754,8 @@ else // Projet if ($conf->projet->enabled) { - print ''; $langs->load('projects'); + print ''; print ''; print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + } } + + print '
'; @@ -2203,7 +2251,7 @@ else else { // Générer - if ($fac->statut == 1 && $user->rights->facture->creer) + if ($fac->statut >= 1 && $user->rights->facture->creer) { if ($fac->paye == 0) { @@ -2216,12 +2264,6 @@ else } } - // On vérifie si la facture est supprimable. Si oui, on propose bouton supprimer - if ($fac->statut == 0 && $fac->is_erasable() && $user->rights->facture->supprimer && $_GET['action'] != 'delete') - { - print ''.$langs->trans('Delete').''; - } - // Envoyer if ($fac->statut == 1 && $user->rights->facture->envoyer) { @@ -2263,6 +2305,12 @@ else // Ajouter bouton "Annuler et Créer facture remplacement" } } + + // Supprimer + if ($fac->is_erasable() && $user->rights->facture->supprimer && $_GET['action'] != 'delete') + { + print ''.$langs->trans('Delete').''; + } print ''; } @@ -2276,7 +2324,7 @@ else $filename=sanitize_string($fac->ref); $filedir=$conf->facture->dir_output . '/' . sanitize_string($fac->ref); $urlsource=$_SERVER['PHP_SELF'].'?facid='.$fac->id; - $genallowed=($fac->statut == 1 && $user->rights->facture->creer); + $genallowed=($fac->statut >= 1 && $user->rights->facture->creer); $delallowed=$user->rights->facture->supprimer; $var=true; @@ -2568,196 +2616,192 @@ else * Mode Liste * * * ***************************************************************************/ - $page = $_GET['page']; + $page =$_GET['page']; $sortorder=$_GET['sortorder']; $sortfield=$_GET['sortfield']; - $month=$_GET['month']; - $year=$_GET['year']; + $month =$_GET['month']; + $year =$_GET['year']; + $limit = $conf->liste_limit; + $offset = $limit * $page ; + + if (! $sortorder) $sortorder='DESC'; + if (! $sortfield) $sortfield='f.datef'; $facturestatic=new Facture($db); if ($page == -1) $page = 0 ; - if ($user->rights->facture->lire) + $sql = 'SELECT s.nom, s.idp,'; + $sql.= ' f.rowid as facid, f.facnumber, f.increment, f.total, f.total_ttc,'; + $sql.= $db->pdate('f.datef').' as df, '.$db->pdate('f.date_lim_reglement').' as datelimite, '; + $sql.= ' f.paye as paye, f.fk_statut'; + if (! $sall) $sql.= ' ,sum(pf.amount) as am'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'societe as s'; + $sql.= ','.MAIN_DB_PREFIX.'facture as f'; + if (! $sall) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'paiement_facture as pf ON f.rowid=pf.fk_facture '; + if ($sall) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'facturedet as fd ON f.rowid=fd.fk_facture '; + $sql.= ' WHERE f.fk_soc = s.idp'; + if ($socidp) $sql .= ' AND s.idp = '.$socidp; + if ($month > 0) $sql .= ' AND date_format(f.datef, \'%m\') = '.$month; + if ($_GET['filtre']) { - $limit = $conf->liste_limit; - $offset = $limit * $page ; - - if (! $sortorder) $sortorder='DESC'; - if (! $sortfield) $sortfield='f.datef'; - - $sql = 'SELECT s.nom, s.idp,'; - $sql.= ' f.rowid as facid, f.facnumber, f.increment, f.total, f.total_ttc,'; - $sql.= $db->pdate('f.datef').' as df, '.$db->pdate('f.date_lim_reglement').' as datelimite, '; - $sql.= ' f.paye as paye, f.fk_statut'; - if (! $sall) $sql.= ' ,sum(pf.amount) as am'; - $sql.= ' FROM '.MAIN_DB_PREFIX.'societe as s'; - $sql.= ','.MAIN_DB_PREFIX.'facture as f'; - if (! $sall) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'paiement_facture as pf ON f.rowid=pf.fk_facture '; - if ($sall) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'facturedet as fd ON f.rowid=fd.fk_facture '; - $sql.= ' WHERE f.fk_soc = s.idp'; - if ($socidp) $sql .= ' AND s.idp = '.$socidp; - if ($month > 0) $sql .= ' AND date_format(f.datef, \'%m\') = '.$month; - if ($_GET['filtre']) + $filtrearr = split(',', $_GET['filtre']); + foreach ($filtrearr as $fil) { - $filtrearr = split(',', $_GET['filtre']); - foreach ($filtrearr as $fil) + $filt = split(':', $fil); + $sql .= ' AND ' . trim($filt[0]) . ' = ' . trim($filt[1]); + } + } + if ($_GET['search_ref']) + { + $sql .= ' AND f.facnumber like \'%'.addslashes(trim($_GET['search_ref'])).'%\''; + } + if ($_GET['search_societe']) + { + $sql .= ' AND s.nom like \'%'.addslashes(trim($_GET['search_societe'])).'%\''; + } + if ($_GET['search_montant_ht']) + { + $sql .= ' AND f.total = \''.addslashes(trim($_GET['search_montant_ht'])).'\''; + } + if ($_GET['search_montant_ttc']) + { + $sql .= ' AND f.total_ttc = \''.addslashes(trim($_GET['search_montant_ttc'])).'\''; + } + if ($year > 0) + { + $sql .= ' AND date_format(f.datef, \'%Y\') = '.$year; + } + if ($_POST['sf_ref']) + { + $sql .= ' AND f.facnumber like \'%'.addslashes(trim($_POST['sf_ref'])) . '%\''; + } + if ($sall) + { + $sql .= ' AND (s.nom like \'%'.addslashes($sall).'%\' OR f.facnumber like \'%'.addslashes($sall).'%\' OR f.note like \'%'.addslashes($sall).'%\' OR fd.description like \'%'.addslashes($sall).'%\')'; + } + + $sql .= ' GROUP BY f.rowid'; + + $sql .= ' ORDER BY '; + $listfield=split(',',$sortfield); + foreach ($listfield as $key => $value) + $sql.= $listfield[$key].' '.$sortorder.','; + $sql .= ' f.rowid DESC '; + + $sql .= $db->plimit($limit+1,$offset); + + $resql = $db->query($sql); + if ($resql) + { + $num = $db->num_rows($resql); + + if ($socidp) + { + $soc = new Societe($db); + $soc->fetch($socidp); + } + + print_barre_liste($langs->trans('BillsCustomers').' '.($socidp?' '.$soc->nom:''),$page,'facture.php','&socidp='.$socidp,$sortfield,$sortorder,'',$num); + + $i = 0; + print ''; + print ''; + print_liste_field_titre($langs->trans('Ref'),$_SERVER['PHP_SELF'],'f.facnumber','','&socidp='.$socidp,'',$sortfield); + print_liste_field_titre($langs->trans('Date'),$_SERVER['PHP_SELF'],'f.datef','','&socidp='.$socidp,'align="center"',$sortfield); + print_liste_field_titre($langs->trans('Company'),$_SERVER['PHP_SELF'],'s.nom','','&socidp='.$socidp,'',$sortfield); + print_liste_field_titre($langs->trans('AmountHT'),$_SERVER['PHP_SELF'],'f.total','','&socidp='.$socidp,'align="right"',$sortfield); + print_liste_field_titre($langs->trans('AmountTTC'),$_SERVER['PHP_SELF'],'f.total_ttc','','&socidp='.$socidp,'align="right"',$sortfield); + print_liste_field_titre($langs->trans('Received'),$_SERVER['PHP_SELF'],'am','','&socidp='.$socidp,'align="right"',$sortfield); + print_liste_field_titre($langs->trans('Status'),$_SERVER['PHP_SELF'],'fk_statut,paye,am','','&socidp='.$socidp,'align="right"',$sortfield); + print ''; + + // Lignes des champs de filtre + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + + if ($num > 0) + { + $var=True; + $total=0; + $totalrecu=0; + + while ($i < min($num,$limit)) { - $filt = split(':', $fil); - $sql .= ' AND ' . $filt[0] . ' = ' . $filt[1]; - } - } - if ($_GET['search_ref']) - { - $sql .= ' AND f.facnumber like \'%'.addslashes($_GET['search_ref']).'%\''; - } - if ($_GET['search_societe']) - { - $sql .= ' AND s.nom like \'%'.addslashes($_GET['search_societe']).'%\''; - } - if ($_GET['search_montant_ht']) - { - $sql .= ' AND f.total = \''.addslashes($_GET['search_montant_ht']).'\''; - } - if ($_GET['search_montant_ttc']) - { - $sql .= ' AND f.total_ttc = \''.addslashes($_GET['search_montant_ttc']).'\''; - } - if ($year > 0) - { - $sql .= ' AND date_format(f.datef, \'%Y\') = '.$year; - } - if ($_POST['sf_ref']) - { - $sql .= ' AND f.facnumber like \'%'.addslashes($_POST['sf_ref']) . '%\''; - } - if ($sall) - { - $sql .= ' AND (s.nom like \'%'.addslashes($sall).'%\' OR f.facnumber like \'%'.addslashes($sall).'%\' OR f.note like \'%'.addslashes($sall).'%\' OR fd.description like \'%'.addslashes($sall).'%\')'; - } + $objp = $db->fetch_object($resql); + $var=!$var; - $sql .= ' GROUP BY f.rowid'; + print ''; + print ''; - $sql .= ' ORDER BY '; - $listfield=split(',',$sortfield); - foreach ($listfield as $key => $value) - $sql.= $listfield[$key].' '.$sortorder.','; - $sql .= ' f.rowid DESC '; - - $sql .= $db->plimit($limit+1,$offset); - - $resql = $db->query($sql); - if ($resql) - { - $num = $db->num_rows($resql); - - if ($socidp) - { - $soc = new Societe($db); - $soc->fetch($socidp); - } - - print_barre_liste($langs->trans('BillsCustomers').' '.($socidp?' '.$soc->nom:''),$page,'facture.php','&socidp='.$socidp,$sortfield,$sortorder,'',$num); - - $i = 0; - print '
'; + print ''; + print ' '; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print '
'.img_object($langs->trans('ShowBill'),'bill').' '; + print ''.$objp->facnumber.''.$objp->increment; + if ($objp->datelimite < (time() - $conf->facture->client->warning_delay) && ! $objp->paye && $objp->fk_statut == 1 && ! $objp->am) print img_warning($langs->trans('Late')); + print '
'; - print ''; - print_liste_field_titre($langs->trans('Ref'),$_SERVER['PHP_SELF'],'f.facnumber','','&socidp='.$socidp,'',$sortfield); - print_liste_field_titre($langs->trans('Date'),$_SERVER['PHP_SELF'],'f.datef','','&socidp='.$socidp,'align="center"',$sortfield); - print_liste_field_titre($langs->trans('Company'),$_SERVER['PHP_SELF'],'s.nom','','&socidp='.$socidp,'',$sortfield); - print_liste_field_titre($langs->trans('AmountHT'),$_SERVER['PHP_SELF'],'f.total','','&socidp='.$socidp,'align="right"',$sortfield); - print_liste_field_titre($langs->trans('AmountTTC'),$_SERVER['PHP_SELF'],'f.total_ttc','','&socidp='.$socidp,'align="right"',$sortfield); - print_liste_field_titre($langs->trans('Received'),$_SERVER['PHP_SELF'],'am','','&socidp='.$socidp,'align="right"',$sortfield); - print_liste_field_titre($langs->trans('Status'),$_SERVER['PHP_SELF'],'fk_statut,paye,am','','&socidp='.$socidp,'align="right"',$sortfield); - print ''; - - // Lignes des champs de filtre - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - - if ($num > 0) - { - $var=True; - $total=0; - $totalrecu=0; - - while ($i < min($num,$limit)) + if ($objp->df > 0 ) { - $objp = $db->fetch_object($resql); - $var=!$var; - - print ''; - print ''; - - if ($objp->df > 0 ) - { - print ''; - } - else - { - print ''; - } - print ''; - print ''; - print ''; - print ''; - - // Affiche statut de la facture - print ''; - - print ''; - $total+=$objp->total; - $total_ttc+=$objp->total_ttc; - $totalrecu+=$objp->am; - $i++; + print ''; } - - if (($offset + $num) <= $limit) + else { - // Print total - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; + print ''; } + print ''; + print ''; + print ''; + print ''; + + // Affiche statut de la facture + print ''; + + print ''; + $total+=$objp->total; + $total_ttc+=$objp->total_ttc; + $totalrecu+=$objp->am; + $i++; } - print '
'; - print ''; - print ' '; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print '
'.img_object($langs->trans('ShowBill'),'bill').' '; - print ''.$objp->facnumber.''.$objp->increment; - if ($objp->datelimite < (time() - $conf->facture->client->warning_delay) && ! $objp->paye && $objp->fk_statut == 1 && ! $objp->am) print img_warning($langs->trans('Late')); - print ''; - $y = strftime('%Y',$objp->df); - $m = strftime('%m',$objp->df); - print strftime('%d',$objp->df); - print ' '; - print substr(strftime('%B',$objp->df),0,3).''; - print ' '; - print strftime('%Y',$objp->df).'!!!'.img_object($langs->trans('ShowCompany'),'company').' '.dolibarr_trunc($objp->nom,48).''.price($objp->total).''.price($objp->total_ttc).''.price($objp->am).''; - print $facturestatic->LibStatut($objp->paye,$objp->fk_statut,5,$objp->am); - print '
'; + $y = strftime('%Y',$objp->df); + $m = strftime('%m',$objp->df); + print strftime('%d',$objp->df); + print ' '; + print substr(strftime('%B',$objp->df),0,3).''; + print ' '; + print strftime('%Y',$objp->df).'
'.$langs->trans('Total').''.price($total).''.price($total_ttc).''.price($totalrecu).' 
!!!'.img_object($langs->trans('ShowCompany'),'company').' '.dolibarr_trunc($objp->nom,48).''.price($objp->total).''.price($objp->total_ttc).''.price($objp->am).''; + print $facturestatic->LibStatut($objp->paye,$objp->fk_statut,5,$objp->am); + print '
'; - $db->free($resql); - } - else - { - dolibarr_print_error($db); + if (($offset + $num) <= $limit) + { + // Print total + print '
'.$langs->trans('Total').''.price($total).''.price($total_ttc).''.price($totalrecu).' 
'; + $db->free($resql); + } + else + { + dolibarr_print_error($db); } } } diff --git a/htdocs/discount.class.php b/htdocs/discount.class.php index 2d86c490b8a..f8cf2707486 100644 --- a/htdocs/discount.class.php +++ b/htdocs/discount.class.php @@ -50,7 +50,7 @@ class DiscountAbsolute /** - * \brief Charge objet remiset depuis la base + * \brief Charge objet remise depuis la base * \param rowid id du projet à charger * \return int <0 si ko, =0 si non trouvé, >0 si ok */ @@ -91,5 +91,31 @@ class DiscountAbsolute return -1; } } + + /** + * \brief Link the discount to a particular invoice + * \param rowid Invoice id + * \return int <0 ko, >0 ok + */ + function link_to_invoice($rowid) + { + dolibarr_syslog("Discount.class::link_to_invoice link discount ".$this->id." to invoice rowid=".$rowid); + + $sql ="UPDATE ".MAIN_DB_PREFIX."societe_remise_except"; + $sql.=" SET fk_facture = ".$rowid; + $sql.=" WHERE rowid = ".$this->id; + $resql = $this->db->query($sql); + if ($resql) + { + return 1; + } + else + { + $this->error=$this->db->error(); + dolibarr_syslog("Discount.class::link_to_invoice ".$this->error." sql=".$sql); + return -1; + } + } + } ?> diff --git a/htdocs/facture.class.php b/htdocs/facture.class.php index d378be036b8..f4d3d649b50 100644 --- a/htdocs/facture.class.php +++ b/htdocs/facture.class.php @@ -63,7 +63,8 @@ class Facture extends CommonObject var $note_public; var $statut; var $paye; // 1 si facture payée COMPLETEMENT, 0 sinon - var $close_code; // Si mis a paye sans paiement complet, code qui justifie + var $fk_facture_source; // id facture source si facture de remplacement ou avoir + var $close_code; // abandon, replaced, avoir, discount_vat var $close_note; // Commentaire si mis a paye sans paiement complet var $propalid; var $projetid; @@ -77,7 +78,7 @@ class Facture extends CommonObject // Pour board var $nbtodo; var $nbtodolate; - + var $specimen; var $error; @@ -108,21 +109,21 @@ class Facture extends CommonObject } /** - * \brief Création de la facture en base - * \param user object utilisateur qui crée + * \brief Création de la facture en base + * \param user Object utilisateur qui crée + * \return int <0 si ko, >0 si ok */ function create($user) { global $langs,$conf,$mysoc; // Nettoyage paramètres + if (! $this->type) $this->type = 0 ; + $this->ref_client=trim($this->ref_client); $this->note=trim($this->note); $this->note_public=trim($this->note_public); - $this->ref_client=trim($this->ref_client); if (! $this->remise) $this->remise = 0 ; if (! $this->mode_reglement_id) $this->mode_reglement_id = 0; - - // On positionne en mode brouillon la facture $this->brouillon = 1; dolibarr_syslog("Facture::create"); @@ -132,6 +133,45 @@ class Facture extends CommonObject $this->db->begin(); + // Verification paramètres + if ($this->type == 1) // si remplacement + { + // Controle que facture source connue + if ($this->fk_facture_source <= 0) + { + $this->error=$langs->trans("ErrorFieldRequired",$langs->trans("InvoiceReplacement")); + $this->db->rollback(); + return -10; + } + + // Charge la facture source a remplacer + $facreplaced=new Facture($this->db); + $result=$facreplaced->fetch($this->fk_facture_source); + if ($result <= 0) + { + $this->error=$langs->trans("ErrorBadInvoice"); + $this->db->rollback(); + return -11; + } + + // Controle que facture source non deja remplacee + $idreplacement=$facreplaced->getIdNextInvoice(); + if ($idreplacement != 0) + { + $this->error=$langs->trans("ErrorInvoiceAlreadyReplaced",$facreplaced->ref); + $this->db->rollback(); + return -12; + } + + $result=$facreplaced->set_canceled($user,'replaced',''); + if ($result < 0) + { + $this->error=$facreplaced->error." sql=".$sql; + $this->db->rollback(); + return -13; + } + } + // Facture récurrente if ($this->fac_rec > 0) { @@ -147,7 +187,7 @@ class Facture extends CommonObject $this->amount = $_facrec->amount; $this->remise_absolue = $_facrec->remise_absolue; $this->remise_percent = $_facrec->remise_percent; - $this->remise = $_facrec->remise; + $this->remise = $_facrec->remise; } // Definition de la date limite @@ -162,19 +202,20 @@ class Facture extends CommonObject $totalht = ($amount - $remise); $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture ('; - $sql.= ' facnumber, fk_soc, datec, amount, remise_absolue, remise_percent,'; + $sql.= ' facnumber, type, fk_soc, datec, amount, remise_absolue, remise_percent,'; $sql.= ' datef,'; $sql.= ' note,'; $sql.= ' note_public,'; $sql.= ' ref_client,'; - $sql.= ' fk_user_author, fk_projet,'; - $sql.= ' fk_cond_reglement, fk_mode_reglement, date_lim_reglement, model_pdf) '; - $sql.= " VALUES ("; - $sql.= "'$number','$socid', now(), '$totalht', '".$this->remise_absolue."'"; + $sql.= ' fk_facture_source, fk_user_author, fk_projet,'; + $sql.= ' fk_cond_reglement, fk_mode_reglement, date_lim_reglement, model_pdf)'; + $sql.= ' VALUES ('; + $sql.= "'$number', '".$this->type."', '$socid', now(), '$totalht', '".$this->remise_absolue."'"; $sql.= ",'".$this->remise_percent."', ".$this->db->idate($this->date); $sql.= ",".($this->note?"'".addslashes($this->note)."'":"null"); $sql.= ",".($this->note_public?"'".addslashes($this->note_public)."'":"null"); $sql.= ",".($this->ref_client?"'".addslashes($this->ref_client)."'":"null"); + $sql.= ",".($this->fk_facture_source?"'".addslashes($this->fk_facture_source)."'":"null"); $sql.= ",".$user->id; $sql.= ",".($this->projetid?$this->projetid:"null"); $sql.= ','.$this->cond_reglement_id; @@ -189,6 +230,7 @@ class Facture extends CommonObject $sql = 'UPDATE '.MAIN_DB_PREFIX."facture SET facnumber='(PROV".$this->id.")' WHERE rowid=".$this->id; $resql=$this->db->query($sql); + // Mise a jour lien avec propal ou commande if ($resql && $this->id && $this->propalid) { $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'fa_pr (fk_facture, fk_propal) VALUES ('.$this->id.','.$this->propalid.')'; @@ -301,6 +343,27 @@ class Facture extends CommonObject } + /** + * \brief Renvoie nom clicable (avec eventuellement le picto) + * \param withpicto Inclut le picto dans le lien + * \param option Sur quoi pointe le lien + * \return string Chaine avec URL + */ + function getNomUrl($withpicto=0,$option='') + { + global $langs; + + $result=''; + + $lien = ''; + $lienfin=''; + + if ($withpicto) $result.=($lien.img_object($langs->trans("ShowInvoice"),'bill').$lienfin.' '); + $result.=$lien.$this->ref.$lienfin; + return $result; + } + + /** * \brief Recupére l'objet facture et ses lignes de factures * \param rowid id de la facture a récupérer @@ -311,20 +374,21 @@ class Facture extends CommonObject { //dolibarr_syslog("Facture::Fetch rowid : $rowid, societe_id : $societe_id"); - $sql = 'SELECT f.fk_soc,f.facnumber,f.amount,f.tva,f.total,f.total_ttc,f.remise_percent,f.remise_absolue,f.remise'; - $sql .= ','.$this->db->pdate('f.datef').' as df, f.fk_projet'; - $sql .= ','.$this->db->pdate('f.date_lim_reglement').' as dlr'; - $sql .= ', f.note, f.note_public, f.fk_statut, f.paye, f.close_code, f.close_note, f.fk_user_author, f.model_pdf'; - $sql .= ', f.fk_mode_reglement, f.ref_client, p.code as mode_reglement_code, p.libelle as mode_reglement_libelle'; - $sql .= ', f.fk_cond_reglement, c.code as cond_reglement_code, c.libelle as cond_reglement_libelle, c.libelle_facture as cond_reglement_libelle_facture'; - $sql .= ', cf.fk_commande'; - $sql .= ' FROM '.MAIN_DB_PREFIX.'cond_reglement as c, '.MAIN_DB_PREFIX.'facture as f'; - $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON f.fk_mode_reglement = p.id'; - $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'co_fa as cf ON cf.fk_facture = f.rowid'; - $sql .= ' WHERE f.rowid='.$rowid.' AND c.rowid = f.fk_cond_reglement'; + $sql = 'SELECT f.facnumber,f.ref_client,f.type,f.fk_soc,f.amount,f.tva,f.total,f.total_ttc,f.remise_percent,f.remise_absolue,f.remise'; + $sql.= ','.$this->db->pdate('f.datef').' as df, f.fk_projet'; + $sql.= ','.$this->db->pdate('f.date_lim_reglement').' as dlr'; + $sql.= ', f.note, f.note_public, f.fk_statut, f.paye, f.close_code, f.close_note, f.fk_user_author, f.model_pdf'; + $sql.= ', f.fk_mode_reglement, p.code as mode_reglement_code, p.libelle as mode_reglement_libelle'; + $sql.= ', f.fk_cond_reglement, c.code as cond_reglement_code, c.libelle as cond_reglement_libelle, c.libelle_facture as cond_reglement_libelle_facture'; + $sql.= ', f.fk_facture_source'; + $sql.= ', cf.fk_commande'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'cond_reglement as c, '.MAIN_DB_PREFIX.'facture as f'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON f.fk_mode_reglement = p.id'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'co_fa as cf ON cf.fk_facture = f.rowid'; + $sql.= ' WHERE f.rowid='.$rowid.' AND c.rowid = f.fk_cond_reglement'; if ($societe_id > 0) { - $sql .= ' AND f.fk_soc = '.$societe_id; + $sql.= ' AND f.fk_soc = '.$societe_id; } $result = $this->db->query($sql); @@ -336,10 +400,11 @@ class Facture extends CommonObject //print strftime('%Y%m%d%H%M%S',$obj->df).' '.$obj->df.' '.dolibarr_print_date($obj->df); $this->id = $rowid; - $this->datep = $obj->dp; - $this->date = $obj->df; $this->ref = $obj->facnumber; $this->ref_client = $obj->ref_client; + $this->type = $obj->type; + $this->datep = $obj->dp; + $this->date = $obj->df; $this->amount = $obj->amount; $this->remise_percent = $obj->remise_percent; $this->remise_absolue = $obj->remise_absolue; @@ -361,6 +426,7 @@ class Facture extends CommonObject $this->cond_reglement = $obj->cond_reglement_libelle; $this->cond_reglement_facture = $obj->cond_reglement_libelle_facture; $this->projetid = $obj->fk_projet; + $this->fk_facture_source = $obj->fk_facture_source; $this->note = $obj->note; $this->note_public = $obj->note_public; $this->user_author = $obj->fk_user_author; @@ -368,15 +434,14 @@ class Facture extends CommonObject $this->commande_id = $obj->fk_commande; $this->lignes = array(); - if ($this->commande_id) { $sql = "SELECT ref"; $sql.= " FROM ".MAIN_DB_PREFIX."commande"; $sql.= " WHERE rowid = ".$this->commande_id; - + $resqlcomm = $this->db->query($sql); - + if ($resqlcomm) { $objc = $this->db->fetch_object($resqlcomm); @@ -465,7 +530,7 @@ class Facture extends CommonObject /** - * \brief Ajout d'une ligne remise fixe dans la facture, en base + * \brief Ajout en base d'une ligne remise fixe en ligne de facture * \param idremise Id de la remise fixe * \return int >0 si ok, <0 si ko */ @@ -480,9 +545,15 @@ class Facture extends CommonObject $remise=new DiscountAbsolute($this->db); $result=$remise->fetch($idremise); - if ($result > 0) { + if ($remise->fk_facture) + { + $this->error=$langs->trans("ErrorDiscountAlreadyUsed"); + $this->db->rollback(); + return -5; + } + $facligne=new FactureLigne($this->db); $facligne->fk_facture=$this->id; $facligne->fk_remise_except=$remise->id; @@ -502,36 +573,46 @@ class Facture extends CommonObject $facligne->total_tva = $tabprice[1]; $facligne->total_ttc = $tabprice[2]; - $result=$facligne->insert(); - if ($result > 0) + $lineid=$facligne->insert(); + if ($lineid > 0) { $result=$this->update_price($this->id); if ($result > 0) { + // Crée lien entre remise et ligne de facture + $result=$remise->link_to_invoice($lineid); + if ($result < 0) + { + $this->error=$remise->error; + $this->db->rollback(); + return -4; + } + $this->db->commit(); return 1; } else { - $this->db->rollback(); + $this->error=$facligne->error; + $this->db->rollback(); return -1; } } else { $this->error=$facligne->error; - $this->db->rollback(); + $this->db->rollback(); return -2; } } else { $this->db->rollback(); - return -2; + return -3; } } - - + + /** * \brief Classe la facture dans un projet * \param projid Id du projet dans lequel classer la facture @@ -574,78 +655,92 @@ class Facture extends CommonObject } /** - * \brief Supprime la facture - * \param rowid id de la facture à supprimer + * \brief Supprime la facture + * \param rowid Id de la facture à supprimer + * \return int <0 si ko, >0 si ok */ function delete($rowid) { global $user,$langs,$conf; + dolibarr_syslog("Facture.class::delete rowid=".$rowid); + $this->db->begin(); - $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_tva_sum WHERE fk_facture = '.$rowid; - if ( $this->db->query( $sql) ) + $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_tva_sum WHERE fk_facture = '.$rowid; + if ($this->db->query($sql)) { $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'fa_pr WHERE fk_facture = '.$rowid; - if ($this->db->query( $sql) ) + if ($this->db->query($sql)) { $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'co_fa WHERE fk_facture = '.$rowid; - if ($this->db->query( $sql) ) + if ($this->db->query($sql)) { - $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facturedet WHERE fk_facture = '.$rowid; - if ($this->db->query( $sql) ) + // On désaffecte de la facture les remises liées + $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; + $sql.= ' SET fk_facture = NULL WHERE fk_facture = '.$rowid; + if ($this->db->query($sql)) { - // On désaffecte de la facture les remises liées - $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; - $sql.= ' SET fk_facture = NULL WHERE fk_facture = '.$rowid; - if ($this->db->query( $sql) ) + $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facturedet WHERE fk_facture = '.$rowid; + if ($this->db->query($sql)) { - $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture WHERE rowid = '.$rowid.' AND fk_statut = 0'; - $resql=$this->db->query($sql) ; - - if ($resql) - { - // Appel des triggers - include_once(DOL_DOCUMENT_ROOT . "/interfaces.class.php"); - $interface=new Interfaces($this->db); - $result=$interface->run_triggers('BILL_DELETE',$this,$user,$langs,$conf); - // Fin appel triggers - - $this->db->commit(); - return 1; - } - else - { - $this->db->rollback(); - return -6; - } - } - else - { - $this->db->rollback(); - return -5; - } + $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture WHERE rowid = '.$rowid; + $resql=$this->db->query($sql); + if ($resql) + { + // Appel des triggers + include_once(DOL_DOCUMENT_ROOT . "/interfaces.class.php"); + $interface=new Interfaces($this->db); + $result=$interface->run_triggers('BILL_DELETE',$this,$user,$langs,$conf); + // Fin appel triggers + + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->error()." sql=".$sql; + dolibarr_syslog("Facture.class::delete ".$this->error); + $this->db->rollback(); + return -6; + } + } + else + { + $this->error=$this->db->error()." sql=".$sql; + dolibarr_syslog("Facture.class::delete ".$this->error); + $this->db->rollback(); + return -4; + } } else { + $this->error=$this->db->error()." sql=".$sql; + dolibarr_syslog("Facture.class::delete ".$this->error); $this->db->rollback(); - return -4; + return -5; } } else { + $this->error=$this->db->error()." sql=".$sql; + dolibarr_syslog("Facture.class::delete ".$this->error); $this->db->rollback(); return -3; } } else { + $this->error=$this->db->error()." sql=".$sql; + dolibarr_syslog("Facture.class::delete ".$this->error); $this->db->rollback(); return -2; } } else { + $this->error=$this->db->error()." sql=".$sql; + dolibarr_syslog("Facture.class::delete ".$this->error); $this->db->rollback(); return -1; } @@ -796,25 +891,48 @@ class Facture extends CommonObject global $conf,$langs; dolibarr_syslog("Facture.class.php::set_canceled rowid=".$this->id); + + $this->db->begin(); + $sql = 'UPDATE '.MAIN_DB_PREFIX.'facture SET'; $sql.= ' fk_statut=3'; if ($close_code) $sql.= ", close_code='".addslashes($close_code)."'"; if ($close_note) $sql.= ", close_note='".addslashes($close_note)."'"; $sql.= ' WHERE rowid = '.$this->id; - $resql = $this->db->query($sql); + $resql = $this->db->query($sql); if ($resql) { - $this->use_webcal=($conf->global->PHPWEBCALENDAR_BILLSTATUS=='always'?1:0); + // On désaffecte de la facture les remises liées + $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; + $sql.= ' SET fk_facture = NULL WHERE fk_facture = '.$this->id; + $resql=$this->db->query($sql); + if ($resql) + { + $this->use_webcal=($conf->global->PHPWEBCALENDAR_BILLSTATUS=='always'?1:0); - // Appel des triggers - include_once(DOL_DOCUMENT_ROOT . "/interfaces.class.php"); - $interface=new Interfaces($this->db); - $result=$interface->run_triggers('BILL_CANCEL',$this,$user,$langs,$conf); - // Fin appel triggers + // Appel des triggers + include_once(DOL_DOCUMENT_ROOT . "/interfaces.class.php"); + $interface=new Interfaces($this->db); + $result=$interface->run_triggers('BILL_CANCEL',$this,$user,$langs,$conf); + // Fin appel triggers + + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->error()." sql=".$sql; + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$this->db->error()." sql=".$sql; + $this->db->rollback(); + return -2; } - - return 1; } /** @@ -836,7 +954,7 @@ class Facture extends CommonObject // on vérifie si la facture est en numérotation provisoire $facref = substr($this->ref, 1, 4); - + if ($force_number) { $numfa = $force_number; @@ -910,7 +1028,7 @@ class Facture extends CommonObject { // Ligne de remise dolibarr_syslog("Facture.class::set_valid: recherche si remise ".$this->lignes[$i]->fk_remise_except." toujours dispo"); - + // On recherche si ligne de remise pas deja attribuée $sql = 'SELECT fk_facture'; $sql.= ' FROM '.MAIN_DB_PREFIX.'societe_remise_except'; @@ -923,7 +1041,7 @@ class Facture extends CommonObject if ($num >= 1) { dolibarr_syslog("Facture.class::set_valid: top ligne de remise ".$this->lignes[$i]->fk_remise_except." pour ligne de facture ".$this->lignes[$i]->rowid); - + // On met à jour ligne de remise comme utilisée $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; $sql.= ' SET fk_facture = '.$this->lignes[$i]->rowid; @@ -931,7 +1049,7 @@ class Facture extends CommonObject $resql=$this->db->query($sql); if ($resql) { - + } else { @@ -947,7 +1065,7 @@ class Facture extends CommonObject $this->error=$langs->trans("InvoiceDiscountNotAvailable"); dolibarr_syslog("Facture.class::set_valid: Error ".$this->error); break; - } + } } else { @@ -969,7 +1087,7 @@ class Facture extends CommonObject $sql = 'SELECT fk_product FROM '.MAIN_DB_PREFIX.'facturedet'; $sql.= ' WHERE fk_facture = '.$this->id; $sql.= ' AND fk_product > 0'; - + $resql = $this->db->query($sql); if ($resql) { @@ -996,7 +1114,7 @@ class Facture extends CommonObject $soc=new Societe($this->db); $soc->id = $this->socidp; $result=$soc->set_as_client(); - + $this->ref = $numfa; $this->use_webcal=($conf->global->PHPWEBCALENDAR_BILLSTATUS=='always'?1:0); @@ -1017,7 +1135,7 @@ class Facture extends CommonObject } } } - + /** * * @@ -1026,7 +1144,7 @@ class Facture extends CommonObject { $sql = "UPDATE ".MAIN_DB_PREFIX."facture SET fk_statut = 0"; $sql .= " WHERE rowid = $this->id;"; - + if ($this->db->query($sql) ) { return 1; @@ -1049,7 +1167,7 @@ class Facture extends CommonObject { $sql = "UPDATE ".MAIN_DB_PREFIX."facture SET model_pdf = '$modelpdf'"; $sql .= " WHERE rowid = $this->id AND fk_statut < 2 ;"; - + if ($this->db->query($sql) ) { $this->modelpdf=$modelpdf; @@ -1127,7 +1245,7 @@ class Facture extends CommonObject // Calcul du total TTC et de la TVA pour la ligne a partir de // qty, pu, remise_percent et txtva - // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker + // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva. $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva); $total_ht = $tabprice[0]; @@ -1157,7 +1275,7 @@ class Facture extends CommonObject $ligne->subprice=$subprice; $ligne->remise=$remise; $ligne->date_start=$date_start; - $ligne->date_end=$date_end; + $ligne->date_end=$date_end; $ligne->ventil=$ventil; $ligne->rang=-1; $ligne->info_bits=$info_bits; @@ -1166,12 +1284,12 @@ class Facture extends CommonObject $ligne->total_tva=$total_tva; $ligne->total_ttc=$total_ttc; - $result=$ligne->insert(); + $result=$ligne->insert(); if ($result > 0) { // Mise a jour informations denormalisees au niveau de la facture meme $result=$this->update_price($facid); - if ($result > 0) + if ($result > 0) { $this->db->commit(); return 1; @@ -1213,7 +1331,7 @@ class Facture extends CommonObject if ($this->brouillon) { $this->db->begin(); - + // Nettoyage paramètres $remise_percent=price2num($remise_percent); $qty=price2num($qty); @@ -1223,7 +1341,7 @@ class Facture extends CommonObject // Calcul du total TTC et de la TVA pour la ligne a partir de // qty, pu, remise_percent et txtva - // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker + // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva. $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva); $total_ht = $tabprice[0]; @@ -1246,7 +1364,7 @@ class Facture extends CommonObject $ligne=new FactureLigne($this->db); $ligne->rowid=$rowid; $ligne->fetch($rowid); - + $ligne->desc=$desc; $ligne->price=$price; $ligne->qty=$qty; @@ -1255,12 +1373,12 @@ class Facture extends CommonObject $ligne->subprice=$subprice; $ligne->remise=$remise; $ligne->date_start=$date_start; - $ligne->date_end=$date_end; + $ligne->date_end=$date_end; $ligne->total_ht=$total_ht; $ligne->total_tva=$total_tva; $ligne->total_ttc=$total_ttc; - $result=$ligne->update(); + $result=$ligne->update(); if ($result > 0) { // Mise a jour info denormalisees au niveau facture @@ -1282,16 +1400,45 @@ class Facture extends CommonObject } /** - * \brief Supprime une ligne facture de la base - * \param rowid id de la ligne de facture a supprimer + * \brief Supprime une ligne facture de la base + * \param rowid Id de la ligne de facture a supprimer */ function deleteline($rowid) { + dolibarr_syslog("Facture.class::deleteline rowid=".$rowid." ".$this->brouillon); + if ($this->brouillon) { + $this->db->begin(); + + // Libere remise liee a ligne de facture + $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; + $sql.= ' SET fk_facture = NULL where fk_facture = '.$rowid; + $result = $this->db->query($sql); + if ($result < 0) + { + $this->error=$this->db->error(); + dolibarr_syslog("Facture.class::deleteline Error ".$this->error); + $this->db->rollback(); + return -1; + } + + // Efface ligne de facture $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facturedet WHERE rowid = '.$rowid; - $result = $this->db->query( $sql); - $this->update_price($this->id); + $result = $this->db->query($sql); + if ($result < 0) + { + $this->error=$this->db->error(); + dolibarr_syslog("Facture.class::deleteline Error ".$this->error); + $this->db->rollback(); + return -1; + } + + $result=$this->update_price($this->id); + + $this->db->commit(); + + return 1; } } @@ -1522,6 +1669,50 @@ class Facture extends CommonObject } } + /** + * \brief Renvoie l'id de la facture qui la remplace + * \return int <0 si ko, 0 si aucune facture ne remplace, id facture sinon + */ + function getIdNextInvoice() + { + $sql = 'SELECT rowid'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'facture'; + $sql.= ' WHERE fk_facture_source = '.$this->id; + $resql=$this->db->query($sql); + if ($resql) + { + $obj = $this->db->fetch_object($resql); + if ($obj) + { + // Si il y en a + return $obj->rowid; + } + else + { + // Si aucune facture ne remplace + return 0; + } + } + else + { + return -1; + } + } + + /** + * \brief Retourne le libellé du type de facture + * \return string Libelle + */ + function getLibType() + { + global $langs; + if ($this->type == 0) return $langs->trans("InvoiceStandard"); + if ($this->type == 1) return $langs->trans("InvoiceReplacement"); + if ($this->type == 2) return $langs->trans("InvoiceAvoir"); + return $langs->trans("Unknown"); + } + + /** * \brief Retourne le libellé du statut d'une facture (brouillon, validée, abandonnée, payée) * \param mode 0=libellé long, 1=libellé court, 2=Picto + Libellé court, 3=Picto, 4=Picto + Libellé long @@ -1859,7 +2050,7 @@ class Facture extends CommonObject $ventilExportCompta++; } } - + if ($ventilExportCompta <> 0) { return 1; @@ -1869,8 +2060,8 @@ class Facture extends CommonObject return 0; } } - - + + /** * \brief Renvoi si une facture peut etre supprimée complètement. * La règle est la suivante: @@ -1886,7 +2077,7 @@ class Facture extends CommonObject $facref = substr($this->ref, 1, 4); // Si facture non brouillon et non provisoire - if ($facref != 'PROV' && $conf->compta->enabled && $conf->global->FACTURE_ENABLE_EDITDELETE) + if ($facref != 'PROV' && ! $conf->comptaexpert->enabled && $conf->global->FACTURE_ENABLE_EDITDELETE) { // On ne peut supprimer que la dernière facture validée // pour ne pas avoir de trou dans la numérotation @@ -1898,7 +2089,7 @@ class Facture extends CommonObject { $maxfacnumber = $this->db->fetch_row($resql); } - + $ventilExportCompta = $this->getVentilExportCompta(); // Si derniere facture et si non ventilée, on peut supprimer @@ -1911,16 +2102,52 @@ class Facture extends CommonObject { return 1; } - + return 0; } - - - /** - * \brief Créé une demande de prélèvement + + + /** + * \brief Renvoi liste des factures remplacables + * Statut validee + aucun paiement + non paye + * \param socid Id societe + * \return array Tableau des factures ($id => $ref) + */ + function list_replacable_invoices($socid=0) + { + global $conf; + + $return = array(); + + $sql = "SELECT f.rowid, f.facnumber"; + $sql.= " FROM ".MAIN_DB_PREFIX."facture as f"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON f.rowid = pf.fk_facture"; + $sql.= " WHERE f.fk_statut = 1 AND f.paye = 0 AND pf.fk_paiement IS NULL"; + if ($socid > 0) $sql.=" AND f.fk_soc = ".$socid; + $sql.= " ORDER BY f.facnumber"; + + dolibarr_syslog("Facture.class::list_replacable_invoices sq=$sql"); + $resql=$this->db->query($sql); + if ($resql) + { + while ($obj=$this->db->fetch_object($resql)) + { + $return[$obj->rowid]=$obj->facnumber; + } + + return $return; + } + else + { + return -1; + } + } + + /** + * \brief Créé une demande de prélèvement * \param user Utilisateur créant la demande * \return int <0 si ko, >0 si ok - */ + */ function demande_prelevement($user) { dolibarr_syslog("Facture::demande_prelevement $this->statut $this->paye $this->mode_reglement_id"); @@ -2299,7 +2526,7 @@ class FactureLigne var $libelle; // Label produit var $product_desc; // Description produit - + /** * \brief Constructeur d'objets ligne de facture * \param DB handler d'accès base de donnée @@ -2349,7 +2576,7 @@ class FactureLigne $this->fk_code_ventilation = $objp->fk_code_ventilation; $this->fk_export_compta = $objp->fk_export_compta; $this->rang = $objp->rang; - + $this->ref = $objp->product_ref; $this->libelle = $objp->product_libelle; $this->product_desc = $objp->product_desc; @@ -2391,7 +2618,7 @@ class FactureLigne return -1; } } - + // Insertion dans base de la ligne $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facturedet'; $sql.= ' (fk_facture, description, price, qty, tva_taux,'; @@ -2429,8 +2656,10 @@ class FactureLigne $resql=$this->db->query($sql); if ($resql) { + $this->rowid=$this->db->last_insert_id(MAIN_DB_PREFIX.'facturedet'); + $this->db->commit(); - return 1; + return $this->rowid; } else { @@ -2440,8 +2669,8 @@ class FactureLigne return -2; } } - - + + /** * \brief Mise a jour de l'objet ligne de facture en base * \return int <0 si ko, >0 si ok @@ -2478,7 +2707,7 @@ class FactureLigne if ($resql) { $this->db->commit(); - return 1; + return 1; } else { @@ -2488,7 +2717,7 @@ class FactureLigne return -2; } } - + /** * \brief Mise a jour en base des champs total_xxx de ligne de facture * \return int <0 si ko, >0 si ok @@ -2510,7 +2739,7 @@ class FactureLigne if ($resql) { $this->db->commit(); - return 1; + return 1; } else { @@ -2519,7 +2748,7 @@ class FactureLigne $this->db->rollback(); return -2; } - } + } } ?> diff --git a/htdocs/langs/en_US/bills.lang b/htdocs/langs/en_US/bills.lang index 2789463247a..10956f8c8ee 100644 --- a/htdocs/langs/en_US/bills.lang +++ b/htdocs/langs/en_US/bills.lang @@ -8,6 +8,17 @@ BillsCustomersUnpayedForCompany=Unpayed customers' invoices for %s BillsSuppliersUnpayed=Unpayed suppliers' invoices BillsUnpayed=Unpayed BillsStatistics=Invoices statistics +InvoiceStandard=Standard invoice +InvoiceStandardAsk=Standard invoice +InvoiceStandardDesc=This kind of invoice is the common invoice. +InvoiceReplacement=Replacement invoice. Must replace invoice with reference +InvoiceReplacementAsk=Replacement invoice for following invoice +InvoiceReplacementDesc=Replacement invoice is used to cancel and replace completely an invoice with no paiement already recevided.
Reference of canceled invoice is required. +InvoiceAvoir=Avoir invoice +InvoiceAvoirAsk=Avoir invoice +InvoiceAvoirDesc=La facture d'avoir est une facture négative destinée à compenser une facture comportant un montant supérieur à ce qui a été ou sera réellement payé (toutes causes possibles). +ReplaceInvoice=Replace invoice %s +ReplacedByInvoice=Replaced by invoice %s CardBill=Invoice card Invoice=Invoice Invoices=Invoices @@ -68,6 +79,8 @@ ErrorVATIntraNotConfigured=Intracommunautary VAT number not yet defined ErrorNoPaiementModeConfigured=No paiment mode yet defined ErrorCreateBankAccount=Creat a bank account then go to Setup panel of Invoice module to define paiement modes ErrorBillNotFound=Invoice %s does not exists +ErrorInvoiceAlreadyReplaced=Error, invoice %s has already been replaced +ErrorDiscountAlreadyUsed=Error, discount already used BillFrom=From BillTo=Bill to ActionsOnBill=Actions on invoice @@ -99,6 +112,7 @@ ValidateBill=Validate invoice NumberOfBills=Nb of invoices NumberOfBillsByMonth=Nb of invoices by month ShowBill=Show invoice +ShowInvoice=Show invoice ShowPayment=Show payment File=File AlreadyPayed=Already payed diff --git a/htdocs/langs/fr_FR/bills.lang b/htdocs/langs/fr_FR/bills.lang index 67eb3aa5532..b9012415c04 100644 --- a/htdocs/langs/fr_FR/bills.lang +++ b/htdocs/langs/fr_FR/bills.lang @@ -8,6 +8,17 @@ BillsCustomersUnpayedForCompany=Factures clients impay BillsSuppliersUnpayed=Factures fournisseurs impayées BillsUnpayed=Impayées BillsStatistics=Statistiques factures +InvoiceStandard=Facture standard +InvoiceStandardAsk=Facture standard +InvoiceStandardDesc=Ce type de facture est la facture traditionnelle. On l'appelle aussi facture de doit. +InvoiceReplacement=Facture de remplacement +InvoiceReplacementAsk=Facture de remplacement de la facture suivante +InvoiceReplacementDesc=La facture de remplacement sert à annuler et remplacer une facture existante sur laquelle aucun paiement n'a encore eu lieu.
La référence de la facture qui doit être annulée est obligatoire. +InvoiceAvoir=Facture avoir +InvoiceAvoirAsk=Facture avoir +InvoiceAvoirDesc=La facture d'avoir est une facture négative destinée à compenser une facture comportant un montant supérieur à ce qui a été ou sera réellement payé (toutes causes possibles). +ReplaceInvoice=Remplace la facture %s +ReplacedByInvoice=Remplacée par la facture %s CardBill=Fiche facture Invoice=Facture Invoices=Factures @@ -68,6 +79,8 @@ ErrorVATIntraNotConfigured=Num ErrorNoPaiementModeConfigured=Aucun mode de règlement défini ErrorCreateBankAccount=Créer un compte bancaire puis aller dans la configuration du module facture pour définir les modes de règlement ErrorBillNotFound=Facture %s inexistante +ErrorInvoiceAlreadyReplaced=Erreur, la facture %s a déjà été remplacée +ErrorDiscountAlreadyUsed=Erreur, la remise a déjà été attribuée BillFrom=Émetteur BillTo=Adressé à ActionsOnBill=Actions sur la facture @@ -99,6 +112,7 @@ ValidateBill=Valider facture NumberOfBills=Nb de factures NumberOfBillsByMonth=Nb de factures par mois ShowBill=Afficher facture +ShowInvoice=Afficher facture ShowPayment=Afficher paiement File=Fichier AlreadyPayed=Déjà réglé diff --git a/htdocs/lib/functions.inc.php b/htdocs/lib/functions.inc.php index a84b3b2ab89..24b33232130 100644 --- a/htdocs/lib/functions.inc.php +++ b/htdocs/lib/functions.inc.php @@ -762,8 +762,8 @@ function img_help($usehelpcursor=1,$usealttitle=1) $s ='theme.'/img/info.png" border="0"'; - if ($usealttitle) $s.=' alt="'.$langs->trans("Info").'" title="'.$langs->trans("Info"); - $s.='">'; + if ($usealttitle) $s.=' alt="'.$langs->trans("Info").'" title="'.$langs->trans("Info").'"'; + $s.='>'; return $s; }