v. 0.3.0 : customization form for each recurring invoice

This commit is contained in:
Chl 2021-03-23 15:27:33 +01:00
parent 3f14164994
commit b5bc4bca93
12 changed files with 1470 additions and 524 deletions

View file

@ -1,5 +1,8 @@
# CHANGELOG SENDRECURRINGINVOICEBYMAIL FOR <a href="https://www.dolibarr.org">DOLIBARR ERP CRM</a> # CHANGELOG SENDRECURRINGINVOICEBYMAIL FOR <a href="https://www.dolibarr.org">DOLIBARR ERP CRM</a>
## 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 ## 0.2.7
Add the possibility to overwrite some email fields (recipients, subject, body) for each template. Add the possibility to overwrite some email fields (recipients, subject, body) for each template.

View file

@ -2,62 +2,31 @@
## Features ## 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. You can customize the mail globally or by recurring invoice.
```
This is a good client (this is outside of the %%% blocks so it won't appear in the mails :)
%%% sendrecurringinvoicebymail::body ![Screenshot n° 1](img/screenshot1.png?raw=true)
Hello dear client,
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__ This module is triggered by the cron (Scheduled jobs module) and will not send emails when manually generating an invoice.
%%%
%%% sendrecurringinvoicebymail::subject
My custom subject
%%%
%%% sendrecurringinvoicebymail::sendto
test1@example.org, "Mr. Test2" <test2@example.com>
%%%
```
## Requirements ## 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.
![Screenshot sendrecurringinvoicebymail](img/screenshot_sendrecurringinvoicebymail.png?raw=true "sendrecurringinvoicebymail"){imgmd}
-->
Other modules are available on <a href="https://www.dolistore.com" target="_new">Dolistore.com</a>. Other modules are available on <a href="https://www.dolistore.com" target="_new">Dolistore.com</a>.
## Install
<!--
### Translations
Translations can be define manually by editing files into directories *langs*.
This module contains also a sample configuration for Transifex, under the hidden directory [.tx](.tx), so it is possible to manage translation using this service.
For more informations, see the [translator's documentation](https://wiki.dolibarr.org/index.php/Translator_documentation).
There is a [Transifex project](https://transifex.com/projects/p/dolibarr-module-template) for this module.
-->
<!--
Install
-------
### From the ZIP file and GUI interface ### From the ZIP file and GUI interface
@ -99,7 +68,7 @@ cd ....../custom
git clone git@github.com:bugness-chl/sendrecurringinvoicebymail.git sendrecurringinvoicebymail git clone git@github.com:bugness-chl/sendrecurringinvoicebymail.git sendrecurringinvoicebymail
``` ```
### <a name="final_steps"></a>Final steps ### Final steps
From your browser: From your browser:
@ -108,12 +77,14 @@ From your browser:
- You should now be able to find and enable the module - You should now be able to find and enable the module
## Updating instructions
--> * Disable the module,
* Update the files (see Install),
* Re-enable the module.
Licenses ## Licenses
--------
### Main code ### Main code

View file

@ -23,224 +23,174 @@
* Put detailed description here. * Put detailed description here.
*/ */
// Load needed classes/lib
require_once 'sribmcustommailinfo.class.php';
/** /**
* Class Actionssendrecurringinvoicebymail * Class Actionssendrecurringinvoicebymail
*/ */
class Actionssendrecurringinvoicebymail class Actionssendrecurringinvoicebymail
{ {
/** /**
* @var DoliDB Database handler. * @var DoliDB Database handler.
*/ */
public $db; public $db;
/** /**
* @var string Error code (or message) * @var string Error code (or message)
*/ */
public $error = ''; public $error = '';
/** /**
* @var array Errors * @var array Errors
*/ */
public $errors = array(); public $errors = array();
/** /**
* @var array Hook results. Propagated to $hookmanager->resArray for later reuse * @var array Hook results. Propagated to $hookmanager->resArray for later reuse
*/ */
public $results = array(); public $results = array();
/** /**
* @var string String displayed by executeHook() immediately after return * @var string String displayed by executeHook() immediately after return
*/ */
public $resprints; public $resprints;
/** /**
* Constructor * Constructor
* *
* @param DoliDB $db Database handler * @param DoliDB $db Database handler
*/ */
public function __construct($db) public function __construct($db)
{ {
$this->db = $db; $this->db = $db;
} }
/** /**
* Overloading the doActions function : replacing the parent's function with the one below * Overloading the doActions function : replacing the parent's function with the one below
* *
* @param array $parameters Hook metadatas (context, etc...) * @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 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 string $action Current action (if set). Generally create or edit or null
* @param HookManager $hookmanager Hook manager propagated to allow calling another hook * @param HookManager $hookmanager Hook manager propagated to allow calling another hook
* @return int < 0 on error, 0 on success, 1 to replace standard code * @return int < 0 on error, 0 on success, 1 to replace standard code
*/ */
public function afterCreationOfRecurringInvoice($parameters, &$object, &$action, $hookmanager) public function afterCreationOfRecurringInvoice($parameters, &$object, &$action, $hookmanager)
{ {
global $conf, $user, $langs; global $conf, $user, $langs;
$langs->load('mails'); $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 // We only send the mail when the invoice is not a draft
if ($object->brouillon) { // and the sending is enabled for the template.
return 0; if ($object->brouillon || !$mailObject->active) {
} return 0;
}
// Fetch the mail template // Prepare the substitions for mail's subject and message (ex-body)
// (pas très précise mais je commence à en avoir marre de creuser tout dolibarr pour trouver les bonnes fonctions...) $substitutionarray = getCommonSubstitutionArray($langs, 0, null, $object);
$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"); complete_substitutions_array($substitutionarray, $langs, $object); // lourd et n'a rien ajouté lors de mes tests
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 body // Adding some useful substitions of our own...
$substitutionarray = getCommonSubstitutionArray($langs, 0, null, $object); if ( ! empty($object->linkedObjects['contrat'])) {
complete_substitutions_array($substitutionarray, $langs, $object); // lourd et n'a rien ajouté lors de mes tests $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... // Initialisations
if ( ! empty($object->linkedObjects['contrat'])) { $mail_data = array(
$contrat = reset($object->linkedObjects['contrat']); // no deep search, we take the first linked contract 'from' => $mailObject->frommail,
$substitutionarray['__CONTRACT_REF__'] = $contrat->ref; '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 // Check that we have a recipient, to avoid some frequent error...
$mail_data = array( if (empty($mail_data['to'] . $mail_data['cc'] . $mail_data['bcc'])) {
'sendto' => $object->thirdparty->name . ' <' . $object->thirdparty->email . '>', dol_syslog("Empty recipient for thirdparty " . $object->thirdparty->id . ". Not sending facturerec " . $facturerec->ref . " (id:" . $facturerec->id . ").");
'from' => $conf->global->MAIN_MAIL_EMAIL_FROM, return 0;
'errorsTo' => $conf->global->MAIN_MAIL_ERRORS_TO, }
'replyTo' => $conf->global->MAIN_MAIL_ERRORS_TO,
'subject' => $template->topic,
'body' => $template->content,
);
// If the invoice has some custom parameters (subject, body, sendto, ...) // Make the substitutions
$mail_data = array_merge($mail_data, $this->getCustomFieldsMail($object)); 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... // Check if we have to attach the file
if (empty($mail_data['sendto'])) { $filePath = array();
dol_syslog("Empty recipient for thirdparty " . $object->thirdparty->id . ". Not sending facturerec " . $facturerec->ref . " (id:" . $facturerec->id . ")."); $fileMime = array();
return 0; $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 // At last, send the mail
foreach (array('subject', 'body') as $key) { $mailfile = new CMailFile(
$mail_data[$key] = make_substitutions($mail_data[$key], $substitutionarray, $langs); $mail_data['subject'],
if (method_exists($object, 'makeSubstitution')) { $mail_data['to'],
$mail_data[$key] = $object->makeSubstitution($mail_data[$key]); $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 if ($mailfile->sendfile()) {
$filePath = array(); dol_syslog("Success sending email for " . $facturerec->ref . " (id:" . $facturerec->id . ").");
$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));
}
// At last, send the mail // Adds info to object for trigger
$mailfile = new CMailFile( // (maybe make a copy of the object instead of modifying it directly ?)
$mail_data['subject'], $object->email_msgid = $mailfile->msgid;
$mail_data['sendto'], $object->email_from = $mail_data['from'];
$mail_data['from'], $object->email_subject = $mail_data['subject'];
$mail_data['body'], $object->email_to = $mail_data['to'];
$filePath, $object->email_tocc = $mail_data['cc'];
$fileMime, $object->email_tobcc = $mail_data['bcc'];
$fileName, $object->actiontypecode = 'AC_OTH_AUTO';
'', // CC $object->actionmsg2=$langs->transnoentities('MailSentBy').' '.CMailFile::getValidAddress($mail_data['from'],4,0,1).' '.$langs->transnoentities('To').' '.CMailFile::getValidAddress($mail_data['to'],4,0,1);
'', // BCC $object->actionmsg = $langs->transnoentities('MailFrom').': '.dol_escape_htmltag($mail_data['from']);
0, //deliveryreceipt $object->actionmsg = dol_concatdesc($object->actionmsg, $langs->transnoentities('MailTo').': '.dol_escape_htmltag($mail_data['to']));
0, //msgishtml $object->actionmsg = dol_concatdesc($object->actionmsg, $langs->transnoentities('MailTopic') . ": " . $mail_data['subject']);
$mail_data['errorsTo'], $object->actionmsg = dol_concatdesc($object->actionmsg, $langs->transnoentities('TextUsedInTheMessageBody') . ":");
'', // css $object->actionmsg = dol_concatdesc($object->actionmsg, $mail_data['message']);
'', // trackid
'', // moreinheader
'standard', // sendcontext
$mail_data['replyTo']);
if ($mailfile->sendfile()) { // Launch triggers
dol_syslog("Success sending email for " . $facturerec->ref . " (id:" . $facturerec->id . ")."); $interface = new Interfaces($this->db);
$resultTrigger = $interface->run_triggers('BILL_SENTBYMAIL', $object, $user, $langs, $conf);
// Adds info to object for trigger } else {
// (maybe make a copy of the object instead of modifying it directly ?) $this->error = "Error sending email for " . $facturerec->ref . " (id:" . $facturerec->id . ").";
$object->email_msgid = $mailfile->msgid; $this->errors[] = $this->error;
$object->email_from = $mail_data['from']; dol_syslog($this->error);
$object->email_subject = $mail_data['subject']; $error++;
$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(?<subject>.*)%%%(\n|$)/sU',
'body' => '/(^|\n)%%% sendrecurringinvoicebymail::body\n(?<body>.*)%%%(\n|$)/sU',
'sendto' => '/(^|\n)%%% sendrecurringinvoicebymail::sendto\n(?<sendto>.*)%%%(\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 ($error ? -1 : 0);
}
} }

View file

@ -0,0 +1,516 @@
<?php
/* Cpoyright (C) 2021 chl-dev@bugness.org
*
* 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/>.
*/
/**
* \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 <foo@example.com>, 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 <foo@example.com>, 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 <foo@example.com>, 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 <foo@example.com>, 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;
}
}

View file

@ -1,6 +1,6 @@
<?php <?php
/* Copyright (C) 2004-2018 Laurent Destailleur <eldy@users.sourceforge.net> /* Copyright (C) 2004-2018 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com> * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
* Copyright (C) 2018 SuperAdmin * Copyright (C) 2018 SuperAdmin
* *
* This program is free software; you can redistribute it and/or modify * 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. * \brief sendrecurringinvoicebymail module descriptor.
* *
* \file htdocs/sendrecurringinvoicebymail/core/modules/modsendrecurringinvoicebymail.class.php * \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 class modsendrecurringinvoicebymail extends DolibarrModules
{ {
/** /**
* Constructor. Define names, constants, directories, boxes, permissions * Constructor. Define names, constants, directories, boxes, permissions
* *
* @param DoliDB $db Database handler * @param DoliDB $db Database handler
*/ */
public function __construct($db) public function __construct($db)
{ {
global $langs,$conf; global $langs,$conf;
$this->db = $db; $this->db = $db;
// Id for module (must be unique). // Id for module (must be unique).
// Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id). // 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 $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...) // Key text used to identify module (for permissions, menus, etc...)
$this->rights_class = 'sendrecurringinvoicebymail'; $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','...' // 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 // It is used to group modules by family in module setup page
$this->family = "crm"; $this->family = "crm";
// Module position in the family on 2 digits ('01', '10', '20', ...) // Module position in the family on 2 digits ('01', '10', '20', ...)
$this->module_position = '90'; $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) // 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"))); //$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). // 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)); $this->name = preg_replace('/^mod/i','',get_class($this));
// Module description, used if translation string 'ModulesendrecurringinvoicebymailDesc' not found (sendrecurringinvoicebymail is name of module). // Module description, used if translation string 'ModulesendrecurringinvoicebymailDesc' not found (sendrecurringinvoicebymail is name of module).
$this->description = "Send generated invoice by email"; $this->description = "Send generated invoice by email";
// Used only if file README.md and README-LL.md not found. // 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->descriptionlong = "This module hooks onto the recurring invoice generation to automatically send the generated PDF.";
$this->editor_name = 'Bugness'; $this->editor_name = 'Bugness';
$this->editor_url = 'https://code.bugness.org/Dolibarr/sendrecurringinvoicebymail'; $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' // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z'
$this->version = '0.2.7'; $this->version = '0.3.0';
//Url to the file with your last numberversion of this module //Url to the file with your last numberversion of this module
//$this->url_last_version = 'http://www.example.com/versionmodule.txt'; //$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) // 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); $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
// Name of image file used for this module. // 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 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' // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module'
$this->picto = 'sendrecurringinvoicebymail@sendrecurringinvoicebymail'; $this->picto = 'sendrecurringinvoicebymail@sendrecurringinvoicebymail';
// Define some features supported by module (triggers, login, substitutions, menus, css, etc...) // Define some features supported by module (triggers, login, substitutions, menus, css, etc...)
$this->module_parts = array( $this->module_parts = array(
'triggers' => 0, // Set this to 1 if module has its own trigger directory (core/triggers) '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) '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) '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) '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) '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) '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) '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) '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 'css' => 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 //'css' => array('/sendrecurringinvoicebymail/css/sendrecurringinvoicebymail.css.php'), // Set this to relative path of css file if module has its own css file
'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' 'js' => array(),
'moduleforexternal' => 0 // Set this to 1 if feature of module are opened to external users //'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. // Data directories to create when module is enabled.
// Example: this->dirs = array("/sendrecurringinvoicebymail/temp","/sendrecurringinvoicebymail/subdir"); // Example: this->dirs = array("/sendrecurringinvoicebymail/temp","/sendrecurringinvoicebymail/subdir");
$this->dirs = array("/sendrecurringinvoicebymail/temp"); $this->dirs = array("/sendrecurringinvoicebymail/temp");
// Config pages. Put here list of php page, stored into sendrecurringinvoicebymail/admin directory, to use to setup module. // 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"); //$this->config_page_url = array("setup.php@sendrecurringinvoicebymail");
// Dependencies // Dependencies
$this->hidden = false; // A condition to hide module $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->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->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->conflictwith = array(); // List of module class names as string this module is in conflict with. Example: array('modModuleToDisable1', ...)
$this->langfiles = array("sendrecurringinvoicebymail@sendrecurringinvoicebymail"); $this->langfiles = array("sendrecurringinvoicebymail@sendrecurringinvoicebymail");
//$this->phpmin = array(5,4); // Minimum version of PHP required by module //$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->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 = 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->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->automatic_activation = array('FR'=>'sendrecurringinvoicebymailWasAutomaticallyActivatedBecauseOfYourCountryChoice');
//$this->always_enabled = true; // If true, can't be disabled //$this->always_enabled = true; // If true, can't be disabled
// Constants // Constants
// List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive) // 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), // 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) // 1=>array('SENDRECURRINGINVOICEBYMAIL_MYNEWCONST2','chaine','myvalue','This is another constant to add',0, 'current', 1)
// ); // );
$this->const = array( $this->const = array(
//1=>array('SENDRECURRINGINVOICEBYMAIL_MYCONSTANT', 'chaine', 'avalue', 'This is a constant to add', 1, 'allentities', 1) //1=>array('SENDRECURRINGINVOICEBYMAIL_MYCONSTANT', 'chaine', 'avalue', 'This is a constant to add', 1, 'allentities', 1)
); );
// Some keys to add into the overwriting translation tables // Some keys to add into the overwriting translation tables
/*$this->overwrite_translation = array( /*$this->overwrite_translation = array(
'en_US:ParentCompany'=>'Parent company or reseller', 'en_US:ParentCompany'=>'Parent company or reseller',
'fr_FR:ParentCompany'=>'Maison mère ou revendeur' 'fr_FR:ParentCompany'=>'Maison mère ou revendeur'
)*/ )*/
if (! isset($conf->sendrecurringinvoicebymail) || ! isset($conf->sendrecurringinvoicebymail->enabled)) if (! isset($conf->sendrecurringinvoicebymail) || ! isset($conf->sendrecurringinvoicebymail->enabled))
{ {
$conf->sendrecurringinvoicebymail=new stdClass(); $conf->sendrecurringinvoicebymail=new stdClass();
$conf->sendrecurringinvoicebymail->enabled=0; $conf->sendrecurringinvoicebymail->enabled=0;
} }
// Array to add new pages in new tabs // Array to add new pages in new tabs
$this->tabs = array(); $this->tabs = array();
// Example: $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
// $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 // Example:
// $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:+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:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname // $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 // 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) // '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 // 'contact' to add a tab in contact view
// 'contract' to add a tab in contract view // 'contract' to add a tab in contract view
// 'group' to add a tab in group view // 'group' to add a tab in group view
// 'intervention' to add a tab in intervention view // 'intervention' to add a tab in intervention view
// 'invoice' to add a tab in customer invoice view // 'invoice' to add a tab in customer invoice view
// 'invoice_supplier' to add a tab in supplier invoice view // 'invoice_supplier' to add a tab in supplier invoice view
// 'member' to add a tab in fundation member view // 'member' to add a tab in fundation member view
// 'opensurveypoll' to add a tab in opensurvey poll view // 'opensurveypoll' to add a tab in opensurvey poll view
// 'order' to add a tab in customer order view // 'order' to add a tab in customer order view
// 'order_supplier' to add a tab in supplier order view // 'order_supplier' to add a tab in supplier order view
// 'payment' to add a tab in payment view // 'payment' to add a tab in payment view
// 'payment_supplier' to add a tab in supplier payment view // 'payment_supplier' to add a tab in supplier payment view
// 'product' to add a tab in product view // 'product' to add a tab in product view
// 'propal' to add a tab in propal view // 'propal' to add a tab in propal view
// 'project' to add a tab in project view // 'project' to add a tab in project view
// 'stock' to add a tab in stock view // 'stock' to add a tab in stock view
// 'thirdparty' to add a tab in third party view // 'thirdparty' to add a tab in third party view
// 'user' to add a tab in user view // 'user' to add a tab in user view
// Dictionaries // Dictionaries
$this->dictionaries=array(); $this->dictionaries=array();
/* Example: /* Example:
$this->dictionaries=array( $this->dictionaries=array(
'langs'=>'mylangfile@sendrecurringinvoicebymail', '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 '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 '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 '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 '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) '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) '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) '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') '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 'tabcond'=>array($conf->sendrecurringinvoicebymail->enabled,$conf->sendrecurringinvoicebymail->enabled,$conf->sendrecurringinvoicebymail->enabled) // Condition to show each dictionary
); );
*/ */
// Boxes/Widgets // 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( $this->boxes = array(
//0=>array('file'=>'sendrecurringinvoicebymailwidget1.php@sendrecurringinvoicebymail','note'=>'Widget provided by sendrecurringinvoicebymail','enabledbydefaulton'=>'Home'), //0=>array('file'=>'sendrecurringinvoicebymailwidget1.php@sendrecurringinvoicebymail','note'=>'Widget provided by sendrecurringinvoicebymail','enabledbydefaulton'=>'Home'),
//1=>array('file'=>'sendrecurringinvoicebymailwidget2.php@sendrecurringinvoicebymail','note'=>'Widget provided by sendrecurringinvoicebymail'), //1=>array('file'=>'sendrecurringinvoicebymailwidget2.php@sendrecurringinvoicebymail','note'=>'Widget provided by sendrecurringinvoicebymail'),
//2=>array('file'=>'sendrecurringinvoicebymailwidget3.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) // 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 // unit_frequency must be 60 for minute, 3600 for hour, 86400 for day, 604800 for week
$this->cronjobs = array( $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) //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), // 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) // 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 // Permissions
$this->rights = array(); // Permission array used by this module $this->rights = array(); // Permission array used by this module
/* /*
$r=0; $r=0;
$this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) $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][1] = 'Read myobject of sendrecurringinvoicebymail'; // Permission label
$this->rights[$r][3] = 1; // Permission by default for new user (0/1) $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][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) $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->sendrecurringinvoicebymail->level1->level2)
$r++; $r++;
$this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) $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][1] = 'Create/Update myobject of sendrecurringinvoicebymail'; // Permission label
$this->rights[$r][3] = 1; // Permission by default for new user (0/1) $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][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) $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->sendrecurringinvoicebymail->level1->level2)
$r++; $r++;
$this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used) $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][1] = 'Delete myobject of sendrecurringinvoicebymail'; // Permission label
$this->rights[$r][3] = 1; // Permission by default for new user (0/1) $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][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) $this->rights[$r][5] = ''; // In php code, permission will be checked by test if ($user->rights->sendrecurringinvoicebymail->level1->level2)
*/ */
// Main menu entries // Main menu entries
$this->menu = array(); // List of menus to add $this->menu = array(); // List of menus to add
$r=0; $r=0;
// Add here entries to declare new menus // Add here entries to declare new menus
/* BEGIN MODULEBUILDER TOPMENU */ /* 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 $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 'type'=>'top', // This is a Top menu entry
'titre'=>'sendrecurringinvoicebymail', 'titre'=>'sendrecurringinvoicebymail',
'mainmenu'=>'sendrecurringinvoicebymail', 'mainmenu'=>'sendrecurringinvoicebymail',
'leftmenu'=>'', 'leftmenu'=>'',
'url'=>'/sendrecurringinvoicebymail/sendrecurringinvoicebymailindex.php', 'url'=>'/sendrecurringinvoicebymail/sendrecurringinvoicebymailindex.php',
'langs'=>'sendrecurringinvoicebymail@sendrecurringinvoicebymail', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 'langs'=>'sendrecurringinvoicebymail@sendrecurringinvoicebymail', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
'position'=>1000+$r, '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. '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 'perms'=>'1', // Use 'perms'=>'$user->rights->sendrecurringinvoicebymail->level1->level2' if you want your menu with a permission rules
'target'=>'', 'target'=>'',
'user'=>2); // 0=Menu for internal users, 1=external users, 2=both 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both
*/ */
/* END MODULEBUILDER TOPMENU */ /* END MODULEBUILDER TOPMENU */
/* BEGIN 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 $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 'type'=>'left', // This is a Left menu entry
'titre'=>'List MyObject', 'titre'=>'List MyObject',
'mainmenu'=>'sendrecurringinvoicebymail', 'mainmenu'=>'sendrecurringinvoicebymail',
'leftmenu'=>'sendrecurringinvoicebymail_myobject_list', 'leftmenu'=>'sendrecurringinvoicebymail_myobject_list',
'url'=>'/sendrecurringinvoicebymail/myobject_list.php', 'url'=>'/sendrecurringinvoicebymail/myobject_list.php',
'langs'=>'sendrecurringinvoicebymail@sendrecurringinvoicebymail', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. 'langs'=>'sendrecurringinvoicebymail@sendrecurringinvoicebymail', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
'position'=>1000+$r, '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. '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 'perms'=>'1', // Use 'perms'=>'$user->rights->sendrecurringinvoicebymail->level1->level2' if you want your menu with a permission rules
'target'=>'', 'target'=>'',
'user'=>2); // 0=Menu for internal users, 1=external users, 2=both '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 $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 'type'=>'left', // This is a Left menu entry
'titre'=>'New MyObject', 'titre'=>'New MyObject',
'mainmenu'=>'sendrecurringinvoicebymail', 'mainmenu'=>'sendrecurringinvoicebymail',
'leftmenu'=>'sendrecurringinvoicebymail_myobject_new', 'leftmenu'=>'sendrecurringinvoicebymail_myobject_new',
'url'=>'/sendrecurringinvoicebymail/myobject_page.php?action=create', '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. 'langs'=>'sendrecurringinvoicebymail@sendrecurringinvoicebymail', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
'position'=>1000+$r, '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. '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 'perms'=>'1', // Use 'perms'=>'$user->rights->sendrecurringinvoicebymail->level1->level2' if you want your menu with a permission rules
'target'=>'', 'target'=>'',
'user'=>2); // 0=Menu for internal users, 1=external users, 2=both 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both
END MODULEBUILDER LEFTMENU MYOBJECT */ END MODULEBUILDER LEFTMENU MYOBJECT */
// Exports // Exports
$r=1; $r=1;
/* BEGIN MODULEBUILDER EXPORT MYOBJECT */ /* BEGIN MODULEBUILDER EXPORT MYOBJECT */
/* /*
$langs->load("sendrecurringinvoicebymail@sendrecurringinvoicebymail"); $langs->load("sendrecurringinvoicebymail@sendrecurringinvoicebymail");
$this->export_code[$r]=$this->rights_class.'_'.$r; $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_label[$r]='MyObjectLines'; // Translation key (used only if key ExportDataset_xxx_z not found)
$this->export_icon[$r]='myobject@sendrecurringinvoicebymail'; $this->export_icon[$r]='myobject@sendrecurringinvoicebymail';
$keyforclass = 'MyObject'; $keyforclassfile='/mymobule/class/myobject.class.php'; $keyforelement='myobject'; $keyforclass = 'MyObject'; $keyforclassfile='/mymobule/class/myobject.class.php'; $keyforelement='myobject';
include DOL_DOCUMENT_ROOT.'/core/commonfieldsinexport.inc.php'; include DOL_DOCUMENT_ROOT.'/core/commonfieldsinexport.inc.php';
$keyforselect='myobject'; $keyforaliasextra='extra'; $keyforelement='myobject'; $keyforselect='myobject'; $keyforaliasextra='extra'; $keyforelement='myobject';
include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php'; 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_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_start[$r]='SELECT DISTINCT ';
$this->export_sql_end[$r] =' FROM '.MAIN_DB_PREFIX.'myobject as t'; $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] .=' WHERE 1 = 1';
$this->export_sql_end[$r] .=' AND t.entity IN ('.getEntity('myobject').')'; $this->export_sql_end[$r] .=' AND t.entity IN ('.getEntity('myobject').')';
$r++; */ $r++; */
/* END MODULEBUILDER EXPORT MYOBJECT */ /* END MODULEBUILDER EXPORT MYOBJECT */
} }
/** /**
* Function called when module is enabled. * Function called when module is enabled.
* The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database.
* It also creates data directories * It also creates data directories
* *
* @param string $options Options when enabling module ('', 'noboxes') * @param string $options Options when enabling module ('', 'noboxes')
* @return int 1 if OK, 0 if KO * @return int 1 if OK, 0 if KO
*/ */
public function init($options='') public function init($options='')
{ {
$sql = array(); // 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 // Launch small and conditional SQL queries
$result = $this->db->query("SELECT COUNT(*) AS cpt FROM " . MAIN_DB_PREFIX."c_email_templates WHERE module = 'sendrecurringinvoicebymail'"); $sql = array();
if ($result) { // we check if our model already exists
$row = $this->db->fetch_object($result); $result = $this->db->query("SELECT COUNT(*) AS cpt FROM " . MAIN_DB_PREFIX . "c_email_templates WHERE module = 'sendrecurringinvoicebymail'");
if ($row->cpt == 0) { if ($result) {
$sql[] = "INSERT INTO " . MAIN_DB_PREFIX."c_email_templates $row = $this->db->fetch_object($result);
(module, type_template, lang, label, joinfiles, topic, content) if ($row->cpt == 0) {
VALUES ( $sql[] = "INSERT INTO " . MAIN_DB_PREFIX."c_email_templates
'sendrecurringinvoicebymail', (module, type_template, lang, label, joinfiles, topic, content)
'facture_send', VALUES (
'', 'sendrecurringinvoicebymail',
'SendRecurringInvoiceByMail : original template', 'facture_send',
'1', '',
'[__MYCOMPANY_NAME__] __(NewBill)__ __REF__', 'SendRecurringInvoiceByMail : original template',
'__(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__')"; '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'";
/** // Cleaning up old (and ugly) system which
* Function called when module is disabled. // used note_private to store overriding data.
* Remove from database constants, boxes and permissions from Dolibarr database. // TODO : Remove this block at next version.
* Data directories are not deleted $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) {
* @param string $options Options when enabling module ('', 'noboxes') while($row = $this->db->fetch_object($result)) {
* @return int 1 if OK, 0 if KO $mail_data = $this->parseCustomFieldsMail($row->note_private);
*/ $sid = $row->sid;
public function remove($options = '') if (! $sid) {
{ $this->db->query("INSERT INTO " . MAIN_DB_PREFIX . "sribm_custom_mail_info (fk_facture_rec) VALUES (" . (int)$row->rid . ")");
$sql = array(); $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(?<subject>.*)%%%(\n|$)/sU',
'body' => '/(^|\n)%%% sendrecurringinvoicebymail::body\n(?<body>.*)%%%(\n|$)/sU',
'sendto' => '/(^|\n)%%% sendrecurringinvoicebymail::sendto\n(?<sendto>.*)%%%(\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);
}
} }

326
fiche-rec-tab1.php Normal file
View file

@ -0,0 +1,326 @@
<?php
/* Copyright (C) 2017 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2021 Chl <chl-dev@bugness.org>
*
* 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/>.
*/
// 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').' :<br>'."\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)) . '<br>';
}
/**
* 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 .= '<div class="inline-block floatleft valignmiddle refid refidpadding">' . $mailObject->fac_rec_object->ref . "</div>\n";
$output .= '<div class="refidno">' . $langs->trans('ThirdParty') . ' : ' . $mailObject->fac_rec_object->thirdparty->getNomUrl(1) . "</div>\n";
$output .= "</div><!-- Closing div class='tabBar' -->\n\n";
$output .= '<div class="titre inline-block">' . $langs->trans("Options") . "</div>\n";
$output .= '<form id="sribmform" name="sribmform" method="POST" action="#sribmform">';
$output .= '<table class="liste" summary="mail options"><tbody>';
$output .= '<tr class="oddeven">';
$output .= ' <td><label for="active">' . $langs->trans('OptionEnable') . "</label></td>\n";
$output .= ' <td><input type="checkbox" id="active" name="active" value="1"' . ((empty($_POST) && $mailObject->active || GETPOSTISSET('active')) ? ' checked="checked"' : '') . " /></td>\n";
$output .= "</tr>\n";
$output .= "</tbody></table>\n";
// Little explanations
$output .= '<div class="titre inline-block" style="margin-top: 1.5em;">' . $langs->trans("CustomizationTitle") . "</div>\n";
// TODO: translation
$output .= "<p>" . $langs->trans('CustomizationIntro', $langs->trans('Reset')) . "<br />\n";
$output .= $langs->trans('CustomizationLinkToGlobalTemplate', DOL_URL_ROOT . '/admin/mails_templates.php?search_label=sendrecurring') . "</p>\n\n";
$output .= '<table class="tableforemailform boxtablenotop" width="100%">';
$output .= '<tr><td class="fieldrequired minwidth200">'.$langs->trans("MailFrom").'</td><td>';
$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 .= "</td></tr>\n";
// Recipient(s)
$output .= '<tr><td class="minwidth200 fieldrequired">';
$output .= $form->textwithpicto($langs->trans("MailTo"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
$output .= "</td>\n<td>";
$output .= '<input class="minwidth200" id="sendto_free" name="sendto_free" value="'.(GETPOST("sendto_free", "alpha") ? GETPOST("sendto_free", "alpha") : htmlentities($mailObject->sendto_free)) . '" />';
$output .= " " . $langs->trans("and") . "/" . $langs->trans("or") . " ";
$output .= $form->multiselectarray('sendto_socpeople', $listContacts, $preselected['to']);
$output .= "</td></tr>\n";
// CC
$output .= '<tr><td class="minwidth200">';
$output .= $form->textwithpicto($langs->trans("MailCC"), $langs->trans("YouCanUseCommaSeparatorForSeveralRecipients"));
$output .= "</td>\n<td>";
$output .= '<input class="minwidth200" id="sendto_free" name="sendcc_free" value="'.(GETPOST("sendcc_free", "alpha") ? GETPOST("sendcc_free", "alpha") : htmlentities($mailObject->sendcc_free)) . '" />';
$output .= " " . $langs->trans("and") . "/" . $langs->trans("or") . " ";
$output .= $form->multiselectarray('sendcc_socpeople', $listContacts, $preselected['cc']);
$output .= "</td></tr>\n";
// Subject
$output .= '<tr><td class="minwidth200 fieldrequired">';
$output .= $form->textwithpicto($langs->trans("MailTopic"), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfromtopic');
$output .= "</td>\n<td>";
$output .= '<input type="text" class="quatrevingtpercent" id="subject" name="subject" value="'. (GETPOST('subject', 'alpha') ? GETPOST('subject', 'alpha') : htmlentities($mailObject->subject)) . '" />';
$output .= "</td></tr>\n";
// addmaindocfile
$output .= '<tr><td>' . $langs->trans('MailFile') . "</td>\n";
$tmp_addmaindocfile = $mailObject->addmaindocfile;
if (! empty($_POST)) {
$tmp_addmaindocfile = GETPOSTISSET('addmaindocfile') ? 1 : 0;
}
$output .= '<td><input type="checkbox" name="addmaindocfile" value="1"' . ($tmp_addmaindocfile ? ' checked="checked"' : '') . ' /> ' . $langs->trans("JoinMainDoc") . "</td>\n";
// body_plaintext
$output .= '<tr><td class="minwidth200" valign="top">';
$output .= $form->textwithpicto($langs->trans("MailText"), $helpforsubstitution, 1, 'help', '', 0, 2, 'substittooltipfrombody');
$output .= "</td>\n<td>";
/*
// doleditor does some weird stuff, adding <br> and newlines, I'll get more into it when I have time.
// fallback to simple <textarea> for the time being.
require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
$doleditor = new DolEditor('body_plaintext', (GETPOST('body_plaintext', 'alpha') ? GETPOST('body_plaintext', 'alpha') : $mailObject->body_plaintext), '', 280);
$output .= $doleditor->Create(1);
*/
$output .= '<textarea id="body_plaintext" name="body_plaintext" rows="14" cols="80" class="flat">';
$output .= htmlentities(GETPOST('body_plaintext', 'alpha') ? GETPOST('body_plaintext', 'alpha') : $mailObject->body_plaintext);
$output .= "</textarea>\n";
$output .= "</td></tr>\n";
$output .= "</table>\n";
$output .= '<br><div class="center">';
$output .= '<input class="button" type="submit" id="save" name="save" value="'.$langs->trans("Save").'" />';
$output .= '<input class="button warning" type="submit" id="reset" name="reset" value="'.$langs->trans("Reset").'"';
$output .= ($mailObject->id ? '' : ' title="' . $langs->trans('ResetTooltipNoCustomisationToReset') . '" disabled="disabled"') . ' />';
$output .= "</div>\n";
} while (false);
// Print everything
llxHeader('', $langs->trans('RepeatableInvoice') . ' - ' . $langs->trans('SendingByMail'), '');
print $output;
llxFooter();

BIN
img/screenshot1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

View file

@ -41,13 +41,12 @@ About = About
sendrecurringinvoicebymailAbout = About sendrecurringinvoicebymail sendrecurringinvoicebymailAbout = About sendrecurringinvoicebymail
sendrecurringinvoicebymailAboutPage = sendrecurringinvoicebymail about page sendrecurringinvoicebymailAboutPage = sendrecurringinvoicebymail about page
# # Tab title on the fiche-rec page
# Sample 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.
MyPageName = My page name CustomizationLinkToGlobalTemplate = As a note, the global email template can be found <a href="%s">here</a>.
OptionEnable = Send mail when generating via cron (cf. module "Scheduled Jobs")
# Reset = Reset
# Sample widget ResetDone = Reset done : customization deleted
# ResetTooltipNoCustomisationToReset = No customization to delete.
MyWidget = My widget SendingByMail = Sending by email
MyWidgetDescription = My widget description

View file

@ -37,12 +37,13 @@ sendrecurringinvoicebymailAbout = À propos de sendrecurringinvoicebymail
sendrecurringinvoicebymailAboutPage = Page à propos de sendrecurringinvoicebymail sendrecurringinvoicebymailAboutPage = Page à propos de sendrecurringinvoicebymail
# #
# Page d'exemple # Page de personnalisation par modèle
# #
MyPageName = Nom de ma page 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 <a href="%s">ici</a>.
# Box d'exemple OptionEnable = Envoyer par email lors d'une génération automatique via le module "Travaux planifiés"
# Reset = Réinitialiser
MyWidget = Mon widget ResetDone = Réinitialisation effectuée : personnalisation supprimée.
MyWidgetDescription = Description de mon widget ResetTooltipNoCustomisationToReset = Aucune personnalisation à supprimer.
SendingByMail = Envoi par courriel

14
sql/data.sql Normal file
View file

@ -0,0 +1,14 @@
-- Copyright (C) 2021 Chl <chl-dev@bugness.org>
--
-- 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/>.

View file

@ -0,0 +1,29 @@
-- Copyright (C) 2021 Chl <chl-dev@bugness.org>
--
-- 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;

View file

@ -0,0 +1,49 @@
-- Copyright (C) 2021 Chl <chl-dev@bugness.org>
--
-- 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;