Modulo Newsletter

This commit is contained in:
Thomas Zilio 2019-08-27 17:25:52 +02:00
parent f096a53608
commit 6611429546
13 changed files with 423 additions and 22 deletions

View File

@ -139,6 +139,8 @@ function renderHook(hook, result) {
var total = result.progress.total;
var percentage = total == 0 ? current / total * 100 : 100;
percentage = Math.round(percentage * 100) / 100;
content += '<div class="progress" style="margin-bottom: 0px;"><div class="progress-bar" role="progressbar" aria-valuenow="' + percentage + '" aria-valuemin="0" aria-valuemax="100" style="width:' + percentage + '%">' + percentage + '% (' + current + '/' + total + ')</div></div>';
}

View File

@ -11,6 +11,7 @@ return [
'modules/ritenute' => 'Modules\Ritenute',
'modules/ritenute_contributi' => 'Modules\RitenuteContributi',
'modules/rivalse' => 'Modules\Rivalse',
'modules/newsletter' => 'Modules\Newsletter',
'modules/iva' => 'Modules\Iva',
'modules/ddt' => 'Modules\DDT',
'modules/fatture' => 'Modules\Fatture',
@ -27,7 +28,6 @@ return [
'modules/stati_intervento' => 'Modules\StatiIntervento',
'modules/stati_preventivo' => 'Modules\StatiPreventivo',
'modules/stati_contratto' => 'Modules\StatiContratto',
'modules/stato_servizi' => 'Modules\StatoServizi',
'modules/tipi_intervento' => 'Modules\TipiIntervento',
'plugins/exportFE' => 'Plugins\ExportFE',
'plugins/importFE' => 'Plugins\ImportFE',

View File

@ -230,7 +230,7 @@ if (!API\Response::isAPIRequest()) {
$id_record = filter('id_record');
$id_parent = filter('id_parent');
$id_record = $id_record == $id_parent ? '' : $id_record;
$id_record = $id_record == $id_parent ? null : $id_record;
Modules::setCurrent(filter('id_module'));
Plugins::setCurrent(filter('id_plugin'));

View File

@ -179,7 +179,7 @@ switch ($resource) {
// Nota Bene: nel campo id viene specificato idtipoanagrafica-idanagrafica -> modulo Utenti e permessi, creazione nuovo utente
case 'anagrafiche':
$query = "SELECT CONCAT(an_tipianagrafiche.idtipoanagrafica, '-', an_anagrafiche.idanagrafica) AS id, CONCAT_WS('', ragione_sociale, IF(citta !='' OR provincia != '', CONCAT(' (', citta, IF(provincia!='', CONCAT(' ', provincia), ''), ')'), ''), IF(deleted_at IS NULL, '', ' (".tr('eliminata').")')) AS descrizione, idtipointervento_default FROM an_anagrafiche INNER JOIN (an_tipianagrafiche_anagrafiche INNER JOIN an_tipianagrafiche ON an_tipianagrafiche_anagrafiche.idtipoanagrafica=an_tipianagrafiche.idtipoanagrafica) ON an_anagrafiche.idanagrafica=an_tipianagrafiche_anagrafiche.idanagrafica |where| ORDER BY ragione_sociale";
$query = "SELECT an_anagrafiche.idanagrafica AS id, CONCAT_WS('', ragione_sociale, IF(citta !='' OR provincia != '', CONCAT(' (', citta, IF(provincia!='', CONCAT(' ', provincia), ''), ')'), ''), IF(deleted_at IS NULL, '', ' (".tr('eliminata').")')) AS descrizione, `an_tipianagrafiche`.`descrizione` AS optgroup FROM an_anagrafiche INNER JOIN (an_tipianagrafiche_anagrafiche INNER JOIN an_tipianagrafiche ON an_tipianagrafiche_anagrafiche.idtipoanagrafica=an_tipianagrafiche.idtipoanagrafica) ON an_anagrafiche.idanagrafica=an_tipianagrafiche_anagrafiche.idanagrafica |where| ORDER BY `optgroup` ASC, ragione_sociale ASC";
foreach ($elements as $element) {
$filter[] = 'an_anagrafiche.idanagrafica='.prepare($element);
@ -195,7 +195,30 @@ switch ($resource) {
$search_fields[] = 'provincia LIKE '.prepare('%'.$search.'%');
}
// $custom['idtipointervento'] = 'idtipointervento_default';
// Aggiunta filtri di ricerca
if (!empty($search_fields)) {
$where[] = '('.implode(' OR ', $search_fields).')';
}
if (!empty($filter)) {
$where[] = '('.implode(' OR ', $filter).')';
}
$query = str_replace('|where|', !empty($where) ? 'WHERE '.implode(' AND ', $where) : '', $query);
$rs = $dbo->fetchArray($query);
foreach ($rs as $r) {
if ($prev != $r['optgroup']) {
$results[] = ['text' => $r['optgroup'], 'children' => []];
$prev = $r['optgroup'];
}
$results[count($results) - 1]['children'][] = [
'id' => $r['id'],
'text' => $r['descrizione'],
'descrizione' => $r['descrizione'],
];
}
break;
case 'sedi':

View File

@ -52,17 +52,21 @@ class EmailHook extends Manager
$diff = date('Y-m-d', strtotime('-4 hours'));
$user = auth()->getUser();
$remaining = Mail::whereNull('sent_at')
$failed = function($query) use ($diff) {
$query->whereDate('failed_at', '<', $diff)
->orWhereNull('failed_at');
};
$current = Mail::whereDate('sent_at', '>', $yesterday)
->where('created_by', $user->id)
->count();
$total = Mail::whereDate('sent_at', '>', $yesterday)
->orWhereNull('sent_at')
->where('created_by', $user->id)
->count();
$current = $total - $remaining;
$total_remaining = Mail::whereNull('sent_at')
->whereDate('failed_at', '<', $diff)
->where($failed)
->count();
$message = !empty($remaining) ? tr('Invio email in corso...') : tr('Invio email completato!');

View File

@ -0,0 +1,82 @@
<?php
use Models\MailTemplate;
use Modules\Newsletter\Newsletter;
include_once __DIR__.'/../../core.php';
switch (filter('op')) {
case 'add':
$template = MailTemplate::find(filter('id_template'));
$newsletter = Newsletter::build($user, $template, filter('name'));
$id_record = $newsletter->id;
flash()->info(tr('Nuova campagna newsletter creata!'));
break;
case 'update':
$newsletter->name = filter('name');
$newsletter->state = filter('state');
$newsletter->completed_at = filter('completed_at');
$newsletter->subject = filter('subject');
$newsletter->content = filter('content');
$newsletter->save();
flash()->info(tr('Campagna newsletter salvata!'));
break;
case 'delete':
$newsletter->delete();
flash()->info(tr('Campagna newsletter rimossa!'));
break;
case 'send':
$anagrafiche = $newsletter->anagrafiche;
$template = $newsletter->template;
foreach ($anagrafiche as $anagrafica) {
if (empty($anagrafica['email'])) {
continue;
}
$mail = \Models\Mail::build($user, $template, $anagrafica->id);
$mail->addReceiver($anagrafica['email']);
$mail->subject = $newsletter->subject;
$mail->content = $newsletter->content;
$mail->save();
}
$newsletter->state = 'WAIT';
$newsletter->save();
flash()->info(tr('Campagna newsletter in invio!'));
break;
case 'add_receivers':
$receivers = post('receivers');
$newsletter->anagrafiche()->attach($receivers);
flash()->info(tr('Nuovi destinatari della newsletter aggiunti!'));
break;
case 'remove_receiver':
$receiver = post('id');
$newsletter->anagrafiche()->detach($receiver);
flash()->info(tr('Destinatario rimosso dalla newsletter!'));
break;
}

View File

@ -0,0 +1,26 @@
<?php
include_once __DIR__.'/../../core.php';
echo '
<form action="" method="post" id="add-form">
<input type="hidden" name="op" value="add">
<input type="hidden" name="backto" value="record-edit">
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Template email').'", "name": "id_template", "values": "query=SELECT id, name AS descrizione FROM em_templates", "required": 1 ]}
</div>
<div class="col-md-6">
{[ "type": "text", "label": "'.tr('Nome').'", "name": "name", "required": 1 ]}
</div>
</div>
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-primary"><i class="fa fa-plus"></i> '.tr('Aggiungi').'</button>
</div>
</div>
</form>';

View File

@ -0,0 +1,8 @@
<?php
if ($newsletter->state == 'DEV') {
echo '
<button type="button" class="btn btn-primary ask" data-msg="'.tr('Procedere ad inviare la newsletter?').'" data-op="send" data-button="'.tr('Invia').'" data-class="btn btn-lg btn-warning">
<i class="fa fa-envelope"></i> '.tr('Invia newsletter').'
</button>';
}

155
modules/newsletter/edit.php Normal file
View File

@ -0,0 +1,155 @@
<?php
use Models\Mail;
include_once __DIR__.'/../../core.php';
$block_edit = $newsletter->state != 'DEV';
$stati = [
[
'id' => 'DEV',
'text' => 'Bozza',
],
[
'id' => 'WAIT',
'text' => 'Invio in corso',
],
[
'id' => 'OK',
'text' => 'Completata',
],
];
echo '
<form action="" method="post" id="edit-form">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="op" value="update">
<!-- DATI -->
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">'.tr('Dati campagna').'</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Template email').'", "name": "id_template", "values": "query=SELECT id, name AS descrizione FROM em_templates", "required": 1, "value": "$id_template$", "disabled": 1 ]}
</div>
<div class="col-md-6">
{[ "type": "text", "label": "'.tr('Nome').'", "name": "name", "required": 1, "value": "$name$" ]}
</div>
</div>
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Stato').'", "name": "state", "values": '.json_encode($stati).', "required": 1, "value": "$state$", "class": "unblockable" ]}
</div>
<div class="col-md-6">
{[ "type": "timestamp", "label": "'.tr('Data di completamento').'", "name": "completed_at", "value": "$completed_at$" ]}
</div>
</div>
<div class="row">
<div class="col-md-12">
{[ "type": "text", "label": "'.tr('Oggetto').'", "name": "subject", "value": "$subject$" ]}
</div>
</div>
<div class="row">
<div class="col-md-12">
{[ "type": "ckeditor", "label": "'.tr('Contenuto').'", "name": "content", "value": "$content$" ]}
</div>
</div>
</div>
</div>
</form>
<form action="" method="post" id="receivers-form">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="op" value="add_receivers">
<!-- Destinatari -->
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">'.tr('Destinatari').'</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-9">
{[ "type": "select", "label": "'.tr('Destinatari').'", "name": "receivers[]", "ajax-source": "anagrafiche", "multiple": 1 ]}
</div>
<div class="col-md-3 text-right">
<button type="submit" class="btn btn-primary">
<i class="fa fa-plus"></i> '.tr('Aggiungi').'
</button>
</div>
</div>';
$anagrafiche = $newsletter->anagrafiche;
if (!$anagrafiche->isEmpty()) {
echo '
<table class="table table-striped table-hover table-condensed table-bordered">
<thead>
<tr>
<th>'.tr('Nome').'</th>
<th class="text-center">'.tr('Data di invio').'</th>
<th class="text-center" width="60">#</th>
</tr>
</thead>
<tbody>';
foreach ($anagrafiche as $anagrafica) {
$mail_id = $anagrafica->pivot->id_email;
if (!empty($mail_id)) {
$data = Mail::find($mail_id)->sent_at;
$data = timestampFormat($data);
} else {
$data = tr('Non ancora inviata');
}
echo '
<tr>
<td>'.Modules::link('Anagrafiche', $anagrafica->id, $anagrafica->ragione_sociale).'</td>
<td class="text-center">'.$data.'</td>
<td class="text-center">
<a class="btn btn-danger ask btn-sm" data-backto="record-edit" data-op="remove_receiver" data-id="'.$anagrafica->id.'">
<i class="fa fa-trash"></i>
</a>
</td>
</tr>';
}
echo '
</tbody>
</table>';
} else {
echo '
<p>'.tr('Nessuna anagrafica collegata alla campagna').'.</p>';
}
echo '
</div>
</div>
</form>
<a class="btn btn-danger ask" data-backto="record-list">
<i class="fa fa-trash"></i> '.tr('Elimina').'
</a>';
if ($block_edit) {
echo '
<script>
$(document).ready(function() {
$("#receivers").parent().hide();
$("#receivers-form .btn").hide();
});
</script>';
}

View File

@ -0,0 +1,11 @@
<?php
use Modules\Newsletter\Newsletter;
include_once __DIR__.'/../../core.php';
if (isset($id_record)) {
$newsletter = Newsletter::find($id_record);
$record = $newsletter->toArray();
}

View File

@ -0,0 +1,63 @@
<?php
namespace Modules\Newsletter;
use Common\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Models\Mail;
use Models\MailAccount;
use Models\MailTemplate;
use Models\User;
use Modules\Anagrafiche\Anagrafica;
class Newsletter extends Model
{
use SoftDeletes;
protected $table = 'em_campaigns';
public static function build(User $user, MailTemplate $template, $name)
{
$model = parent::build();
$model->user()->associate($user);
$model->template()->associate($template);
$model->name = $name;
$model->subject = $template->subject;
$model->content = $template->body;
$model->state = 'DEV';
$model->save();
return $model;
}
// Relazione Eloquent
public function anagrafiche()
{
return $this->belongsToMany(Anagrafica::class, 'em_campaign_anagrafica', 'id_campaign', 'id_anagrafica')->withPivot('id_email');
}
public function emails()
{
return $this->belongsToMany(Mail::class, 'em_campaign_anagrafica', 'id_campaign', 'id_email')->withPivot('id_anagrafica');
}
public function account()
{
return $this->belongsTo(MailAccount::class, 'id_account');
}
public function template()
{
return $this->belongsTo(MailTemplate::class, 'id_template');
}
public function user()
{
return $this->belongsTo(User::class, 'created_by');
}
}

View File

@ -183,6 +183,28 @@ class Mail extends Model
return $this->options['read-notify'];
}
public function setSubjecyAttribute($value)
{
if (isset($this->template)) {
$module = $this->template->module;
$value = $module->replacePlaceholders($this->id_record, $value);
}
$this->attributes['subject'] = $value;
}
public function setContentAttribute($value)
{
if (isset($this->template)) {
$module = $this->template->module;
$value = $module->replacePlaceholders($this->id_record, $value);
}
$this->attributes['content'] = $value;
}
/**
* Imposta il titolo della notifica.
*
@ -205,6 +227,11 @@ class Mail extends Model
return $this->belongsTo(MailTemplate::class, 'id_template');
}
public function user()
{
return $this->belongsTo(User::class, 'created_by');
}
protected function resetFromTemplate()
{
$template = $this->template;
@ -213,18 +240,8 @@ class Mail extends Model
$this->read_notify = $template->read_notify;
// Contentuto e oggetto
$body = $template->body;
$subject = $template->subject;
if (!empty($this->id_record)) {
$module = $this->template->module;
$body = $module->replacePlaceholders($this->id_record, $body);
$subject = $module->replacePlaceholders($this->id_record, $subject);
}
$this->content = $body;
$this->subject = $subject;
$this->content = $template->body;
$this->subject = $template->subject;
// Reply To
if (!empty($template['reply_to'])) {

View File

@ -334,14 +334,16 @@ UPDATE zz_views SET query = REPLACE(query, 'zz_smtps', 'em_accounts');
CREATE TABLE IF NOT EXISTS `em_campaigns` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`id_account` int(11) NOT NULL,
`id_template` int(11) NOT NULL,
`state` varchar(25) NOT NULL,
`subject` varchar(255) NOT NULL,
`content` TEXT NOT NULL,
`created_by` int(11) NOT NULL,
`completed_at` TIMESTAMP NULL DEFAULT NULL,
`deleted_at` TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`id_account`) REFERENCES `em_accounts`(`id`) ON DELETE CASCADE,
FOREIGN KEY (`id_template`) REFERENCES `em_templates`(`id`) ON DELETE CASCADE
FOREIGN KEY (`id_template`) REFERENCES `em_templates`(`id`) ON DELETE CASCADE,
FOREIGN KEY (`created_by`) REFERENCES `zz_users`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `em_emails` (
@ -376,3 +378,11 @@ CREATE TABLE IF NOT EXISTS `em_campaign_anagrafica` (
) ENGINE=InnoDB;
INSERT INTO `zz_hooks` (`id`, `name`, `class`, `frequency`, `id_module`) VALUES (NULL, 'Email', 'Modules\\Emails\\EmailHook', '1 minute', (SELECT `id` FROM `zz_modules` WHERE `name` = 'Account email'));
INSERT INTO `zz_modules` (`id`, `name`, `title`, `directory`, `options`, `options2`, `icon`, `version`, `compatibility`, `order`, `parent`, `default`, `enabled`) VALUES (NULL, 'Newsletter', 'Newsletter', 'newsletter', 'SELECT |select| FROM `em_campaigns` WHERE 1=1 AND deleted_at IS NULL HAVING 2=2', '', 'fa fa-newspaper-o ', '2.4.11', '2.4.11', '1', (SELECT `id` FROM `zz_modules` t WHERE t.`name` = 'Gestione email'), '1', '1');
INSERT INTO `zz_views` (`id_module`, `name`, `query`, `order`, `search`, `slow`, `default`, `visible`) VALUES
((SELECT `id` FROM `zz_modules` WHERE `name` = 'Newsletter'), 'id', 'id', 1, 0, 0, 1, 0),
((SELECT `id` FROM `zz_modules` WHERE `name` = 'Newsletter'), 'Nome', 'name', 2, 1, 0, 0, 1),
((SELECT `id` FROM `zz_modules` WHERE `name` = 'Newsletter'), 'Template', '(SELECT name FROM em_templates WHERE id = em_campaigns.id_template)', 3, 1, 0, 1, 1),
((SELECT `id` FROM `zz_modules` WHERE `name` = 'Newsletter'), 'Completato', 'IF(completed_at IS NULL, ''No'', ''Si'')', 4, 1, 0, 1, 1);