diff --git a/class/saturneform.class.php b/class/saturneform.class.php
new file mode 100644
index 00000000..65c2dbd1
--- /dev/null
+++ b/class/saturneform.class.php
@@ -0,0 +1,204 @@
+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * \file class/saturneform.class.php
+ * \ingroup saturne
+ * \brief Class file for manage SaturneForm
+ */
+
+// Load Dolibarr libraries
+require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
+require_once DOL_DOCUMENT_ROOT . '/core/lib/functions.lib.php';
+
+/**
+ * Class for SaturneForm
+ */
+class SaturneForm
+{
+ /**
+ * @var bool Browser layout is on phone
+ */
+ public bool $OnPhone = false;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ global $conf;
+
+ if ($conf->browser->layout == 'phone') {
+ $this->OnPhone = true;
+ }
+ }
+
+ /**
+ * Show modify button
+ *
+ * @param SaturneObject $object Current object
+ * @param array $moreParams More parameters
+ */
+ public function showModifyButton(SaturneObject $object, array $moreParams = [])
+ {
+ global $langs;
+
+ // Modify
+ $displayButton = $this->OnPhone ? '' : '' . ' ' . $langs->trans('Modify');
+ if (($object->status == $object::STATUS_DRAFT || $moreParams['check'])) {
+ print '' . $displayButton . '';
+ } else {
+ print '' . $displayButton . '';
+ }
+ }
+
+ /**
+ * Show validate button
+ *
+ * @param SaturneObject $object Current object
+ * @param array $moreParams More parameters
+ */
+ public function showValidateButton(SaturneObject $object, array $moreParams = [])
+ {
+ global $langs;
+
+ // Validate
+ $displayButton = $this->OnPhone ? '' : '' . ' ' . $langs->trans('Validate');
+ if (($object->status == $object::STATUS_DRAFT || $moreParams['check'])) {
+ print '' . $displayButton . '';
+ } elseif ($object->status < $object::STATUS_DRAFT) {
+ print '' . $displayButton . '';
+ }
+ }
+
+ /**
+ * Show reopen button
+ *
+ * @param SaturneObject $object Current object
+ */
+ public function showReOpenButton(SaturneObject $object)
+ {
+ global $langs;
+
+ // ReOpen
+ $displayButton = $this->OnPhone ? '' : '' . ' ' . $langs->trans('ReOpenDoli');
+ if ($object->status == $object::STATUS_VALIDATED) {
+ print '' . $displayButton . '';
+ } elseif ($object->status > $object::STATUS_VALIDATED) {
+ print '' . $displayButton . '';
+ }
+ }
+
+ /**
+ * Show sign button
+ *
+ * @param SaturneObject $object Current object
+ * @param SaturneSignature $signatory Signatory object
+ * @throws Exception
+ */
+ public function showSignButton(SaturneObject $object, SaturneSignature $signatory)
+ {
+ global $langs;
+
+ // Sign
+ $displayButton = $this->OnPhone ? '' : '' . ' ' . $langs->trans('Sign');
+ if ($object->status == $object::STATUS_VALIDATED && !$signatory->checkSignatoriesSignatures($object->id, $object->element)) {
+ print '' . $displayButton . '';
+ } else {
+ print '' . $displayButton . '';
+ }
+ }
+
+ /**
+ * Show lock button
+ *
+ * @param SaturneObject $object Current object
+ * @param SaturneSignature $signatory Signatory object
+ * @throws Exception
+ */
+ public function showlockButton(SaturneObject $object, SaturneSignature $signatory)
+ {
+ global $langs;
+
+ // Lock
+ $displayButton = $this->OnPhone ? '' : '' . ' ' . $langs->trans('Lock');
+ if ($object->status == $object::STATUS_VALIDATED && $signatory->checkSignatoriesSignatures($object->id, $object->element)) {
+ print '' . $displayButton . '';
+ } else {
+ print '' . $displayButton . '';
+ }
+ }
+
+ /**
+ * Show send email button
+ *
+ * @param SaturneObject $object Current object
+ * @param string $uploadDir Upload dir path
+ */
+ public function showSendEmailButton(SaturneObject $object, string $uploadDir)
+ {
+ global $langs;
+
+ // Send email
+ $displayButton = $this->OnPhone ? '' : '' . ' ' . $langs->trans('SendMail');
+ if ($object->status == $object::STATUS_LOCKED) {
+ $fileParams = dol_most_recent_file($uploadDir . '/' . $object->element . 'document' . '/' . $object->ref);
+ $file = $fileParams['fullname'];
+ if (file_exists($file) && !strstr($fileParams['name'], 'specimen')) {
+ $forceBuildDoc = 0;
+ } else {
+ $forceBuildDoc = 1;
+ }
+ print dolGetButtonAction($displayButton, '', 'default', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=presend&forcebuilddoc=' . $forceBuildDoc . '&mode=init#formmailbeforetitle');
+ } else {
+ print '' . $displayButton . '';
+ }
+ }
+
+ /**
+ * Show archive button
+ *
+ * @param SaturneObject $object Current object
+ */
+ public function showArchiveButton(SaturneObject $object)
+ {
+ global $langs;
+
+ // Archive
+ $displayButton = $this->OnPhone ? '' : '' . ' ' . $langs->trans('Archive');
+ if ($object->status == $object::STATUS_LOCKED) {
+ print '' . $displayButton . '';
+ } else {
+ print '' . $displayButton . '';
+ }
+ }
+
+ /**
+ * Show delete button
+ *
+ * @param SaturneObject $object Current object
+ * @param int $permissionToDelete Delete object permission
+ */
+ public function showDeleteButton(SaturneObject $object, int $permissionToDelete)
+ {
+ global $langs;
+
+ // Delete (need delete permission, or if draft, just need create/modify permission)
+ $displayButton = $this->OnPhone ? '' : '' . ' ' . $langs->trans('Delete');
+ print dolGetButtonAction($displayButton, '', 'delete', $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&action=delete&token=' . newToken(), '', $permissionToDelete || ($object->status == $object::STATUS_DRAFT));
+ }
+}