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 .= '