From c93f88e47ab0550bce1a45e721b65169e8467c69 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 13 Apr 2021 19:38:55 +0200 Subject: [PATCH] Debug mass action after regression on close on proposal --- htdocs/comm/propal/card.php | 6 +- .../comm/propal/class/api_proposals.class.php | 2 +- htdocs/comm/propal/class/propal.class.php | 162 ++++++------------ htdocs/comm/propal/list.php | 77 +++++++-- htdocs/core/actions_massactions.inc.php | 36 ---- 5 files changed, 116 insertions(+), 167 deletions(-) diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index 61bacfb3e66..c91d5dd5ca3 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -623,7 +623,7 @@ if (empty($reshook)) { // Classify billed $db->begin(); - $result = $object->cloture($user, $object::STATUS_BILLED, ''); + $result = $object->classifyBilled($user, 0, ''); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); $error++; @@ -639,12 +639,12 @@ if (empty($reshook)) { if (!(GETPOST('statut', 'int') > 0)) { setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("CloseAs")), null, 'errors'); $action = 'closeas'; - } else { + } elseif (GETPOST('statut', 'int') == $object::STATUS_SIGNED || GETPOST('statut', 'int') == $object::STATUS_NOTSIGNED) { // prevent browser refresh from closing proposal several times if ($object->statut == $object::STATUS_VALIDATED) { $db->begin(); - $result = $object->signature($user, GETPOST('statut', 'int'), GETPOST('note_private', 'restricthtml')); + $result = $object->closeProposal($user, GETPOST('statut', 'int'), GETPOST('note_private', 'restricthtml')); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); $error++; diff --git a/htdocs/comm/propal/class/api_proposals.class.php b/htdocs/comm/propal/class/api_proposals.class.php index 042303b7eed..c697b1b9eb9 100644 --- a/htdocs/comm/propal/class/api_proposals.class.php +++ b/htdocs/comm/propal/class/api_proposals.class.php @@ -766,7 +766,7 @@ class Proposals extends DolibarrApi throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } - $result = $this->propal->cloture(DolibarrApiAccess::$user, $status, $note_private, $notrigger); + $result = $this->propal->closeProposal(DolibarrApiAccess::$user, $status, $note_private, $notrigger); if ($result == 0) { throw new RestException(304, 'Error nothing done. May be object is already closed'); } diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 5ffe0f362c7..ffee98ffbba 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -118,6 +118,13 @@ class Propal extends CommonObject */ public $statut; + /** + * Status of the quote + * @var int + * @see Propal::STATUS_DRAFT, Propal::STATUS_VALIDATED, Propal::STATUS_SIGNED, Propal::STATUS_NOTSIGNED, Propal::STATUS_BILLED + */ + public $status; + /** * @deprecated * @see $date_creation @@ -2502,15 +2509,15 @@ class Propal extends CommonObject } /** - * Sign the commercial proposal + * Close/set the commercial proposal to status signed or refused (fill also date signature) * * @param User $user Object user that close - * @param int $statut Status + * @param int $status Status (self::STATUS_BILLED or self::STATUS_REFUSED) * @param string $note Complete private note with this note * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers * @return int <0 if KO, >0 if OK */ - public function signature($user, $statut, $note = '', $notrigger = 0) + public function closeProposal($user, $status, $note = '', $notrigger = 0) { global $langs,$conf; @@ -2522,15 +2529,16 @@ class Propal extends CommonObject $newprivatenote = dol_concatdesc($this->note_private, $note); $sql = "UPDATE ".MAIN_DB_PREFIX."propal"; - $sql .= " SET fk_statut = ".$statut.", note_private = '".$this->db->escape($newprivatenote)."', date_signature='".$this->db->idate($now)."', fk_user_signature=".$user->id; + $sql .= " SET fk_statut = ".((int) $status).", note_private = '".$this->db->escape($newprivatenote)."', date_signature='".$this->db->idate($now)."', fk_user_signature=".$user->id; $sql .= " WHERE rowid = ".$this->id; $resql = $this->db->query($sql); if ($resql) { + // Status self::STATUS_REFUSED by default $modelpdf = $conf->global->PROPALE_ADDON_PDF_ODT_CLOSED ? $conf->global->PROPALE_ADDON_PDF_ODT_CLOSED : $this->model_pdf; $trigger_name = 'PROPAL_CLOSE_REFUSED'; - if ($statut == self::STATUS_SIGNED) { + if ($status == self::STATUS_SIGNED) { // Status self::STATUS_SIGNED $trigger_name = 'PROPAL_CLOSE_SIGNED'; $modelpdf = $conf->global->PROPALE_ADDON_PDF_ODT_TOBILL ? $conf->global->PROPALE_ADDON_PDF_ODT_TOBILL:$this->model_pdf; @@ -2561,7 +2569,8 @@ class Propal extends CommonObject if (!$error) { $this->oldcopy= clone $this; - $this->statut = $statut; + $this->statut = $status; + $this->status = $status; $this->date_signature = $now; $this->note_private = $newprivatenote; } @@ -2580,6 +2589,7 @@ class Propal extends CommonObject return 1; } else { $this->statut = $this->oldcopy->statut; + $this->status = $this->oldcopy->statut; $this->date_signature = $this->oldcopy->date_signature; $this->note_private = $this->oldcopy->note_private; @@ -2587,100 +2597,6 @@ class Propal extends CommonObject return -1; } } else { - $this->error=$this->db->lasterror(); - $this->db->rollback(); - return -1; - } - } - - /** - * Close the commercial proposal - * - * @param User $user Object user that close - * @param int $status Status - * @param string $note Complete private note with this note - * @param int $notrigger 1=Does not execute triggers, 0=Execute triggers - * @return int <0 if KO, >0 if OK - */ - public function cloture($user, $status, $note = "", $notrigger = 0) - { - global $langs, $conf; - - $error = 0; - $now = dol_now(); - - $this->db->begin(); - - $newprivatenote = dol_concatdesc($this->note_private, $note); - - $sql = "UPDATE ".MAIN_DB_PREFIX."propal"; - $sql .= " SET fk_statut = ".((int) $status).", note_private = '".$this->db->escape($newprivatenote)."', date_cloture='".$this->db->idate($now)."', fk_user_cloture=".$user->id; - $sql .= " WHERE rowid = ".$this->id; - - $resql = $this->db->query($sql); - if ($resql) { - $modelpdf = $conf->global->PROPALE_ADDON_PDF_ODT_CLOSED ? $conf->global->PROPALE_ADDON_PDF_ODT_CLOSED : $this->model_pdf; - $triggerName = 'PROPAL_CLOSE_REFUSED'; - - if ($status == self::STATUS_SIGNED) { - $triggerName = 'PROPAL_CLOSE_SIGNED'; - $modelpdf = $conf->global->PROPALE_ADDON_PDF_ODT_TOBILL ? $conf->global->PROPALE_ADDON_PDF_ODT_TOBILL : $this->model_pdf; - - // The connected company is classified as a client - $soc = new Societe($this->db); - $soc->id = $this->socid; - $result = $soc->set_as_client(); - - if ($result < 0) { - $this->error = $this->db->lasterror(); - $this->db->rollback(); - return -2; - } - } - if ($status == self::STATUS_BILLED) { // ->cloture() can also be called when we set it to billed, after setting it to signed - $triggerName = 'PROPAL_CLASSIFY_BILLED'; - } - - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) { - // Define output language - $outputlangs = $langs; - if (!empty($conf->global->MAIN_MULTILANGS)) { - $outputlangs = new Translate("", $conf); - $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $this->thirdparty->default_lang); - $outputlangs->setDefaultLang($newlang); - } - //$ret=$object->fetch($id); // Reload to get new records - $this->generateDocument($modelpdf, $outputlangs); - } - - if (!$error) { - $this->oldcopy = clone $this; - $this->statut = $status; - $this->date_cloture = $now; - $this->note_private = $newprivatenote; - } - - if (!$notrigger && empty($error)) { - // Call trigger - $result = $this->call_trigger($triggerName, $user); - if ($result < 0) { - $error++; - } - // End call triggers - } - - if (!$error) { - $this->db->commit(); - return 1; - } else { - $this->statut = $this->oldcopy->statut; - $this->date_cloture = $this->oldcopy->date_cloture; - $this->note_private = $this->oldcopy->note_private; - - $this->db->rollback(); - return -1; - } - } else { $this->error = $this->db->lasterror(); $this->db->rollback(); return -1; @@ -2688,36 +2604,66 @@ class Propal extends CommonObject } /** - * Class invoiced the Propal + * Classify the proposal to status Billed * * @param User $user Object user * @param int $notrigger 1=Does not execute triggers, 0= execute triggers - * @return int <0 si ko, >0 si ok + * @param string $note Complete private note with this note + * @return int <0 if KO, 0 = nothing done, >0 if OK */ - public function classifyBilled(User $user, $notrigger = 0) + public function classifyBilled(User $user, $notrigger = 0, $note = '') { + global $conf, $langs; + $error = 0; + $now = dol_now(); + $num = 0; + + $triggerName = 'PROPAL_CLASSIFY_BILLED'; + $this->db->begin(); - $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal SET fk_statut = '.self::STATUS_BILLED; - $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > '.self::STATUS_DRAFT; + $newprivatenote = dol_concatdesc($this->note_private, $note); + + $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal SET fk_statut = '.self::STATUS_BILLED.", "; + $sql .= " note_private = '".$this->db->escape($newprivatenote)."', date_cloture='".$this->db->idate($now)."', fk_user_cloture=".$user->id; + $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut = '.self::STATUS_SIGNED; dol_syslog(__METHOD__, LOG_DEBUG); $resql = $this->db->query($sql); if (!$resql) { $this->errors[] = $this->db->error(); $error++; + } else { + $num = $this->db->affected_rows($resql); } if (!$error) { + $modelpdf = $conf->global->PROPALE_ADDON_PDF_ODT_CLOSED ? $conf->global->PROPALE_ADDON_PDF_ODT_CLOSED : $this->model_pdf; + + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) { + // Define output language + $outputlangs = $langs; + if (!empty($conf->global->MAIN_MULTILANGS)) { + $outputlangs = new Translate("", $conf); + $newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $this->thirdparty->default_lang); + $outputlangs->setDefaultLang($newlang); + } + + //$ret=$object->fetch($id); // Reload to get new records + $this->generateDocument($modelpdf, $outputlangs); + } + $this->oldcopy = clone $this; $this->statut = self::STATUS_BILLED; + $this->date_cloture = $now; + $this->note_private = $newprivatenote; } if (!$notrigger && empty($error)) { // Call trigger - $result = $this->call_trigger('PROPAL_MODIFY', $user); + $result = $this->call_trigger($triggerName, $user); if ($result < 0) { $error++; } @@ -2726,7 +2672,7 @@ class Propal extends CommonObject if (!$error) { $this->db->commit(); - return 1; + return $num; } else { foreach ($this->errors as $errmsg) { dol_syslog(__METHOD__.' Error: '.$errmsg, LOG_ERR); @@ -2922,7 +2868,7 @@ class Propal extends CommonObject } if (count($linkedInvoices) > 0) { - $sql = "SELECT rowid as facid, ref, total, datef as df, fk_user_author, fk_statut, paye"; + $sql = "SELECT rowid as facid, ref, total_ht as total, datef as df, fk_user_author, fk_statut, paye"; $sql .= " FROM ".MAIN_DB_PREFIX."facture"; $sql .= " WHERE rowid IN (".$this->db->sanitize(implode(',', $linkedInvoices)).")"; diff --git a/htdocs/comm/propal/list.php b/htdocs/comm/propal/list.php index f5ac2ebae7a..ed9cabd8c5c 100644 --- a/htdocs/comm/propal/list.php +++ b/htdocs/comm/propal/list.php @@ -125,11 +125,6 @@ if (!$sortorder) { $sortorder = 'DESC'; } -$permissiontoread = $user->rights->propal->lire; -$permissiontoadd = $user->rights->propal->write; -$permissiontodelete = $user->rights->propal->supprimer; -$permissiontoclose = $user->rights->propal->cloturer; - // Security check $module = 'propal'; $dbtable = ''; @@ -218,6 +213,12 @@ $arrayfields = array( // Extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php'; +$permissiontoread = $user->rights->propal->lire; +$permissiontoadd = $user->rights->propal->write; +$permissiontodelete = $user->rights->propal->supprimer; +$permissiontoclose = $user->rights->propal->cloturer; + + /* * Actions @@ -295,7 +296,7 @@ if (empty($reshook)) { include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php'; } -if ($action == 'validate') { +if ($action == 'validate' && $permissiontoadd) { if (GETPOST('confirm') == 'yes') { $tmpproposal = new Propal($db); $db->begin(); @@ -325,16 +326,16 @@ if ($action == 'validate') { } } -if ($action == "sign") { +if ($action == "sign" && $permissiontoclose) { if (GETPOST('confirm') == 'yes') { $tmpproposal = new Propal($db); $db->begin(); $error = 0; foreach ($toselect as $checked) { if ($tmpproposal->fetch($checked)) { - if ($tmpproposal->statut == 1) { - $tmpproposal->statut = 2; - if ($tmpproposal->update($user)) { + if ($tmpproposal->statut == $tmpproposal::STATUS_VALIDATED) { + $tmpproposal->statut = $tmpproposal::STATUS_SIGNED;; + if ($tmpproposal->closeProposal($user, $tmpproposal::STATUS_SIGNED)) { setEventMessage($tmpproposal->ref." ".$langs->trans('Signed'), 'mesgs'); } else { dol_print_error($db); @@ -356,16 +357,16 @@ if ($action == "sign") { } } } -if ($action == "nosign") { +if ($action == "nosign" && $permissiontoclose) { if (GETPOST('confirm') == 'yes') { $tmpproposal = new Propal($db); $db->begin(); $error = 0; foreach ($toselect as $checked) { if ($tmpproposal->fetch($checked)) { - if ($tmpproposal->statut == 1) { - $tmpproposal->statut = 3; - if ($tmpproposal->update($user)) { + if ($tmpproposal->statut == $tmpproposal::STATUS_VALIDATED) { + $tmpproposal->statut = $tmpproposal::STATUS_NOTSIGNED; + if ($tmpproposal->closeProposal($user, $tmpproposal::STATUS_NOTSIGNED)) { setEventMessage($tmpproposal->ref." ".$langs->trans('NoSigned'), 'mesgs'); } else { dol_print_error($db); @@ -388,6 +389,43 @@ if ($action == "nosign") { } } +// Closed records +if (!$error && $massaction === 'setbilled' && $permissiontoclose) { + $db->begin(); + + $objecttmp = new $objectclass($db); + $nbok = 0; + foreach ($toselect as $toselectid) { + $result = $objecttmp->fetch($toselectid); + if ($result > 0) { + $result = $objecttmp->classifyBilled($user, 0); + if ($result <= 0) { + setEventMessages($objecttmp->error, $objecttmp->errors, 'errors'); + $error++; + break; + } else { + $nbok++; + } + } else { + setEventMessages($objecttmp->error, $objecttmp->errors, 'errors'); + $error++; + break; + } + } + + if (!$error) { + if ($nbok > 1) { + setEventMessages($langs->trans("RecordsModified", $nbok), null, 'mesgs'); + } else { + setEventMessages($langs->trans("RecordsModified", $nbok), null, 'mesgs'); + } + $db->commit(); + } else { + $db->rollback(); + } +} + + /* * View @@ -776,15 +814,16 @@ if ($resql) { 'builddoc'=>$langs->trans("PDFMerge"), 'presend'=>$langs->trans("SendByMail"), 'prevalidate'=>$langs->trans("Validate"), - 'presign'=>$langs->trans("Sign"), - 'nopresign'=>$langs->trans("NoSign"), ); + if ($user->rights->propal->cloturer) { + $arrayofmassactions['presign']=$langs->trans("Sign"); + $arrayofmassactions['nopresign']=$langs->trans("NoSign"); + $arrayofmassactions['setbilled'] = $langs->trans("ClassifyBilled"); + } if ($user->rights->propal->supprimer) { $arrayofmassactions['predelete'] = ''.$langs->trans("Delete"); } - if ($user->rights->propal->cloturer) { - $arrayofmassactions['closed'] = $langs->trans("Close"); - } + if (in_array($massaction, array('presend', 'predelete', 'closed'))) { $arrayofmassactions = array(); } diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php index 13cb7126769..c7954384fae 100644 --- a/htdocs/core/actions_massactions.inc.php +++ b/htdocs/core/actions_massactions.inc.php @@ -1265,42 +1265,6 @@ if (!$error && $massaction == 'validate' && $permissiontoadd) { } } -// Closed records -if (!$error && $massaction == 'closed' && $objectclass == "Propal" && $permissiontoclose) { - $db->begin(); - - $objecttmp = new $objectclass($db); - $nbok = 0; - foreach ($toselect as $toselectid) { - $result = $objecttmp->fetch($toselectid); - if ($result > 0) { - $result = $objecttmp->cloture($user, 3); - if ($result <= 0) { - setEventMessages($objecttmp->error, $objecttmp->errors, 'errors'); - $error++; - break; - } else { - $nbok++; - } - } else { - setEventMessages($objecttmp->error, $objecttmp->errors, 'errors'); - $error++; - break; - } - } - - if (!$error) { - if ($nbok > 1) { - setEventMessages($langs->trans("RecordsModified", $nbok), null, 'mesgs'); - } else { - setEventMessages($langs->trans("RecordsModified", $nbok), null, 'mesgs'); - } - $db->commit(); - } else { - $db->rollback(); - } -} - //var_dump($_POST);var_dump($massaction);exit; // Delete record from mass action (massaction = 'delete' for direct delete, action/confirm='delete'/'yes' with a confirmation step before)