';
+
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