Move email/ resources to mail/, added invoice generated email to admin, updated email template

This commit is contained in:
Deon George 2024-08-03 10:06:25 +10:00
parent f8453ae391
commit 0469d64577
40 changed files with 439 additions and 213 deletions

View File

@ -3,7 +3,6 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Mail;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use App\Models\{Invoice,Site}; use App\Models\{Invoice,Site};
@ -15,7 +14,9 @@ class InvoiceEmail extends Command
* *
* @var string * @var string
*/ */
protected $signature = 'invoice:email {site} {id}'; protected $signature = 'invoice:email'
.' {--s|site : Site ID}'
.' {id?}';
/** /**
* The console command description. * The console command description.
@ -31,21 +32,23 @@ class InvoiceEmail extends Command
*/ */
public function handle() public function handle()
{ {
Config::set('site',Site::findOrFail($this->argument('site'))); Config::set(
'site',
$this->option('site')
? Site::findOrFail($this->option('site'))
: Site::where('url',config('app.url'))->sole()
);
$o = Invoice::findOrFail($this->argument('id')); $o = Invoice::findOrFail($this->argument('id'));
$result = Mail::to($o->account->user->email)->send(new \App\Mail\InvoiceEmail($o));
try { try {
$o->print_status = TRUE; $o->send();
//$o->reminders = $o->reminders('send');
$o->save(); $o->save();
} catch (\Exception $e) { } catch (\Exception $e) {
dd($e); dd($e);
} }
dump($result->getDebug()); return self::SUCCESS;
} }
} }

View File

@ -2,6 +2,7 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use Carbon\Carbon;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Config;
@ -14,7 +15,11 @@ class InvoiceGenerate extends Command
* *
* @var string * @var string
*/ */
protected $signature = 'invoice:generate {site} {account?} {--p|preview : Preview} {--l|list : List Items}'; protected $signature = 'invoice:generate'
.' {--l|list : List Items}'
.' {--p|preview : Preview}'
.' {--s|site : Site ID}'
.' {id?}';
/** /**
* The console command description. * The console command description.
@ -30,37 +35,50 @@ class InvoiceGenerate extends Command
*/ */
public function handle() public function handle()
{ {
Config::set('site',Site::findOrFail($this->argument('site'))); Config::set(
'site',
$this->option('site')
? Site::findOrFail($this->option('site'))
: Site::where('url',config('app.url'))->sole()
);
if ($this->argument('account')) if ($this->argument('id'))
$accounts = collect()->push(Account::find($this->argument('account'))); $accounts = collect()->push(Account::find($this->argument('id')));
else else
$accounts = Account::active()->get(); $accounts = Account::active()->get();
foreach ($accounts as $o) { foreach ($accounts as $o) {
$items = $o->invoice_next(Carbon::now());
if (! $items->count()) {
$this->warn(sprintf('No items for account (%s) [%d]',$o->name,$o->id));
continue;
}
$this->info(sprintf('Account: %s [%d]',$o->name,$o->lid));
$io = new Invoice; $io = new Invoice;
$io->account_id = $o->id; $io->account_id = $o->id;
foreach ($o->services(TRUE)->get() as $so) { foreach ($items as $oo)
foreach ($so->next_invoice_items(FALSE) as $ooo) $io->items_active->push($oo);
$io->items->push($ooo);
}
// If there are no items, no reason to do anything // If there are no items, no reason to do anything
if (! $io->items->count() OR $io->total < 0) if ($io->total < 0) {
$this->warn(sprintf(' - Invoice totals [%3.2f] - skipping',$io->total));
continue; continue;
}
$io->account_id = $o->id; $io->account_id = $o->id;
if ($this->option('list')) { if ($this->option('list')) {
$this->warn(sprintf('|%4s|%4s|%-50s|%8s|', $this->line(sprintf('|%4s|%4s|%-50s|%8s|',
'SID', 'SID',
'PID', 'PID',
'Name', 'Name',
'Amount', 'Amount',
)); ));
foreach ($io->items as $oo) { foreach ($io->items_active as $oo) {
$this->info(sprintf('|%4s|%4s|%-50s|%8.2f|', $this->info(sprintf('|%4s|%4s|%-50s|%8.2f|',
$oo->service_id, $oo->service_id,
$oo->product_id, $oo->product_id,
@ -70,8 +88,9 @@ class InvoiceGenerate extends Command
} }
} }
//dump($io);
if ($this->option('preview')) { if ($this->option('preview')) {
$this->info(sprintf('Invoice for Account [%d] - [%d] items totalling [%3.2f]',$o->id,$io->items->count(),$io->total)); $this->info(sprintf('=> Invoice for Account [%d] - [%d] items totalling [%3.2f]',$o->id,$io->items_active->count(),$io->total));
continue; continue;
} }
@ -81,5 +100,7 @@ class InvoiceGenerate extends Command
$io->pushNew(); $io->pushNew();
} }
return self::SUCCESS;
} }
} }

View File

@ -52,7 +52,7 @@ class CancelRequest extends Mailable
} }
return $this return $this
->markdown('email.admin.service.cancel') ->markdown('mail.admin.service.cancel')
->subject($subject) ->subject($subject)
->with(['site'=>$this->service->site]); ->with(['site'=>$this->service->site]);
} }

