1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-09-19 16:01:34 +02:00

Added HTML email designs

This commit is contained in:
Hillel Coren 2015-12-02 15:26:06 +02:00
parent 7109b30673
commit c5a1abf66f
31 changed files with 593 additions and 102 deletions

View File

@ -46,29 +46,78 @@ class CheckData extends Command {
public function fire()
{
$this->info(date('Y-m-d') . ' Running CheckData...');
$today = new DateTime();
if (!$this->option('client_id')) {
// update client paid_to_date value
$clients = DB::table('clients')
->join('payments', 'payments.client_id', '=', 'clients.id')
->join('invoices', 'invoices.id', '=', 'payments.invoice_id')
->where('payments.is_deleted', '=', 0)
->where('invoices.is_deleted', '=', 0)
->groupBy('clients.id')
->havingRaw('clients.paid_to_date != sum(payments.amount) and clients.paid_to_date != 999999999.9999')
->get(['clients.id', 'clients.paid_to_date', DB::raw('sum(payments.amount) as amount')]);
$this->info(count($clients) . ' clients with incorrect paid to date');
$this->checkPaidToDate();
}
$this->checkBalances();
$this->checkActivityAccount();
$this->info('Done');
}
private function checkActivityAccount()
{
$entityTypes = [
ENTITY_INVOICE,
ENTITY_CLIENT,
ENTITY_CONTACT,
ENTITY_PAYMENT,
ENTITY_INVITATION,
];
foreach ($entityTypes as $entityType) {
$activities = DB::table('activities')
->join("{$entityType}s", "{$entityType}s.id", '=', "activities.{$entityType}_id");
if ($entityType != ENTITY_CLIENT) {
$activities = $activities->join('clients', 'clients.id', '=', 'activities.client_id');
}
$activities = $activities->where('activities.account_id', '!=', DB::raw("{$entityType}s.account_id"))
->get(['activities.id', "clients.account_id", "clients.user_id"]);
$this->info(count($activities) . " {$entityType} activity with incorrect account id");
if ($this->option('fix') == 'true') {
foreach ($clients as $client) {
DB::table('clients')
->where('id', $client->id)
->update(['paid_to_date' => $client->amount]);
foreach ($activities as $activity) {
DB::table('activities')
->where('id', $activity->id)
->update([
'account_id' => $activity->account_id,
'user_id' => $activity->user_id,
]);
}
}
}
}
private function checkPaidToDate()
{
// update client paid_to_date value
$clients = DB::table('clients')
->join('payments', 'payments.client_id', '=', 'clients.id')
->join('invoices', 'invoices.id', '=', 'payments.invoice_id')
->where('payments.is_deleted', '=', 0)
->where('invoices.is_deleted', '=', 0)
->groupBy('clients.id')
->havingRaw('clients.paid_to_date != sum(payments.amount) and clients.paid_to_date != 999999999.9999')
->get(['clients.id', 'clients.paid_to_date', DB::raw('sum(payments.amount) as amount')]);
$this->info(count($clients) . ' clients with incorrect paid to date');
if ($this->option('fix') == 'true') {
foreach ($clients as $client) {
DB::table('clients')
->where('id', $client->id)
->update(['paid_to_date' => $client->amount]);
}
}
}
private function checkBalances()
{
// find all clients where the balance doesn't equal the sum of the outstanding invoices
$clients = DB::table('clients')
->join('invoices', 'invoices.client_id', '=', 'clients.id')
@ -249,8 +298,6 @@ class CheckData extends Command {
->update($data);
}
}
$this->info('Done');
}
protected function getArguments()

View File

@ -432,6 +432,11 @@ class AccountController extends BaseController
{
if (Auth::user()->account->isPro()) {
$account = Auth::user()->account;
$account->email_design_id = Input::get('email_design_id');
if (Utils::isNinja()) {
$account->enable_email_markup = Input::get('enable_email_markup') ? true : false;
}
foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_PAYMENT, REMINDER1, REMINDER2, REMINDER3] as $type) {
$subjectField = "email_subject_{$type}";

View File

@ -253,6 +253,7 @@ if (!defined('CONTACT_EMAIL')) {
define('ENTITY_CONTACT', 'contact');
define('ENTITY_INVOICE', 'invoice');
define('ENTITY_INVOICE_ITEMS', 'invoice_items');
define('ENTITY_INVITATION', 'invitation');
define('ENTITY_RECURRING_INVOICE', 'recurring_invoice');
define('ENTITY_PAYMENT', 'payment');
define('ENTITY_CREDIT', 'credit');
@ -446,6 +447,7 @@ if (!defined('CONTACT_EMAIL')) {
define('PHANTOMJS_CLOUD', 'http://api.phantomjscloud.com/api/browser/v2/');
define('PHP_DATE_FORMATS', 'http://php.net/manual/en/function.date.php');
define('REFERRAL_PROGRAM_URL', 'https://www.invoiceninja.com/referral-program/');
define('EMAIL_MARKUP_URL', 'https://developers.google.com/gmail/markup/overview');
define('COUNT_FREE_DESIGNS', 4);
define('COUNT_FREE_DESIGNS_SELF_HOST', 5); // include the custom design
@ -498,6 +500,9 @@ if (!defined('CONTACT_EMAIL')) {
define('API_SERIALIZER_ARRAY', 'array');
define('API_SERIALIZER_JSON', 'json');
define('EMAIL_DESIGN_PLAIN', 1);
define('FLAT_BUTTON_CSS', 'border:0 none;border-radius:6px;padding:12px 40px;margin:0 6px;cursor:hand;display:inline-block;font-size:14px;color:#fff;text-transform:none');
$creditCards = [
1 => ['card' => 'images/credit_cards/Test-Visa-Icon.png', 'text' => 'Visa'],
2 => ['card' => 'images/credit_cards/Test-MasterCard-Icon.png', 'text' => 'Master Card'],
@ -522,7 +527,6 @@ if (!defined('CONTACT_EMAIL')) {
'invoiceStatus' => 'App\Models\InvoiceStatus',
'frequencies' => 'App\Models\Frequency',
'gateways' => 'App\Models\Gateway',
'themes' => 'App\Models\Theme',
];
define('CACHED_TABLES', serialize($cachedTables));

View File

@ -279,9 +279,19 @@ class Utils
return json_decode(json_encode((array) $data), true);
}
public static function toSpaceCase($camelStr)
public static function toSpaceCase($string)
{
return preg_replace('/([a-z])([A-Z])/s', '$1 $2', $camelStr);
return preg_replace('/([a-z])([A-Z])/s', '$1 $2', $string);
}
public static function toSnakeCase($string)
{
return preg_replace('/([a-z])([A-Z])/s', '$1_$2', $string);
}
public static function toCamelCase($string)
{
return lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $string))));
}
public static function timestampToDateTimeString($timestamp)

View File

@ -5,6 +5,7 @@ use Utils;
use Session;
use DateTime;
use Event;
use Cache;
use App;
use File;
use App\Events\UserSettingsChanged;
@ -204,10 +205,26 @@ class Account extends Eloquent
return $this->date_format ? $this->date_format->format : DEFAULT_DATE_FORMAT;
}
public function formatMoney($amount, $client = null)
{
$currency = ($client && $client->currency) ? $client->currency : $this->currency;
if ( ! $currency) {
$currencies = Cache::get('currencies')->filter(function($item) {
return $item->id == DEFAULT_CURRENCY;
});
$currency = $currencies->first();
}
return $currency->symbol . number_format($amount, $currency->precision, $currency->decimal_separator, $currency->thousand_separator);
}
public function formatDate($date)
{
if (!$date) {
if ( ! $date) {
return null;
} elseif ( ! $date instanceof \DateTime) {
$date = new \DateTime($date);
}
return $date->format($this->getCustomDateFormat());
@ -677,9 +694,9 @@ class Account extends Eloquent
$entityType = ENTITY_INVOICE;
}
$template = "<div>\$client,</div><br/>" .
"<div>" . trans("texts.{$entityType}_message", ['amount' => '$amount']) . "</div><br/>" .
"<div><a href=\"\$link\">\$link</a></div><br/>";
$template = "<div>\$client,</div><br>" .
"<div>" . trans("texts.{$entityType}_message", ['amount' => '$amount']) . "</div><br>" .
"<div><a href=\"\$viewLink\">\$viewLink</a></div><br>";
if ($message) {
$template .= "$message<p/>\r\n\r\n";
@ -693,13 +710,14 @@ class Account extends Eloquent
if ($this->isPro()) {
$field = "email_template_{$entityType}";
$template = $this->$field;
if ($template) {
return $template;
}
}
return $this->getDefaultEmailTemplate($entityType, $message);
if (!$template) {
$template = $this->getDefaultEmailTemplate($entityType, $message);
}
// <br/> is causing page breaks with the email designs
return str_replace('/>', ' />', $template);
}
public function getEmailFooter()
@ -708,7 +726,7 @@ class Account extends Eloquent
// Add line breaks if HTML isn't already being used
return strip_tags($this->email_footer) == $this->email_footer ? nl2br($this->email_footer) : $this->email_footer;
} else {
return "<p>" . trans('texts.email_signature') . "\n<br>\$account</p>";
return "<p>" . trans('texts.email_signature') . "\n<br>\$account</ p>";
}
}

