diff --git a/ChangeLog.md b/ChangeLog.md index 4cc1cb8..906f983 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,8 @@ # CHANGELOG SENDRECURRINGINVOICEBYMAIL FOR DOLIBARR ERP CRM +## 0.3.0 +Dedicated tab on the template invoice's page, to be able to customize more cleanly the recipients, and the email content. + ## 0.2.7 Add the possibility to overwrite some email fields (recipients, subject, body) for each template. diff --git a/README.md b/README.md index 904240b..39a3144 100644 --- a/README.md +++ b/README.md @@ -2,62 +2,31 @@ ## Features -This module send the PDF generated with recurring invoices by email to the client. +(en) This module send the invoice generated with recurring invoices by email to the client. -You can customize the mail template in Home > Setup > Emails > Email templates. +(fr) Ce module envoie par mail les factures générées automatiquement par les travaux planifiés et les factures modèles. -Beta - test in progress : you can also customize for each template invoice, by adding some of those blocks in the private notes of the template. -``` -This is a good client (this is outside of the %%% blocks so it won't appear in the mails :) +You can customize the mail globally or by recurring invoice. -%%% sendrecurringinvoicebymail::body -Hello dear client, +![Screenshot n° 1](img/screenshot1.png?raw=true) -Please find attached... invoice __REF__... +To edit the default global mail template, go to Home > Setup > Emails > Email templates, and modify the `SendRecurringInvoiceByMail : original template`. If you don't want to attach the PDF of the invoice to the mails, set the `Attach file` input to 0 (default: 1, PDF attached). -__(Sincerely)__, +To edit the default sender address, go to Home > Setup > Emails, and edit the `Sender email for automatic emails` field. -__MYCOMPANY_NAME__ -%%% - -%%% sendrecurringinvoicebymail::subject -My custom subject -%%% -%%% sendrecurringinvoicebymail::sendto -test1@example.org, "Mr. Test2" -%%% -``` +This module is triggered by the cron (Scheduled jobs module) and will not send emails when manually generating an invoice. ## Requirements -It requires Dolibarr version 10.0 at least (first version with the 'cron/afterCreationOfRecurringInvoice()' hook). +It requires Dolibarr version 10.0 at least (first version with the `cron/afterCreationOfRecurringInvoice()` hook). - +Don't forget to also activate the **Scheduled jobs** module. Other modules are available on Dolistore.com. - - - - - +* Disable the module, +* Update the files (see Install), +* Re-enable the module. -Licenses --------- +## Licenses ### Main code diff --git a/class/actions_sendrecurringinvoicebymail.class.php b/class/actions_sendrecurringinvoicebymail.class.php index f1080d2..b569c95 100644 --- a/class/actions_sendrecurringinvoicebymail.class.php +++ b/class/actions_sendrecurringinvoicebymail.class.php @@ -23,224 +23,174 @@ * Put detailed description here. */ + // Load needed classes/lib + require_once 'sribmcustommailinfo.class.php'; + /** * Class Actionssendrecurringinvoicebymail */ class Actionssendrecurringinvoicebymail { - /** - * @var DoliDB Database handler. - */ - public $db; + /** + * @var DoliDB Database handler. + */ + public $db; - /** - * @var string Error code (or message) - */ - public $error = ''; + /** + * @var string Error code (or message) + */ + public $error = ''; - /** - * @var array Errors - */ - public $errors = array(); + /** + * @var array Errors + */ + public $errors = array(); - /** - * @var array Hook results. Propagated to $hookmanager->resArray for later reuse - */ - public $results = array(); + /** + * @var array Hook results. Propagated to $hookmanager->resArray for later reuse + */ + public $results = array(); - /** - * @var string String displayed by executeHook() immediately after return - */ - public $resprints; + /** + * @var string String displayed by executeHook() immediately after return + */ + public $resprints; - /** - * Constructor - * - * @param DoliDB $db Database handler - */ - public function __construct($db) - { - $this->db = $db; - } + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + $this->db = $db; + } - /** - * Overloading the doActions function : replacing the parent's function with the one below - * - * @param array $parameters Hook metadatas (context, etc...) - * @param CommonObject $object The object to process (an invoice if you are in invoice module, a propale in propale's module, etc...) - * @param string $action Current action (if set). Generally create or edit or null - * @param HookManager $hookmanager Hook manager propagated to allow calling another hook - * @return int < 0 on error, 0 on success, 1 to replace standard code - */ - public function afterCreationOfRecurringInvoice($parameters, &$object, &$action, $hookmanager) - { - global $conf, $user, $langs; - $langs->load('mails'); + /** + * Overloading the doActions function : replacing the parent's function with the one below + * + * @param array $parameters Hook metadatas (context, etc...) + * @param CommonObject $object The object to process (an invoice if you are in invoice module, a propale in propale's module, etc...) + * @param string $action Current action (if set). Generally create or edit or null + * @param HookManager $hookmanager Hook manager propagated to allow calling another hook + * @return int < 0 on error, 0 on success, 1 to replace standard code + */ + public function afterCreationOfRecurringInvoice($parameters, &$object, &$action, $hookmanager) + { + global $conf, $user, $langs; + $langs->load('mails'); - $error = 0; // Error counter + $error = 0; // Error counter - $facturerec = $parameters['facturerec']; + $facturerec = $parameters['facturerec']; + $mailObject = new SRIBMCustomMailInfo($this->db); + if ($mailObject->fetch(null, $facturerec->id, true) != 1) { + dol_syslog("Error loading SRIBMCustomMailInfo for facture rec " . (isset($facturerec->id) ? $facturerec->id : "(facturerec->id not set ??)")); + return -1; + } - // We only send the mail when the invoice is not a draft - if ($object->brouillon) { - return 0; - } + // We only send the mail when the invoice is not a draft + // and the sending is enabled for the template. + if ($object->brouillon || !$mailObject->active) { + return 0; + } - // Fetch the mail template - // (pas très précise mais je commence à en avoir marre de creuser tout dolibarr pour trouver les bonnes fonctions...) - $result = $this->db->query("SELECT * FROM " . MAIN_DB_PREFIX . "c_email_templates WHERE module = 'sendrecurringinvoicebymail' AND active = 1 AND enabled = '1' ORDER BY tms DESC LIMIT 1"); - if ( ! $result or ! ($template = $this->db->fetch_object($result))) { - $this->error = "Can't find mail template for sendrecurringinvoicebymail"; - $this->errors[] = $this->error; - $error++; - return -1; - } + // Prepare the substitions for mail's subject and message (ex-body) + $substitutionarray = getCommonSubstitutionArray($langs, 0, null, $object); + complete_substitutions_array($substitutionarray, $langs, $object); // lourd et n'a rien ajouté lors de mes tests - // Prepare the substitions for mail's subject and body - $substitutionarray = getCommonSubstitutionArray($langs, 0, null, $object); - complete_substitutions_array($substitutionarray, $langs, $object); // lourd et n'a rien ajouté lors de mes tests + // Adding some useful substitions of our own... + if ( ! empty($object->linkedObjects['contrat'])) { + $contrat = reset($object->linkedObjects['contrat']); // no deep search, we take the first linked contract + $substitutionarray['__CONTRACT_REF__'] = $contrat->ref; + } - // Adding some useful substitions of our own... - if ( ! empty($object->linkedObjects['contrat'])) { - $contrat = reset($object->linkedObjects['contrat']); // no deep search, we take the first linked contract - $substitutionarray['__CONTRACT_REF__'] = $contrat->ref; - } + // Initialisations + $mail_data = array( + 'from' => $mailObject->frommail, + 'to' => implode(', ', $mailObject->compileEmails('to', true)), + 'cc' => implode(', ', $mailObject->compileEmails('cc', true)), + 'bcc' => implode(', ', $mailObject->compileEmails('bcc', true)), + 'errorsTo' => $conf->global->MAIN_MAIL_ERRORS_TO, + 'replyTo' => $conf->global->MAIN_MAIL_ERRORS_TO, + 'subject' => $mailObject->subject, + 'message' => $mailObject->body_plaintext, + ); - // Initialisations - $mail_data = array( - 'sendto' => $object->thirdparty->name . ' <' . $object->thirdparty->email . '>', - 'from' => $conf->global->MAIN_MAIL_EMAIL_FROM, - 'errorsTo' => $conf->global->MAIN_MAIL_ERRORS_TO, - 'replyTo' => $conf->global->MAIN_MAIL_ERRORS_TO, - 'subject' => $template->topic, - 'body' => $template->content, - ); + // Check that we have a recipient, to avoid some frequent error... + if (empty($mail_data['to'] . $mail_data['cc'] . $mail_data['bcc'])) { + dol_syslog("Empty recipient for thirdparty " . $object->thirdparty->id . ". Not sending facturerec " . $facturerec->ref . " (id:" . $facturerec->id . ")."); + return 0; + } - // If the invoice has some custom parameters (subject, body, sendto, ...) - $mail_data = array_merge($mail_data, $this->getCustomFieldsMail($object)); + // Make the substitutions + foreach (array('subject', 'message') as $key) { + $mail_data[$key] = make_substitutions($mail_data[$key], $substitutionarray, $langs); + if (method_exists($object, 'makeSubstitution')) { + $mail_data[$key] = $object->makeSubstitution($mail_data[$key]); + } + } - // Check that we have a recipient, to avoid some frequent error... - if (empty($mail_data['sendto'])) { - dol_syslog("Empty recipient for thirdparty " . $object->thirdparty->id . ". Not sending facturerec " . $facturerec->ref . " (id:" . $facturerec->id . ")."); - return 0; - } + // Check if we have to attach the file + $filePath = array(); + $fileMime = array(); + $fileName = array(); + if ($mailObject->addmaindocfile) { + $filePath = array(DOL_DATA_ROOT . '/' . $object->last_main_doc); + $fileMime = array('application/pdf'); // FIXME: à rendre dynamique, même si ce sera toujours du PDF ? + $fileName = array(basename($object->last_main_doc)); + } - // Make the substitutions - foreach (array('subject', 'body') as $key) { - $mail_data[$key] = make_substitutions($mail_data[$key], $substitutionarray, $langs); - if (method_exists($object, 'makeSubstitution')) { - $mail_data[$key] = $object->makeSubstitution($mail_data[$key]); - } - } + // At last, send the mail + $mailfile = new CMailFile( + $mail_data['subject'], + $mail_data['to'], + $mail_data['from'], + $mail_data['message'], + $filePath, + $fileMime, + $fileName, + $mail_data['cc'], // CC + $mail_data['bcc'], // BCC + 0, //deliveryreceipt + 0, //msgishtml + $mail_data['errorsTo'], + '', // css + '', // trackid + '', // moreinheader + 'standard', // sendcontext + $mail_data['replyTo']); - // Check if we have to attach the file - $filePath = array(); - $fileMime = array(); - $fileName = array(); - if ($template->joinfiles) { - $filePath = array(DOL_DATA_ROOT . '/' . $object->last_main_doc); - $fileMime = array('application/pdf'); // FIXME: à rendre dynamique, même si ce sera toujours du PDF ? - $fileName = array(basename($object->last_main_doc)); - } + if ($mailfile->sendfile()) { + dol_syslog("Success sending email for " . $facturerec->ref . " (id:" . $facturerec->id . ")."); - // At last, send the mail - $mailfile = new CMailFile( - $mail_data['subject'], - $mail_data['sendto'], - $mail_data['from'], - $mail_data['body'], - $filePath, - $fileMime, - $fileName, - '', // CC - '', // BCC - 0, //deliveryreceipt - 0, //msgishtml - $mail_data['errorsTo'], - '', // css - '', // trackid - '', // moreinheader - 'standard', // sendcontext - $mail_data['replyTo']); + // Adds info to object for trigger + // (maybe make a copy of the object instead of modifying it directly ?) + $object->email_msgid = $mailfile->msgid; + $object->email_from = $mail_data['from']; + $object->email_subject = $mail_data['subject']; + $object->email_to = $mail_data['to']; + $object->email_tocc = $mail_data['cc']; + $object->email_tobcc = $mail_data['bcc']; + $object->actiontypecode = 'AC_OTH_AUTO'; + $object->actionmsg2=$langs->transnoentities('MailSentBy').' '.CMailFile::getValidAddress($mail_data['from'],4,0,1).' '.$langs->transnoentities('To').' '.CMailFile::getValidAddress($mail_data['to'],4,0,1); + $object->actionmsg = $langs->transnoentities('MailFrom').': '.dol_escape_htmltag($mail_data['from']); + $object->actionmsg = dol_concatdesc($object->actionmsg, $langs->transnoentities('MailTo').': '.dol_escape_htmltag($mail_data['to'])); + $object->actionmsg = dol_concatdesc($object->actionmsg, $langs->transnoentities('MailTopic') . ": " . $mail_data['subject']); + $object->actionmsg = dol_concatdesc($object->actionmsg, $langs->transnoentities('TextUsedInTheMessageBody') . ":"); + $object->actionmsg = dol_concatdesc($object->actionmsg, $mail_data['message']); - if ($mailfile->sendfile()) { - dol_syslog("Success sending email for " . $facturerec->ref . " (id:" . $facturerec->id . ")."); - - // Adds info to object for trigger - // (maybe make a copy of the object instead of modifying it directly ?) - $object->email_msgid = $mailfile->msgid; - $object->email_from = $mail_data['from']; - $object->email_subject = $mail_data['subject']; - $object->email_to = $mail_data['sendto']; - //$object->email_tocc = $sendtocc; - //$object->email_tobcc = $sendtobcc; - $object->actiontypecode = 'AC_OTH_AUTO'; - $object->actionmsg2=$langs->transnoentities('MailSentBy').' '.CMailFile::getValidAddress($mail_data['from'],4,0,1).' '.$langs->transnoentities('To').' '.CMailFile::getValidAddress($mail_data['sendto'],4,0,1); - $object->actionmsg = $langs->transnoentities('MailFrom').': '.dol_escape_htmltag($mail_data['from']); - $object->actionmsg = dol_concatdesc($object->actionmsg, $langs->transnoentities('MailTo').': '.dol_escape_htmltag($mail_data['sendto'])); - $object->actionmsg = dol_concatdesc($object->actionmsg, $langs->transnoentities('MailTopic') . ": " . $mail_data['subject']); - $object->actionmsg = dol_concatdesc($object->actionmsg, $langs->transnoentities('TextUsedInTheMessageBody') . ":"); - $object->actionmsg = dol_concatdesc($object->actionmsg, $mail_data['body']); - - // Launch triggers - $interface = new Interfaces($this->db); - $resultTrigger = $interface->run_triggers('BILL_SENTBYMAIL', $object, $user, $langs, $conf); - } else { - $this->error = "Error sending email for " . $facturerec->ref . " (id:" . $facturerec->id . ")."; - $this->errors[] = $this->error; - dol_syslog($this->error); - $error++; - } - - return ($error ? -1 : 0); - } - - - /** - * FIXME: For the time being, we abuse of note_private to store our customizations - */ - public function getCustomFieldsMail($object) - { - return $this->parseCustomFieldsMail($object->note_private); - } - - /** - * FIXME: For the time being, we abuse of note_private to store our customizations - * - * This expect something like this in note_private: - * This is a good client... (other private infos) - * %%% sendrecurringinvoicebymail::subject - * New invoice __REF__ - * %%% - * %%% sendrecurringinvoicebymail::sendto - * recipient1@example.org, recipient2@example.org - * %%% - * %%% sendrecurringinvoicebymail::body - * Hello dear client, - * Please find attached... - * %%% - */ - public function parseCustomFieldsMail($data) - { - $output = []; - - // Remove eventual windows' "\r" - $data = str_replace("\r", "", $data); - - $regexps = array( - 'subject' => '/(^|\n)%%% sendrecurringinvoicebymail::subject\n(?.*)%%%(\n|$)/sU', - 'body' => '/(^|\n)%%% sendrecurringinvoicebymail::body\n(?.*)%%%(\n|$)/sU', - 'sendto' => '/(^|\n)%%% sendrecurringinvoicebymail::sendto\n(?.*)%%%(\n|$)/sU', - ); - foreach ($regexps as $key => $r) { - $result_regexp = []; - if (preg_match_all($r, $data, $result_regexp)) { - $output[$key] = trim($result_regexp[$key][0]); - } - } - - return $output; - } + // Launch triggers + $interface = new Interfaces($this->db); + $resultTrigger = $interface->run_triggers('BILL_SENTBYMAIL', $object, $user, $langs, $conf); + } else { + $this->error = "Error sending email for " . $facturerec->ref . " (id:" . $facturerec->id . ")."; + $this->errors[] = $this->error; + dol_syslog($this->error); + $error++; + } + return ($error ? -1 : 0); + } } diff --git a/class/sribmcustommailinfo.class.php b/class/sribmcustommailinfo.class.php new file mode 100644 index 0000000..6559134 --- /dev/null +++ b/class/sribmcustommailinfo.class.php @@ -0,0 +1,516 @@ +. + */ + +/** + * \file class/sribmcustommailinfo.class.php + * \brief File of class for objects storing custom mail informations (module SRIBM : SendRecurringInvoiceByMail) + */ + +require_once DOL_DOCUMENT_ROOT . '/core/class/commonobject.class.php'; +require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture-rec.class.php'; +require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php'; + +/** + * Class for objects storing custom mail informations. + * + * Part of module SRIBM : SendRecurringInvoiceByMail + */ +class SRIBMCustomMailInfo extends CommonObject +{ + /** + * @var string Id to identify managed objects + */ + public $element = 'sribmcustommailinfo'; + + /** + * @var string Name of table without prefix where object is stored + */ + public $table_element = 'sribm_custom_mail_info'; + + // Database fields + + /** + * @var int + */ + public $fk_facture_rec; + + /** + * @var int + */ + public $active = 1; + + /** + * @var string + */ + public $addmaindocfile = 1; + + /** + * @var string Type of sender, could be 'robot', 'user' or 'company', + * usually meaning the mail sender is determined by the + * PHP/Dolibarr config (cf. admin/mails.php?mainmenu=home ), + * this object's creator email or the company email. + */ + public $fromtype = 'robot'; + + /** + * @var string + */ + public $frommail; + + /** + * @var int 1: Send to societe main's email, 0: don't. + */ + public $sendto_thirdparty = 1; + + /** + * @var string Format expected: "Foo , bar@example.net" + */ + public $sendto_free; + + /** + * @var int 1: Send to societe main's email, 0: don't. + */ + public $sendcc_thirdparty = 0; + + /** + * @var string Format expected: "Foo , bar@example.net" + */ + public $sendcc_free; + + /** + * @var int 1: Send to societe main's email, 0: don't. + */ + public $sendbcc_thirdparty = 0; + + /** + * @var string Format expected: "Foo , bar@example.net" + */ + public $sendbcc_free; + + /** + * @var string + */ + public $subject; + + /** + * @var string + */ + public $body_plaintext; + + /** + * @var string (not used at the moment) + */ + public $body_html; + + // End of database fields + + /** + * FactureRec object linked to this object + * + * Note : the class Facture use $fac_rec and fk_fac_rec_source which both + * seem to be integer (I don't really see the distinction), so we suffix + * with '_object' to avoid future conflict. + * + * @var FactureRec + */ + public $fac_rec_object; + + /** + * @var array SocPeoples linked via table llx_sribm_custom_mail_info_socpeople (FIXME: describe format) + */ + public $linkToSocPeoples = array(); + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + public function __construct(DoliDB $db) + { + global $conf; + + $this->db = $db; + + // Fill default values + $this->frommail = $conf->global->MAIN_MAIL_EMAIL_FROM; + } + + /** + * Create object into database + * + * Since only one mail can exist for each invoice template, this method + * only insert a row with the id of the template and delegate all the work + * on the rest of the data to the update() method. + * + * @param User $user User that creates (at the moment, we don't use it) + * @param int $notrigger 1=do not execute triggers, 0 otherwise + * @return int >0 if OK, < 0 if KO + */ + public function create(User $user, $notrigger = 0) + { + $error=0; + + $this->db->begin(); + + $sql = "INSERT INTO " . MAIN_DB_PREFIX . $this->table_element; + $sql .= " (fk_facture_rec, fromtype, frommail)"; + $sql .= sprintf( + " VALUES (%d, '%s', '%s')", + (int)$this->fk_facture_rec, + $this->db->escape($this->fromtype), + $this->db->escape($this->frommail) + ); + + dol_syslog("SRIBMCustomMailInfo::create", LOG_DEBUG); + + $result = $this->db->query($sql); + if ($result) { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element); + $result = $this->update($user, 1); + if ($result < 0) { + $this->db->rollback(); + return -3; + } + + if (! $notrigger) + { + // Call trigger + $result=$this->call_trigger('SRIBM_CUSTOM_MAIL_INFO_CREATE', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + + if ($error) { + dol_syslog(get_class($this) . "::create " . $this->error, LOG_ERR); + $this->db->rollback(); + return -2; + } + } else { + $this->error = $this->db->lasterror(); + $this->db->rollback(); + return -1; + } + + $this->db->commit(); + return $this->id; + } + + /** + * Update object in database + * + * @param User $user User that creates (at the moment, we don't use it) + * @param int $notrigger 1=do not execute triggers, 0 otherwise + * @return int >0 if OK, < 0 if KO + */ + public function update(User $user, $notrigger = 0) + { + $error=0; + + //$this->db->begin(); + + $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element; + $sql .= " SET "; + $sql .= " fk_facture_rec = " . (int)$this->fk_facture_rec; + $sql .= ", active = " . (int)$this->active; + $sql .= ", addmaindocfile = '" . (int)$this->addmaindocfile . "'"; + $sql .= ", fromtype = '" . $this->db->escape($this->fromtype) . "'"; + $sql .= ", frommail = '" . $this->db->escape($this->frommail) . "'"; + $sql .= ", sendto_thirdparty = " . (int)$this->db->escape($this->sendto_thirdparty); + $sql .= ", sendto_free = '" . $this->db->escape($this->sendto_free) . "'"; + $sql .= ", sendcc_thirdparty = " . (int)$this->db->escape($this->sendcc_thirdparty); + $sql .= ", sendcc_free = '" . $this->db->escape($this->sendcc_free) . "'"; + $sql .= ", sendbcc_thirdparty = " . (int)$this->db->escape($this->sendbcc_thirdparty); + $sql .= ", sendbcc_free = '" . $this->db->escape($this->sendbcc_free) . "'"; + $sql .= ", subject = '" . $this->db->escape($this->subject) . "'"; + $sql .= ", body_plaintext = '" . $this->db->escape($this->body_plaintext) . "'"; + $sql .= ", body_html = '" . $this->db->escape($this->body_html) . "'"; + $sql .= " WHERE rowid = " . (int)$this->id; + + $result = $this->db->query($sql); + if ($result) { + if (! $notrigger) + { + // Call trigger + $result=$this->call_trigger('SRIBM_CUSTOM_MAIL_INFO_MODIFY', $user); + if ($result < 0) { + $error++; + } + // End call triggers + } + + if ($error) { + dol_syslog(get_class($this) . "::update " . $this->error, LOG_ERR); + $this->db->rollback(); + return -$error; + } + } else { + $this->error = $this->db->lasterror(); + $this->db->rollback(); + return -1; + } + + //$this->db->commit(); + return 1; + } + + /** + * Populate object with data from DB + * + * @param int $rowid Id of the SRIBMCustomMailInfo to load + * @param int $ref Id of the fac_rec_object + * @param bool $fill_defaults_from_template If true and the model doesn't exist in DB, fill attributes using the template + * @return int < 0 if KO, > 0 if OK + */ + public function fetch($rowid, $ref=null, $fill_defaults_from_template = false) + { + global $conf; + + $sql = "SELECT rowid, fk_facture_rec, active, addmaindocfile, fromtype, frommail, sendto_thirdparty, sendto_free, sendcc_thirdparty, sendcc_free, sendbcc_thirdparty, sendbcc_free, subject, body_plaintext, body_html"; + $sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element; + $sql .= " WHERE " . (isset($ref) ? 'fk_facture_rec = ' . (int)$ref : "rowid = " . (int)$rowid); + + dol_syslog("SRIBMCustomMailInfo::fetch", LOG_DEBUG); + + $result = $this->db->query($sql); + if (! $result) { + $this->error=$this->db->lasterror(); + return -1; + } + + if ($this->db->num_rows($result)) { + $obj = $this->db->fetch_object($result); + + $this->id = $obj->rowid; + $this->fk_facture_rec = $obj->fk_facture_rec; + $this->active = $obj->active; + $this->addmaindocfile = $obj->addmaindocfile; + $this->fromtype = $obj->fromtype; + $this->frommail = $obj->frommail; + $this->sendto_thirdparty = $obj->sendto_thirdparty; + $this->sendto_free = $obj->sendto_free; + $this->sendcc_thirdparty = $obj->sendcc_thirdparty; + $this->sendcc_free = $obj->sendcc_free; + $this->sendbcc_thirdparty = $obj->sendbcc_thirdparty; + $this->sendbcc_free = $obj->sendbcc_free; + $this->subject = $obj->subject; + $this->body_plaintext = $obj->body_plaintext; + $this->body_html = $obj->body_html; + $ref = $obj->fk_facture_rec; + } elseif (!$fill_defaults_from_template) { + $this->error = "SRIBMCustomMailInfo not found (id: " . var_export($rowid, true) . ", ref: " . var_export($ref, true); + dol_syslog("SRIBMCustomMailInfo::fetch error " . $this->error, LOG_ERR); + } + + // It seems to be usual to fully fetch by default (cf. Facture source + // code with fetch_optionals()) so we copy the Dolibarr behaviour + // Link to the facture_rec + $this->fac_rec_object = new FactureRec($this->db); + if ($this->fac_rec_object->fetch($ref) <= 0) { + $this->error = "Unable to fetch FactureRec $ref."; + dol_syslog("FactureRec::Fetch error " . $this->error, LOG_ERR); + return -2; + } + if ($this->fac_rec_object->fetch_thirdparty() <= 0) { + $this->error = "Unable to fetch ThirdParty for FactureRec $ref."; + dol_syslog("FactureRec::FetchThirdParty error " . $this->error, LOG_ERR); + return -3; + } + $result = $this->fac_rec_object->fetchObjectLinked(null, '', null, '', 'OR', 1, 'sourcetype', 0); // This load $_facrec->linkedObjectsIds + + // link to socpeople + if ($this->id) { + // FIXME: create a dedicated PHP class? + $sql = "SELECT fk_socpeople, sendtype"; + $sql .= " FROM " . MAIN_DB_PREFIX . "sribm_custom_mail_info_socpeople"; + $sql .= " WHERE fk_sribm_cmi = " . (int)$this->id; + $result = $this->db->query($sql); + if (! $result) { + $this->error=$this->db->lasterror(); + return -1; + } + + // reset the attribute + $this->linkToSocPeoples = array(); + while ($obj = $this->db->fetch_object($result)) { + $tmp = new Contact($this->db); + if ($tmp->fetch($obj->fk_socpeople) > 0) { + $tmp->pivot = $obj; + $this->linkToSocPeoples[] = $tmp; + } + } + } + + // Optionally, if the model hasn't been found (no id), we fill with the template's data + if (!$this->id && $fill_defaults_from_template) { + $result = $this->db->query("SELECT topic, content, joinfiles FROM " . MAIN_DB_PREFIX . "c_email_templates WHERE module = 'sendrecurringinvoicebymail' AND active = 1 AND enabled = '1' ORDER BY tms DESC LIMIT 1"); + if ( ! $result or ! ($template = $this->db->fetch_object($result))) { + $this->error = "Can't find mail template for sendrecurringinvoicebymail"; + dol_syslog("SRIBMCustomMailInfo::fetch error " . $this->error, LOG_ERR); + return -4; + } + + $this->subject = $template->topic; + $this->body_plaintext = $template->content; + $this->addmaindocfile = $template->joinfiles; + } + + return 1; + } + + /** + * Delete this object's record in database + * + * @return int <0 on error, >0 if OK + */ + public function delete() + { + $error=0; + + //$this->db->begin(); + + $sql = "DELETE FROM " . MAIN_DB_PREFIX . $this->table_element; + $sql .= " WHERE rowid = " . (int)$this->id; + + $result = $this->db->query($sql); + if (! $result) { + //$this->db->rollback(); + $this->error = $this->db->lasterror(); + return -1; + } + + // Call trigger + $result = $this->call_trigger('SRIBM_CUSTOM_MAIL_INFO_DELETE', $user); + if ($result < 0) { + $error++; + } + // End call triggers + + if ($error) { + dol_syslog(get_class($this) . "::delete " . $this->error, LOG_ERR); + //$this->db->rollback(); + return -$error; + } + + //$this->db->commit(); + return 1; + } + + /** + * Quick function to synchronize the links between this object and its contacts + * + * Format of the data : + * array( + * array('id' => id_contact_1, 'sendtype' => 'to'), + * array('id' => id_contact_2, 'sendtype' => 'cc'), + * ... + * + * @param array $data Format : see above + * @return int <0 on error, >0 if OK + */ + public function updateLinkSocPeople($data) + { + $this->db->begin(); + + $result = $this->db->query("DELETE FROM " . MAIN_DB_PREFIX . "sribm_custom_mail_info_socpeople where fk_sribm_cmi = " . (int)$this->id); + if (! $result) { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return -1; + } + + if ($data) { + $sql = "INSERT INTO " . MAIN_DB_PREFIX . "sribm_custom_mail_info_socpeople"; + $sql .= " (fk_sribm_cmi, fk_socpeople, sendtype) VALUES (%d, %d, '%s')"; + foreach ($data as $item) { + // We insert one by one to maximize compatibility + // (if there happens to be thousands of links, I'll rework it :) + $result = $this->db->query(sprintf( + $sql, + $this->id, + $item['id'], + $this->db->escape($item['sendtype']) + )); + if (! $result) { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return -2; + } + } + } + + $this->db->commit(); + return 1; + } + + /** + * Helper to compile the recipients in one string from sendto_thirdparty, + * sendto_free and socpeople. + * + * @param string $sendtype One of 'to', 'cc', 'bcc' + * @param bool $filterBadEmail If true, don't include recipients with empty/bad email address + * @return string String compiling emails in the format 'Foo , bar@example.com' + */ + public function compileEmails($sendtype, $filterBadEmails = false) + { + $output = array(); + + $listContacts = $this->fac_rec_object->thirdparty->thirdparty_and_contact_email_array(1); + + switch ($sendtype) { + case 'to': + if ($this->sendto_free) { + $output[] = $this->sendto_free; + } + if ($this->sendto_thirdparty) { + $output[] = $listContacts['thirdparty']; + } + break; + + case 'cc': + if ($this->sendcc_free) { + $output[] = $this->sendcc_free; + } + if ($this->sendcc_thirdparty) { + $output[] = $listContacts['thirdparty']; + } + break; + + case 'bcc': + if ($this->sendbcc_free) { + $output[] = $this->sendbcc_free; + } + if ($this->sendbcc_thirdparty) { + $output[] = $listContacts['thirdparty']; + } + break; + } + + foreach ($this->linkToSocPeoples as $contact) { + if ($contact->pivot->sendtype == $sendtype) { + $output[] = $listContacts[$contact->id]; + } + } + + if ($filterBadEmails) { + // TODO + } + + return $output; + } +} diff --git a/core/modules/modsendrecurringinvoicebymail.class.php b/core/modules/modsendrecurringinvoicebymail.class.php index 176e9b7..9d816d3 100644 --- a/core/modules/modsendrecurringinvoicebymail.class.php +++ b/core/modules/modsendrecurringinvoicebymail.class.php @@ -1,6 +1,6 @@ - * Copyright (C) 2018 Nicolas ZABOURI + * Copyright (C) 2018 Nicolas ZABOURI * Copyright (C) 2018 SuperAdmin * * This program is free software; you can redistribute it and/or modify @@ -18,7 +18,7 @@ */ /** - * \defgroup sendrecurringinvoicebymail Module sendrecurringinvoicebymail + * \defgroup sendrecurringinvoicebymail Module sendrecurringinvoicebymail * \brief sendrecurringinvoicebymail module descriptor. * * \file htdocs/sendrecurringinvoicebymail/core/modules/modsendrecurringinvoicebymail.class.php @@ -33,324 +33,412 @@ include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php'; */ class modsendrecurringinvoicebymail extends DolibarrModules { - /** - * Constructor. Define names, constants, directories, boxes, permissions - * - * @param DoliDB $db Database handler - */ - public function __construct($db) - { + /** + * Constructor. Define names, constants, directories, boxes, permissions + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { global $langs,$conf; $this->db = $db; - // Id for module (must be unique). - // Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id). - $this->numero = 468101; // TODO Go on page https://wiki.dolibarr.org/index.php/List_of_modules_id to reserve id number for your module - // Key text used to identify module (for permissions, menus, etc...) - $this->rights_class = 'sendrecurringinvoicebymail'; + // Id for module (must be unique). + // Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id). + $this->numero = 468101; // TODO Go on page https://wiki.dolibarr.org/index.php/List_of_modules_id to reserve id number for your module + // Key text used to identify module (for permissions, menus, etc...) + $this->rights_class = 'sendrecurringinvoicebymail'; - // Family can be 'base' (core modules),'crm','financial','hr','projects','products','ecm','technic' (transverse modules),'interface' (link with external tools),'other','...' - // It is used to group modules by family in module setup page - $this->family = "crm"; - // Module position in the family on 2 digits ('01', '10', '20', ...) - $this->module_position = '90'; - // Gives the possibility for the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this) - //$this->familyinfo = array('myownfamily' => array('position' => '01', 'label' => $langs->trans("MyOwnFamily"))); + // Family can be 'base' (core modules),'crm','financial','hr','projects','products','ecm','technic' (transverse modules),'interface' (link with external tools),'other','...' + // It is used to group modules by family in module setup page + $this->family = "crm"; + // Module position in the family on 2 digits ('01', '10', '20', ...) + $this->module_position = '90'; + // Gives the possibility for the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this) + //$this->familyinfo = array('myownfamily' => array('position' => '01', 'label' => $langs->trans("MyOwnFamily"))); - // Module label (no space allowed), used if translation string 'ModulesendrecurringinvoicebymailName' not found (sendrecurringinvoicebymail is name of module). - $this->name = preg_replace('/^mod/i','',get_class($this)); - // Module description, used if translation string 'ModulesendrecurringinvoicebymailDesc' not found (sendrecurringinvoicebymail is name of module). - $this->description = "Send generated invoice by email"; - // Used only if file README.md and README-LL.md not found. - $this->descriptionlong = "This module hooks onto the recurring invoice generation to automatically send the generated PDF."; + // Module label (no space allowed), used if translation string 'ModulesendrecurringinvoicebymailName' not found (sendrecurringinvoicebymail is name of module). + $this->name = preg_replace('/^mod/i','',get_class($this)); + // Module description, used if translation string 'ModulesendrecurringinvoicebymailDesc' not found (sendrecurringinvoicebymail is name of module). + $this->description = "Send generated invoice by email"; + // Used only if file README.md and README-LL.md not found. + $this->descriptionlong = "This module hooks onto the recurring invoice generation to automatically send the generated PDF."; - $this->editor_name = 'Bugness'; - $this->editor_url = 'https://code.bugness.org/Dolibarr/sendrecurringinvoicebymail'; + $this->editor_name = 'Bugness'; + $this->editor_url = 'https://code.bugness.org/Dolibarr/sendrecurringinvoicebymail'; - // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z' - $this->version = '0.2.7'; + // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z' + $this->version = '0.3.0'; - //Url to the file with your last numberversion of this module - //$this->url_last_version = 'http://www.example.com/versionmodule.txt'; - // Key used in llx_const table to save module status enabled/disabled (where SENDRECURRINGINVOICEBYMAIL is value of property name of module in uppercase) - $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); - // Name of image file used for this module. - // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue' - // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module' - $this->picto = 'sendrecurringinvoicebymail@sendrecurringinvoicebymail'; + //Url to the file with your last numberversion of this module + //$this->url_last_version = 'http://www.example.com/versionmodule.txt'; + // Key used in llx_const table to save module status enabled/disabled (where SENDRECURRINGINVOICEBYMAIL is value of property name of module in uppercase) + $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); + // Name of image file used for this module. + // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue' + // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module' + $this->picto = 'sendrecurringinvoicebymail@sendrecurringinvoicebymail'; - // Define some features supported by module (triggers, login, substitutions, menus, css, etc...) - $this->module_parts = array( - 'triggers' => 0, // Set this to 1 if module has its own trigger directory (core/triggers) - 'login' => 0, // Set this to 1 if module has its own login method file (core/login) - 'substitutions' => 0, // Set this to 1 if module has its own substitution function file (core/substitutions) - 'menus' => 0, // Set this to 1 if module has its own menus handler directory (core/menus) - 'theme' => 0, // Set this to 1 if module has its own theme directory (theme) - 'tpl' => 0, // Set this to 1 if module overwrite template dir (core/tpl) - 'barcode' => 0, // Set this to 1 if module has its own barcode directory (core/modules/barcode) - 'models' => 0, // Set this to 1 if module has its own models directory (core/modules/xxx) - //'css' => array('/sendrecurringinvoicebymail/css/sendrecurringinvoicebymail.css.php'), // Set this to relative path of css file if module has its own css file - //'js' => array('/sendrecurringinvoicebymail/js/sendrecurringinvoicebymail.js.php'), // Set this to relative path of js file if module must load a js on all pages - 'hooks' => array('cron'), // Set here all hooks context managed by module. To find available hook context, make a "grep -r '>initHooks(' *" on source code. You can also set hook context 'all' - 'moduleforexternal' => 0 // Set this to 1 if feature of module are opened to external users - ); + // Define some features supported by module (triggers, login, substitutions, menus, css, etc...) + $this->module_parts = array( + 'triggers' => 0, // Set this to 1 if module has its own trigger directory (core/triggers) + 'login' => 0, // Set this to 1 if module has its own login method file (core/login) + 'substitutions' => 0, // Set this to 1 if module has its own substitution function file (core/substitutions) + 'menus' => 0, // Set this to 1 if module has its own menus handler directory (core/menus) + 'theme' => 0, // Set this to 1 if module has its own theme directory (theme) + 'tpl' => 0, // Set this to 1 if module overwrite template dir (core/tpl) + 'barcode' => 0, // Set this to 1 if module has its own barcode directory (core/modules/barcode) + 'models' => 0, // Set this to 1 if module has its own models directory (core/modules/xxx) + 'css' => array(), + //'css' => array('/sendrecurringinvoicebymail/css/sendrecurringinvoicebymail.css.php'), // Set this to relative path of css file if module has its own css file + 'js' => array(), + //'js' => array('/sendrecurringinvoicebymail/js/sendrecurringinvoicebymail.js.php'), // Set this to relative path of js file if module must load a js on all pages + 'hooks' => array('cron'), // Set here all hooks context managed by module. To find available hook context, make a "grep -r '>initHooks(' *" on source code. You can also set hook context 'all' + 'moduleforexternal' => 0 // Set this to 1 if feature of module are opened to external users + ); - // Data directories to create when module is enabled. - // Example: this->dirs = array("/sendrecurringinvoicebymail/temp","/sendrecurringinvoicebymail/subdir"); - $this->dirs = array("/sendrecurringinvoicebymail/temp"); + // Data directories to create when module is enabled. + // Example: this->dirs = array("/sendrecurringinvoicebymail/temp","/sendrecurringinvoicebymail/subdir"); + $this->dirs = array("/sendrecurringinvoicebymail/temp"); - // Config pages. Put here list of php page, stored into sendrecurringinvoicebymail/admin directory, to use to setup module. - //$this->config_page_url = array("setup.php@sendrecurringinvoicebymail"); + // Config pages. Put here list of php page, stored into sendrecurringinvoicebymail/admin directory, to use to setup module. + //$this->config_page_url = array("setup.php@sendrecurringinvoicebymail"); - // Dependencies - $this->hidden = false; // A condition to hide module - $this->depends = array('modFacture'); // List of module class names as string that must be enabled if this module is enabled. Example: array('always1'=>'modModuleToEnable1','always2'=>'modModuleToEnable2', 'FR1'=>'modModuleToEnableFR'...) - $this->requiredby = array(); // List of module class names as string to disable if this one is disabled. Example: array('modModuleToDisable1', ...) - $this->conflictwith = array(); // List of module class names as string this module is in conflict with. Example: array('modModuleToDisable1', ...) - $this->langfiles = array("sendrecurringinvoicebymail@sendrecurringinvoicebymail"); - //$this->phpmin = array(5,4); // Minimum version of PHP required by module - $this->need_dolibarr_version = array(10,0); // Minimum version of Dolibarr required by module - $this->warnings_activation = array(); // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','ES'='textes'...) - $this->warnings_activation_ext = array(); // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','ES'='textes'...) - //$this->automatic_activation = array('FR'=>'sendrecurringinvoicebymailWasAutomaticallyActivatedBecauseOfYourCountryChoice'); - //$this->always_enabled = true; // If true, can't be disabled + // Dependencies + $this->hidden = false; // A condition to hide module + $this->depends = array('modFacture'); // List of module class names as string that must be enabled if this module is enabled. Example: array('always1'=>'modModuleToEnable1','always2'=>'modModuleToEnable2', 'FR1'=>'modModuleToEnableFR'...) + $this->requiredby = array(); // List of module class names as string to disable if this one is disabled. Example: array('modModuleToDisable1', ...) + $this->conflictwith = array(); // List of module class names as string this module is in conflict with. Example: array('modModuleToDisable1', ...) + $this->langfiles = array("sendrecurringinvoicebymail@sendrecurringinvoicebymail"); + //$this->phpmin = array(5,4); // Minimum version of PHP required by module + $this->need_dolibarr_version = array(10,0); // Minimum version of Dolibarr required by module + $this->warnings_activation = array(); // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','ES'='textes'...) + $this->warnings_activation_ext = array(); // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','ES'='textes'...) + //$this->automatic_activation = array('FR'=>'sendrecurringinvoicebymailWasAutomaticallyActivatedBecauseOfYourCountryChoice'); + //$this->always_enabled = true; // If true, can't be disabled - // Constants - // List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive) - // Example: $this->const=array(0=>array('SENDRECURRINGINVOICEBYMAIL_MYNEWCONST1','chaine','myvalue','This is a constant to add',1), - // 1=>array('SENDRECURRINGINVOICEBYMAIL_MYNEWCONST2','chaine','myvalue','This is another constant to add',0, 'current', 1) - // ); - $this->const = array( - //1=>array('SENDRECURRINGINVOICEBYMAIL_MYCONSTANT', 'chaine', 'avalue', 'This is a constant to add', 1, 'allentities', 1) - ); + // Constants + // List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive) + // Example: $this->const=array(0=>array('SENDRECURRINGINVOICEBYMAIL_MYNEWCONST1','chaine','myvalue','This is a constant to add',1), + // 1=>array('SENDRECURRINGINVOICEBYMAIL_MYNEWCONST2','chaine','myvalue','This is another constant to add',0, 'current', 1) + // ); + $this->const = array( + //1=>array('SENDRECURRINGINVOICEBYMAIL_MYCONSTANT', 'chaine', 'avalue', 'This is a constant to add', 1, 'allentities', 1) + ); - // Some keys to add into the overwriting translation tables - /*$this->overwrite_translation = array( - 'en_US:ParentCompany'=>'Parent company or reseller', - 'fr_FR:ParentCompany'=>'Maison mère ou revendeur' - )*/ + // Some keys to add into the overwriting translation tables + /*$this->overwrite_translation = array( + 'en_US:ParentCompany'=>'Parent company or reseller', + 'fr_FR:ParentCompany'=>'Maison mère ou revendeur' + )*/ - if (! isset($conf->sendrecurringinvoicebymail) || ! isset($conf->sendrecurringinvoicebymail->enabled)) - { - $conf->sendrecurringinvoicebymail=new stdClass(); - $conf->sendrecurringinvoicebymail->enabled=0; - } + if (! isset($conf->sendrecurringinvoicebymail) || ! isset($conf->sendrecurringinvoicebymail->enabled)) + { + $conf->sendrecurringinvoicebymail=new stdClass(); + $conf->sendrecurringinvoicebymail->enabled=0; + } - // Array to add new pages in new tabs + // Array to add new pages in new tabs $this->tabs = array(); - // Example: - // $this->tabs[] = array('data'=>'objecttype:+tabname1:Title1:mylangfile@sendrecurringinvoicebymail:$user->rights->sendrecurringinvoicebymail->read:/sendrecurringinvoicebymail/mynewtab1.php?id=__ID__'); // To add a new tab identified by code tabname1 - // $this->tabs[] = array('data'=>'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@sendrecurringinvoicebymail:$user->rights->othermodule->read:/sendrecurringinvoicebymail/mynewtab2.php?id=__ID__', // To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key. - // $this->tabs[] = array('data'=>'objecttype:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname + $this->tabs[] = array('data'=>'invoice-rec:+sendrecurringinvoicebymail:SendingByMail:sendrecurringinvoicebymail@sendrecurringinvoicebymail:sendrecurringinvoicebymail/fiche-rec-tab1.php?id=__ID__'); // To add a new tab identified by code tabname1 + // Example: + // $this->tabs[] = array('data'=>'objecttype:+tabname1:Title1:mylangfile@sendrecurringinvoicebymail:$user->rights->sendrecurringinvoicebymail->read:/sendrecurringinvoicebymail/mynewtab1.php?id=__ID__'); // To add a new tab identified by code tabname1 + // $this->tabs[] = array('data'=>'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@sendrecurringinvoicebymail:$user->rights->othermodule->read:/sendrecurringinvoicebymail/mynewtab2.php?id=__ID__', // To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key. + // $this->tabs[] = array('data'=>'objecttype:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname // // Where objecttype can be - // 'categories_x' to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member) - // 'contact' to add a tab in contact view - // 'contract' to add a tab in contract view - // 'group' to add a tab in group view - // 'intervention' to add a tab in intervention view - // 'invoice' to add a tab in customer invoice view - // 'invoice_supplier' to add a tab in supplier invoice view - // 'member' to add a tab in fundation member view - // 'opensurveypoll' to add a tab in opensurvey poll view - // 'order' to add a tab in customer order view - // 'order_supplier' to add a tab in supplier order view - // 'payment' to add a tab in payment view - // 'payment_supplier' to add a tab in supplier payment view - // 'product' to add a tab in product view - // 'propal' to add a tab in propal view - // 'project' to add a tab in project view - // 'stock' to add a tab in stock view - // 'thirdparty' to add a tab in third party view - // 'user' to add a tab in user view + // 'categories_x' to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member) + // 'contact' to add a tab in contact view + // 'contract' to add a tab in contract view + // 'group' to add a tab in group view + // 'intervention' to add a tab in intervention view + // 'invoice' to add a tab in customer invoice view + // 'invoice_supplier' to add a tab in supplier invoice view + // 'member' to add a tab in fundation member view + // 'opensurveypoll' to add a tab in opensurvey poll view + // 'order' to add a tab in customer order view + // 'order_supplier' to add a tab in supplier order view + // 'payment' to add a tab in payment view + // 'payment_supplier' to add a tab in supplier payment view + // 'product' to add a tab in product view + // 'propal' to add a tab in propal view + // 'project' to add a tab in project view + // 'stock' to add a tab in stock view + // 'thirdparty' to add a tab in third party view + // 'user' to add a tab in user view // Dictionaries - $this->dictionaries=array(); + $this->dictionaries=array(); /* Example: $this->dictionaries=array( 'langs'=>'mylangfile@sendrecurringinvoicebymail', - 'tabname'=>array(MAIN_DB_PREFIX."table1",MAIN_DB_PREFIX."table2",MAIN_DB_PREFIX."table3"), // List of tables we want to see into dictonnary editor - 'tablib'=>array("Table1","Table2","Table3"), // Label of tables - 'tabsql'=>array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table1 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table2 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table3 as f'), // Request to select fields - 'tabsqlsort'=>array("label ASC","label ASC","label ASC"), // Sort order - 'tabfield'=>array("code,label","code,label","code,label"), // List of fields (result of select to show dictionary) - 'tabfieldvalue'=>array("code,label","code,label","code,label"), // List of fields (list of fields to edit a record) - 'tabfieldinsert'=>array("code,label","code,label","code,label"), // List of fields (list of fields for insert) - 'tabrowid'=>array("rowid","rowid","rowid"), // Name of columns with primary key (try to always name it 'rowid') - 'tabcond'=>array($conf->sendrecurringinvoicebymail->enabled,$conf->sendrecurringinvoicebymail->enabled,$conf->sendrecurringinvoicebymail->enabled) // Condition to show each dictionary + 'tabname'=>array(MAIN_DB_PREFIX."table1",MAIN_DB_PREFIX."table2",MAIN_DB_PREFIX."table3"), // List of tables we want to see into dictonnary editor + 'tablib'=>array("Table1","Table2","Table3"), // Label of tables + 'tabsql'=>array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table1 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table2 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table3 as f'), // Request to select fields + 'tabsqlsort'=>array("label ASC","label ASC","label ASC"), // Sort order + 'tabfield'=>array("code,label","code,label","code,label"), // List of fields (result of select to show dictionary) + 'tabfieldvalue'=>array("code,label","code,label","code,label"), // List of fields (list of fields to edit a record) + 'tabfieldinsert'=>array("code,label","code,label","code,label"), // List of fields (list of fields for insert) + 'tabrowid'=>array("rowid","rowid","rowid"), // Name of columns with primary key (try to always name it 'rowid') + 'tabcond'=>array($conf->sendrecurringinvoicebymail->enabled,$conf->sendrecurringinvoicebymail->enabled,$conf->sendrecurringinvoicebymail->enabled) // Condition to show each dictionary ); */ // Boxes/Widgets - // Add here list of php file(s) stored in sendrecurringinvoicebymail/core/boxes that contains class to show a widget. + // Add here list of php file(s) stored in sendrecurringinvoicebymail/core/boxes that contains class to show a widget. $this->boxes = array( - //0=>array('file'=>'sendrecurringinvoicebymailwidget1.php@sendrecurringinvoicebymail','note'=>'Widget provided by sendrecurringinvoicebymail','enabledbydefaulton'=>'Home'), - //1=>array('file'=>'sendrecurringinvoicebymailwidget2.php@sendrecurringinvoicebymail','note'=>'Widget provided by sendrecurringinvoicebymail'), - //2=>array('file'=>'sendrecurringinvoicebymailwidget3.php@sendrecurringinvoicebymail','note'=>'Widget provided by sendrecurringinvoicebymail') + //0=>array('file'=>'sendrecurringinvoicebymailwidget1.php@sendrecurringinvoicebymail','note'=>'Widget provided by sendrecurringinvoicebymail','enabledbydefaulton'=>'Home'), + //1=>array('file'=>'sendrecurringinvoicebymailwidget2.php@sendrecurringinvoicebymail','note'=>'Widget provided by sendrecurringinvoicebymail'), + //2=>array('file'=>'sendrecurringinvoicebymailwidget3.php@sendrecurringinvoicebymail','note'=>'Widget provided by sendrecurringinvoicebymail') ); - // Cronjobs (List of cron jobs entries to add when module is enabled) - // unit_frequency must be 60 for minute, 3600 for hour, 86400 for day, 604800 for week - $this->cronjobs = array( - //0=>array('label'=>'MyJob label', 'jobtype'=>'method', 'class'=>'/sendrecurringinvoicebymail/class/myobject.class.php', 'objectname'=>'MyObject', 'method'=>'doScheduledJob', 'parameters'=>'', 'comment'=>'Comment', 'frequency'=>2, 'unitfrequency'=>3600, 'status'=>0, 'test'=>'$conf->sendrecurringinvoicebymail->enabled', 'priority'=>50) - ); - // Example: $this->cronjobs=array(0=>array('label'=>'My label', 'jobtype'=>'method', 'class'=>'/dir/class/file.class.php', 'objectname'=>'MyClass', 'method'=>'myMethod', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>2, 'unitfrequency'=>3600, 'status'=>0, 'test'=>'$conf->sendrecurringinvoicebymail->enabled', 'priority'=>50), - // 1=>array('label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>1, 'unitfrequency'=>3600*24, 'status'=>0, 'test'=>'$conf->sendrecurringinvoicebymail->enabled', 'priority'=>50) - // ); + // Cronjobs (List of cron jobs entries to add when module is enabled) + // unit_frequency must be 60 for minute, 3600 for hour, 86400 for day, 604800 for week + $this->cronjobs = array( + //0=>array('label'=>'MyJob label', 'jobtype'=>'method', 'class'=>'/sendrecurringinvoicebymail/class/myobject.class.php', 'objectname'=>'MyObject', 'method'=>'doScheduledJob', 'parameters'=>'', 'comment'=>'Comment', 'frequency'=>2, 'unitfrequency'=>3600, 'status'=>0, 'test'=>'$conf->sendrecurringinvoicebymail->enabled', 'priority'=>50) + ); + // Example: $this->cronjobs=array(0=>array('label'=>'My label', 'jobtype'=>'method', 'class'=>'/dir/class/file.class.php', 'objectname'=>'MyClass', 'method'=>'myMethod', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>2, 'unitfrequency'=>3600, 'status'=>0, 'test'=>'$conf->sendrecurringinvoicebymail->enabled', 'priority'=>50), + // 1=>array('label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>1, 'unitfrequency'=>3600*24, 'status'=>0, 'test'=>'$conf->sendrecurringinvoicebymail->enabled', 'priority'=>50) + // ); - // Permissions - $this->rights = array(); // Permission array used by this module - /* - $r=0; - $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) - $this->rights[$r][1] = 'Read myobject of sendrecurringinvoicebymail'; // Permission label - $this->rights[$r][3] = 1; // Permission by default for new user (0/1) - $this->rights[$r][4] = 'read'; // In php code, permission will be checked by test if ($user->rights->sendrecurringinvoicebymail->level1->level2) - $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->sendrecurringinvoicebymail->level1->level2) + // Permissions + $this->rights = array(); // Permission array used by this module + /* + $r=0; + $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) + $this->rights[$r][1] = 'Read myobject of sendrecurringinvoicebymail'; // Permission label + $this->rights[$r][3] = 1; // Permission by default for new user (0/1) + $this->rights[$r][4] = 'read'; // In php code, permission will be checked by test if ($user->rights->sendrecurringinvoicebymail->level1->level2) + $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->sendrecurringinvoicebymail->level1->level2) - $r++; - $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) - $this->rights[$r][1] = 'Create/Update myobject of sendrecurringinvoicebymail'; // Permission label - $this->rights[$r][3] = 1; // Permission by default for new user (0/1) - $this->rights[$r][4] = 'write'; // In php code, permission will be checked by test if ($user->rights->sendrecurringinvoicebymail->level1->level2) - $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->sendrecurringinvoicebymail->level1->level2) + $r++; + $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) + $this->rights[$r][1] = 'Create/Update myobject of sendrecurringinvoicebymail'; // Permission label + $this->rights[$r][3] = 1; // Permission by default for new user (0/1) + $this->rights[$r][4] = 'write'; // In php code, permission will be checked by test if ($user->rights->sendrecurringinvoicebymail->level1->level2) + $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->sendrecurringinvoicebymail->level1->level2) - $r++; - $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) - $this->rights[$r][1] = 'Delete myobject of sendrecurringinvoicebymail'; // Permission label - $this->rights[$r][3] = 1; // Permission by default for new user (0/1) - $this->rights[$r][4] = 'delete'; // In php code, permission will be checked by test if ($user->rights->sendrecurringinvoicebymail->level1->level2) - $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->sendrecurringinvoicebymail->level1->level2) - */ + $r++; + $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) + $this->rights[$r][1] = 'Delete myobject of sendrecurringinvoicebymail'; // Permission label + $this->rights[$r][3] = 1; // Permission by default for new user (0/1) + $this->rights[$r][4] = 'delete'; // In php code, permission will be checked by test if ($user->rights->sendrecurringinvoicebymail->level1->level2) + $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->sendrecurringinvoicebymail->level1->level2) + */ - // Main menu entries - $this->menu = array(); // List of menus to add - $r=0; + // Main menu entries + $this->menu = array(); // List of menus to add + $r=0; - // Add here entries to declare new menus + // Add here entries to declare new menus - /* BEGIN MODULEBUILDER TOPMENU */ - /* - $this->menu[$r++]=array('fk_menu'=>'', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode - 'type'=>'top', // This is a Top menu entry - 'titre'=>'sendrecurringinvoicebymail', - 'mainmenu'=>'sendrecurringinvoicebymail', - 'leftmenu'=>'', - 'url'=>'/sendrecurringinvoicebymail/sendrecurringinvoicebymailindex.php', - 'langs'=>'sendrecurringinvoicebymail@sendrecurringinvoicebymail', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. - 'position'=>1000+$r, - 'enabled'=>'$conf->sendrecurringinvoicebymail->enabled', // Define condition to show or hide menu entry. Use '$conf->sendrecurringinvoicebymail->enabled' if entry must be visible if module is enabled. - 'perms'=>'1', // Use 'perms'=>'$user->rights->sendrecurringinvoicebymail->level1->level2' if you want your menu with a permission rules - 'target'=>'', - 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both - */ + /* BEGIN MODULEBUILDER TOPMENU */ + /* + $this->menu[$r++]=array('fk_menu'=>'', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode + 'type'=>'top', // This is a Top menu entry + 'titre'=>'sendrecurringinvoicebymail', + 'mainmenu'=>'sendrecurringinvoicebymail', + 'leftmenu'=>'', + 'url'=>'/sendrecurringinvoicebymail/sendrecurringinvoicebymailindex.php', + 'langs'=>'sendrecurringinvoicebymail@sendrecurringinvoicebymail', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. + 'position'=>1000+$r, + 'enabled'=>'$conf->sendrecurringinvoicebymail->enabled', // Define condition to show or hide menu entry. Use '$conf->sendrecurringinvoicebymail->enabled' if entry must be visible if module is enabled. + 'perms'=>'1', // Use 'perms'=>'$user->rights->sendrecurringinvoicebymail->level1->level2' if you want your menu with a permission rules + 'target'=>'', + 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both + */ - /* END MODULEBUILDER TOPMENU */ + /* END MODULEBUILDER TOPMENU */ - /* BEGIN MODULEBUILDER LEFTMENU MYOBJECT - $this->menu[$r++]=array( 'fk_menu'=>'fk_mainmenu=sendrecurringinvoicebymail', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode - 'type'=>'left', // This is a Left menu entry - 'titre'=>'List MyObject', - 'mainmenu'=>'sendrecurringinvoicebymail', - 'leftmenu'=>'sendrecurringinvoicebymail_myobject_list', - 'url'=>'/sendrecurringinvoicebymail/myobject_list.php', - 'langs'=>'sendrecurringinvoicebymail@sendrecurringinvoicebymail', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. - 'position'=>1000+$r, - 'enabled'=>'$conf->sendrecurringinvoicebymail->enabled', // Define condition to show or hide menu entry. Use '$conf->sendrecurringinvoicebymail->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. - 'perms'=>'1', // Use 'perms'=>'$user->rights->sendrecurringinvoicebymail->level1->level2' if you want your menu with a permission rules - 'target'=>'', - 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both - $this->menu[$r++]=array( 'fk_menu'=>'fk_mainmenu=sendrecurringinvoicebymail,fk_leftmenu=sendrecurringinvoicebymail', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode - 'type'=>'left', // This is a Left menu entry - 'titre'=>'New MyObject', - 'mainmenu'=>'sendrecurringinvoicebymail', - 'leftmenu'=>'sendrecurringinvoicebymail_myobject_new', - 'url'=>'/sendrecurringinvoicebymail/myobject_page.php?action=create', - 'langs'=>'sendrecurringinvoicebymail@sendrecurringinvoicebymail', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. - 'position'=>1000+$r, - 'enabled'=>'$conf->sendrecurringinvoicebymail->enabled', // Define condition to show or hide menu entry. Use '$conf->sendrecurringinvoicebymail->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. - 'perms'=>'1', // Use 'perms'=>'$user->rights->sendrecurringinvoicebymail->level1->level2' if you want your menu with a permission rules - 'target'=>'', - 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both - END MODULEBUILDER LEFTMENU MYOBJECT */ + /* BEGIN MODULEBUILDER LEFTMENU MYOBJECT + $this->menu[$r++]=array( 'fk_menu'=>'fk_mainmenu=sendrecurringinvoicebymail', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode + 'type'=>'left', // This is a Left menu entry + 'titre'=>'List MyObject', + 'mainmenu'=>'sendrecurringinvoicebymail', + 'leftmenu'=>'sendrecurringinvoicebymail_myobject_list', + 'url'=>'/sendrecurringinvoicebymail/myobject_list.php', + 'langs'=>'sendrecurringinvoicebymail@sendrecurringinvoicebymail', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. + 'position'=>1000+$r, + 'enabled'=>'$conf->sendrecurringinvoicebymail->enabled', // Define condition to show or hide menu entry. Use '$conf->sendrecurringinvoicebymail->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. + 'perms'=>'1', // Use 'perms'=>'$user->rights->sendrecurringinvoicebymail->level1->level2' if you want your menu with a permission rules + 'target'=>'', + 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both + $this->menu[$r++]=array( 'fk_menu'=>'fk_mainmenu=sendrecurringinvoicebymail,fk_leftmenu=sendrecurringinvoicebymail', // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode + 'type'=>'left', // This is a Left menu entry + 'titre'=>'New MyObject', + 'mainmenu'=>'sendrecurringinvoicebymail', + 'leftmenu'=>'sendrecurringinvoicebymail_myobject_new', + 'url'=>'/sendrecurringinvoicebymail/myobject_page.php?action=create', + 'langs'=>'sendrecurringinvoicebymail@sendrecurringinvoicebymail', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. + 'position'=>1000+$r, + 'enabled'=>'$conf->sendrecurringinvoicebymail->enabled', // Define condition to show or hide menu entry. Use '$conf->sendrecurringinvoicebymail->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. + 'perms'=>'1', // Use 'perms'=>'$user->rights->sendrecurringinvoicebymail->level1->level2' if you want your menu with a permission rules + 'target'=>'', + 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both + END MODULEBUILDER LEFTMENU MYOBJECT */ - // Exports - $r=1; + // Exports + $r=1; - /* BEGIN MODULEBUILDER EXPORT MYOBJECT */ - /* - $langs->load("sendrecurringinvoicebymail@sendrecurringinvoicebymail"); - $this->export_code[$r]=$this->rights_class.'_'.$r; - $this->export_label[$r]='MyObjectLines'; // Translation key (used only if key ExportDataset_xxx_z not found) - $this->export_icon[$r]='myobject@sendrecurringinvoicebymail'; - $keyforclass = 'MyObject'; $keyforclassfile='/mymobule/class/myobject.class.php'; $keyforelement='myobject'; - include DOL_DOCUMENT_ROOT.'/core/commonfieldsinexport.inc.php'; - $keyforselect='myobject'; $keyforaliasextra='extra'; $keyforelement='myobject'; - include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php'; - //$this->export_dependencies_array[$r]=array('mysubobject'=>'ts.rowid', 't.myfield'=>array('t.myfield2','t.myfield3')); // To force to activate one or several fields if we select some fields that need same (like to select a unique key if we ask a field of a child to avoid the DISTINCT to discard them, or for computed field than need several other fields) - $this->export_sql_start[$r]='SELECT DISTINCT '; - $this->export_sql_end[$r] =' FROM '.MAIN_DB_PREFIX.'myobject as t'; - $this->export_sql_end[$r] .=' WHERE 1 = 1'; - $this->export_sql_end[$r] .=' AND t.entity IN ('.getEntity('myobject').')'; - $r++; */ - /* END MODULEBUILDER EXPORT MYOBJECT */ - } + /* BEGIN MODULEBUILDER EXPORT MYOBJECT */ + /* + $langs->load("sendrecurringinvoicebymail@sendrecurringinvoicebymail"); + $this->export_code[$r]=$this->rights_class.'_'.$r; + $this->export_label[$r]='MyObjectLines'; // Translation key (used only if key ExportDataset_xxx_z not found) + $this->export_icon[$r]='myobject@sendrecurringinvoicebymail'; + $keyforclass = 'MyObject'; $keyforclassfile='/mymobule/class/myobject.class.php'; $keyforelement='myobject'; + include DOL_DOCUMENT_ROOT.'/core/commonfieldsinexport.inc.php'; + $keyforselect='myobject'; $keyforaliasextra='extra'; $keyforelement='myobject'; + include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php'; + //$this->export_dependencies_array[$r]=array('mysubobject'=>'ts.rowid', 't.myfield'=>array('t.myfield2','t.myfield3')); // To force to activate one or several fields if we select some fields that need same (like to select a unique key if we ask a field of a child to avoid the DISTINCT to discard them, or for computed field than need several other fields) + $this->export_sql_start[$r]='SELECT DISTINCT '; + $this->export_sql_end[$r] =' FROM '.MAIN_DB_PREFIX.'myobject as t'; + $this->export_sql_end[$r] .=' WHERE 1 = 1'; + $this->export_sql_end[$r] .=' AND t.entity IN ('.getEntity('myobject').')'; + $r++; */ + /* END MODULEBUILDER EXPORT MYOBJECT */ + } - /** - * Function called when module is enabled. - * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. - * It also creates data directories - * - * @param string $options Options when enabling module ('', 'noboxes') - * @return int 1 if OK, 0 if KO - */ - public function init($options='') - { - $sql = array(); + /** + * Function called when module is enabled. + * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. + * It also creates data directories + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + public function init($options='') + { + // Launch SQL files + $result=$this->_load_tables('/' . basename(dirname(dirname(dirname(__FILE__)))) . '/sql/'); + if ($result < 0) return -1; // Do not activate module if error 'not allowed' returned when loading module SQL queries (the _load_table run sql with run_sql with the error allowed parameter set to 'default') - // we check if our model already exists - $result = $this->db->query("SELECT COUNT(*) AS cpt FROM " . MAIN_DB_PREFIX."c_email_templates WHERE module = 'sendrecurringinvoicebymail'"); - if ($result) { - $row = $this->db->fetch_object($result); - if ($row->cpt == 0) { - $sql[] = "INSERT INTO " . MAIN_DB_PREFIX."c_email_templates - (module, type_template, lang, label, joinfiles, topic, content) - VALUES ( - 'sendrecurringinvoicebymail', - 'facture_send', - '', - 'SendRecurringInvoiceByMail : original template', - '1', - '[__MYCOMPANY_NAME__] __(NewBill)__ __REF__', - '__(Hello)__,\n\nPlease find attached your new invoice.\n\nIn case of payment via bank transfer (our bank infos added at the bottom of the invoice), remember to add some references :\n- invoice number __REF__ for a one-time transfer,\n- or the contract/subscription reference __CONTRACT_REF__ for periodic transfers.\n\n__(Sincerely)__,\n\n__MYCOMPANY_NAME__')"; - } - } + // Launch small and conditional SQL queries + $sql = array(); + // we check if our model already exists + $result = $this->db->query("SELECT COUNT(*) AS cpt FROM " . MAIN_DB_PREFIX . "c_email_templates WHERE module = 'sendrecurringinvoicebymail'"); + if ($result) { + $row = $this->db->fetch_object($result); + if ($row->cpt == 0) { + $sql[] = "INSERT INTO " . MAIN_DB_PREFIX."c_email_templates + (module, type_template, lang, label, joinfiles, topic, content) + VALUES ( + 'sendrecurringinvoicebymail', + 'facture_send', + '', + 'SendRecurringInvoiceByMail : original template', + '1', + '[__MYCOMPANY_NAME__] __(NewBill)__ __REF__', + '__(Hello)__,\n\nPlease find attached your new invoice.\n\nIn case of payment via bank transfer (our bank infos added at the bottom of the invoice), remember to add some references :\n- invoice number __REF__ for a one-time transfer,\n- or the contract/subscription reference __CONTRACT_REF__ for periodic transfers.\n\n__(Sincerely)__,\n\n__MYCOMPANY_NAME__')"; + } + } - return $this->_init($sql, $options); - } + // Reactivate the template in case the module has been + // uninstalled which should have disabled the template. + $sql[] = "UPDATE " . MAIN_DB_PREFIX . "c_email_templates SET enabled = 1 WHERE module = 'sendrecurringinvoicebymail'"; - /** - * Function called when module is disabled. - * Remove from database constants, boxes and permissions from Dolibarr database. - * Data directories are not deleted - * - * @param string $options Options when enabling module ('', 'noboxes') - * @return int 1 if OK, 0 if KO - */ - public function remove($options = '') - { - $sql = array(); + // Cleaning up old (and ugly) system which + // used note_private to store overriding data. + // TODO : Remove this block at next version. + $result = $this->db->query("SELECT r.rowid AS rid, r.note_private, s.rowid AS sid FROM " . MAIN_DB_PREFIX . "facture_rec AS r LEFT JOIN " . MAIN_DB_PREFIX . "sribm_custom_mail_info AS s ON r.rowid = s.fk_facture_rec WHERE r.note_private LIKE '%sendrecurringinvoicebymail::%'"); + if ($result) { + while($row = $this->db->fetch_object($result)) { + $mail_data = $this->parseCustomFieldsMail($row->note_private); + $sid = $row->sid; + if (! $sid) { + $this->db->query("INSERT INTO " . MAIN_DB_PREFIX . "sribm_custom_mail_info (fk_facture_rec) VALUES (" . (int)$row->rid . ")"); + $sid = $this->db->last_insert_id(MAIN_DB_PREFIX . 'sribm_custom_mail_info'); + } + foreach (array('subject' => 'subject', 'body' => 'body_plaintext', 'sendto' => 'sendto_free') as $key => $item) { + if (! empty($mail_data[$key])) { + // We loop on each field. + // Not optimized, I know. + $this->db->query("UPDATE " . MAIN_DB_PREFIX . "sribm_custom_mail_info SET " . $item . " = '" . $this->db->escape($mail_data[$key]) . "' WHERE rowid = " . (int)$sid); + if ($key == 'sendto') { + // If the note_private specified a recipient, we disable sending to the + // main societe's mail. + $this->db->query("UPDATE " . MAIN_DB_PREFIX . "sribm_custom_mail_info SET sendto_thirdparty = 0 WHERE rowid = " . (int)$row->rid); + } + } + } + $regexps = array( + '/%%% sendrecurringinvoicebymail::subject.*%%%/sU', + '/%%% sendrecurringinvoicebymail::body.*%%%/sU', + '/%%% sendrecurringinvoicebymail::sendto.*%%%/sU', + ); + $row->note_private = preg_replace($regexps, array('', '', ''), $row->note_private); + $this->db->query("UPDATE " . MAIN_DB_PREFIX . "facture_rec SET note_private = '" . $this->db->escape($row->note_private) . "' WHERE rowid = " . (int)$row->rid); + } + } - $sql[] = "DELETE FROM " . MAIN_DB_PREFIX."c_email_templates WHERE module = 'sendrecurringinvoicebymail'"; + return $this->_init($sql, $options); + } + + /** + * Function called when module is disabled. + * Remove from database constants, boxes and permissions from Dolibarr database. + * Data directories are not deleted + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + public function remove($options = '') + { + $sql = array(); + + // Disable the template + // (instead of deleting it, which may cause unwanted work loss) + // (Yeah, counterside is data bloat... sorry...) + $sql[] = "UPDATE " . MAIN_DB_PREFIX . "c_email_templates SET enabled = 0 WHERE module = 'sendrecurringinvoicebymail'"; + + return $this->_remove($sql, $options); + } + + /** + * FIXME: Obsolete. Replaced by SRIBMCustomMailInfo. To be removed. + * For the time being, we abuse of note_private to store our customizations + * + * This expect something like this in note_private: + * This is a good client... (other private infos) + * %%% sendrecurringinvoicebymail::subject + * New invoice __REF__ + * %%% + * %%% sendrecurringinvoicebymail::sendto + * recipient1@example.org, recipient2@example.org + * %%% + * %%% sendrecurringinvoicebymail::body + * Hello dear client, + * Please find attached... + * %%% + */ + public function parseCustomFieldsMail($data) + { + $output = []; + + // Remove eventual windows' "\r" + $data = str_replace("\r", "", $data); + + $regexps = array( + 'subject' => '/(^|\n)%%% sendrecurringinvoicebymail::subject\n(?.*)%%%(\n|$)/sU', + 'body' => '/(^|\n)%%% sendrecurringinvoicebymail::body\n(?.*)%%%(\n|$)/sU', + 'sendto' => '/(^|\n)%%% sendrecurringinvoicebymail::sendto\n(?.*)%%%(\n|$)/sU', + ); + foreach ($regexps as $key => $r) { + $result_regexp = []; + if (preg_match_all($r, $data, $result_regexp)) { + $output[$key] = trim($result_regexp[$key][0]); + } + } + + return $output; + } - return $this->_remove($sql, $options); - } } diff --git a/fiche-rec-tab1.php b/fiche-rec-tab1.php new file mode 100644 index 0000000..efc57ec --- /dev/null +++ b/fiche-rec-tab1.php @@ -0,0 +1,326 @@ + + * Copyright (C) 2021 Chl + * + * 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 . + */ + +// Initially copied from modulebuilder/template/myobject_card.php + +// Load Dolibarr environment +$res=0; +// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined) +if (! $res && ! empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res=@include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php"; +// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME +$tmp=empty($_SERVER['SCRIPT_FILENAME'])?'':$_SERVER['SCRIPT_FILENAME'];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1; +while($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i]==$tmp2[$j]) { $i--; $j--; } +if (! $res && $i > 0 && file_exists(substr($tmp, 0, ($i+1))."/main.inc.php")) $res=@include substr($tmp, 0, ($i+1))."/main.inc.php"; +if (! $res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i+1)))."/main.inc.php")) $res=@include dirname(substr($tmp, 0, ($i+1)))."/main.inc.php"; +// Try main.inc.php using relative path +if (! $res && file_exists("../main.inc.php")) $res=@include "../main.inc.php"; +if (! $res && file_exists("../../main.inc.php")) $res=@include "../../main.inc.php"; +if (! $res && file_exists("../../../main.inc.php")) $res=@include "../../../main.inc.php"; +if (! $res) die("Include of main fails"); + +// Load needed classes/lib +require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture-rec.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/invoice.lib.php'; +require_once 'class/sribmcustommailinfo.class.php'; + +// Get parameters +$id = GETPOST('id', 'int'); +$output = ''; + +// Check security (take care of everything, even page layout, if something goes wrong) +restrictedArea($user, 'facture', $id, 'facture_rec'); + +// Load translation files required by the page +$langs->loadLangs(array('bills', 'compta', 'other', 'mails', 'products', 'companies', 'sendrecurringinvoicebymail@sendrecurringinvoicebymail')); + +// Wrap everything in a do-while(false) as a try-catch mecanisme +// in order to print llxFooter whatever happens. +do { + /** + * Part 0 : Preparations + */ + + // Load necessary data + $object = new FactureRec($db); + $mailObject = new SRIBMCustomMailInfo($db); + $form = new Form($db); + if ($object->fetch($id) <= 0 or !$object->id) + { + setEventMessages($langs->trans("ErrorRecordNotFound"), null, 'errors'); + break; + } + if ($mailObject->fetch(null, $object->id, true) <= 0) { + setEventMessages("Weird stuff, shouldn't happen : " . $mailObject->error); + break; + } + + // List of senders (user, company, robot, ...) + $listFrom = array(); + $listFrom['robot'] = $conf->global->MAIN_MAIL_EMAIL_FROM; + $listFrom['company'] = $conf->global->MAIN_INFO_SOCIETE_NOM .' <'.$conf->global->MAIN_INFO_SOCIETE_MAIL.'>'; + if (!empty($user->email)) { + $listFrom['user'] = $user->getFullName($langs) . ' <' . $user->email . '>'; + } + // If the address in the SRIBM object is not the same as the user (basically, + // the user has changed its email address or the address has been set by another + // user), we add an 'old' = 'no modification' option. + if ($mailObject->id + && $mailObject->fromtype == 'user' + && isset($listFrom['user']) + && $listFrom['user'] != $mailObject->frommail + ) { + $listFrom['old'] = $mailObject->frommail; + } + + // List of contacts of the third party + $listContacts = $mailObject->fac_rec_object->thirdparty->thirdparty_and_contact_email_array(1); + + // Substitution array/string + $helpforsubstitution = $langs->trans('AvailableVariables').' :
'."\n"; + $tmparray = getCommonSubstitutionArray($langs, 0, null, $object); + complete_substitutions_array($tmparray, $langs); + foreach($tmparray as $key => $val) { + $helpforsubstitution .= $key . ' -> ' . $langs->trans(dol_string_nohtmltag($val)) . '
'; + } + + + /** + * Part 1 : Treatment of form submission + */ + + // If the mail form has been submitted, check and record the data + if (GETPOST('save')) { + do { + // Validate input data + if (! array_key_exists(GETPOST('fromtype', 'alpha'), $listFrom)) { + setEventMessages('Unexpected from value', null, 'errors'); + break; + } + if (GETPOST('sendto_socpeople', 'array') != array_intersect(GETPOST('sendto_socpeople', 'array'), array_keys($listContacts))) { + setEventMessages("Unexpected contact value in 'to'", null, 'errors'); + break; + } + if (GETPOST('sendcc_socpeople', 'array') != array_intersect(GETPOST('sendcc_socpeople', 'array'), array_keys($listContacts))) { + setEventMessages("Unexpected contact value in 'cc'", null, 'errors'); + break; + } + // Validate some non-breaking stuff after feeding + if (empty(GETPOST('sendto_free', 'alpha')) && empty(GETPOST('sendto_socpeople', 'array'))) { + // Kinda weird behaviour from CMailFile but better alert the user beforehand + // FIXME: check if there is a workaround ? + setEventMessages("In some configuration, CMailFile doesn't allow empty 'to' recipient. You should set at least one.", null, 'warnings'); + //break; + } + if (! strlen(GETPOST('subject', 'alpha'))) { + // Kinda weird behaviour from CMailFile but better alert the user beforehand + // FIXME: check if there is a workaround ? + setEventMessages("In some configuration, CMailFile doesn't allow empty subject. You should set one.", null, 'warnings'); + //break; + } + + // Feed the input data to the model + $mailObject->active = GETPOST('active', 'int') ? 1 : 0; + $mailObject->addmaindocfile = GETPOST('addmaindocfile', 'int') ? 1 : 0; + + $mailObject->fromtype = GETPOST('fromtype', 'alpha'); + $mailObject->frommail = $listFrom[$mailObject->fromtype]; + + $mailObject->sendto_free = GETPOST('sendto_free', 'alpha'); + $mailObject->sendto_thirdparty = in_array('thirdparty', GETPOST('sendto_socpeople', 'array')); + + $mailObject->sendcc_free = GETPOST('sendcc_free', 'alpha'); + $mailObject->sendcc_thirdparty = in_array('thirdparty', GETPOST('sendcc_socpeople', 'array')); + + $mailObject->subject = GETPOST('subject', 'alpha'); + $mailObject->body_plaintext = GETPOST('body_plaintext', 'alpha'); + + // Save into database + if ($mailObject->id) { + if ($mailObject->update($user) != 1) { + setEventMessages($langs->trans("ErrorSQL") . ' : ' . $mailObject->error, null, 'errors'); + break; + } + } else { + $mailObject->fk_facture_rec = $object->id; + if ($mailObject->create($user) < 0) { + setEventMessages($langs->trans("ErrorSQL") . ' : ' . $mailObject->error, null, 'errors'); + break; + } + } + // Update the linked contacts + $data = array_merge( + array_map( + function ($id) { return array('id' => $id, 'sendtype' => 'to'); }, + array_filter(GETPOST('sendto_socpeople', 'array'), 'is_numeric') + ), + array_map( + function ($id) { return array('id' => $id, 'sendtype' => 'cc'); }, + array_filter(GETPOST('sendcc_socpeople', 'array'), 'is_numeric') + ) + ); + if ($mailObject->updateLinkSocPeople($data) != 1) { + setEventMessages($langs->trans("ErrorSQL") . ' : ' . $mailObject->error, null, 'errors'); + break; + } + + // Everything seems ok + setEventMessages($langs->trans("CorrectlyUpdated"), null, 'mesgs'); + // ... + redirect to cleanly reload all data and avoid some F5 misbehaviour + header("Location: fiche-rec-tab1.php?id=" . (int) $id, true, 302); + return; + } while(false); + } else if (GETPOST('reset') && $mailObject->id) { + if ($mailObject->delete() == 1) { + // Success message... + setEventMessages($langs->trans("ResetDone"), null, 'mesgs'); + + // ... + redirect to cleanly reload all data + header("Location: fiche-rec-tab1.php?id=" . (int) $id, true, 302); + return; + } else { + setEventMessages($langs->trans("ErrorSQL") . " : " . $mailObject->error , null, 'errors'); + } + } + + // Prepare the pre-selected id for To/Cc select inputs + $preselected = array( + 'to' => array(), + 'cc' => array(), + ); + if (GETPOSTISSET('sendto_socpeople') || GETPOSTISSET('sendcc_socpeople')) { + // Retrieve data from last form submission + $preselected['to'] = GETPOST('sendto_socpeople'); + $preselected['cc'] = GETPOST('sendcc_socpeople'); + } else { + // Retrieve data from model + foreach ($mailObject->linkToSocPeoples as $contact) { + $preselected[$contact->pivot->sendtype][] = $contact->id; + } + // add the third-party's email in case sendXX_thirdparty is true + if ($mailObject->sendto_thirdparty) { + $preselected['to'][] = 'thirdparty'; + } + if ($mailObject->sendcc_thirdparty) { + $preselected['cc'][] = 'thirdparty'; + } + } + + /** + * Part 2 : Display + */ + + // Same tabs than the main page + $head=invoice_rec_prepare_head($object); + $output .= dol_get_fiche_head($head, 'sendrecurringinvoicebymail', $langs->trans("RepeatableInvoice"), -1, 'bill'); // Add a div + $output .= '
' . $mailObject->fac_rec_object->ref . "
\n"; + $output .= '
' . $langs->trans('ThirdParty') . ' : ' . $mailObject->fac_rec_object->thirdparty->getNomUrl(1) . "
\n"; + $output .= "\n\n"; + + $output .= '
' . $langs->trans("Options") . "
\n"; + $output .= '
'; + $output .= ''; + $output .= ''; + $output .= ' \n"; + $output .= ' \n"; + $output .= "\n"; + $output .= "
active || GETPOSTISSET('active')) ? ' checked="checked"' : '') . " />
\n"; + + // Little explanations + $output .= '
' . $langs->trans("CustomizationTitle") . "
\n"; + // TODO: translation + $output .= "