View File

@ -52,7 +52,7 @@ class ChangeRequest extends Mailable
} }
return $this return $this
->markdown('email.admin.service.change') ->markdown('mail.admin.service.change')
->subject($subject) ->subject($subject)
->with(['site'=>$this->service->site]); ->with(['site'=>$this->service->site]);
} }

View File

@ -2,21 +2,20 @@
namespace App\Mail; namespace App\Mail;
use App\Models\Site;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable; use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Config;
use App\Models\Invoice; use App\Models\Invoice;
class InvoiceEmail extends Mailable class InvoiceEmail extends Mailable implements ShouldQueue
{ {
use Queueable, SerializesModels; use Queueable, SerializesModels;
public $invoice; protected Invoice $io;
public $site;
/** /**
* Create a new message instance. * Create a new message instance.
@ -25,28 +24,33 @@ class InvoiceEmail extends Mailable
*/ */
public function __construct(Invoice $o) public function __construct(Invoice $o)
{ {
$this->invoice = $o; $this->io = $o;
$this->queue = 'user';
} }
/** /**
* Build the message. * Get the message envelope.
*
* @return $this
*/ */
public function build() public function envelope(): Envelope
{ {
Config::set('site',Site::findOrFail($this->invoice->site_id)); return new Envelope(
$this->site = config('site'); subject: sprintf('Invoice %d for services, due %s',
$this->io->lid,
$this->io->due_at->format('Y-m-d')),
);
}
return $this /**
->markdown('email.user.invoice',['site'=>config('site')]) * Get the message content definition.
->subject(sprintf( 'Invoice: %s - Total: $%s - Due: %s', */
$this->invoice->id, public function content(): Content
number_format($this->invoice->total,2), {
$this->invoice->due_at->format('Y-m-d'))) return new Content(
->with([ markdown: 'mail.invoice',
'user'=>$this->invoice->account->user, with: [
'site'=>$this->invoice->account->user->site, 'io'=>$this->io,
]); 'site'=>$this->io->site,
]
);
} }
} }

View File

@ -0,0 +1,57 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
use App\Models\Invoice;
class InvoiceGeneratedAdmin extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
protected Invoice $io;
/**
* Create a new message instance.
*
* @param Invoice $o
*/
public function __construct(Invoice $o)
{
$this->io = $o;
$this->queue = 'admin';
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: sprintf('Invoice %d generated for %s, due %s',
$this->io->lid,
$this->io->account->name,
$this->io->due_at->format('Y-m-d')),
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
markdown: 'mail.admin.invoice.generated',
with: [
'io'=>$this->io,
'site'=>$this->io->site,
]
);
}
}

View File

@ -52,7 +52,7 @@ class OrderRequest extends Mailable
} }
return $this return $this
->markdown('email.admin.order.approve') ->markdown('mail.admin.order.approve')
->subject($subject) ->subject($subject)
->with(['site'=>$this->service->site]); ->with(['site'=>$this->service->site]);
} }

View File

@ -51,7 +51,7 @@ class OrderRequestApprove extends Mailable
} }
return $this return $this
->markdown('email.admin.order.approve') ->markdown('mail.admin.order.approve')
->subject($subject) ->subject($subject)
->with(['site'=>$this->so->site]); ->with(['site'=>$this->so->site]);
} }

View File

