diff --git a/htdocs/compta/facture/class/facture-rec.class.php b/htdocs/compta/facture/class/facture-rec.class.php index b0a7bab2899..14ec77600c7 100644 --- a/htdocs/compta/facture/class/facture-rec.class.php +++ b/htdocs/compta/facture/class/facture-rec.class.php @@ -52,6 +52,11 @@ class FactureRec extends Facture var $db_table; var $propalid; + var $date_last_gen; + var $next_gen; + var $nb_gen_done; + var $nb_gen_max; + var $rang; var $special_code; @@ -214,17 +219,17 @@ class FactureRec extends Facture /** - * Recupere l'objet facture et ses lignes de factures + * Load object and lines * * @param int $rowid Id of object to load - * @param string $ref Reference of invoice + * @param string $ref Reference of recurring invoice * @param string $ref_ext External reference of invoice * @param int $ref_int Internal reference of other object * @return int >0 if OK, <0 if KO, 0 if not found */ function fetch($rowid, $ref='', $ref_ext='', $ref_int='') { - $sql = 'SELECT f.titre,f.fk_soc,f.amount,f.tva,f.total,f.total_ttc,f.remise_percent,f.remise_absolue,f.remise'; + $sql = 'SELECT f.rowid, f.titre, f.fk_soc, f.amount, f.tva, f.total, f.total_ttc, f.remise_percent, f.remise_absolue, f.remise'; $sql.= ', f.date_lim_reglement as dlr'; $sql.= ', f.note_private, f.note_public, f.fk_user_author'; $sql.= ', f.fk_mode_reglement, f.fk_cond_reglement, f.fk_projet'; @@ -232,19 +237,18 @@ class FactureRec extends Facture $sql.= ', f.frequency, f.unit_frequency, f.date_when, f.date_last_gen, f.nb_gen_done, f.nb_gen_max, f.usenewprice, f.auto_validate'; $sql.= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle'; $sql.= ', c.code as cond_reglement_code, c.libelle as cond_reglement_libelle, c.libelle_facture as cond_reglement_libelle_doc'; - $sql.= ', el.fk_source'; + //$sql.= ', el.fk_source'; $sql.= ' FROM '.MAIN_DB_PREFIX.'facture_rec as f'; $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as c ON f.fk_cond_reglement = c.rowid'; $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON f.fk_mode_reglement = p.id'; - $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture'"; - $sql.= ' WHERE f.rowid='.$rowid; - if ($ref) $sql.= " AND f.titre='".$this->db->escape($ref)."'"; + //$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = f.rowid AND el.targettype = 'facture'"; + if ($rowid) $sql.= ' WHERE f.rowid='.$rowid; + elseif ($ref) $sql.= " WHERE f.titre='".$this->db->escape($ref)."'"; /* This field are not used for template invoice if ($ref_ext) $sql.= " AND f.ref_ext='".$this->db->escape($ref_ext)."'"; if ($ref_int) $sql.= " AND f.ref_int='".$this->db->escape($ref_int)."'"; */ - dol_syslog(get_class($this)."::fetch rowid=".$rowid, LOG_DEBUG); $result = $this->db->query($sql); if ($result) { @@ -252,7 +256,7 @@ class FactureRec extends Facture { $obj = $this->db->fetch_object($result); - $this->id = $rowid; + $this->id = $obj->rowid; $this->titre = $obj->titre; $this->ref = $obj->titre; $this->ref_client = $obj->ref_client; @@ -290,8 +294,8 @@ class FactureRec extends Facture $this->special_code = $obj->special_code; $this->frequency = $obj->frequency; $this->unit_frequency = $obj->unit_frequency; - $this->date_when = $obj->date_when; - $this->date_last_gen = $obj->date_last_gen; + $this->date_when = $this->db->jdate($obj->date_when); + $this->date_last_gen = $this->db->jdate($obj->date_last_gen); $this->nb_gen_done = $obj->nb_gen_done; $this->nb_gen_max = $obj->nb_gen_max; $this->usenewprice = $obj->usenewprice; @@ -305,14 +309,14 @@ class FactureRec extends Facture $result=$this->fetch_lines(); if ($result < 0) { - $this->error=$this->db->error(); + $this->error=$this->db->lasterror(); return -3; } return 1; } else { - $this->error='Bill with id '.$rowid.' not found sql='.$sql; + $this->error='Bill with id '.$rowid.' or ref '.$ref.' not found sql='.$sql; dol_syslog('Facture::Fetch Error '.$this->error, LOG_ERR); return -2; } @@ -336,7 +340,7 @@ class FactureRec extends Facture $sql.= ' l.remise, l.remise_percent, l.subprice,'; $sql.= ' l.total_ht, l.total_tva, l.total_ttc,'; $sql.= ' l.rang, l.special_code,'; - $sql.= ' l.fk_unit,'; + $sql.= ' l.fk_unit, l.fk_contract_line,'; $sql.= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc'; $sql.= ' FROM '.MAIN_DB_PREFIX.'facturedet_rec as l'; $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON l.fk_product = p.rowid'; @@ -380,7 +384,8 @@ class FactureRec extends Facture $line->rang = $objp->rang; $line->special_code = $objp->special_code; $line->fk_unit = $objp->fk_unit; - + $line->fk_contract_line = $objp->fk_contract_line; + // Ne plus utiliser $line->price = $objp->price; $line->remise = $objp->remise; @@ -578,53 +583,101 @@ class FactureRec extends Facture function getNextDate() { if (empty($this->date_when)) return false; - return dol_time_plus_duree(strtotime($this->date_when), $this->frequency, $this->unit_frequency); + return dol_time_plus_duree($this->date_when, $this->frequency, $this->unit_frequency); } /** - * Create all recurrents invoices + * Create all recurrents invoices. + * A result may also be provided into this->output * - * @return int number of created invoices + * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) */ function createRecurringInvoices() { - global $db,$user; + global $langs, $db, $user; + + $langs->load("bills"); $nb_create=0; - $today = date('Y-m-d 23:59:59'); + $now = dol_now(); + $tmparray=dol_getdate($now); + $today = dol_mktime(23,59,59,$tmparray['mon'],$tmparray['mday'],$tmparray['year']); // Today is last second of current day + dol_syslog("createRecurringInvoices"); $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'facture_rec'; - $sql.= ' WHERE date_when IS NOT NULL AND frequency > 0'; - $sql.= ' AND date_when <= "'.$db->escape($today).'"'; - $sql.= ' AND nb_gen_done < nb_gen_max'; + $sql.= ' WHERE frequency > 0'; // A recurring invoice is an invoice with a frequency + $sql.= " AND (date_when IS NULL OR date_when <= '".$db->idate($today)."')"; + $sql.= ' AND (nb_gen_done < nb_gen_max OR nb_gen_max = 0)'; + //print $sql;exit; $resql = $db->query($sql); if ($resql) { - while ($line = $db->fetch_object($resql)) + $i=0; + $num = $db->num_rows($resql); + + if ($num) $this->output.=$langs->trans("FoundXQualifiedRecurringInvoiceTemplate", $num)."\n"; + else $this->output.=$langs->trans("NoQualifiedRecurringInvoiceTemplateFound"); + + while ($i < $num) { + $line = $db->fetch_object($resql); + + $db->begin(); + $facturerec = new FactureRec($db); $facturerec->fetch($line->rowid); - $facture = new Facture($db); - $result = $facture->createFromRec($user, $facturerec); - - // >0 create and validate if auto_validate - // =0 create but not validate if auto_validate - // <0 broken - if ($result >= 0) + dol_syslog("createRecurringInvoices Process invoice template id=".$facturerec->id.", ref=".$facturerec->ref); + + $error=0; + + $facture = new Facture($db); + $facture->fac_rec = $facturerec->id; // We will create $facture from this recurring invoice + $facture->type = self::TYPE_STANDARD; + $facture->brouillon = 1; + $facture->date = $now; + $facture->socid = $facturerec->socid; + + $invoiceidgenerated = $facture->create($user); // This will also update fields of recurring invoice + if ($invoiceidgenerated <= 0) + { + $this->errors = $facture->errors; + $this->error = $facture->error; + $error++; + } + if (! $error && $facturerec->auto_validate) + { + $result = $facture->validate($user); + if ($result <= 0) + { + $this->errors = $facture->errors; + $this->error = $facture->error; + $error++; + } + } + + if (! $error && $invoiceidgenerated >= 0) { - $next_date = $facturerec->getNextDate(); - $facturerec->setNextDate($next_date,1); - + $db->commit(); + dol_syslog("createRecurringInvoices Process invoice template ".$facturerec->ref." is finished with a success generation"); $nb_create++; + $this->output.=$langs->trans("InvoiceGeneratedFromTemplate", $facture->ref, $facturerec->ref)."\n"; + } + else + { + $db->rollback(); } + $i++; } } + else dol_print_error($db); - return $nb_create; + $this->output=trim($this->output); + + return $error?$error:0; } /** diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index dd1d9b6ca8c..8b3f43fd26e 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -217,6 +217,7 @@ class Facture extends CommonInvoice /** * Create invoice in database * Note: this->ref can be set or empty. If empty, we will use "(PROV)" + * Note: this->fac_rec must be set to create from recurring invoice * * @param User $user Object user that create * @param int $notrigger 1=Does not execute triggers, 0 otherwise @@ -270,16 +271,17 @@ class Facture extends CommonInvoice $this->db->begin(); - // Create invoice from a predefined invoice + // Create invoice from a template invoice if ($this->fac_rec > 0) { require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php'; $_facrec = new FactureRec($this->db); $result=$_facrec->fetch($this->fac_rec); + $this->socid = $_facrec->socid; + $this->fk_project = $_facrec->fk_project; $this->fk_account = $_facrec->fk_account; - $this->note_private = $_facrec->note_private; $this->cond_reglement_id = $_facrec->cond_reglement_id; $this->mode_reglement_id = $_facrec->mode_reglement_id; $this->remise_absolue = $_facrec->remise_absolue; @@ -287,14 +289,31 @@ class Facture extends CommonInvoice $this->fk_incoterms = $_facrec->fk_incoterms; $this->location_incoterms= $_facrec->location_incoterms; + $this->note_public = $_facrec->note_public; + $this->note_private = $_facrec->note_private; + // Clean parameters if (! $this->type) $this->type = self::TYPE_STANDARD; $this->ref_client=trim($this->ref_client); - $this->note_private=trim($this->note_private); $this->note_public=trim($this->note_public); + $this->note_private=trim($this->note_private); + $this->note_private=dol_concatdesc($facture->note_private, $langs->trans("GeneratedFromRecurringInvoice", $_facrec->ref)); + //if (! $this->remise) $this->remise = 0; if (! $this->mode_reglement_id) $this->mode_reglement_id = 0; $this->brouillon = 1; + + $forceduedate = $this->calculate_date_lim_reglement(); + + // Update date and number of last generation of recurring template invoice, before inserting new invoice + if ($_facrec->frequency > 0) + { + $_facrec->nb_gen_done++; + $next_date = $_facrec->getNextDate(); // Calculate next date + $_facrec->setValueFrom('date_last_gen', $now, '', null, 'date'); + $_facrec->setValueFrom('nb_gen_done', $_facrec->nb_gen_done + 1); + $_facrec->setNextDate($next_date,1); + } } // Define due date if not already defined @@ -919,60 +938,6 @@ class Facture extends CommonInvoice else return -1; } - /** - * Create a new invoice in database from facturerec - * - * @param User $user Object user that ask creation - * @param FactureRec $facturerec Object facturerec source - * @return int <0 if KO, 0 if not validate, >0 if OK - */ - function createFromRec($user, $facturerec) - { - - // Clean parameters - $this->type = self::TYPE_STANDARD; - $this->brouillon = 1; - - // Charge facture source - $facture=new Facture($facturerec->db); - - $facture->socid = $facturerec->socid; - $facture->date = dol_mktime(12, 0, 0, date('m'), date('d'), date('Y')); - $facture->note_public = $facturerec->note_public; - $facture->note_private = $facturerec->note_private; - $facture->fk_project = $facturerec->fk_project; - $facture->fk_account = $facturerec->fk_account; - $facture->cond_reglement_id = $facturerec->cond_reglement_id; - $facture->mode_reglement_id = $facturerec->mode_reglement_id; - - $new_date_lim_reglement = $facture->calculate_date_lim_reglement(); - $facture->date_lim_reglement = $new_date_lim_reglement; - - $facture->remise_absolue = $facturerec->remise_absolue; - $facture->remise_percent = $facturerec->remise_percent; - - $facture->lines = $facturerec->lines; // Tableau des lignes de factures - - // Loop on each line of new invoice - foreach($facture->lines as $i => $line) - { - $facture->lines[$i]->fk_prev_id = $facturerec->lines[$i]->rowid; - } - - dol_syslog(get_class($this)."::createFromRec socid=".$this->socid." nboflines=".count($facture->lines)); - - $facid = $facture->create($user); - if ($facid <= 0) return -1; - - if ($facturerec->auto_validate) - { - $result = $facture->validate($user); - if ($result<=0) return 0; - } - - return $facid; - } - /** * Return clicable link of object (with eventually picto) * diff --git a/htdocs/compta/facture/fiche-rec.php b/htdocs/compta/facture/fiche-rec.php index 350682ec619..adcdeb64744 100644 --- a/htdocs/compta/facture/fiche-rec.php +++ b/htdocs/compta/facture/fiche-rec.php @@ -38,6 +38,7 @@ $langs->load('compta'); // Security check $id=(GETPOST('facid','int')?GETPOST('facid','int'):GETPOST('id','int')); +$ref=GETPOST('ref','alpha'); $action=GETPOST('action', 'alpha'); if ($user->societe_id) $socid=$user->societe_id; $objecttype = 'facture_rec'; @@ -58,9 +59,9 @@ if ($sortfield == "") $sortfield="f.datef"; $object = new FactureRec($db); -if ($id > 0 && $action != 'create' && $action != 'add') +if (($id > 0 || $ref) && $action != 'create' && $action != 'add') { - $ret = $object->fetch($id); + $ret = $object->fetch($id, $ref); if (!$ret) { setEventMessages($langs->trans("ErrorRecordNotFound"), null, 'errors'); @@ -192,6 +193,7 @@ $permissionnote=$user->rights->facture->creer; // Used by the include of actions include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not includ_once + /* * View */ @@ -201,6 +203,11 @@ llxHeader('',$langs->trans("RepeatableInvoices"),'ch-facture.html#s-fac-facture- $form = new Form($db); $companystatic = new Societe($db); +$now = dol_now(); +$tmparray=dol_getdate($now); +$today = dol_mktime(23,59,59,$tmparray['mon'],$tmparray['mday'],$tmparray['year']); // Today is last second of current day + + /* * Create mode */ @@ -211,7 +218,7 @@ if ($action == 'create') $object = new Facture($db); // Source invoice $product_static = new Product($db); - if ($object->fetch($id) > 0) + if ($object->fetch($id, $ref) > 0) { print '