2
0
forked from Wavyzz/dolibarr

Add sendEmailsRemindersOnSupplierInvoiceDueDate cron function (#28378)

Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
This commit is contained in:
Alban Durrheimer
2024-02-23 16:50:21 +01:00
committed by GitHub
parent 85803c9dbf
commit 36d364fb2d
7 changed files with 342 additions and 3 deletions

View File

@@ -8753,6 +8753,9 @@ function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null,
if (is_object($object) && $object->element == 'supplier_proposal') {
$substitutionarray['__URL_SUPPLIER_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/supplier_proposal/card.php?id=".$object->id;
}
if (is_object($object) && $object->element == 'invoice_supplier') {
$substitutionarray['__URL_SUPPLIER_INVOICE__'] = DOL_MAIN_URL_ROOT."/fourn/facture/card.php?id=".$object->id;
}
if (is_object($object) && $object->element == 'shipping') {
$substitutionarray['__URL_SHIPMENT__'] = DOL_MAIN_URL_ROOT."/expedition/card.php?id=".$object->id;
}

View File

@@ -155,6 +155,22 @@ class modFournisseur extends DolibarrModules
'unitfrequency'=>3600 * 24,
'priority'=>51,
'status'=>1,
'test'=>'isModEnabled("supplier_invoice")',
'datestart'=>$datestart
),
1 => array(
'label' => 'SendEmailsRemindersOnSupplierInvoiceDueDate',
'jobtype' => 'method',
'class' => 'fourn/class/fournisseur.facture.class.php',
'objectname' => 'FactureFournisseur',
'method' => 'sendEmailsRemindersOnSupplierInvoiceDueDate',
'parameters' => '10,all,EmailTemplateCode,duedate',
'comment' => 'Send an email when we reach the supplier invoice due date (or supplier invoice date) - n days. First param is n, the number of days before due date (or supplier invoice date) to send the remind (or after if value is negative), second parameter is "all" or a payment mode code, third parameter is the code of the email template to use (an email template with the EmailTemplateCode must exists. The version of the email template in the language of the thirdparty will be used in priority. Language of the thirdparty will be also used to update the PDF of the sent supplier invoice). The fourth parameter is the string "duedate" (default) or "invoicedate" to define which date of the supplier invoice to use.',
'frequency' => 1,
'unitfrequency' => 3600 * 24,
'priority' => 50,
'status' => 0,
'test'=>'isModEnabled("supplier_invoice")',
'datestart'=>$datestart
));

View File