@ -38,7 +38,7 @@ class OrderRequestReject extends Mailable
Config::set('site',$this->service->site); Config::set('site',$this->service->site);
return $this return $this
->markdown('email.admin.order.reject') ->markdown('mail.admin.order.reject')
->subject(sprintf('Your order: #%s was rejected',$this->service->id)) ->subject(sprintf('Your order: #%s was rejected',$this->service->id))
->with(['site'=>$this->service->site]); ->with(['site'=>$this->service->site]);
} }

View File

@ -39,7 +39,7 @@ class SocialLink extends Mailable
Config::set('site',$this->site); Config::set('site',$this->site);
return $this return $this
->markdown('email.system.social_link') ->markdown('mail.system.social_link')
->subject('Link your Account') ->subject('Link your Account')
->with([ ->with([
'site'=>$this->site, 'site'=>$this->site,

View File

@ -36,7 +36,7 @@ class TestEmail extends Mailable
Config::set('site',$this->user->site); Config::set('site',$this->user->site);
return $this return $this
->markdown('email.system.test_email') ->markdown('mail.system.test_email')
->subject('Just a test...') ->subject('Just a test...')
->with([ ->with([
'site'=>$this->user->site, 'site'=>$this->user->site,

View File

@ -39,7 +39,7 @@ class TrafficMismatch extends Mailable
Config::set('site',$x=Site::find(1)); // @todo To auto determine; Config::set('site',$x=Site::find(1)); // @todo To auto determine;
return $this return $this
->markdown('email.system.broadband_traffic_mismatch') ->markdown('mail.system.broadband_traffic_mismatch')
->subject('Traffic Mismatch for '.$this->date) ->subject('Traffic Mismatch for '.$this->date)
->with([ ->with([
'site'=>$x, 'site'=>$x,

View File

@ -253,13 +253,15 @@ class Account extends Model implements IDs
/* METHODS */ /* METHODS */
public function invoice_next(): Collection public function invoice_next(Carbon $date=NULL): Collection
{ {
// Collect all the invoice items for our active services $svs = $this
$nextdate = ($x=$this
->services_active ->services_active
->filter(fn($item)=>$item->isBilled() && $item->invoice_next) ->filter(fn($item)=>$item->isBilled() && $item->invoice_next)
->sortBy(fn($item)=>(string)$item->invoice_next)) ->sortBy(fn($item)=>(string)$item->invoice_next);
// Collect all the invoice items for our active services
$nextdate = $date ?: $svs
->first() ->first()
?->invoice_next ?->invoice_next
->clone(); ->clone();
@ -271,7 +273,7 @@ class Account extends Model implements IDs
->subDay() ->subDay()
->endOfday(); ->endOfday();
$items = $x $items = $svs
->filter(fn($item)=>$item->invoice_next->lessThan($nextitemsdate)) ->filter(fn($item)=>$item->invoice_next->lessThan($nextitemsdate))
->sortBy(fn($item)=>$item->invoice_next.$item->name) ->sortBy(fn($item)=>$item->invoice_next.$item->name)
->map(fn($item)=>$item->next_invoice_items($nextitemsdate)) ->map(fn($item)=>$item->next_invoice_items($nextitemsdate))

View File

@ -75,7 +75,7 @@ class Charge extends Model
return sprintf('%s %s', return sprintf('%s %s',
$this->description, $this->description,
$this->getAttribute('attributes') $this->getAttribute('attributes')
? join('|',unserialize($this->getAttribute('attributes'))) ? $this->getAttribute('attributes')->join('|')
: ''); : '');
} }

View File

@ -8,12 +8,14 @@ use Clarkeash\Doorman\Models\Invite;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Mail;
use Leenooks\Casts\LeenooksCarbon; use Leenooks\Casts\LeenooksCarbon;
use Leenooks\Traits\ScopeActive; use Leenooks\Traits\ScopeActive;
use App\Casts\CollectionOrNull; use App\Casts\CollectionOrNull;
use App\Interfaces\IDs; use App\Interfaces\IDs;
use App\Traits\PushNew; use App\Mail\{InvoiceEmail,InvoiceGeneratedAdmin};
use App\Traits\{PushNew,SiteID};
/** /**
* Class Invoice * Class Invoice
@ -36,7 +38,7 @@ use App\Traits\PushNew;
*/ */
class Invoice extends Model implements IDs class Invoice extends Model implements IDs
{ {
use PushNew,ScopeActive; use PushNew,ScopeActive,SiteID;
protected $casts = [ protected $casts = [
'created_at' => 'datetime:Y-m-d', 'created_at' => 'datetime:Y-m-d',
@ -95,8 +97,8 @@ class Invoice extends Model implements IDs
], ],
]; ];
// Array of items that can be updated with PushNew // Our related items that need to be updated when we call pushNew()
protected $pushable = ['items']; protected $pushable = ['items_active'];
protected $with = [ protected $with = [
'items_active:id,start_at,stop_at,quantity,price_base,discount_amt,item_type,product_id,service_id,invoice_id', 'items_active:id,start_at,stop_at,quantity,price_base,discount_amt,item_type,product_id,service_id,invoice_id',
@ -108,6 +110,21 @@ class Invoice extends Model implements IDs
/* STATIC METHODS */ /* STATIC METHODS */
public static function boot()
{
parent::boot();
static::created(function($model) {
// Send an email to an admin that the invoice was created
$uo = User::where('email',config('osb.admin'))->sole();
Mail::to($uo->email)
->send(new InvoiceGeneratedAdmin($model));
// @todo Queue an email to the user
});
}
/** /**
* This works out what multiplier to use to change billing periods * This works out what multiplier to use to change billing periods
* *
@ -565,6 +582,28 @@ class Invoice extends Model implements IDs
return parent::save($options); return parent::save($options);
} }
/**
* Record the invoice being sent
*
* @return int
*/
public function send(): int
{
$result = Mail::to($this->account->user->email)
->send(new InvoiceEmail($this));
$this->print_status = TRUE;
if ($this->reminders->has('sent'))
$this->reminders->put('sent',collect($this->reminders->get('sent')));
else
$this->reminders->put('sent',collect());
$this->reminders->get('sent')->push(Carbon::now());
return $result;
}
/** /**
* Group the invoice items by product ID, returning the number of products and total * Group the invoice items by product ID, returning the number of products and total
* *
@ -574,12 +613,20 @@ class Invoice extends Model implements IDs
{ {
$return = collect(); $return = collect();
foreach ($this->items_active->groupBy('product_id') as $o) { foreach ($this->items_active->groupBy('product_id') as $id => $o) {
$po = $o->first()->product; if (! $id) {
$po = new Product;
$po->translate = new ProductTranslate;
$po->translate->name_detail = 'Miscellanious';
} else {
$po = $o->first()->product;
}
$po->count = count($o->pluck('service_id')->unique()); $po->count = count($o->pluck('service_id')->unique());
$return->push([ $return->push([
'product' => $o->first()->product, 'product' => $po,
'services' => $o->pluck('service_id')->unique(), 'services' => $o->pluck('service_id')->unique(),
'sub_total' => $o->sum('sub_total'), 'sub_total' => $o->sum('sub_total'),
'tax_total' => $o->sum('tax'), 'tax_total' => $o->sum('tax'),
@ -589,4 +636,21 @@ class Invoice extends Model implements IDs
return $return->sortBy('product.name'); return $return->sortBy('product.name');
} }
public function summary_other(): Collection
{
$result = collect();
foreach ($this->items_active->whereNull('service_id') as $o) {
dd($o);
$result->push([
'description' => 'Account Items',
'sub_total' => $o->sub_total,
'tax_total' => $o->tax,
'total' => $o->total,
]);
}
return $result;
}
} }

View File

@ -52,6 +52,22 @@ class InvoiceItem extends Model
127 => 'Rounding', // * SERVICE_ID is NULL, MODULE_ID is NULL, MODULE_REF is NULL 127 => 'Rounding', // * SERVICE_ID is NULL, MODULE_ID is NULL, MODULE_REF is NULL
]; ];
/* STATIC */
public static function boot()
{
parent::boot();
static::created(function($model) {
// If this items were a charge, we'll update the charge to processed
if (($model->module_id === 30) && $model->module_ref) {
$o = Charge::findOrfail($model->module_ref);
$o->processed = TRUE;
$o->save();
}
});
}
/* RELATIONS */ /* RELATIONS */
public function invoice() public function invoice()

View File

@ -8,6 +8,7 @@
namespace App\Traits; namespace App\Traits;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Log;
trait PushNew trait PushNew
{ {
@ -22,7 +23,7 @@ trait PushNew
// us to recurse into all of these nested relations for the model instance. // us to recurse into all of these nested relations for the model instance.
foreach ($this->relations as $key => $models) { foreach ($this->relations as $key => $models) {
// If we are not pushable, jump to the next item. // If we are not pushable, jump to the next item.
if (! is_array($this->pushable) OR ! in_array($key,$this->pushable)) if ((! is_array($this->pushable)) || (! in_array($key,$this->pushable)))
continue; continue;
$models = $models instanceof Collection $models = $models instanceof Collection
@ -32,6 +33,8 @@ trait PushNew
$model->setAttribute($this->getForeignKey(),$this->{$this->getKeyName()}); $model->setAttribute($this->getForeignKey(),$this->{$this->getKeyName()});
if (! $model->pushNew()) { if (! $model->pushNew()) {
Log::alert('Failed to save model',['attrs'=>$model->getAttributes()]);
return false; return false;
} }
} }

View File

@ -4,5 +4,6 @@ return [
'language_id' => 1, 'language_id' => 1,
'invoice_text' => 'Thank you for using our Internet Services.', 'invoice_text' => 'Thank you for using our Internet Services.',
'invoice_days' => 30, // Days in Advance to invoice 'invoice_days' => 30, // Days in Advance to invoice
'invoice_review' => 3, // Days to review an invoice before it is emailed
'admin' => env('APP_ADMIN'), 'admin' => env('APP_ADMIN'),
]; ];

View File

@ -1,27 +0,0 @@
@component('mail::message',['site'=>$site,'heading'=>'Invoice: '.$invoice->id])
Hi {{ isset($user) ? $user->name_full.',' : '' }}
A new invoice has been generated on your account. A summary of that invoice is below.
@component('mail::table')
| # | ID | Name | Amount |
| -: | - |:-----| ------:|
@foreach ($invoice->summary_products() as $item)
| {{ $item['services']->count() }} | {{ $item['product']->lid }} | {{ $item['product']->name }} | ${{ number_format($item['total'],2) }} |
@endforeach
||| Sub Total | ${{ number_format($invoice->sub_total,2) }} |
||| Tax | ${{ number_format($invoice->tax_total,2) }} |
||| Total | ${{ number_format($invoice->total,2) }} |
||| Payments | ${{ number_format($invoice->paid,2) }} |
||| Still Due | ${{ number_format($invoice->due,2) }} |
@endcomponent
If you would like a PDF copy of that invoice, please click on the link below:
@component('mail::panel',['url'=>$invoice->download_link()])
Download PDF
@endcomponent
Thanks,<br>
{{ config('mail.from.name') }}
@endcomponent

View File

@ -0,0 +1,25 @@
@component('mail::message',['site'=>$site,'heading'=>'Invoice: #'.$io->id,'subheading'=>sprintf('Due: <strong>%s</strong>',$io->due_at->format('Y-m-d'))])
Hi {{ isset($user) ? $user->name_full.',' : '' }}
A new invoice has been generated for <strong>{{ $io->account->name }}</strong>. A summary of that invoice is below:
@component('mail::table')
| ID | # | Name | Amount |
| -: | -: |:-----| ------:|
@foreach ($io->summary_products() as $item)
| {{ $item['product']->lid }} | {{ $item['services']->count() }} | {{ $item['product']->name }} | ${{ number_format($item['total'],2) }} |
@endforeach
||| Sub Total | ${{ number_format($io->sub_total,2) }} |
||| Tax | ${{ number_format($io->tax_total,2) }} |
||| **Total** | **${{ number_format($io->total,2) }}** |
@endcomponent
This invoice will be automatically emailed in {{ config('osb.invoice_review') }} days time.
@component('mail::button',['url'=>url('u/invoice',$io->id)])
Review
@endcomponent
Thanks,<br>
{{ config('mail.from.name') }}
@endcomponent

View File

@ -1,8 +1,6 @@
@component('mail::message',['site'=>$site]) @component('mail::message',['site'=>$site])
# Your order was rejected. # Your order was rejected.
@component('mail::panel')
@component('mail::table') @component('mail::table')
| Service | Details | | Service | Details |
| :---------- | :---------------- | | :---------- | :---------------- |
@ -22,8 +20,6 @@
**REASON:** {{ $reason }} **REASON:** {{ $reason }}
@endcomponent
Thanks,<br> Thanks,<br>
{{ config('app.name') }} {{ config('app.name') }}
@endcomponent @endcomponent

View File

@ -0,0 +1,29 @@
@component('mail::message',['site'=>$site,'heading'=>'Invoice: #'.$io->lid,'subheading'=>sprintf('Due: <strong>%s</strong>',$io->due_at->format('Y-m-d'))])
Hi {{ isset($user) ? $user->name_full.',' : '' }}
A new invoice has been generated on your account. A summary of that invoice is below:
@component('mail::table')
| ID | # | Name | Amount |
| -: | -: |:-----| ------:|
@foreach ($io->summary_products() as $item)
| {{ $item['product']->lid }} | {{ $item['services']->count() }} | {{ $item['product']->name }} | ${{ number_format($item['total'],2) }} |
@endforeach
||| Sub Total | ${{ number_format($io->sub_total,2) }} |
||| Tax | ${{ number_format($io->tax_total,2) }} |
||| **Total** | **${{ number_format($io->total,2) }}** |
@if($io->paid)
||| Payments | ${{ number_format($io->paid,2) }} |
||| Still Due | ${{ number_format($io->due,2) }} |
@endif
@endcomponent
If you would like a PDF copy of that invoice, please click on the link below:
@component('mail::button',['url'=>$io->download_link()])
Download
@endcomponent
Thanks,<br>
{{ config('mail.from.name') }}
@endcomponent

View File

@ -5,8 +5,8 @@ A request was made to link your account to a social login.
If you didnt make this request, you can ignore this, and the request will be ignored. If you didnt make this request, you can ignore this, and the request will be ignored.
If you did make the request, then please enter the code displayed below. If you did make the request, then please enter the code displayed below.
@component('mail::panel') @component('mail::button')
{{ $token }} {{ $token }}
@endcomponent @endcomponent
Once you've keyed in this code, you'll be able to login to your account using your social login instead of a username and a password. Once you've keyed in this code, you'll be able to login to your account using your social login instead of a username and a password.
@ -15,7 +15,7 @@ Thanks,
{{ config('mail.from.name') }} {{ config('mail.from.name') }}
@component('mail::subcopy') @component('mail::subcontent')
If you didnt make this request, you can safely ignore this email - no change was made to your account, nor was it accessed by an unauthorised person. If you didnt make this request, you can safely ignore this email - no change was made to your account, nor was it accessed by an unauthorised person.
@endcomponent @endcomponent
@endcomponent @endcomponent

View File

@ -6,12 +6,12 @@ You are receiving this email because we received a password reset request for yo
If you did not request a password reset, no further action is required. If you did not request a password reset, no further action is required.
To reset your password, please follow this link, or click on the URL below: To reset your password, please follow this link, or click on the URL below:
@component('mail::panel',['url'=>$reset_link]) @component('mail::button',['url'=>$reset_link])
Reset Password Reset Password
@endcomponent @endcomponent
@component('mail::subcopy') @component('mail::subcontent')
Reset password: {{ $reset_link }} Reset password: {{ $reset_link }}
@endcomponent @endcomponent
Thanks,<br> Thanks,<br>

View File

@ -128,6 +128,19 @@
@endforeach @endforeach
@endforeach @endforeach
@endforeach @endforeach
@if($o->summary_other()->count())
<tr>
<td colspan="7">{{ $item['description'] }}</td>
</tr>
@foreach($o->summary_other() as $item)
<tr>
<td colspan="2">&nbsp;</td>
<td>{{ $item['description'] }}</td>
</tr>
@endforeach
@endif
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -0,0 +1,9 @@
<div style="margin: auto; text-align: center; padding-top: 20px;padding-bottom: 20px;">
<div class="button">
@isset($url)
<a href="{{ $url }}">{{ $slot }}</a>
@else
{{ $slot }}
@endisset
</div>
</div>

View File

@ -1,3 +1 @@
<div class="footer"> {{ Illuminate\Mail\Markdown::parse($slot) }}
{{ Illuminate\Mail\Markdown::parse($slot) }}
</div>

View File

@ -1,6 +1,5 @@
<div class="header"> <img class="right" src="{{ url($site->email_logo) }}"><br>
<div class="fixedw"> <div class="heading">{{ $slot }}</div>
<img src="{{ url($site->email_logo) }}"><br> @if($subheading)
<div class="subject">{{ $slot }}</div> <div class="subheading">{!! $subheading !!}</div>
</div> @endif
</div>

View File

@ -1,25 +1,32 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="color-scheme" content="light only"> <meta name="color-scheme" content="light only">
<meta name="supported-color-schemes" content="light only"> <meta name="supported-color-schemes" content="light only">
<link href='http://fonts.googleapis.com/css?family=Bree+Serif' rel='stylesheet' type='text/css'> {{--
<link href="http://fonts.googleapis.com/css?family=Roboto:400,300,100,500,700,900,400italic,300italic" rel="stylesheet" type="text/css"> <link href='http://fonts.googleapis.com/css?family=Bree+Serif' rel='stylesheet' type='text/css'>
--}}
<link href="http://fonts.googleapis.com/css?family=Roboto:400,300,100,500,700,900,400italic,300italic" rel="stylesheet" type="text/css">
</head> </head>
<body> <body>
{{ $header ?? '' }} <section class="header">
<div class="fixedw main-header">
{{ $header ?? '' }}
</div>
</section>
<section class="content">
<div class="fixedw main-body">
{{ Illuminate\Mail\Markdown::parse($slot) }}
</div>
<section class="content"> {{ $subcontent ?? '' }}
<div class="fixedw main-body"> </section>
{{ Illuminate\Mail\Markdown::parse($slot) }} <section class="footer">
</div> <div class="fixedw main-footer">
{{ $footer ?? '' }}
{{ $subcopy ?? '' }} </div>
</section> </section>
{{ $footer ?? '' }}
</body> </body>
</html> </html>

View File

@ -1,7 +1,7 @@
@component('mail::layout') @component('mail::layout')
{{-- Header --}} {{-- Header --}}
@slot('header') @slot('header')
@component('mail::header',['site'=>$site]) @component('mail::header',['site'=>$site,'subheading'=>$subheading ?? NULL])
{{ $heading }} {{ $heading }}
@endcomponent @endcomponent
@endslot @endslot
@ -9,11 +9,11 @@
{{-- Body --}} {{-- Body --}}
{{ $slot }} {{ $slot }}
{{-- Subcopy --}} {{-- Sub Content --}}
@isset($subcopy) @isset($subcontent)
@slot('subcopy') @slot('subcontent')
@component('mail::subcopy') @component('mail::subcontent')
{{ $subcopy }} {{ $subcontent }}
@endcomponent @endcomponent
@endslot @endslot
@endisset @endisset
@ -21,11 +21,9 @@
{{-- Footer --}} {{-- Footer --}}
@slot('footer') @slot('footer')
@component('mail::footer') @component('mail::footer')
<div class="fixedw" style="text-align: right; font-size: 0.8em;">
{{ config('mail.from.name') }}<br> {{ config('mail.from.name') }}<br>
{!! $site->address->join('<br>') !!}<br> {!! $site->address->join('<br>') !!}<br>
{{ $site->site_email }} {{ $site->site_email }}
</div>
@endcomponent @endcomponent
@endslot @endslot
@endcomponent @endcomponent

View File

@ -1,9 +0,0 @@
<div style="margin: auto; text-align: center; padding-bottom: 20px;">
<div class="panel">
@isset($url)
<a href="{{ $url }}">{{ $slot }}</a>
@else
{{ $slot }}
@endisset
</div>
</div>

View File

@ -1,3 +1 @@
<div class="light-box">
{{ Illuminate\Mail\Markdown::parse($slot) }} {{ Illuminate\Mail\Markdown::parse($slot) }}
</div>

View File

@ -1,88 +1,104 @@
body{ body{
margin: 0 auto; margin:0 auto;
font-family: 'Bree Serif'; font-family:'Roboto', serif;
background: #f4f4f4; color:#121212;
color: #6c7584; font-size:1.0em;
font-size: 1.2em; padding-top:20px;
} }
.header{ .header{
background: #232323; margin-bottom:0;
border-bottom: 5px solid #454d59;
padding: 20px 0px 10px 0px;
margin-bottom: 30px;
color: #f4f4f4;
font-weight: 300;
} }
.footer{ .footer{
background: #232323;
border-top: 5px solid #454d59;
padding: 10px 0px 20px 0px;
margin-top: 30px;
color: #f4f4f4;
font-weight: 100;
} }
.subject{ .main-header{
font-weight: 300; background:#fafafa;
font-family: 'Bree Serif',serif; border-top-left-radius:10px;
font-size: 1.5em; border-top-right-radius:10px;
/* text-align: right; */ color:#121212;
font-weight:400;
padding:10px 20px;
border-top:1px solid #dbdbdb;
border-right:1px solid #dbdbdb;
border-left:1px solid #dbdbdb;
} }
.panel{ .main-header img{
background:#454d59; width:250px;
border-radius: 10px;
margin-top: 20px;
padding: 20px;
font-weight: 300;
color: #f4f4f4;
font-size: 1.4em;
display: inline-block
} }
.light-box{ .main-header .heading{
background: #f9f9f9; font-weight:bold;
border-radius: 10px; font-size:1.4em;
padding: 10px; padding:5px 0;
font-weight: 300; }
margin-top: 10px; .main-header .subheading{
font-size: 0.8em; font-size:0.8em;
margin-bottom: 10px; padding:5px 0;
} }
.main-body{ .main-body{
background: #ffffff; background:#ffffff;
border-radius: 10px;
color:#6c7584;
font-weight: 400;
padding:10px 20px; padding:10px 20px;
border-top:1px solid #dbdbdb; border-top:1px solid #dbdbdb;
border-left:1px solid #dbdbdb; border-left:1px solid #dbdbdb;
border-right:1px solid #dbdbdb; border-right:1px solid #dbdbdb;
border-bottom:3px solid #dbdbdb; border-bottom:1px solid #dbdbdb;
}
.main-body table{
width: 100%;
background:#fdfdfd;
border-radius:10px;
padding:10px;
font-weight:300;
margin-top:10px;
font-size:0.8em;
margin-bottom:10px;
border: 1px dashed #dbdbdb
} }
.main-body table thead td{ .main-body table thead td{
font-weight: 300; font-weight:300;
border-bottom: 1px solid #dbdbdb; border-bottom:1px solid #dbdbdb;
color: #ccc
} }
.main-body table td.title{ .main-body table td.title{
font-size: 1.1em; font-size:1.1em;
line-height: 20px; line-height:20px;
color:#6c7584
} }
.main-body table td.title small{ .main-body table td.title small{
font-weight: 300; font-weight:300;
font-size: 0.9em; font-size:0.9em;
color: #6c7584 color:#6c7584
} }
.main-body .note{ .main-body .note{
font-size:0.8em;
font-weight:300;
font-style:normal;
}
.main-footer{
background:#2f2f2f;
border-bottom-left-radius:10px;
border-bottom-right-radius:10px;
color:#fefefe;
padding:10px 20px;
margin: 0 0 0 auto;
border-bottom:1px solid #dbdbdb;
border-right:1px solid #dbdbdb;
border-left:1px solid #dbdbdb;
font-size: 0.8em; font-size: 0.8em;
font-weight: 300; text-align: right;
font-style: normal;
} }
.panel a{ .button{
text-decoration: underline; background:#2f2f2f;
color: #f4f4f4; border-radius:5px;
padding:10px;
color:#fafafa;
font-size:1em;
display:inline-block
} }
.panel a:hover{ .button a{
text-decoration: none; text-decoration:none;
color: #ffffff; color:#fafafa;
}
.button a:hover{
text-decoration:none;
color:#ffffff;
} }
/* -- TO VALIDATE -- */ /* -- TO VALIDATE -- */
@ -114,15 +130,17 @@ h3{
color: #333; color: #333;
font-size:18px; font-size:18px;
} }
.links table td span, .links table td a{font-weight: 400} .links table td span, .links table td a{
.border-l{border-left:1px solid #ccc} font-weight: 400
}
.apikey{font-size: 18px; color:#333} .apikey{font-size: 18px; color:#333}
.apikey p{border-bottom: 1px solid #dbdbdb; padding: 10px 0 10px 0;margin: 0 0;} .apikey p{border-bottom: 1px solid #dbdbdb; padding: 10px 0 10px 0;margin: 0 0;}
.apikey p.last{border-bottom: none} .apikey p.last{border-bottom: none}
.apikey small{font-size: 80%; font-weight: 300} .apikey small{font-size: 80%; font-weight: 300}
.twitter{padding: 20px; font-weight: 300;font-size:16px;}
.fixedw{width: 80%; margin: 0 auto;} .fixedw{width: 80%; margin: 0 auto;}
.right{float:right} .right{float:right}
.left{float:left} .left{float:left}
.clear{clear: both;} .clear{clear: both;}
table thead td {font-size: 16px;}
pre {white-space:pre-wrap;}

View File

@ -0,0 +1 @@
{{ $slot }}