diff --git a/htdocs/admin/facture.php b/htdocs/admin/facture.php index 9eec54b03a7..599aac27c3f 100644 --- a/htdocs/admin/facture.php +++ b/htdocs/admin/facture.php @@ -225,6 +225,12 @@ if ($action == 'updateMask') { setEventMessages($langs->trans("Error"), null, 'errors'); } } +} elseif ($action == 'set_INVOICE_CHECK_POSTERIOR_DATE') { + $check_posterior_date = GETPOST('INVOICE_CHECK_POSTERIOR_DATE', 'int'); + $res = dolibarr_set_const($db, 'INVOICE_CHECK_POSTERIOR_DATE', $check_posterior_date, 'chaine', 0, '', $conf->entity); + if (!($res > 0)) { + $error++; + } } @@ -761,6 +767,25 @@ print '\n"; print ''; + +print ''.$langs->trans("InvoiceCheckPosteriorDate"). ' ' ; +print $form->textwithpicto('', $langs->trans("InvoiceCheckPosteriorDateHelp"), 1, 'help') . ''; +print ''; +if ($conf->use_javascript_ajax) { + print ajax_constantonoff('INVOICE_CHECK_POSTERIOR_DATE'); +} else { + print '
'; + print ''; + print ''; + $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); + print $form->selectarray("INVOICE_CHECK_POSTERIOR_DATE", $arrval, $conf->global->INVOICE_CHECK_POSTERIOR_DATE); + print ''; + print ''; + print ''; + print '
'; +} +print ''; + print ''; print ''; diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index a81aa6cafad..65aa707547c 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -302,6 +302,14 @@ if (empty($reshook)) { // Validation $object->fetch($id); + if (!empty($conf->global-> INVOICE_CHECK_POSTERIOR_DATE)) { + $last_of_type = $object->willBeLastOfSameType(); + if (empty($object->date_validation) && !$last_of_type[0]) { + setEventMessages($langs->transnoentities("ErrorInvoiceIsNotLastOfSameType", $object->ref, dol_print_date($object->date, 'day'), dol_print_date($last_of_type[1], 'day')), null, 'errors'); + $action = ''; + } + } + // On verifie signe facture if ($object->type == Facture::TYPE_CREDIT_NOTE) { // Si avoir, le signe doit etre negatif diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index d67ea43198f..3574eb8db2c 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -2673,6 +2673,13 @@ class Facture extends CommonInvoice dol_syslog(get_class($this)."::validate ".$this->error.' MAIN_USE_ADVANCED_PERMS='.$conf->global->MAIN_USE_ADVANCED_PERMS, LOG_ERR); return -1; } + if (!empty($conf->global-> INVOICE_CHECK_POSTERIOR_DATE)) { + $last_of_type = $this->willBeLastOfSameType(); + if (!$last_of_type[0]) { + $this->error = $langs->transnoentities("ErrorInvoiceIsNotLastOfSameType", $this->ref, dol_print_date($this->date, 'day'), dol_print_date($last_of_type[1], 'day')); + return -1; + } + } // Check for mandatory fields in thirdparty (defined into setup) if (!empty($this->thirdparty) && is_object($this->thirdparty)) { @@ -5180,6 +5187,37 @@ class Facture extends CommonInvoice return $error; } } + + /** + * See if current invoice date is posterior to the last invoice date among validated invoices of same type. + * @return boolean + */ + public function willBeLastOfSameType() + { + // get date of last validated invoices of same type + $sql = "SELECT datef"; + $sql .= " FROM ".MAIN_DB_PREFIX."facture"; + $sql .= " WHERE type = " . (int) $this->type ; + $sql .= " AND date_valid IS NOT NULL"; + $sql .= " ORDER BY datef DESC LIMIT 1"; + + $result = $this->db->query($sql); + if ($result) { + // compare with current validation date + if ($this->db->num_rows($result)) { + $obj = $this->db->fetch_object($result); + $last_date = $this->db->jdate($obj->datef); + $invoice_date = $this->date; + + return [$invoice_date >= $last_date, $last_date]; + } else { + // element is first of type to be validated + return [true]; + } + } else { + dol_print_error($this->db); + } + } } /** diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php index d32418d7550..573ed2230f5 100644 --- a/htdocs/core/actions_massactions.inc.php +++ b/htdocs/core/actions_massactions.inc.php @@ -1218,6 +1218,26 @@ if (!$error && $massaction == 'validate' && $permissiontoadd) { setEventMessages($langs->trans('ErrorMassValidationNotAllowedWhenStockIncreaseOnAction'), null, 'errors'); $error++; } + if ($objecttmp->element == 'facture') { + if (!empty($toselect) && !empty($conf->global->INVOICE_CHECK_POSTERIOR_DATE)) { + // order $toselect by date + $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."facture"; + $sql .= " WHERE rowid IN (".$db->sanitize(implode(",", $toselect)).")"; + $sql .= " ORDER BY datef"; + + $resql = $db->query($sql); + if ($resql) { + $toselectnew = []; + while ( !empty($arr = $db->fetch_row($resql))) { + $toselectnew[] = $arr[0]; + } + $toselect = (empty($toselectnew)) ? $toselect : $toselectnew; + } else { + dol_print_error($db); + $error++; + } + } + } if (!$error) { $db->begin(); diff --git a/htdocs/core/modules/modFacture.class.php b/htdocs/core/modules/modFacture.class.php index fac768b9c60..72838e92079 100644 --- a/htdocs/core/modules/modFacture.class.php +++ b/htdocs/core/modules/modFacture.class.php @@ -99,14 +99,6 @@ class modFacture extends DolibarrModules $this->const[$r][4] = 0; $r++; - /*$this->const[$r][0] = "FACTURE_DRAFT_WATERMARK"; - $this->const[$r][1] = "chaine"; - $this->const[$r][2] = "__(Draft)__"; - $this->const[$r][3] = 'Watermark to show on draft invoices'; - $this->const[$r][4] = 0; - $r++;*/ - - // Boxes //$this->boxes = array(0=>array(1=>'box_factures_imp.php'),1=>array(1=>'box_factures.php')); $this->boxes = array( diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index cf618d6b2b1..794893e2133 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -1424,6 +1424,8 @@ WatermarkOnDraftInvoices=Watermark on draft invoices (none if empty) PaymentsNumberingModule=Payments numbering model SuppliersPayment=Vendor payments SupplierPaymentSetup=Vendor payments setup +InvoiceCheckPosteriorDate=Check facture date before validation +InvoiceCheckPosteriorDateHelp=Validating an invoice will be forbidden if its date is anterior to the date of last invoice of same type. ##### Proposals ##### PropalSetup=Commercial proposals module setup ProposalsNumberingModules=Commercial proposal numbering models diff --git a/htdocs/langs/en_US/bills.lang b/htdocs/langs/en_US/bills.lang index b9b4b111b43..68c08c9f234 100644 --- a/htdocs/langs/en_US/bills.lang +++ b/htdocs/langs/en_US/bills.lang @@ -156,6 +156,7 @@ ErrorInvoiceAvoirMustBeNegative=Error, correct invoice must have a negative amou ErrorInvoiceOfThisTypeMustBePositive=Error, this type of invoice must have an amount excluding tax positive (or null) ErrorCantCancelIfReplacementInvoiceNotValidated=Error, can't cancel an invoice that has been replaced by another invoice that is still in draft status ErrorThisPartOrAnotherIsAlreadyUsedSoDiscountSerieCantBeRemoved=This part or another is already used so discount series cannot be removed. +ErrorInvoiceIsNotLastOfSameType=Error: The date of invoice %s is %s. It must be posterior or equal to last date for same type invoices (%s). Please change the invoice date. BillFrom=From BillTo=To ActionsOnBill=Actions on invoice