diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php
index cecb4fff28a..dc923e4e1dc 100644
--- a/htdocs/comm/propal/card.php
+++ b/htdocs/comm/propal/card.php
@@ -642,7 +642,7 @@ if (empty($reshook)) {
if ($object->statut == $object::STATUS_VALIDATED) {
$db->begin();
- $result = $object->cloture($user, GETPOST('statut', 'int'), GETPOST('note_private', 'restricthtml'));
+ $result = $object->signature($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/propal.class.php b/htdocs/comm/propal/class/propal.class.php
index 3674356af20..c9f736fcfff 100644
--- a/htdocs/comm/propal/class/propal.class.php
+++ b/htdocs/comm/propal/class/propal.class.php
@@ -140,6 +140,16 @@ class Propal extends CommonObject
*/
public $date_validation;
+ /**
+ * @var integer|string $date_signature;
+ */
+ public $date_signature;
+
+ /**
+ * @var User $user_signature
+ */
+ public $user_signature;
+
/**
* @var integer|string date of the quote;
*/
@@ -2489,6 +2499,97 @@ class Propal extends CommonObject
}
}
+ /**
+ * Sign the commercial proposal
+ *
+ * @param User $user Object user that close
+ * @param int $statut 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
+ */
+ function signature($user, $statut, $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 = ".$statut.", 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) {
+ $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) {
+ $trigger_name = '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 (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 = $statut;
+ $this->date_signature = $now;
+ $this->note_private = $newprivatenote;
+ }
+
+ if (!$notrigger && empty($error)) {
+ // Call trigger
+ $result=$this->call_trigger($trigger_name, $user);
+ if ($result < 0) {
+ $error++;
+ }
+ // End call triggers
+ }
+
+ if (!$error ) {
+ $this->db->commit();
+ return 1;
+ } else {
+ $this->statut = $this->oldcopy->statut;
+ $this->date_signature = $this->oldcopy->date_signature;
+ $this->note_private = $this->oldcopy->note_private;
+
+ $this->db->rollback();
+ return -1;
+ }
+ } else {
+ $this->error=$this->db->lasterror();
+ $this->db->rollback();
+ return -1;
+ }
+ }
/**
* Close the commercial proposal
@@ -3113,8 +3214,8 @@ class Propal extends CommonObject
public function info($id)
{
$sql = "SELECT c.rowid, ";
- $sql .= " c.datec, c.date_valid as datev, c.date_cloture as dateo,";
- $sql .= " c.fk_user_author, c.fk_user_valid, c.fk_user_cloture";
+ $sql .= " c.datec, c.date_valid as datev, c.date_signature, c.date_cloture as dateo,";
+ $sql .= " c.fk_user_author, c.fk_user_valid, c.fk_user_signature, c.fk_user_cloture";
$sql .= " FROM ".MAIN_DB_PREFIX."propal as c";
$sql .= " WHERE c.rowid = ".((int) $id);
@@ -3128,6 +3229,7 @@ class Propal extends CommonObject
$this->date_creation = $this->db->jdate($obj->datec);
$this->date_validation = $this->db->jdate($obj->datev);
+ $this->date_signature = $this->db->jdate($obj->date_signature);
$this->date_cloture = $this->db->jdate($obj->dateo);
$cuser = new User($this->db);
@@ -3140,6 +3242,12 @@ class Propal extends CommonObject
$this->user_validation = $vuser;
}
+ if ($obj->fk_user_signature) {
+ $user_signature = new User($this->db);
+ $user_signature->fetch($obj->fk_user_signature);
+ $this->user_signature = $user_signature;
+ }
+
if ($obj->fk_user_cloture) {
$cluser = new User($this->db);
$cluser->fetch($obj->fk_user_cloture);
diff --git a/htdocs/core/lib/functions2.lib.php b/htdocs/core/lib/functions2.lib.php
index 0703df95255..3f7e02b9bad 100644
--- a/htdocs/core/lib/functions2.lib.php
+++ b/htdocs/core/lib/functions2.lib.php
@@ -507,6 +507,61 @@ function dol_print_object_info($object, $usetable = 0)
}
}
+ // User signature
+ if (!empty($object->user_signature)) {
+ if ($usetable) {
+ print '
| ';
+ }
+ print $langs->trans('SignedBy');
+ if ($usetable) {
+ print ' | ';
+ } else {
+ print ': ';
+ }
+ if (is_object($object->user_signature)) {
+ if ($object->user_signature->id) {
+ print $object->user_signature->getNomUrl(-1, '', 0, 0, 0);
+ } else {
+ print $langs->trans('Unknown');
+ }
+ } else {
+ $userstatic = new User($db);
+ $userstatic->fetch($object->user_signature);
+ if ($userstatic->id) {
+ print $userstatic->getNomUrl(-1, '', 0, 0, 0);
+ } else {
+ print $langs->trans('Unknown');
+ }
+ }
+ if ($usetable) {
+ print ' |
';
+ } else {
+ print '
';
+ }
+ }
+
+ // Date signature
+ if (!empty($object->date_signature)) {
+ if ($usetable) {
+ print '| ';
+ }
+ print $langs->trans('DateSigning');
+ if ($usetable) {
+ print ' | ';
+ } else {
+ print ': ';
+ }
+ print dol_print_date($object->date_signature, 'dayhour');
+ if ($deltadateforuser) {
+ print ' '.$langs->trans('CurrentHour').' / '.dol_print_date($object->date_signature,'dayhour', 'tzuserrel').' '.$langs->trans('ClientHour');
+ }
+ if ($usetable) {
+ print ' |
';
+ } else {
+ print '
';
+ }
+ }
+
// User close
if (!empty($object->user_cloture) || !empty($object->user_closing)) {
if (isset($object->user_cloture) && !empty($object->user_cloture)) {
diff --git a/htdocs/install/mysql/migration/13.0.0-14.0.0.sql b/htdocs/install/mysql/migration/13.0.0-14.0.0.sql
index 772f0e51bdf..0c71b94f4f1 100644
--- a/htdocs/install/mysql/migration/13.0.0-14.0.0.sql
+++ b/htdocs/install/mysql/migration/13.0.0-14.0.0.sql
@@ -282,5 +282,11 @@ DELETE FROM llx_boxes_def WHERE file IN ('box_graph_ticket_by_severity', 'box_ti
ALTER TABLE llx_c_ticket_category ADD COLUMN public integer DEFAULT 0;
+ALTER TABLE llx_propal ADD COLUMN date_signature datetime AFTER date_valid;
+ALTER TABLE llx_propal ADD COLUMN fk_user_signature integer AFTER fk_user_valid;
+ALTER TABLE llx_propal ADD CONSTRAINT fk_propal_fk_user_signature FOREIGN KEY (fk_user_signature) REFERENCES llx_user (rowid);
+UPDATE llx_propal SET fk_user_signature = fk_user_cloture WHERE fk_user_signature IS NULL AND fk_user_cloture IS NOT NULL;
+UPDATE llx_propal SET date_signature = date_cloture WHERE date_signature IS NULL AND date_cloture IS NOT NULL;
+
diff --git a/htdocs/install/mysql/tables/llx_propal.key.sql b/htdocs/install/mysql/tables/llx_propal.key.sql
index 89a0c54ad83..d0265e6fcdf 100644
--- a/htdocs/install/mysql/tables/llx_propal.key.sql
+++ b/htdocs/install/mysql/tables/llx_propal.key.sql
@@ -24,6 +24,7 @@ ALTER TABLE llx_propal ADD UNIQUE INDEX uk_propal_ref (ref, entity);
ALTER TABLE llx_propal ADD INDEX idx_propal_fk_soc (fk_soc);
ALTER TABLE llx_propal ADD INDEX idx_propal_fk_user_author (fk_user_author);
ALTER TABLE llx_propal ADD INDEX idx_propal_fk_user_valid (fk_user_valid);
+ALTER TABLE llx_propal ADD INDEX idx_propal_fk_user_signature (fk_user_signature);
ALTER TABLE llx_propal ADD INDEX idx_propal_fk_user_cloture (fk_user_cloture);
ALTER TABLE llx_propal ADD INDEX idx_propal_fk_projet (fk_projet);
ALTER TABLE llx_propal ADD INDEX idx_propal_fk_account(fk_account);
@@ -33,6 +34,7 @@ ALTER TABLE llx_propal ADD INDEX idx_propal_fk_warehouse(fk_warehouse);
ALTER TABLE llx_propal ADD CONSTRAINT fk_propal_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid);
ALTER TABLE llx_propal ADD CONSTRAINT fk_propal_fk_user_author FOREIGN KEY (fk_user_author) REFERENCES llx_user (rowid);
ALTER TABLE llx_propal ADD CONSTRAINT fk_propal_fk_user_valid FOREIGN KEY (fk_user_valid) REFERENCES llx_user (rowid);
+ALTER TABLE llx_propal ADD CONSTRAINT fk_propal_fk_user_signature FOREIGN KEY (fk_user_signature) REFERENCES llx_user (rowid);
ALTER TABLE llx_propal ADD CONSTRAINT fk_propal_fk_user_cloture FOREIGN KEY (fk_user_cloture) REFERENCES llx_user (rowid);
ALTER TABLE llx_propal ADD CONSTRAINT fk_propal_fk_projet FOREIGN KEY (fk_projet) REFERENCES llx_projet (rowid);
--ALTER TABLE llx_propal ADD CONSTRAINT fk_propal_fk_warehouse FOREIGN KEY (fk_warehouse) REFERENCES llx_entrepot(rowid);
diff --git a/htdocs/install/mysql/tables/llx_propal.sql b/htdocs/install/mysql/tables/llx_propal.sql
index 004bb027d35..7c94086b3b9 100644
--- a/htdocs/install/mysql/tables/llx_propal.sql
+++ b/htdocs/install/mysql/tables/llx_propal.sql
@@ -37,11 +37,13 @@ create table llx_propal
datep date, -- date de la propal
fin_validite datetime, -- date de fin de validite
date_valid datetime, -- date de validation
+ date_signature datetime, -- date signature
date_cloture datetime, -- date de cloture
fk_user_author integer, -- user making creation
fk_user_modif integer, -- user making last change
fk_user_valid integer, -- user validating
- fk_user_cloture integer, -- user closing (signed or not)
+ fk_user_signature integer, -- user signing (signed or not)
+ fk_user_cloture integer, -- user closing
fk_statut smallint DEFAULT 0 NOT NULL, -- 0=draft, 1=validated, 2=accepted, 3=refused, 4=billed/closed
price real DEFAULT 0, -- (obsolete)
remise_percent real DEFAULT 0, -- remise globale relative en pourcent (obsolete)
diff --git a/htdocs/langs/fr_FR/main.lang b/htdocs/langs/fr_FR/main.lang
index 86ba2247682..a8b13c7e914 100644
--- a/htdocs/langs/fr_FR/main.lang
+++ b/htdocs/langs/fr_FR/main.lang
@@ -278,6 +278,7 @@ DateModificationShort=Date modif.
IPModification=Modification IP
DateLastModification=Date de dernière modification
DateValidation=Date validation
+DateSigning=Date signature
DateClosing=Date clôture
DateDue=Date échéance
DateValue=Date valeur
diff --git a/htdocs/langs/fr_FR/other.lang b/htdocs/langs/fr_FR/other.lang
index 3023cd7216e..a8078129464 100644
--- a/htdocs/langs/fr_FR/other.lang
+++ b/htdocs/langs/fr_FR/other.lang
@@ -114,6 +114,7 @@ DemoCompanyAll=Société avec de multiples activités (tous les modules principa
CreatedBy=Créé par %s
ModifiedBy=Modifié par %s
ValidatedBy=Validé par %s
+SignedBy=Signé par %s
ClosedBy=Clôturé par %s
CreatedById=Id utilisateur créateur
ModifiedById=Id utilisateur du dernier changement