@@ -3389,6 +3389,313 @@ class FactureFournisseur extends CommonInvoice
return 0;
}
}
/**
* Send reminders by emails for supplier invoices validated that are due.
* CAN BE A CRON TASK
*
* @param int $nbdays Delay before due date (or after if delay is negative)
* @param string $paymentmode '' or 'all' by default (no filter), or 'LIQ', 'CHQ', CB', ...
* @param int|string $template Name (or id) of email template (Must be a template of type 'invoice_supplier_send')
* @param string $datetouse 'duedate' (default) or 'invoicedate'
* @param string $forcerecipient Force email of recipient (for example to send the email to an accountant supervisor instead of the customer)
* @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK)
*/
public function sendEmailsRemindersOnSupplierInvoiceDueDate($nbdays = 0, $paymentmode = 'all', $template = '', $datetouse = 'duedate', $forcerecipient = '')
{
global $conf, $langs, $user;
$error = 0;
$this->output = '';
$this->error = '';
$nbMailSend = 0;
$errorsMsg = array();
$langs->load('bills');
if (!isModEnabled(empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) ? 'fournisseur' : 'supplier_invoice')) { // Should not happen. If module disabled, cron job should not be visible.
$this->output .= $langs->trans('ModuleNotEnabled', $langs->transnoentitiesnoconv('Suppliers'));
return 0;
}
if (!in_array($datetouse, array('duedate', 'invoicedate'))) {
$this->output .= 'Bad value for parameter datetouse. Must be "duedate" or "invoicedate"';
return 0;
}
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
$formmail = new FormMail($this->db);
$now = dol_now();
$tmpidate = dol_get_first_hour(dol_time_plus_duree($now, $nbdays, 'd'), 'gmt');
$tmpinvoice = new FactureFournisseur($this->db);
dol_syslog(__METHOD__." start", LOG_INFO);
// Select all action comm reminder
$sql = "SELECT rowid as id FROM ".MAIN_DB_PREFIX."facture_fourn as f";
if (!empty($paymentmode) && $paymentmode != 'all') {
$sql .= ", ".MAIN_DB_PREFIX."c_paiement as cp";
}
$sql .= " WHERE f.paye = 0"; // Only unpaid
$sql .= " AND f.fk_statut = ".self::STATUS_VALIDATED; // Only validated status
if ($datetouse == 'invoicedate') {
$sql .= " AND f.datef = '".$this->db->idate($tmpidate, 'gmt')."'";
} else {
$sql .= " AND f.date_lim_reglement = '".$this->db->idate($tmpidate, 'gmt')."'";
}
$sql .= " AND f.entity IN (".getEntity('supplier_invoice', 0).")"; // One batch process only one company (no sharing)
if (!empty($paymentmode) && $paymentmode != 'all') {
$sql .= " AND f.fk_mode_reglement = cp.id AND cp.code = '".$this->db->escape($paymentmode)."'";
}
// TODO Add a filter to check there is no payment started yet
if ($datetouse == 'invoicedate') {
$sql .= $this->db->order("datef", "ASC");
} else {
$sql .= $this->db->order("date_lim_reglement", "ASC");
}
$resql = $this->db->query($sql);
$stmpidate = dol_print_date($tmpidate, 'day', 'gmt');
if ($datetouse == 'invoicedate') {
$this->output .= $langs->transnoentitiesnoconv("SearchValidatedSupplierInvoicesWithDate", $stmpidate);
} else {
$this->output .= $langs->transnoentitiesnoconv("SearchUnpaidSupplierInvoicesWithDueDate", $stmpidate);
}
if (!empty($paymentmode) && $paymentmode != 'all') {
$this->output .= ' ('.$langs->transnoentitiesnoconv("PaymentMode").' '.$paymentmode.')';
}
$this->output .= '<br>';
if ($resql) {
while ($obj = $this->db->fetch_object($resql)) {
if (!$error) {
// Load event
$res = $tmpinvoice->fetch($obj->id);
if ($res > 0) {
$tmpinvoice->fetch_thirdparty();
$outputlangs = new Translate('', $conf);
if ($tmpinvoice->thirdparty->default_lang) {
$outputlangs->setDefaultLang($tmpinvoice->thirdparty->default_lang);
$outputlangs->loadLangs(array("main", "suppliers"));
} else {
$outputlangs = $langs;
}
// Select email template according to language of recipient
$templateId = 0;
$templateLabel = '';
if (empty($template) || $template == 'EmailTemplateCode') {
$templateLabel = '(SendingReminderEmailOnUnpaidSupplierInvoice)';
} else {
if (is_numeric($template)) {
$templateId = $template;
} else {
$templateLabel = $template;
}
}
$arraymessage = $formmail->getEMailTemplate($this->db, 'invoice_supplier_send', $user, $outputlangs, $templateId, 1, $templateLabel);
if (is_numeric($arraymessage) && $arraymessage <= 0) {
$langs->load("errors");
$this->output .= $langs->trans('ErrorFailedToFindEmailTemplate', $template);
return 0;
}
// PREPARE EMAIL
$errormesg = '';
// Make substitution in email content
$substitutionarray = getCommonSubstitutionArray($outputlangs, 0, '', $tmpinvoice);
complete_substitutions_array($substitutionarray, $outputlangs, $tmpinvoice);
// Topic
$sendTopic = make_substitutions(empty($arraymessage->topic) ? $outputlangs->transnoentitiesnoconv('InformationMessage') : $arraymessage->topic, $substitutionarray, $outputlangs, 1);
// Content
$content = $outputlangs->transnoentitiesnoconv($arraymessage->content);
$sendContent = make_substitutions($content, $substitutionarray, $outputlangs, 1);
// Recipient
$to = array();
if ($forcerecipient) { // If a recipient was forced
$to = array($forcerecipient);
} else {
$res = $tmpinvoice->fetch_thirdparty();
$recipient = $tmpinvoice->thirdparty;
if ($res > 0) {
$tmparraycontact = $tmpinvoice->liste_contact(-1, 'internal', 0, 'SALESREPFOLL');
if (is_array($tmparraycontact) && count($tmparraycontact) > 0) {
foreach ($tmparraycontact as $data_email) {
if (!empty($data_email['email'])) {
$to[] = $data_email['email'];
}
}
}
if (empty($to) && !empty($recipient->email)) {
$to[] = $recipient->email;
}
if (empty($to)) {
$errormesg = "Failed to send remind to thirdparty id=".$tmpinvoice->socid.". No email defined for supplier invoice or customer.";
$error++;
}
} else {
$errormesg = "Failed to load recipient with thirdparty id=".$tmpinvoice->socid;
$error++;
}
}
// Sender
$from = getDolGlobalString('MAIN_MAIL_EMAIL_FROM');
if (!empty($arraymessage->email_from)) { // If a sender is defined into template, we use it in priority
$from = $arraymessage->email_from;
}
if (empty($from)) {
$errormesg = "Failed to get sender into global setup MAIN_MAIL_EMAIL_FROM";
$error++;
}
if (!$error && !empty($to)) {
$this->db->begin();
$to = implode(',', $to);
if (!empty($arraymessage->email_to)) { // If a recipient is defined into template, we add it
$to = $to.','.$arraymessage->email_to;
}
// Errors Recipient
$errors_to = $conf->global->MAIN_MAIL_ERRORS_TO;
$trackid = 'inv'.$tmpinvoice->id;
$sendcontext = 'standard';
$email_tocc = '';
if (!empty($arraymessage->email_tocc)) { // If a CC is defined into template, we use it
$email_tocc = $arraymessage->email_tocc;
}
$email_tobcc = '';
if (!empty($arraymessage->email_tobcc)) { // If a BCC is defined into template, we use it
$email_tobcc = $arraymessage->email_tobcc;
}
// Mail Creation
$cMailFile = new CMailFile($sendTopic, $to, $from, $sendContent, array(), array(), array(), $email_tocc, $email_tobcc, 0, 1, $errors_to, '', $trackid, '', $sendcontext, '');
// Sending Mail
if ($cMailFile->sendfile()) {
$nbMailSend++;
// Add a line into event table
require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
// Insert record of emails sent
$actioncomm = new ActionComm($this->db);
$actioncomm->type_code = 'AC_OTH_AUTO'; // Event insert into agenda automatically
$actioncomm->socid = $tmpinvoice->thirdparty->id; // To link to a company
$actioncomm->contact_id = 0;
$actioncomm->code = 'AC_EMAIL';
$actioncomm->label = 'sendEmailsRemindersOnInvoiceDueDateOK (nbdays='.$nbdays.' paymentmode='.$paymentmode.' template='.$template.' datetouse='.$datetouse.' forcerecipient='.$forcerecipient.')';
$actioncomm->note_private = $sendContent;
$actioncomm->fk_project = $tmpinvoice->fk_project;
$actioncomm->datep = dol_now();
$actioncomm->datef = $actioncomm->datep;
$actioncomm->percentage = -1; // Not applicable
$actioncomm->authorid = $user->id; // User saving action
$actioncomm->userownerid = $user->id; // Owner of action
// Fields when action is an email (content should be added into note)
$actioncomm->email_msgid = $cMailFile->msgid;
$actioncomm->email_subject = $sendTopic;
$actioncomm->email_from = $from;
$actioncomm->email_sender = '';
$actioncomm->email_to = $to;
//$actioncomm->email_tocc = $sendtocc;
//$actioncomm->email_tobcc = $sendtobcc;
//$actioncomm->email_subject = $subject;
$actioncomm->errors_to = $errors_to;
$actioncomm->elementtype = 'invoice_supplier';
$actioncomm->fk_element = $tmpinvoice->id;
//$actioncomm->extraparams = $extraparams;
$actioncomm->create($user);
} else {
$errormesg = $cMailFile->error.' : '.$to;
$error++;
// Add a line into event table
require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
// Insert record of emails sent
$actioncomm = new ActionComm($this->db);
$actioncomm->type_code = 'AC_OTH_AUTO'; // Event insert into agenda automatically
$actioncomm->socid = $tmpinvoice->thirdparty->id; // To link to a company
$actioncomm->contact_id = 0;
$actioncomm->code = 'AC_EMAIL';
$actioncomm->label = 'sendEmailsRemindersOnInvoiceDueDateKO';
$actioncomm->note_private = $errormesg;
$actioncomm->fk_project = $tmpinvoice->fk_project;
$actioncomm->datep = dol_now();
$actioncomm->datef = $actioncomm->datep;
$actioncomm->percentage = -1; // Not applicable
$actioncomm->authorid = $user->id; // User saving action
$actioncomm->userownerid = $user->id; // Owner of action
// Fields when action is an email (content should be added into note)
$actioncomm->email_msgid = $cMailFile->msgid;
$actioncomm->email_from = $from;
$actioncomm->email_sender = '';
$actioncomm->email_to = $to;
//$actioncomm->email_tocc = $sendtocc;
//$actioncomm->email_tobcc = $sendtobcc;
//$actioncomm->email_subject = $subject;
$actioncomm->errors_to = $errors_to;
//$actioncomm->extraparams = $extraparams;
$actioncomm->create($user);
}
$this->db->commit(); // We always commit
}
if ($errormesg) {
$errorsMsg[] = $errormesg;
}
} else {
$errorsMsg[] = 'Failed to fetch record invoice with ID = '.$obj->id;
$error++;
}
}
}
} else {
$error++;
}
if (!$error) {
$this->output .= 'Nb of emails sent : '.$nbMailSend;
dol_syslog(__METHOD__." end - ".$this->output, LOG_INFO);
return 0;
} else {
$this->error = 'Nb of emails sent : '.$nbMailSend.', '.(!empty($errorsMsg)) ? join(', ', $errorsMsg) : $error;
dol_syslog(__METHOD__." end - ".$this->error, LOG_INFO);
return $error;
}
}
}