" . $langs->trans('CustomizationIntro', $langs->trans('Reset')) . "
\n"; + $output .= $langs->trans('CustomizationLinkToGlobalTemplate', DOL_URL_ROOT . '/admin/mails_templates.php?search_label=sendrecurring') . "

\n\n"; + + $output .= ''; + $output .= '\n"; + + + // Recipient(s) + $output .= '\n\n"; + + + // CC + $output .= '\n\n"; + + + // Subject + $output .= '\n\n"; + + + // addmaindocfile + $output .= '\n"; + $tmp_addmaindocfile = $mailObject->addmaindocfile; + if (! empty($_POST)) { + $tmp_addmaindocfile = GETPOSTISSET('addmaindocfile') ? 1 : 0; + } + $output .= '\n"; + + + // body_plaintext + $output .= '\n\n"; + + $output .= "
'.$langs->trans("MailFrom").''; + $defaultFrom = 'robot'; + if (isset($listFrom['old'])) { + $defaultFrom = 'old'; + } elseif ($mailObject->id) { + $defaultFrom = $mailObject->fromtype; + } + $output .= $form->selectarray('fromtype', $listFrom, GETPOST('fromtype', 'alpha') ? GETPOST('fromtype', 'alpha') : $defaultFrom); + $output .= "
'; + $output .= $form->textwithpicto($langs->trans("MailTo"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients")); + $output .= ""; + $output .= 'sendto_free)) . '" />'; + $output .= " " . $langs->trans("and") . "/" . $langs->trans("or") . " "; + $output .= $form->multiselectarray('sendto_socpeople', $listContacts, $preselected['to']); + $output .= "
'; + $output .= $form->textwithpicto($langs->trans("MailCC"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients")); + $output .= ""; + $output .= 'sendcc_free)) . '" />'; + $output .= " " . $langs->trans("and") . "/" . $langs->trans("or") . " "; + $output .= $form->multiselectarray('sendcc_socpeople', $listContacts, $preselected['cc']); + $output .= "
'; + $output .= $form->textwithpicto($langs->trans("MailTopic"), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfromtopic'); + $output .= ""; + $output .= ''; + $output .= "
' . $langs->trans('MailFile') . " ' . $langs->trans("JoinMainDoc") . "
'; + $output .= $form->textwithpicto($langs->trans("MailText"), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfrombody'); + $output .= ""; + /* + // doleditor does some weird stuff, adding
and newlines, I'll get more into it when I have time. + // fallback to simple \n"; + $output .= "
\n"; + + $output .= '
'; + $output .= ''; + $output .= 'id ? '' : ' title="' . $langs->trans('ResetTooltipNoCustomisationToReset') . '" disabled="disabled"') . ' />'; + $output .= "
\n"; +} while (false); + +// Print everything +llxHeader('', $langs->trans('RepeatableInvoice') . ' - ' . $langs->trans('SendingByMail'), ''); +print $output; +llxFooter(); diff --git a/img/screenshot1.png b/img/screenshot1.png new file mode 100644 index 0000000..53ba700 Binary files /dev/null and b/img/screenshot1.png differ diff --git a/langs/en_US/sendrecurringinvoicebymail.lang b/langs/en_US/sendrecurringinvoicebymail.lang index 38b8b89..53fc304 100644 --- a/langs/en_US/sendrecurringinvoicebymail.lang +++ b/langs/en_US/sendrecurringinvoicebymail.lang @@ -41,13 +41,12 @@ About = About sendrecurringinvoicebymailAbout = About sendrecurringinvoicebymail sendrecurringinvoicebymailAboutPage = sendrecurringinvoicebymail about page -# -# Sample page -# -MyPageName = My page name - -# -# Sample widget -# -MyWidget = My widget -MyWidgetDescription = My widget description +# Tab title on the fiche-rec page +CustomizationTitle = Customization +CustomizationIntro = Below, you can override the global email template for this particular recurring invoice. To remove all customization, click on the %s button. +CustomizationLinkToGlobalTemplate = As a note, the global email template can be found here. +OptionEnable = Send mail when generating via cron (cf. module "Scheduled Jobs") +Reset = Reset +ResetDone = Reset done : customization deleted +ResetTooltipNoCustomisationToReset = No customization to delete. +SendingByMail = Sending by email diff --git a/langs/fr_FR/sendrecurringinvoicebymail.lang b/langs/fr_FR/sendrecurringinvoicebymail.lang index a43e076..1a37c1e 100644 --- a/langs/fr_FR/sendrecurringinvoicebymail.lang +++ b/langs/fr_FR/sendrecurringinvoicebymail.lang @@ -37,12 +37,13 @@ sendrecurringinvoicebymailAbout = À propos de sendrecurringinvoicebymail sendrecurringinvoicebymailAboutPage = Page à propos de sendrecurringinvoicebymail # -# Page d'exemple +# Page de personnalisation par modèle # -MyPageName = Nom de ma page - -# -# Box d'exemple -# -MyWidget = Mon widget -MyWidgetDescription = Description de mon widget +CustomizationTitle = Personnalisation +CustomizationIntro = Ci-dessous, vous pouvez personnaliser les emails pour cette facture-modèle. Pour annuler toute personnalisation, cliquez sur le bouton '%s'. +CustomizationLinkToGlobalTemplate = Pour mémoire, le template global est configurable par ici. +OptionEnable = Envoyer par email lors d'une génération automatique via le module "Travaux planifiés" +Reset = Réinitialiser +ResetDone = Réinitialisation effectuée : personnalisation supprimée. +ResetTooltipNoCustomisationToReset = Aucune personnalisation à supprimer. +SendingByMail = Envoi par courriel diff --git a/sql/data.sql b/sql/data.sql new file mode 100644 index 0000000..720ba96 --- /dev/null +++ b/sql/data.sql @@ -0,0 +1,14 @@ +-- Copyright (C) 2021 Chl +-- +-- 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 . diff --git a/sql/llx_sribm_custom_mail_info.key.sql b/sql/llx_sribm_custom_mail_info.key.sql new file mode 100644 index 0000000..b95e23d --- /dev/null +++ b/sql/llx_sribm_custom_mail_info.key.sql @@ -0,0 +1,29 @@ +-- Copyright (C) 2021 Chl +-- +-- 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 http://www.gnu.org/licenses/. + + +-- BEGIN MODULEBUILDER INDEXES +--ALTER TABLE llx_mymodule_myobject ADD INDEX idx_fieldobject (fieldobject); +-- END MODULEBUILDER INDEXES + +--ALTER TABLE llx_mymodule_myobject ADD UNIQUE INDEX uk_mymodule_myobject_fieldxy(fieldx, fieldy); + +--ALTER TABLE llx_mymodule_myobject ADD CONSTRAINT llx_mymodule_myobject_fk_field FOREIGN KEY (fk_field) REFERENCES llx_mymodule_myotherobject(rowid); + +ALTER TABLE llx_sribm_custom_mail_info ADD UNIQUE INDEX llx_sribm_custom_mail_info_uniq_frec (fk_facture_rec); +ALTER TABLE llx_sribm_custom_mail_info ADD CONSTRAINT llx_sribm_custom_mail_info_fk_rowid FOREIGN KEY (fk_facture_rec) REFERENCES llx_facture_rec(rowid) ON DELETE CASCADE ON UPDATE CASCADE; + +ALTER TABLE llx_sribm_custom_mail_info_socpeople ADD CONSTRAINT llx_sribm_custom_mail_info_socpeople_c_fk FOREIGN KEY (fk_sribm_cmi) REFERENCES llx_sribm_custom_mail_info(rowid) ON DELETE CASCADE ON UPDATE CASCADE; +ALTER TABLE llx_sribm_custom_mail_info_socpeople ADD CONSTRAINT llx_sribm_custom_mail_info_socpeople_s_fk FOREIGN KEY (fk_socpeople) REFERENCES llx_socpeople(rowid) ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/sql/llx_sribm_custom_mail_info.sql b/sql/llx_sribm_custom_mail_info.sql new file mode 100644 index 0000000..188cacd --- /dev/null +++ b/sql/llx_sribm_custom_mail_info.sql @@ -0,0 +1,49 @@ +-- Copyright (C) 2021 Chl +-- +-- 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 http://www.gnu.org/licenses/. + + +-- Sorry for the schema's complexity, but we have to manage 3 types +-- of recipients : +-- * the email in the societe/company's profile (default for the module) +-- * the contacts (table 'llx_socpeople') +-- * the email from the free text input +-- The From can also be a little difficult since, for the time being, +-- we avoid a free text input for the source email. +CREATE TABLE llx_sribm_custom_mail_info( + rowid INTEGER AUTO_INCREMENT PRIMARY KEY, + fk_facture_rec INTEGER NOT NULL, + active smallint DEFAULT 1 NOT NULL, + addmaindocfile smallint DEFAULT 1 NOT NULL, + fromtype text NOT NULL, + frommail text NOT NULL, + sendto_thirdparty smallint DEFAULT 1 NOT NULL, + sendto_free text, + sendcc_thirdparty smallint DEFAULT 0 NOT NULL, + sendcc_free text, + sendbcc_thirdparty smallint DEFAULT 0 NOT NULL, + sendbcc_free text, + subject text, + body_plaintext mediumtext, + body_html mediumtext +) ENGINE=innodb; + + +-- sendtype should only be one of 'to', 'cc' and 'bcc' but +-- I'm kinda afraid to do an ENUM with Dolibarr black magic on SQL. +CREATE TABLE llx_sribm_custom_mail_info_socpeople( + fk_sribm_cmi INTEGER NOT NULL, + fk_socpeople INTEGER NOT NULL, + sendtype text NOT NULL +) ENGINE=innodb;