/** * Tag invoice as validated + call trigger BILL_VALIDATE * Object must have lines loaded with fetch_lines * * @param User $user Object user that validate * @param string $force_number Reference to force on invoice * @param int $idwarehouse Id of warehouse to use for stock decrease if option to decreasenon stock is on (0=no decrease) * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers * @return int <0 if KO, >0 if OK */ function validate($user, $force_number = '', $idwarehouse = 0, $notrigger = 0) { global $conf, $langs; require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; $now = dol_now(); $error = 0; dol_syslog(get_class($this) . '::validate user='******', force_number=' . $force_number . ', idwarehouse=' . $idwarehouse); // Check parameters if (!$this->brouillon) { dol_syslog(get_class($this) . "::validate no draft status", LOG_WARNING); return 0; } if (empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->facture->creer) || !empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->facture->invoice_advance->validate)) { $this->error = 'Permission denied'; dol_syslog(get_class($this) . "::validate " . $this->error, LOG_ERR); return -1; } $this->db->begin(); $this->fetch_thirdparty(); $this->fetch_lines(); // Check parameters if ($this->type == self::TYPE_REPLACEMENT) { // 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 par une autre $idreplacement = $facreplaced->getIdReplacingInvoice('validated'); if ($idreplacement && $idreplacement != $this->id) { $facreplacement = new Facture($this->db); $facreplacement->fetch($idreplacement); $this->error = $langs->trans("ErrorInvoiceAlreadyReplaced", $facreplaced->ref, $facreplacement->ref); $this->db->rollback(); return -12; } $result = $facreplaced->set_canceled($user, 'replaced', ''); if ($result < 0) { $this->error = $facreplaced->error; $this->db->rollback(); return -13; } } // Define new ref if ($force_number) { $num = $force_number; } else { if (preg_match('/^[\\(]?PROV/i', $this->ref) || empty($this->ref)) { if (!empty($conf->global->FAC_FORCE_DATE_VALIDATION)) { $this->date = dol_now(); $this->date_lim_reglement = $this->calculate_date_lim_reglement(); } $num = $this->getNextNumRef($this->client); } else { $num = $this->ref; } } $this->newref = $num; if ($num) { $this->update_price(1); // Validate $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture'; $sql .= " SET facnumber='" . $num . "', fk_statut = " . self::STATUS_VALIDATED . ", fk_user_valid = " . $user->id . ", date_valid = '" . $this->db->idate($now) . "'"; if (!empty($conf->global->FAC_FORCE_DATE_VALIDATION)) { $sql .= ", datef='" . $this->db->idate($this->date) . "'"; $sql .= ", date_lim_reglement='" . $this->db->idate($this->date_lim_reglement) . "'"; } $sql .= ' WHERE rowid = ' . $this->id; dol_syslog(get_class($this) . "::validate", LOG_DEBUG); $resql = $this->db->query($sql); if (!$resql) { dol_print_error($this->db); $error++; } // On verifie si la facture etait une provisoire if (!$error && preg_match('/^[\\(]?PROV/i', $this->ref)) { // La verif qu'une remise n'est pas utilisee 2 fois est faite au moment de l'insertion de ligne } if (!$error) { // Define third party as a customer $result = $this->client->set_as_client(); // Si active on decremente le produit principal et ses composants a la validation de facture if ($this->type != self::TYPE_DEPOSIT && $result >= 0 && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_BILL) && $idwarehouse > 0) { require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php'; $langs->load("agenda"); // Loop on each line $cpt = count($this->lines); for ($i = 0; $i < $cpt; $i++) { if ($this->lines[$i]->fk_product > 0) { $mouvP = new MouvementStock($this->db); $mouvP->origin =& $this; // We decrease stock for product if ($this->type == self::TYPE_CREDIT_NOTE) { $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("InvoiceValidatedInDolibarr", $num)); } else { $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceValidatedInDolibarr", $num)); } if ($result < 0) { $error++; } } } } } // Trigger calls if (!$error && !$notrigger) { // Call trigger $result = $this->call_trigger('BILL_VALIDATE', $user); if ($result < 0) { $error++; } // End call triggers } if (!$error) { $this->oldref = $this->ref; // Rename directory if dir was a temporary ref if (preg_match('/^[\\(]?PROV/i', $this->ref)) { // Rename of object directory ($this->ref = old ref, $num = new ref) // to not lose the linked files $oldref = dol_sanitizeFileName($this->ref); $newref = dol_sanitizeFileName($num); $dirsource = $conf->facture->dir_output . '/' . $oldref; $dirdest = $conf->facture->dir_output . '/' . $newref; if (file_exists($dirsource)) { dol_syslog(get_class($this) . "::validate rename dir " . $dirsource . " into " . $dirdest); if (@rename($dirsource, $dirdest)) { dol_syslog("Rename ok"); // Rename docs starting with $oldref with $newref $listoffiles = dol_dir_list($conf->facture->dir_output . '/' . $newref, 'files', 1, '^' . preg_quote($oldref, '/')); foreach ($listoffiles as $fileentry) { $dirsource = $fileentry['name']; $dirdest = preg_replace('/^' . preg_quote($oldref, '/') . '/', $newref, $dirsource); $dirsource = $fileentry['path'] . '/' . $dirsource; $dirdest = $fileentry['path'] . '/' . $dirdest; @rename($dirsource, $dirdest); } } } } } // Set new ref and define current statut if (!$error) { $this->ref = $num; $this->facnumber = $num; $this->statut = self::STATUS_VALIDATED; $this->brouillon = 0; $this->date_validation = $now; $i = 0; $final = True; while ($i < count($this->lines) && $final == True) { $final = $this->lines[$i]->situation_percent == 100; $i++; } if ($final) { $this->setFinal(); } } } else { $error++; } if (!$error) { $this->db->commit(); return 1; } else { $this->db->rollback(); return -1; } }
/** * Tag invoice as validated + call trigger BILL_VALIDATE * Object must have lines loaded with fetch_lines * * @param User $user Object user that validate * @param string $force_number Reference to force on invoice * @param int $idwarehouse Id of warehouse to use for stock decrease * @return int <0 if KO, >0 if OK */ function validate($user, $force_number = '', $idwarehouse = 0) { global $conf, $langs; require_once DOL_DOCUMENT_ROOT . "/core/lib/files.lib.php"; $now = dol_now(); $error = 0; dol_syslog(get_class($this) . '::validate user='******', force_number=' . $force_number . ', idwarehouse=' . $idwarehouse, LOG_WARNING); // Check parameters if (!$this->brouillon) { dol_syslog(get_class($this) . "::validate no draft status", LOG_WARNING); return 0; } if (!$user->rights->facture->valider) { $this->error = 'Permission denied'; dol_syslog(get_class($this) . "::validate " . $this->error, LOG_ERR); return -1; } $this->db->begin(); $this->fetch_thirdparty(); $this->fetch_lines(); // Check parameters if ($this->type == 1) { // 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 par une autre $idreplacement = $facreplaced->getIdReplacingInvoice('validated'); if ($idreplacement && $idreplacement != $this->id) { $facreplacement = new Facture($this->db); $facreplacement->fetch($idreplacement); $this->error = $langs->trans("ErrorInvoiceAlreadyReplaced", $facreplaced->ref, $facreplacement->ref); $this->db->rollback(); return -12; } $result = $facreplaced->set_canceled($user, 'replaced', ''); if ($result < 0) { $this->error = $facreplaced->error; $this->db->rollback(); return -13; } } // Define new ref if ($force_number) { $num = $force_number; } else { if (preg_match('/^[\\(]?PROV/i', $this->ref)) { if (!empty($conf->global->FAC_FORCE_DATE_VALIDATION)) { $this->date = dol_now(); $this->date_lim_reglement = $this->calculate_date_lim_reglement(); } $num = $this->getNextNumRef($this->client); } else { $num = $this->ref; } } if ($num) { $this->update_price(1); // Validate $sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture'; $sql .= " SET facnumber='" . $num . "', fk_statut = 1, fk_user_valid = " . $user->id . ", date_valid = '" . $this->db->idate($now) . "'"; if (!empty($conf->global->FAC_FORCE_DATE_VALIDATION)) { $sql .= ', datef=' . $this->db->idate($this->date); $sql .= ', date_lim_reglement=' . $this->db->idate($this->date_lim_reglement); } $sql .= ' WHERE rowid = ' . $this->id; dol_syslog(get_class($this) . "::validate sql=" . $sql); $resql = $this->db->query($sql); if (!$resql) { dol_syslog(get_class($this) . "::validate Echec update - 10 - sql=" . $sql, LOG_ERR); dol_print_error($this->db); $error++; } // On verifie si la facture etait une provisoire if (!$error && preg_match('/^[\\(]?PROV/i', $this->ref)) { // La verif qu'une remise n'est pas utilisee 2 fois est faite au moment de l'insertion de ligne } if (!$error) { // Define third party as a customer $result = $this->client->set_as_client(); // Si active on decremente le produit principal et ses composants a la validation de facture if ($this->type != 3 && $result >= 0 && $conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_BILL) { require_once DOL_DOCUMENT_ROOT . "/product/stock/class/mouvementstock.class.php"; $langs->load("agenda"); // Loop on each line $cpt = count($this->lines); for ($i = 0; $i < $cpt; $i++) { if ($this->lines[$i]->fk_product > 0) { $mouvP = new MouvementStock($this->db); // We decrease stock for product if ($this->type == 2) { $result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceValidatedInDolibarr", $num)); } else { $result = $mouvP->livraison($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, $this->lines[$i]->subprice, $langs->trans("InvoiceValidatedInDolibarr", $num)); } if ($result < 0) { $error++; } } } } } if (!$error) { $this->oldref = ''; // Rename directory if dir was a temporary ref if (preg_match('/^[\\(]?PROV/i', $this->ref)) { // On renomme repertoire facture ($this->ref = ancienne ref, $num = nouvelle ref) // afin de ne pas perdre les fichiers attaches $facref = dol_sanitizeFileName($this->ref); $snumfa = dol_sanitizeFileName($num); $dirsource = $conf->facture->dir_output . '/' . $facref; $dirdest = $conf->facture->dir_output . '/' . $snumfa; if (file_exists($dirsource)) { dol_syslog(get_class($this) . "::validate rename dir " . $dirsource . " into " . $dirdest); if (@rename($dirsource, $dirdest)) { $this->oldref = $facref; dol_syslog("Rename ok"); // Suppression ancien fichier PDF dans nouveau rep dol_delete_file($conf->facture->dir_output . '/' . $snumfa . '/' . $facref . '.*'); } } } } // Set new ref and define current statut if (!$error) { $this->ref = $num; $this->facnumber = $num; $this->statut = 1; $this->date_validation = $now; } // Trigger calls if (!$error) { // Appel des triggers include_once DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php"; $interface = new Interfaces($this->db); $result = $interface->run_triggers('BILL_VALIDATE', $this, $user, $langs, $conf); if ($result < 0) { $error++; $this->errors = $interface->errors; } // Fin appel triggers } } else { $error++; } if (!$error) { $this->db->commit(); return 1; } else { $this->db->rollback(); $this->error = $this->db->lasterror(); return -1; } }