View File

@@ -51,3 +51,6 @@ INSERT INTO llx_c_email_templates (entity, module, type_template, label, lang, p
INSERT INTO llx_c_email_templates (entity, module, type_template, label, lang, position, topic, joinfiles, content) VALUES (0, 'partnership', 'partnership_send', '(SendingEmailOnPartnershipCanceled)', '', 100, '[__[MAIN_INFO_SOCIETE_NOM]__] - __(YourPartnershipCanceledTopic)__', 0, '<body>\n <p>__(Hello)__,<br><br>\n__(YourPartnershipCanceledContent)__</p>\n<br />\n\n<br />\n\n __(Sincerely)__ <br />\n __[MAIN_INFO_SOCIETE_NOM]__ <br />\n </body>\n');
INSERT INTO llx_c_email_templates (entity, module, type_template, label, lang, position, topic, joinfiles, content) VALUES (0, 'partnership', 'partnership_send', '(SendingEmailOnPartnershipRefused)', '', 100, '[__[MAIN_INFO_SOCIETE_NOM]__] - __(YourPartnershipRefusedTopic)__', 0, '<body>\n <p>__(Hello)__,<br><br>\n__(YourPartnershipRefusedContent)__</p>\n<br />\n\n<br />\n\n __(Sincerely)__ <br />\n __[MAIN_INFO_SOCIETE_NOM]__ <br />\n </body>\n');
INSERT INTO llx_c_email_templates (entity, module, type_template, label, lang, position, topic, joinfiles, content) VALUES (0, 'partnership', 'partnership_send', '(SendingEmailOnPartnershipAccepted)', '', 100, '[__[MAIN_INFO_SOCIETE_NOM]__] - __(YourPartnershipAcceptedTopic)__', 0, '<body>\n <p>__(Hello)__,<br><br>\n__(YourPartnershipAcceptedContent)__</p>\n<br />\n\n<br />\n\n __(Sincerely)__ <br />\n __[MAIN_INFO_SOCIETE_NOM]__ <br />\n </body>\n');
-- Supplier
INSERT INTO llx_c_email_templates (entity, module, type_template, lang, private, fk_user, datec, label, position, enabled, active, topic, content, content_lines, joinfiles) VALUES (0, 'supplier_invoice','invoice_supplier_send','',0,null,null,'(SendingReminderEmailOnUnpaidSupplierInvoice)',100, 'isModEnabled("supplier_invoice")',1,'[__[MAIN_INFO_SOCIETE_NOM]__] - __(SupplierInvoice)__','__(Hello)__,<br /><br />__(SupplierInvoiceUnpaidContent)__<br />__URL_SUPPLIER_INVOICE__<br /><br />__(Sincerely)__<br />__USER_SIGNATURE__',null, 0);

View File

@@ -253,3 +253,6 @@ ALTER TABLE llx_socpeople ADD COLUMN geopoint point DEFAULT NULL;
ALTER TABLE llx_socpeople ADD COLUMN georesultcode varchar(16) NULL;
ALTER TABLE llx_socpeople ADD COLUMN name_alias varchar(255) NULL;
-- Supplier
INSERT INTO llx_c_email_templates (entity, module, type_template, lang, private, fk_user, datec, label, position, enabled, active, topic, content, content_lines, joinfiles) VALUES (0, 'supplier_invoice','invoice_supplier_send','',0,null,null,'(SendingReminderEmailOnUnpaidSupplierInvoice)',100, 'isModEnabled("supplier_invoice")',1,'[__[MAIN_INFO_SOCIETE_NOM]__] - __(SupplierInvoice)__','__(Hello)__,<br /><br />__(SupplierInvoiceUnpaidContent)__<br />__URL_SUPPLIER_INVOICE__<br /><br />__(Sincerely)__<br />__USER_SIGNATURE__',null, 0);

View File

@@ -653,4 +653,7 @@ InvoiceSubtype=Invoice Subtype
SalaryInvoice=Salary
BillsAndSalaries=Bills & Salaries
CreateCreditNoteWhenClientInvoiceExists=This option is enabled only when validated invoice(s) exist for a customer or when constant INVOICE_CREDIT_NOTE_STANDALONE is used(useful for some countries)
SearchUnpaidSupplierInvoicesWithDueDate=Search unpaid supplier invoices with a due date = %s
SearchValidatedSupplierInvoicesWithDate=Search unpaid supplier invoices with a validation date = %s
SendEmailsRemindersOnSupplierInvoiceDueDate=Send reminder by email for validated and unpaid supplier invoices
PaymentMadeForSeveralInvoices=Payment made for several invoices

View File

@@ -653,3 +653,7 @@ InvoiceSubtype=Sous-type de facture
SalaryInvoice=Salaire
BillsAndSalaries=Factures et salaires
CreateCreditNoteWhenClientInvoiceExists=Cette option est activée uniquement lorsqu'une ou plusieurs factures validées existent pour un client ou lorsque la constante INVOICE_CREDIT_NOTE_STANDALONE est utilisée (utile pour certains pays)
SearchUnpaidSupplierInvoicesWithDueDate=Rechercher les factures fournisseur impayées avec date d'échéance = %s
SearchValidatedSupplierInvoicesWithDate=Rechercher les factures fournisseur impayées avec une date de validation = %s
SupplierInvoiceUnpaidContent=La facture fournisseur __REF__ n'a pas encore été payé :
SendEmailsRemindersOnSupplierInvoiceDueDate=Envoyer un rappel par email pour les factures fournisseur validées et impayées