Fix: protection to not delete invoice if invoice is in bookkeeping
This commit is contained in:
parent
78c4b7f912
commit
8019f73f99
@ -3888,7 +3888,6 @@ else if ($id > 0 || ! empty($ref))
|
||||
print '</td>';
|
||||
}
|
||||
print '<td align="right">' . price($sign * $objp->amount) . '</td>';
|
||||
// TODO Add link to delete payment
|
||||
print '<td align="center">';
|
||||
if ($object->statut == Facture::STATUS_VALIDATED && $object->paye == 0 && $user->societe_id == 0)
|
||||
{
|
||||
@ -4380,13 +4379,30 @@ else if ($id > 0 || ! empty($ref))
|
||||
// Delete
|
||||
if ($user->rights->facture->supprimer)
|
||||
{
|
||||
if ($object->is_erasable() <= 0) {
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecauseNotErasable") . '">' . $langs->trans('Delete') . '</a></div>';
|
||||
} else if ($objectidnext) {
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecauseReplacedInvoice") . '">' . $langs->trans('Delete') . '</a></div>';
|
||||
} elseif ($object->getSommePaiement()) {
|
||||
$isErasable = $object->is_erasable();
|
||||
//var_dump($isErasable);
|
||||
if ($isErasable == -4) {
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecausePayments") . '">' . $langs->trans('Delete') . '</a></div>';
|
||||
} else {
|
||||
}
|
||||
elseif ($isErasable == -3) {
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecauseNotLastSituationInvoice") . '">' . $langs->trans('Delete') . '</a></div>';
|
||||
}
|
||||
elseif ($isErasable == -2) {
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecauseNotLastInvoice") . '">' . $langs->trans('Delete') . '</a></div>';
|
||||
}
|
||||
elseif ($isErasable == -1) {
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecauseDispatchedInBookkeeping") . '">' . $langs->trans('Delete') . '</a></div>';
|
||||
}
|
||||
elseif ($isErasable <= 0) // Any other cases
|
||||
{
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecauseNotErasable") . '">' . $langs->trans('Delete') . '</a></div>';
|
||||
}
|
||||
elseif ($objectidnext)
|
||||
{
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecauseReplacedInvoice") . '">' . $langs->trans('Delete') . '</a></div>';
|
||||
}
|
||||
else
|
||||
{
|
||||
print '<div class="inline-block divButAction"><a class="butActionDelete" href="' . $_SERVER["PHP_SELF"] . '?facid=' . $object->id . '&action=delete">' . $langs->trans('Delete') . '</a></div>';
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -3367,85 +3367,6 @@ class Facture extends CommonInvoice
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renvoi si les lignes de facture sont ventilees et/ou exportees en compta
|
||||
*
|
||||
* @return int <0 if KO, 0=no, 1=yes
|
||||
*/
|
||||
function getVentilExportCompta()
|
||||
{
|
||||
// On verifie si les lignes de factures ont ete exportees en compta et/ou ventilees
|
||||
$ventilExportCompta = 0 ;
|
||||
$num=count($this->lines);
|
||||
for ($i = 0; $i < $num; $i++)
|
||||
{
|
||||
if (! empty($this->lines[$i]->export_compta) && ! empty($this->lines[$i]->code_ventilation))
|
||||
{
|
||||
$ventilExportCompta++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($ventilExportCompta <> 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return if an invoice can be deleted
|
||||
* Rule is:
|
||||
* If invoice is draft and ha a temporary ref -> yes
|
||||
* If hidden option INVOICE_CAN_ALWAYS_BE_REMOVED is on, we can. If hidden option INVOICE_CAN_NEVER_BE_REMOVED is on, we can't.
|
||||
* If invoice has a definitive ref, is last, without payment and not dipatched into accountancy -> yes end of rule
|
||||
*
|
||||
* @return int <0 if KO, 0=no, >0=yes
|
||||
*/
|
||||
function is_erasable()
|
||||
{
|
||||
global $conf;
|
||||
|
||||
// we check if invoice is a temporary number (PROVxxxx)
|
||||
$tmppart = substr($this->ref, 1, 4);
|
||||
|
||||
if ($this->statut == self::STATUS_DRAFT && $tmppart === 'PROV') // If draft invoice and ref not yet defined
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (! empty($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED)) return 2;
|
||||
if (! empty($conf->global->INVOICE_CAN_NEVER_BE_REMOVED)) return 0;
|
||||
|
||||
// TODO Test if there is at least one payment. If yes, refuse to delete.
|
||||
// ...
|
||||
|
||||
// If not a draft invoice and not temporary invoice
|
||||
if ($tmppart !== 'PROV')
|
||||
{
|
||||
// We need to have this->thirdparty defined, in case of numbering rule use tags that depend on thirdparty (like {t} tag).
|
||||
if (empty($this->thirdparty)) $this->fetch_thirdparty();
|
||||
|
||||
$maxfacnumber = $this->getNextNumRef($this->thirdparty,'last');
|
||||
$ventilExportCompta = $this->getVentilExportCompta();
|
||||
|
||||
// If there is no invoice into the reset range and not already dispatched, we can delete
|
||||
if ($maxfacnumber == '' && $ventilExportCompta == 0) return 3;
|
||||
// If invoice to delete is last one and not already dispatched, we can delete
|
||||
if ($maxfacnumber == $this->ref && $ventilExportCompta == 0) return 4;
|
||||
|
||||
if ($this->situation_cycle_ref) {
|
||||
$last = $this->is_last_in_cycle();
|
||||
return $last;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return list of invoices (eventually filtered on a user) into an array
|
||||
|
||||
@ -274,6 +274,100 @@ abstract class CommonInvoice extends CommonObject
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if an invoice can be deleted
|
||||
* Rule is:
|
||||
* If invoice is draft and has a temporary ref -> yes
|
||||
* If hidden option INVOICE_CAN_NEVER_BE_REMOVED is on -> no (0)
|
||||
* If invoice is dispatched in bookkeeping -> no (-1)
|
||||
* If invoice has a definitive ref, is not last and INVOICE_CAN_ALWAYS_BE_REMOVED off -> no (-2)
|
||||
* If invoice not last in a cycle -> no (-3)
|
||||
* If there is payment -> no (-4)
|
||||
*
|
||||
* @return int <=0 if no, >0 if yes
|
||||
*/
|
||||
function is_erasable()
|
||||
{
|
||||
global $conf;
|
||||
|
||||
// We check if invoice is a temporary number (PROVxxxx)
|
||||
$tmppart = substr($this->ref, 1, 4);
|
||||
|
||||
if ($this->statut == self::STATUS_DRAFT && $tmppart === 'PROV') // If draft invoice and ref not yet defined
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (! empty($conf->global->INVOICE_CAN_NEVER_BE_REMOVED)) return 0;
|
||||
|
||||
// If not a draft invoice and not temporary invoice
|
||||
if ($tmppart !== 'PROV')
|
||||
{
|
||||
$ventilExportCompta = $this->getVentilExportCompta();
|
||||
if ($ventilExportCompta != 0) return -1;
|
||||
|
||||
// Get last number of validated invoice
|
||||
if ($this->element != 'invoice_supplier')
|
||||
{
|
||||
if (empty($this->thirdparty)) $this->fetch_thirdparty(); // We need to have this->thirdparty defined, in case of numbering rule use tags that depend on thirdparty (like {t} tag).
|
||||
$maxfacnumber = $this->getNextNumRef($this->thirdparty,'last');
|
||||
|
||||
// If there is no invoice into the reset range and not already dispatched, we can delete
|
||||
// If invoice to delete is last one and not already dispatched, we can delete
|
||||
if (empty($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED) && $maxfacnumber != '' && $maxfacnumber != $this->ref) return -2;
|
||||
|
||||
// TODO If there is payment in bookkeeping, check payment is not dispatched in accounting
|
||||
// ...
|
||||
|
||||
if ($this->situation_cycle_ref) {
|
||||
$last = $this->is_last_in_cycle();
|
||||
if (! $last) return -3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test if there is at least one payment. If yes, refuse to delete.
|
||||
if (empty($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED) && $this->getSommePaiement() > 0) return -4;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if an invoice was dispatched in bookkeeping
|
||||
*
|
||||
* @return int <0 if KO, 0=no, 1=yes
|
||||
*/
|
||||
function getVentilExportCompta()
|
||||
{
|
||||
$alreadydispatched = 0;
|
||||
|
||||
$type = 'customer_invoice';
|
||||
if ($this->element == 'invoice_supplier') $type = 'supplier_invoice';
|
||||
|
||||
$sql = " SELECT COUNT(ab.rowid) as nb FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as ab WHERE ab.doc_type='".$type."' AND ab.fk_doc = ".$this->id;
|
||||
$resql = $this->db->query($sql);
|
||||
if ($resql)
|
||||
{
|
||||
$obj = $this->db->fetch_object($resql);
|
||||
if ($obj)
|
||||
{
|
||||
$alreadydispatched = $obj->nb;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->error = $this->db->lasterror();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ($alreadydispatched)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return label of type of invoice
|
||||
*
|
||||
|
||||
@ -2836,9 +2836,26 @@ else
|
||||
// Delete
|
||||
if ($action != 'confirm_edit' && $user->rights->fournisseur->facture->supprimer)
|
||||
{
|
||||
if ($object->getSommePaiement()) {
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecausePayments") . '">' . $langs->trans('Delete') . '</a></div>';
|
||||
} else {
|
||||
$isErasable=$object->is_erasable();
|
||||
//var_dump($isErasable);
|
||||
if ($isErasable == -4) {
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecausePayments") . '">' . $langs->trans('Delete') . '</a></div>';
|
||||
}
|
||||
elseif ($isErasable == -3) { // Should never happen with supplier invoice
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecauseNotLastSituationInvoice") . '">' . $langs->trans('Delete') . '</a></div>';
|
||||
}
|
||||
elseif ($isErasable == -2) { // Should never happen with supplier invoice
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecauseNotLastInvoice") . '">' . $langs->trans('Delete') . '</a></div>';
|
||||
}
|
||||
elseif ($isErasable == -1) {
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecauseDispatchedInBookkeeping") . '">' . $langs->trans('Delete') . '</a></div>';
|
||||
}
|
||||
elseif ($isErasable <= 0) // Any other cases
|
||||
{
|
||||
print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecauseNotErasable") . '">' . $langs->trans('Delete') . '</a></div>';
|
||||
}
|
||||
else
|
||||
{
|
||||
print '<div class="inline-block divButAction"><a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete">'.$langs->trans('Delete').'</a></div>';
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,8 @@ BillsSuppliersUnpaidForCompany=Unpaid supplier invoices for %s
|
||||
BillsLate=Late payments
|
||||
BillsStatistics=Customers invoices statistics
|
||||
BillsStatisticsSuppliers=Suppliers invoices statistics
|
||||
DisabledBecauseDispatchedInBookkeeping=Disabled because invoice was dispatched into bookkeeping
|
||||
DisabledBecauseNotLastInvoice=Disabled because invoice is not erasable. Some invoices were recorded after this one and it will create holes in the counter.
|
||||
DisabledBecauseNotErasable=Disabled because cannot be erased
|
||||
InvoiceStandard=Standard invoice
|
||||
InvoiceStandardAsk=Standard invoice
|
||||
|
||||
Loading…
Reference in New Issue
Block a user