View File

@ -2,6 +2,7 @@
use Eloquent;
use Omnipay;
use Utils;
class Gateway extends Eloquent
{
@ -44,13 +45,20 @@ class Gateway extends Eloquent
return $this->id == $gatewayId;
}
public static function getPaymentTypeName($type)
{
return Utils::toCamelCase(strtolower(str_replace('PAYMENT_TYPE_', '', $type)));
}
/*
public static function getPaymentTypeLinks() {
$data = [];
foreach (self::$paymentTypes as $type) {
$data[] = strtolower(str_replace('PAYMENT_TYPE_', '', $type));
$data[] = Utils::toCamelCase(strtolower(str_replace('PAYMENT_TYPE_', '', $type)));
}
return $data;
}
*/
public function getHelp()
{

View File

@ -29,7 +29,7 @@ class Invitation extends EntityModel
return $this->belongsTo('App\Models\Account');
}
public function getLink()
public function getLink($type = 'view')
{
if (!$this->account) {
$this->load('account');
@ -46,7 +46,7 @@ class Invitation extends EntityModel
}
}
return "{$url}/view/{$this->invitation_key}";
return "{$url}/{$type}/{$this->invitation_key}";
}
public function getStatus()

View File

@ -1,5 +1,6 @@
<?php namespace App\Ninja\Mailers;
use HTML;
use Utils;
use Event;
use URL;
@ -15,6 +16,21 @@ use App\Events\QuoteWasEmailed;
class ContactMailer extends Mailer
{
public static $variableFields = [
'footer',
'account',
'client',
'amount',
'contact',
'firstName',
'invoice',
'quote',
'viewLink',
'viewButton',
'paymentLink',
'paymentButton',
];
public function sendInvoice(Invoice $invoice, $reminder = false, $pdfString = false)
{
$invoice->load('invitations', 'client.language', 'account');
@ -97,6 +113,7 @@ class ContactMailer extends Mailer
'invoiceId' => $invoice->id,
'invitation' => $invitation,
'account' => $account,
'client' => $client,
'invoice' => $invoice,
];
@ -107,8 +124,14 @@ class ContactMailer extends Mailer
$subject = $this->processVariables($subject, $variables);
$fromEmail = $user->email;
if ($account->email_design_id == EMAIL_DESIGN_PLAIN) {
$view = ENTITY_INVOICE;
} else {
$view = 'design' . ($account->email_design_id - 1);
}
$response = $this->sendTo($invitation->contact->email, $fromEmail, $account->getDisplayName(), $subject, ENTITY_INVOICE, $data);
$response = $this->sendTo($invitation->contact->email, $fromEmail, $account->getDisplayName(), $subject, $view, $data);
if ($response === true) {
return true;
@ -192,22 +215,33 @@ class ContactMailer extends Mailer
private function processVariables($template, $data)
{
$account = $data['account'];
$client = $data['client'];
$invitation = $data['invitation'];
$invoice = $invitation->invoice;
$variables = [
'$footer' => $data['account']->getEmailFooter(),
'$link' => $data['invitation']->getLink(),
'$client' => $data['client']->getDisplayName(),
'$account' => $data['account']->getDisplayName(),
'$contact' => $data['invitation']->contact->getDisplayName(),
'$firstName' => $data['invitation']->contact->first_name,
'$amount' => Utils::formatMoney($data['amount'], $data['client']->getCurrencyId()),
'$invoice' => $data['invitation']->invoice->invoice_number,
'$quote' => $data['invitation']->invoice->invoice_number,
'$advancedRawInvoice->' => '$'
'$footer' => $account->getEmailFooter(),
'$client' => $client->getDisplayName(),
'$account' => $account->getDisplayName(),
'$contact' => $invitation->contact->getDisplayName(),
'$firstName' => $invitation->contact->first_name,
'$amount' => Utils::formatMoney($data['amount'], $client->getCurrencyId()),
'$invoice' => $invoice->invoice_number,
'$quote' => $invoice->invoice_number,
'$link' => $invitation->getLink(),
'$viewLink' => $invitation->getLink(),
'$viewButton' => HTML::emailViewButton($invitation->getLink(), $invoice->getEntityType()),
'$paymentLink' => $invitation->getLink('payment'),
'$paymentButton' => HTML::emailPaymentButton($invitation->getLink('payment')),
];
// Add variables for available payment types
foreach (Gateway::getPaymentTypeLinks() as $type) {
$variables["\${$type}_link"] = URL::to("/payment/{$data['invitation']->invitation_key}/{$type}");
foreach (Gateway::$paymentTypes as $type) {
$camelType = Gateway::getPaymentTypeName($type);
$type = Utils::toSnakeCase($camelType);
$variables["\${$camelType}Link"] = $invitation->getLink() . "/{$type}";
$variables["\${$camelType}Button"] = HTML::emailPaymentButton($invitation->getLink('payment') . "/{$type}");
}
$str = str_replace(array_keys($variables), array_values($variables), $template);

View File

@ -67,7 +67,7 @@ class Mailer
private function handleFailure($exception)
{
if (isset($_ENV['POSTMARK_API_TOKEN']) && $exception->getResponse()) {
if (isset($_ENV['POSTMARK_API_TOKEN']) && method_exists($exception, 'getResponse')) {
$response = $exception->getResponse()->getBody()->getContents();
$response = json_decode($response);
$emailError = nl2br($response->Message);

View File

@ -15,6 +15,17 @@ class InvoicePresenter extends Presenter {
return $this->entity->user->getDisplayName();
}
public function balanceDueLabel()
{
if ($this->entity->partial) {
return 'amount_due';
} elseif ($this->entity->is_quote) {
return 'total';
} else {
return 'balance_due';
}
}
public function balance_due()
{
$amount = $this->entity->getRequestedAmount();

View File

@ -44,7 +44,7 @@ class ActivityRepository
{
$activity = new Activity();
if (Auth::check()) {
if (Auth::check() && Auth::user()->account_id == $entity->account_id) {
$activity->user_id = Auth::user()->id;
$activity->account_id = Auth::user()->account_id;
} else {

View File

@ -65,6 +65,29 @@ class AppServiceProvider extends ServiceProvider {
return 'data:image/jpeg;base64,' . base64_encode(file_get_contents(public_path().'/'.$imagePath));
});
HTML::macro('flatButton', function($label, $color) {
return '<input type="button" value="' . trans("texts.{$label}") . '" style="background-color:' . $color . ';border:0 none;border-radius:5px;padding:12px 40px;margin:0 6px;cursor:hand;display:inline-block;font-size:14px;color:#fff;text-transform:none;font-weight:bold;"/>';
});
HTML::macro('emailViewButton', function($link = '#', $entityType = ENTITY_INVOICE) {
return view('partials.email_button')
->with([
'link' => $link,
'field' => "view_{$entityType}",
'color' => '#0b4d78',
])
->render();
});
HTML::macro('emailPaymentButton', function($link = '#') {
return view('partials.email_button')
->with([
'link' => $link,
'field' => 'pay_now',
'color' => '#36c157',
])
->render();
});
HTML::macro('breadcrumbs', function() {
$str = '<ol class="breadcrumb">';

View File

@ -40,7 +40,7 @@ class UserService extends BaseService
[
'first_name',
function ($model) {
return link_to('users/'.$model->public_id.'/edit', $model->first_name.' '.$model->last_name);
return $model->public_id ? link_to('users/'.$model->public_id.'/edit', $model->first_name.' '.$model->last_name) : ($model->first_name.' '.$model->last_name);
}
],
[

View File

@ -317,12 +317,12 @@ class ConfideSetupUsersTable extends Migration {
$t->date('due_date')->nullable();
$t->text('terms');
$t->text('public_notes');
$t->boolean('is_deleted')->default(false);
$t->boolean('is_recurring');
$t->boolean('is_deleted')->default(false);
$t->boolean('is_recurring')->default(false);
$t->unsignedInteger('frequency_id');
$t->date('start_date')->nullable();
$t->date('end_date')->nullable();
$t->timestamp('last_sent_date')->nullable();
$t->timestamp('last_sent_date')->nullable();
$t->unsignedInteger('recurring_invoice_id')->index()->nullable();
$t->string('tax_name');

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
class AddEmailDesigns extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('accounts', function ($table) {
$table->smallInteger('email_design_id')->default(1);
$table->boolean('enable_email_markup')->default(false);
$table->string('website')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('accounts', function ($table) {
$table->dropColumn('email_design_id');
$table->dropColumn('enable_email_markup');
$table->dropColumn('website');
});
}
}

15
public/css/built.css vendored
View File

@ -3381,4 +3381,19 @@ ul.user-accounts a:hover div.remove {
div.panel-body div.panel-body {
padding-bottom: 0px;
}
.email-button {
border: 0 none;
border-radius: 36px;
padding: 12px 45px;
margin: 0 10px;
cursor: pointer;
display: inline-block;
font-size: 14px;
color: #fff;
text-transform: none;
}

View File

@ -31758,7 +31758,7 @@ NINJA.decodeJavascript = function(invoice, javascript)
} else if (invoice.is_quote && field == 'your_invoice') {
field = 'your_quote';
}
var label = invoiceLabels[field];
var label = invoiceLabels[field];
if (match.indexOf('UC') >= 0) {
label = label.toUpperCase();
}

View File

@ -41,6 +41,10 @@ There are two options:
* [Zapier](https://zapier.com/) integration
* [D3.js](http://d3js.org/) visualizations
### Recommended Providers
* [Stripe](https://stripe.com/)
* [Postmark](https://postmarkapp.com/)
### Documentation
* [Ubuntu and Apache](http://blog.technerdservices.com/index.php/2015/04/techpop-how-to-install-invoice-ninja-on-ubuntu-14-04/)
* [Debian and Nginx](https://www.rosehosting.com/blog/install-invoice-ninja-on-a-debian-7-vps/)
@ -55,10 +59,6 @@ There are two options:
* [Jeramy Simpson](https://github.com/JeramyMywork) - [MyWork](https://www.mywork.com.au)
* [Sigitas Limontas](https://lt.linkedin.com/in/sigitaslimontas)
### Recommended Providers
* [Stripe](https://stripe.com/)
* [Postmark](https://postmarkapp.com/)
### Frameworks/Libraries
* [laravel/laravel](https://github.com/laravel/laravel) - A PHP Framework For Web Artisans
* [twbs/bootstrap](https://github.com/twbs/bootstrap) - Sleek, intuitive, and powerful front-end framework for faster and easier web development.

View File

@ -953,5 +953,16 @@ return array(
'secret_key' => 'Secret Key',
'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process',
'email_design' => 'Email Design',
'due_by' => 'Due by :date',
'enable_email_markup' => 'Enable Email Markup',
'enable_email_markup_help' => 'Make it easier for your clients to pay you by adding schema.org markup to your emails.',
'template_help_title' => 'Templates Help',
'template_help_1' => 'Available variables:',
'email_design_id' => 'Email Design',
'email_design_help' => 'Make your emails look more professional with HTML layouts',
'plain' => 'Plain',
'light' => 'Light',
'dark' => 'Dark',
);

View File

@ -16,6 +16,8 @@
<div class="pull-right"><a href="#" onclick="return resetText('{{ 'subject' }}', '{{ $field }}')">{{ trans("texts.reset") }}</a></div>
{!! Former::text('email_subject_' . $field)
->label(trans('texts.subject'))
->appendIcon('question-sign')
->addGroupClass('email-subject')
->addClass('enable-' . $field) !!}
</div>
<div class="col-md-6">
@ -48,25 +50,30 @@
</div>
</div>
<script type="text/javascript">
$(function() {
var editor = new Quill('#{{ $field }}Editor', {
modules: {
'toolbar': { container: '#{{ $field }}Toolbar' },
'link-tooltip': true
},
theme: 'snow'
});
editor.setHTML($('#email_template_{{ $field }}').val());
editor.on('text-change', function(delta, source) {
if (source == 'api') {
return;
}
var html = editors['{{ $field }}'].getHTML();
$('#email_template_{{ $field }}').val(html);
refreshPreview();
NINJA.formIsChanged = true;
});
editors['{{ $field }}'] = editor;
<script type="text/javascript">
$(function() {
var editor = new Quill('#{{ $field }}Editor', {
modules: {
'toolbar': { container: '#{{ $field }}Toolbar' },
'link-tooltip': true
},
theme: 'snow'
});
</script>
editor.setHTML($('#email_template_{{ $field }}').val());
editor.on('text-change', function(delta, source) {
if (source == 'api') {
return;
}
var html = editors['{{ $field }}'].getHTML();
$('#email_template_{{ $field }}').val(html);
refreshPreview();
NINJA.formIsChanged = true;
});
editors['{{ $field }}'] = editor;
});
$('.email-subject .input-group-addon').click(function() {
$('#templateHelpModal').modal('show');
});
</script>

View File

@ -32,9 +32,35 @@
@endforeach
@endforeach
{!! Former::populateField("enable_reminder1", intval($account->enable_reminder1)) !!}
{!! Former::populateField("enable_reminder2", intval($account->enable_reminder2)) !!}
{!! Former::populateField("enable_reminder3", intval($account->enable_reminder3)) !!}
{!! Former::populateField('enable_reminder1', intval($account->enable_reminder1)) !!}
{!! Former::populateField('enable_reminder2', intval($account->enable_reminder2)) !!}
{!! Former::populateField('enable_reminder3', intval($account->enable_reminder3)) !!}
{!! Former::populateField('enable_email_markup', intval($account->enable_email_markup)) !!}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{!! trans('texts.email_design') !!}</h3>
</div>
<div class="panel-body">
{!! Former::select('email_design_id')
->style('width: 200px')
->addOption(trans('texts.plain'), 1)
->addOption(trans('texts.light'), 2)
->addOption(trans('texts.dark'), 3)
->help(trans('texts.email_design_help')) !!}
@if (Utils::isNinja())
&nbsp;
{!! Former::checkbox('enable_email_markup')
->text(trans('texts.enable_email_markup'))
->label('')
->help(trans('texts.enable_email_markup_help')) !!}
{!! link_to(EMAIL_MARKUP_URL, trans('texts.learn_more'), ['target' => '_blank']) !!}
@endif
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
@ -83,6 +109,39 @@
</div>
<div class="modal fade" id="templateHelpModal" tabindex="-1" role="dialog" aria-labelledby="templateHelpModalLabel" aria-hidden="true">
<div class="modal-dialog" style="min-width:150px">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title" id="templateHelpModalLabel">{{ trans('texts.template_help_title') }}</h4>
</div>
<div class="modal-body">
<p>{{ trans('texts.template_help_1') }}</p>
<ul>
@foreach (\App\Ninja\Mailers\ContactMailer::$variableFields as $field)
<li>${{ $field }}</li>
@endforeach
@if (count($account->account_gateways) > 1)
@foreach (\App\Models\Gateway::$paymentTypes as $type)
@if ($account->getGatewayByType($type))
<li>${{ \App\Models\Gateway::getPaymentTypeName($type) }}Link</li>
<li>${{ \App\Models\Gateway::getPaymentTypeName($type) }}Button</li>
@endif
@endforeach
@endif
</ul>
</div>
<div class="modal-footer" style="margin-top: 0px">
<button type="button" class="btn btn-primary" data-dismiss="modal">{{ trans('texts.close') }}</button>
</div>
</div>
</div>
</div>
@if (Auth::user()->isPro())
<center>
{!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!}
@ -146,34 +205,29 @@
return '';
}
keys = [
'footer',
'account',
'client',
'amount',
'link',
'contact',
'firstName',
'invoice',
'quote'
];
vals = [
var keys = {!! json_encode(\App\Ninja\Mailers\ContactMailer::$variableFields) !!};
var vals = [
{!! json_encode($emailFooter) !!},
"{{ Auth::user()->account->getDisplayName() }}",
"Client Name",
formatMoney(100),
"{{ Auth::user()->account->getSiteUrl() . '...' }}",
"Contact Name",
"First Name",
"0001",
"0001"
"0001",
"{{ URL::to('/view/...') }}",
'{!! HTML::flatButton('view_invoice', '#0b4d78') !!}',
"{{ URL::to('/payment/...') }}",
'{!! HTML::flatButton('pay_now', '#36c157') !!}',
];
// Add any available payment method links
@foreach (\App\Models\Gateway::getPaymentTypeLinks() as $type)
{!! "keys.push('" . $type.'_link' . "');" !!}
{!! "vals.push('" . URL::to("/payment/xxxxxx/{$type}") . "');" !!}
@foreach (\App\Models\Gateway::$paymentTypes as $type)
{!! "keys.push('" . \App\Models\Gateway::getPaymentTypeName($type).'Link' . "');" !!}
{!! "vals.push('" . URL::to('/payment/...') . "');" !!}
{!! "keys.push('" . \App\Models\Gateway::getPaymentTypeName($type).'Button' . "');" !!}
{!! "vals.push('" . HTML::flatButton('pay_now', '#36c157') . "');" !!}
@endforeach
for (var i=0; i<keys.length; i++) {

View File

@ -1 +0,0 @@
{!! nl2br($text) !!}

View File

@ -1 +0,0 @@
{!! $text !!}

View File

@ -0,0 +1,46 @@
@extends('emails.master')
@section('content')
<tr>
<td bgcolor="#F4F5F5" style="border-collapse: collapse;">&nbsp;</td>
</tr>
<tr>
<td style="border-collapse: collapse;">
<table cellpadding="10" cellspacing="0" border="0" bgcolor="#F4F5F5" width="600" align="center"
class="header" style="border-top-width: 6px; border-top-color: {{ $account->primary_color ?: '#2E2B2B' }}; border-top-style: solid;">
<tr>
<td class="logo" width="208" style="border-collapse: collapse; vertical-align: middle;" valign="middle">
@include('emails.partials.account_logo')
</td>
<td width="183" style="border-collapse: collapse; vertical-align: middle;" valign="middle">
<p class="left" style="line-height: 22px; margin: 0; padding: 2px 0 0;">
<span style="font-size: 11px; color: #8f8d8e;">
@if ($invoice->due_date)
{{ strtoupper(trans('texts.due_by', ['date' => $account->formatDate($invoice->due_date)])) }}
@endif
</span><br />
<span style="font-size: 18px;">
{{ trans("texts.{$entityType}") }} {{ $invoice->invoice_number }}
</span>
</p>
</td>
<td style="border-collapse: collapse; vertical-align: middle;" valign="middle">
<p class="right" style="line-height: 14px; margin: 0; padding: 0;">
<span style="font-size: 15px; color: #231F20;">
{{ trans('texts.' . $invoice->present()->balanceDueLabel) }}:
</span><br />
<span class="total" style="font-size: 26px; display: block;margin-top: 5px;">
{{ $account->formatMoney($invoice->getRequestedAmount(), $client) }}
</span>
</p>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td class="content" style="border-collapse: collapse;">
<div style="font-size: 18px; margin: 42px 40px 42px; padding: 0;">{!! $body !!}</div>
</td>
</tr>
@stop

View File

@ -0,0 +1 @@
{!! strip_tags($body) !!}

View File

@ -0,0 +1,46 @@
@extends('emails.master')
@section('content')
<tr>
<td bgcolor="#F4F5F5" style="border-collapse: collapse;">&nbsp;</td>
</tr>
<tr>
<td style="border-collapse: collapse;">
<table cellpadding="10" cellspacing="0" border="0" bgcolor="{{ $account->primary_color ?: '#2E2B2B' }}" width="600" align="center" class="header"
style="border-bottom-width: 6px; border-bottom-color: {{ $account->primary_color ?: '#2E2B2B' }}; border-bottom-style: solid;">
<tr>
<td class="logo" width="205" style="border-collapse: collapse; vertical-align: middle; line-height: 16px;" valign="middle">
@include('emails.partials.account_logo')
</td>
<td width="183" style="border-collapse: collapse; vertical-align: middle; line-height: 16px;" valign="middle">
<p class="left" style="line-height: 22px; margin: 3px 0 0; padding: 0;">
<span style="font-size: 11px; color: #8f8d8e;">
@if ($invoice->due_date)
{{ strtoupper(trans('texts.due_by', ['date' => $account->formatDate($invoice->due_date)])) }}
@endif
</span><br />
<span style="font-size: 19px; color: #FFFFFF;">
{{ trans("texts.{$entityType}") }} {{ $invoice->invoice_number }}
</span>
</p>
</td>
<td style="border-collapse: collapse; vertical-align: middle; line-height: 16px;" valign="middle">
<p style="margin: 0; padding: 0;">
<span style="font-size: 12px; color: #8f8d8e;">
{{ strtoupper(trans('texts.' . $invoice->present()->balanceDueLabel)) }}:
</span><br />
<span class="total" style="font-size: 27px; color: #FFFFFF; margin-top: 5px;display: block;">
{{ $account->formatMoney($invoice->getRequestedAmount(), $client) }}
</span>
</p>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td class="content" style="border-collapse: collapse;">
<div style="font-size: 18px; margin: 42px 40px 42px; padding: 0;">{!! $body !!}</div>
</td>
</tr>
@stop

View File

@ -0,0 +1 @@
{!! strip_tags($body) !!}

View File

@ -4,7 +4,7 @@
<meta charset="utf-8">
</head>
<body>
@if (Utils::isNinjaDev())
@if ($account->enable_email_markup)
@include('emails.view_action', ['link' => $link, 'entityType' => $entityType])
@endif
{!! $body !!}

View File

@ -0,0 +1,85 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml" lang="{{ App::getLocale() }}">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body style="min-height: 700px; color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 12px; -webkit-text-size-adjust: none; -ms-text-size-adjust: none; background: #F4F5F5; margin: 0; padding: 0;"
alink="#FF0000" link="#FF0000" bgcolor="#F4F5F5" text="#000000" yahoo="fix">
@if ($account->enable_email_markup)
@include('emails.view_action', ['link' => $link, 'entityType' => $entityType])
@endif
<style type="text/css">
.footer a:visited {
font-weight: bold; font-size: 10px; color: #A7A6A6; text-decoration: none;
}
span.yshortcuts:hover {
color: #000; background-color: none; border: none;
}
span.yshortcuts:active {
color: #000; background-color: none; border: none;
}
span.yshortcuts:focus {
color: #000; background-color: none; border: none;
}
a:visited {
color: #19BB40; text-decoration: none;
}
a:focus {
color: #19BB40; text-decoration: underline;
}
a:hover {
color: #19BB40; text-decoration: underline;
}
@media only screen and (max-device-width: 480px) {
body[yahoo] #container1 {
display: block !important;
}
body[yahoo] p {
font-size: 10px;
}
}
@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {
body[yahoo] #container1 {
display: block !important;
}
body[yahoo] p {
font-size: 12px;
}
}
</style>
<div id="body_style" style="min-height: 700px; color: #2E2B2B; font-family: Helvetica, sans-serif; font-size: 16px;
background: #F4F5F5; padding: 0px 15px;">
<table cellpadding="0" cellspacing="0" border="0" bgcolor="#FFFFFF" width="600" align="center">
@yield('content')
<tr class="footer" style="text-align: center; color: #a7a6a6;" align="center">
<td bgcolor="#F4F5F5"
style="border-collapse: collapse; padding-top: 32px;">
<p style="color: #A7A6A6; font-size: 13px; line-height: 18px; margin: 0 0 7px; padding: 0;">
{{ $account->address1 }}
@if ($account->address1 && $account->getCityState())
-
@endif
{{ $account->getCityState() }}
@if ($account->address1 || $account->getCityState())
<br />
@endif
@if ($account->website)
<strong><a href="{{ $account->website }}" style="color: #A7A6A6; text-decoration: none; font-weight: bold; font-size: 10px;">{{ $account->website }}</a></strong>
@endif
</p>
</td>
</tr>
</table>
</div>
</body>
</html>

View File

@ -0,0 +1,11 @@
@if ($account->hasLogo())
@if ($account->website)
<a href="{{ $account->website }}" style="color: #19BB40; text-decoration: underline;">
@endif
<img src="{{ $message->embed($account->getLogoPath()) }}" style="max-height:50px; max-width:140px; margin-left: 33px;" />
@if ($account->website)
</a>
@endif
@endif

View File

@ -0,0 +1,22 @@
<!-- https://gist.github.com/elidickinson/9424116#file-html_email_buttons_1-html -->
<div style="display:inline-block;width:190px">
<!--[if mso]>
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="{{ $link }}" style="height:44px;v-text-anchor:middle;width:180px;" arcsize="10%" stroke="f" fillcolor="{{ $color }}">
<w:anchorlock/>
<center style="color:#ffffff;font-family:sans-serif;font-size:16px;font-weight:bold;">
{{ trans("texts.{$field}") }}
</center>
</v:roundrect>
<![endif]-->
<![if !mso]>
<table cellspacing="0" cellpadding="0"> <tr>
<td align="center" width="180" height="44" bgcolor="{{ $color }}" style="-webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; color: #ffffff; display: block;">
<a href="{{ $link }}" style="font-size:16px; font-weight: bold; font-family:sans-serif; text-decoration: none; line-height:44px; width:100%; display:inline-block">
<span style="color: #ffffff;">
{{ trans("texts.{$field}") }}
</span>
</a>
</td>
</tr> </table>
<![endif]>
</div>