Move email/ resources to mail/, added invoice generated email to admin, updated email template
This commit is contained in:
parent
f8453ae391
commit
0469d64577
@ -3,7 +3,6 @@
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
use App\Models\{Invoice,Site};
|
||||
@ -15,7 +14,9 @@ class InvoiceEmail extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'invoice:email {site} {id}';
|
||||
protected $signature = 'invoice:email'
|
||||
.' {--s|site : Site ID}'
|
||||
.' {id?}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
@ -31,21 +32,23 @@ class InvoiceEmail extends Command
|
||||
*/
|
||||
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'));
|
||||
|
||||
$result = Mail::to($o->account->user->email)->send(new \App\Mail\InvoiceEmail($o));
|
||||
|
||||
try {
|
||||
$o->print_status = TRUE;
|
||||
//$o->reminders = $o->reminders('send');
|
||||
$o->send();
|
||||
$o->save();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
dd($e);
|
||||
}
|
||||
|
||||
dump($result->getDebug());
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
|
||||
@ -14,7 +15,11 @@ class InvoiceGenerate extends Command
|
||||
*
|
||||
* @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.
|
||||
@ -30,37 +35,50 @@ class InvoiceGenerate extends Command
|
||||
*/
|
||||
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'))
|
||||
$accounts = collect()->push(Account::find($this->argument('account')));
|
||||
if ($this->argument('id'))
|
||||
$accounts = collect()->push(Account::find($this->argument('id')));
|
||||
else
|
||||
$accounts = Account::active()->get();
|
||||
|
||||
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->account_id = $o->id;
|
||||
|
||||
foreach ($o->services(TRUE)->get() as $so) {
|
||||
foreach ($so->next_invoice_items(FALSE) as $ooo)
|
||||
$io->items->push($ooo);
|
||||
}
|
||||
foreach ($items as $oo)
|
||||
$io->items_active->push($oo);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
$io->account_id = $o->id;
|
||||
|
||||
if ($this->option('list')) {
|
||||
$this->warn(sprintf('|%4s|%4s|%-50s|%8s|',
|
||||
$this->line(sprintf('|%4s|%4s|%-50s|%8s|',
|
||||
'SID',
|
||||
'PID',
|
||||
'Name',
|
||||
'Amount',
|
||||
));
|
||||
|
||||
foreach ($io->items as $oo) {
|
||||
foreach ($io->items_active as $oo) {
|
||||
$this->info(sprintf('|%4s|%4s|%-50s|%8.2f|',
|
||||
$oo->service_id,
|
||||
$oo->product_id,
|
||||
@ -70,8 +88,9 @@ class InvoiceGenerate extends Command
|
||||
}
|
||||
}
|
||||
|
||||
//dump($io);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -81,5 +100,7 @@ class InvoiceGenerate extends Command
|
||||
|
||||
$io->pushNew();
|
||||
}
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
@ -52,7 +52,7 @@ class CancelRequest extends Mailable
|
||||
}
|
||||
|
||||
return $this
|
||||
->markdown('email.admin.service.cancel')
|
||||
->markdown('mail.admin.service.cancel')
|
||||
->subject($subject)
|
||||
->with(['site'=>$this->service->site]);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ class ChangeRequest extends Mailable
|
||||
}
|
||||
|
||||
return $this
|
||||
->markdown('email.admin.service.change')
|
||||
->markdown('mail.admin.service.change')
|
||||
->subject($subject)
|
||||
->with(['site'=>$this->service->site]);
|
||||
}
|
||||
|
@ -2,21 +2,20 @@
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Models\Site;
|
||||
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 Illuminate\Support\Facades\Config;
|
||||
|
||||
use App\Models\Invoice;
|
||||
|
||||
class InvoiceEmail extends Mailable
|
||||
class InvoiceEmail extends Mailable implements ShouldQueue
|
||||
{
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public $invoice;
|
||||
public $site;
|
||||
protected Invoice $io;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
@ -25,28 +24,33 @@ class InvoiceEmail extends Mailable
|
||||
*/
|
||||
public function __construct(Invoice $o)
|
||||
{
|
||||
$this->invoice = $o;
|
||||
$this->io = $o;
|
||||
$this->queue = 'user';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
* Get the message envelope.
|
||||
*/
|
||||
public function build()
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
Config::set('site',Site::findOrFail($this->invoice->site_id));
|
||||
$this->site = config('site');
|
||||
return new Envelope(
|
||||
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')])
|
||||
->subject(sprintf( 'Invoice: %s - Total: $%s - Due: %s',
|
||||
$this->invoice->id,
|
||||
number_format($this->invoice->total,2),
|
||||
$this->invoice->due_at->format('Y-m-d')))
|
||||
->with([
|
||||
'user'=>$this->invoice->account->user,
|
||||
'site'=>$this->invoice->account->user->site,
|
||||
]);
|
||||
/**
|
||||
* Get the message content definition.
|
||||
*/
|
||||
public function content(): Content
|
||||
{
|
||||
return new Content(
|
||||
markdown: 'mail.invoice',
|
||||
with: [
|
||||
'io'=>$this->io,
|
||||
'site'=>$this->io->site,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
57
app/Mail/InvoiceGeneratedAdmin.php
Normal file
57
app/Mail/InvoiceGeneratedAdmin.php
Normal 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,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
@ -52,7 +52,7 @@ class OrderRequest extends Mailable
|
||||
}
|
||||
|
||||
return $this
|
||||
->markdown('email.admin.order.approve')
|
||||
->markdown('mail.admin.order.approve')
|
||||
->subject($subject)
|
||||
->with(['site'=>$this->service->site]);
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class OrderRequestApprove extends Mailable
|
||||
}
|
||||
|
||||
return $this
|
||||
->markdown('email.admin.order.approve')
|
||||
->markdown('mail.admin.order.approve')
|
||||
->subject($subject)
|
||||
->with(['site'=>$this->so->site]);
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ class OrderRequestReject extends Mailable
|
||||
Config::set('site',$this->service->site);
|
||||
|
||||
return $this
|
||||
->markdown('email.admin.order.reject')
|
||||
->markdown('mail.admin.order.reject')
|
||||
->subject(sprintf('Your order: #%s was rejected',$this->service->id))
|
||||
->with(['site'=>$this->service->site]);
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ class SocialLink extends Mailable
|
||||
Config::set('site',$this->site);
|
||||
|
||||
return $this
|
||||
->markdown('email.system.social_link')
|
||||
->markdown('mail.system.social_link')
|
||||
->subject('Link your Account')
|
||||
->with([
|
||||
'site'=>$this->site,
|
||||
|
@ -36,7 +36,7 @@ class TestEmail extends Mailable
|
||||
Config::set('site',$this->user->site);
|
||||
|
||||
return $this
|
||||
->markdown('email.system.test_email')
|
||||
->markdown('mail.system.test_email')
|
||||
->subject('Just a test...')
|
||||
->with([
|
||||
'site'=>$this->user->site,
|
||||
|
@ -39,7 +39,7 @@ class TrafficMismatch extends Mailable
|
||||
Config::set('site',$x=Site::find(1)); // @todo To auto determine;
|
||||
|
||||
return $this
|
||||
->markdown('email.system.broadband_traffic_mismatch')
|
||||
->markdown('mail.system.broadband_traffic_mismatch')
|
||||
->subject('Traffic Mismatch for '.$this->date)
|
||||
->with([
|
||||
'site'=>$x,
|
||||
|
@ -253,13 +253,15 @@ class Account extends Model implements IDs
|
||||
|
||||
/* METHODS */
|
||||
|
||||
public function invoice_next(): Collection
|
||||
public function invoice_next(Carbon $date=NULL): Collection
|
||||
{
|
||||
// Collect all the invoice items for our active services
|
||||
$nextdate = ($x=$this
|
||||
$svs = $this
|
||||
->services_active
|
||||
->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()
|
||||
?->invoice_next
|
||||
->clone();
|
||||
@ -271,7 +273,7 @@ class Account extends Model implements IDs
|
||||
->subDay()
|
||||
->endOfday();
|
||||
|
||||
$items = $x
|
||||
$items = $svs
|
||||
->filter(fn($item)=>$item->invoice_next->lessThan($nextitemsdate))
|
||||
->sortBy(fn($item)=>$item->invoice_next.$item->name)
|
||||
->map(fn($item)=>$item->next_invoice_items($nextitemsdate))
|
||||
|
@ -75,7 +75,7 @@ class Charge extends Model
|
||||
return sprintf('%s %s',
|
||||
$this->description,
|
||||
$this->getAttribute('attributes')
|
||||
? join('|',unserialize($this->getAttribute('attributes')))
|
||||
? $this->getAttribute('attributes')->join('|')
|
||||
: '');
|
||||
}
|
||||
|
||||
|
@ -8,12 +8,14 @@ use Clarkeash\Doorman\Models\Invite;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Leenooks\Casts\LeenooksCarbon;
|
||||
use Leenooks\Traits\ScopeActive;
|
||||
|
||||
use App\Casts\CollectionOrNull;
|
||||
use App\Interfaces\IDs;
|
||||
use App\Traits\PushNew;
|
||||
use App\Mail\{InvoiceEmail,InvoiceGeneratedAdmin};
|
||||
use App\Traits\{PushNew,SiteID};
|
||||
|
||||
/**
|
||||
* Class Invoice
|
||||
@ -36,7 +38,7 @@ use App\Traits\PushNew;
|
||||
*/
|
||||
class Invoice extends Model implements IDs
|
||||
{
|
||||
use PushNew,ScopeActive;
|
||||
use PushNew,ScopeActive,SiteID;
|
||||
|
||||
protected $casts = [
|
||||
'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
|
||||
protected $pushable = ['items'];
|
||||
// Our related items that need to be updated when we call pushNew()
|
||||
protected $pushable = ['items_active'];
|
||||
|
||||
protected $with = [
|
||||
'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 */
|
||||
|
||||
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
|
||||
*
|
||||
@ -565,6 +582,28 @@ class Invoice extends Model implements IDs
|
||||
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
|
||||
*
|
||||
@ -574,12 +613,20 @@ class Invoice extends Model implements IDs
|
||||
{
|
||||
$return = collect();
|
||||
|
||||
foreach ($this->items_active->groupBy('product_id') as $o) {
|
||||
foreach ($this->items_active->groupBy('product_id') as $id => $o) {
|
||||
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());
|
||||
|
||||
$return->push([
|
||||
'product' => $o->first()->product,
|
||||
'product' => $po,
|
||||
'services' => $o->pluck('service_id')->unique(),
|
||||
'sub_total' => $o->sum('sub_total'),
|
||||
'tax_total' => $o->sum('tax'),
|
||||
@ -589,4 +636,21 @@ class Invoice extends Model implements IDs
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -52,6 +52,22 @@ class InvoiceItem extends Model
|
||||
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 */
|
||||
|
||||
public function invoice()
|
||||
|
@ -8,6 +8,7 @@
|
||||
namespace App\Traits;
|
||||
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
trait PushNew
|
||||
{
|
||||
@ -22,7 +23,7 @@ trait PushNew
|
||||
// us to recurse into all of these nested relations for the model instance.
|
||||
foreach ($this->relations as $key => $models) {
|
||||
// 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;
|
||||
|
||||
$models = $models instanceof Collection
|
||||
@ -32,6 +33,8 @@ trait PushNew
|
||||
$model->setAttribute($this->getForeignKey(),$this->{$this->getKeyName()});
|
||||
|
||||
if (! $model->pushNew()) {
|
||||
Log::alert('Failed to save model',['attrs'=>$model->getAttributes()]);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -4,5 +4,6 @@ return [
|
||||
'language_id' => 1,
|
||||
'invoice_text' => 'Thank you for using our Internet Services.',
|
||||
'invoice_days' => 30, // Days in Advance to invoice
|
||||
'invoice_review' => 3, // Days to review an invoice before it is emailed
|
||||
'admin' => env('APP_ADMIN'),
|
||||
];
|
@ -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
|
25
resources/views/mail/admin/invoice/generated.blade.php
Normal file
25
resources/views/mail/admin/invoice/generated.blade.php
Normal 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
|
@ -1,8 +1,6 @@
|
||||
@component('mail::message',['site'=>$site])
|
||||
# Your order was rejected.
|
||||
|
||||
@component('mail::panel')
|
||||
|
||||
@component('mail::table')
|
||||
| Service | Details |
|
||||
| :---------- | :---------------- |
|
||||
@ -22,8 +20,6 @@
|
||||
|
||||
**REASON:** {{ $reason }}
|
||||
|
||||
@endcomponent
|
||||
|
||||
Thanks,<br>
|
||||
{{ config('app.name') }}
|
||||
@endcomponent
|
29
resources/views/mail/invoice.blade.php
Normal file
29
resources/views/mail/invoice.blade.php
Normal 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
|
@ -5,7 +5,7 @@ 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 did make the request, then please enter the code displayed below.
|
||||
|
||||
@component('mail::panel')
|
||||
@component('mail::button')
|
||||
{{ $token }}
|
||||
@endcomponent
|
||||
|
||||
@ -15,7 +15,7 @@ Thanks,
|
||||
|
||||
{{ 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.
|
||||
@endcomponent
|
||||
@endcomponent
|
@ -6,11 +6,11 @@ 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.
|
||||
|
||||
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
|
||||
@endcomponent
|
||||
|
||||
@component('mail::subcopy')
|
||||
@component('mail::subcontent')
|
||||
Reset password: {{ $reset_link }}
|
||||
@endcomponent
|
||||
|
@ -128,6 +128,19 @@
|
||||
@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"> </td>
|
||||
|
||||
<td>{{ $item['description'] }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
9
resources/views/vendor/mail/html/button.blade.php
vendored
Normal file
9
resources/views/vendor/mail/html/button.blade.php
vendored
Normal 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>
|
@ -1,3 +1 @@
|
||||
<div class="footer">
|
||||
{{ Illuminate\Mail\Markdown::parse($slot) }}
|
||||
</div>
|
@ -1,6 +1,5 @@
|
||||
<div class="header">
|
||||
<div class="fixedw">
|
||||
<img src="{{ url($site->email_logo) }}"><br>
|
||||
<div class="subject">{{ $slot }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<img class="right" src="{{ url($site->email_logo) }}"><br>
|
||||
<div class="heading">{{ $slot }}</div>
|
||||
@if($subheading)
|
||||
<div class="subheading">{!! $subheading !!}</div>
|
||||
@endif
|
@ -5,21 +5,28 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="color-scheme" 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">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<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>
|
||||
|
||||
{{ $subcopy ?? '' }}
|
||||
{{ $subcontent ?? '' }}
|
||||
</section>
|
||||
|
||||
<section class="footer">
|
||||
<div class="fixedw main-footer">
|
||||
{{ $footer ?? '' }}
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
@ -1,7 +1,7 @@
|
||||
@component('mail::layout')
|
||||
{{-- Header --}}
|
||||
@slot('header')
|
||||
@component('mail::header',['site'=>$site])
|
||||
@component('mail::header',['site'=>$site,'subheading'=>$subheading ?? NULL])
|
||||
{{ $heading }}
|
||||
@endcomponent
|
||||
@endslot
|
||||
@ -9,11 +9,11 @@
|
||||
{{-- Body --}}
|
||||
{{ $slot }}
|
||||
|
||||
{{-- Subcopy --}}
|
||||
@isset($subcopy)
|
||||
@slot('subcopy')
|
||||
@component('mail::subcopy')
|
||||
{{ $subcopy }}
|
||||
{{-- Sub Content --}}
|
||||
@isset($subcontent)
|
||||
@slot('subcontent')
|
||||
@component('mail::subcontent')
|
||||
{{ $subcontent }}
|
||||
@endcomponent
|
||||
@endslot
|
||||
@endisset
|
||||
@ -21,11 +21,9 @@
|
||||
{{-- Footer --}}
|
||||
@slot('footer')
|
||||
@component('mail::footer')
|
||||
<div class="fixedw" style="text-align: right; font-size: 0.8em;">
|
||||
{{ config('mail.from.name') }}<br>
|
||||
{!! $site->address->join('<br>') !!}<br>
|
||||
{{ $site->site_email }}
|
||||
</div>
|
||||
@endcomponent
|
||||
@endslot
|
||||
@endcomponent
|
@ -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>
|
@ -1,3 +1 @@
|
||||
<div class="light-box">
|
||||
{{ Illuminate\Mail\Markdown::parse($slot) }}
|
||||
</div>
|
120
resources/views/vendor/mail/html/themes/default.css
vendored
120
resources/views/vendor/mail/html/themes/default.css
vendored
@ -1,70 +1,65 @@
|
||||
body{
|
||||
margin:0 auto;
|
||||
font-family: 'Bree Serif';
|
||||
background: #f4f4f4;
|
||||
color: #6c7584;
|
||||
font-size: 1.2em;
|
||||
font-family:'Roboto', serif;
|
||||
color:#121212;
|
||||
font-size:1.0em;
|
||||
padding-top:20px;
|
||||
}
|
||||
.header{
|
||||
background: #232323;
|
||||
border-bottom: 5px solid #454d59;
|
||||
padding: 20px 0px 10px 0px;
|
||||
margin-bottom: 30px;
|
||||
color: #f4f4f4;
|
||||
font-weight: 300;
|
||||
margin-bottom:0;
|
||||
}
|
||||
.footer{
|
||||
background: #232323;
|
||||
border-top: 5px solid #454d59;
|
||||
padding: 10px 0px 20px 0px;
|
||||
margin-top: 30px;
|
||||
color: #f4f4f4;
|
||||
font-weight: 100;
|
||||
}
|
||||
.subject{
|
||||
font-weight: 300;
|
||||
font-family: 'Bree Serif',serif;
|
||||
font-size: 1.5em;
|
||||
/* text-align: right; */
|
||||
.main-header{
|
||||
background:#fafafa;
|
||||
border-top-left-radius:10px;
|
||||
border-top-right-radius:10px;
|
||||
color:#121212;
|
||||
font-weight:400;
|
||||
padding:10px 20px;
|
||||
border-top:1px solid #dbdbdb;
|
||||
border-right:1px solid #dbdbdb;
|
||||
border-left:1px solid #dbdbdb;
|
||||
}
|
||||
.panel{
|
||||
background:#454d59;
|
||||
border-radius: 10px;
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
font-weight: 300;
|
||||
color: #f4f4f4;
|
||||
.main-header img{
|
||||
width:250px;
|
||||
}
|
||||
.main-header .heading{
|
||||
font-weight:bold;
|
||||
font-size:1.4em;
|
||||
display: inline-block
|
||||
padding:5px 0;
|
||||
}
|
||||
.light-box{
|
||||
background: #f9f9f9;
|
||||
.main-header .subheading{
|
||||
font-size:0.8em;
|
||||
padding:5px 0;
|
||||
}
|
||||
.main-body{
|
||||
background:#ffffff;
|
||||
padding:10px 20px;
|
||||
border-top:1px solid #dbdbdb;
|
||||
border-left:1px solid #dbdbdb;
|
||||
border-right:1px 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;
|
||||
}
|
||||
.main-body{
|
||||
background: #ffffff;
|
||||
border-radius: 10px;
|
||||
color:#6c7584;
|
||||
font-weight: 400;
|
||||
padding:10px 20px;
|
||||
border-top:1px solid #dbdbdb;
|
||||
border-left:1px solid #dbdbdb;
|
||||
border-right:1px solid #dbdbdb;
|
||||
border-bottom:3px solid #dbdbdb;
|
||||
border: 1px dashed #dbdbdb
|
||||
}
|
||||
.main-body table thead td{
|
||||
font-weight:300;
|
||||
border-bottom:1px solid #dbdbdb;
|
||||
color: #ccc
|
||||
}
|
||||
.main-body table td.title{
|
||||
font-size:1.1em;
|
||||
line-height:20px;
|
||||
color:#6c7584
|
||||
}
|
||||
.main-body table td.title small{
|
||||
font-weight:300;
|
||||
@ -76,11 +71,32 @@ body{
|
||||
font-weight:300;
|
||||
font-style:normal;
|
||||
}
|
||||
.panel a{
|
||||
text-decoration: underline;
|
||||
color: #f4f4f4;
|
||||
.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;
|
||||
text-align: right;
|
||||
}
|
||||
.panel a:hover{
|
||||
.button{
|
||||
background:#2f2f2f;
|
||||
border-radius:5px;
|
||||
padding:10px;
|
||||
color:#fafafa;
|
||||
font-size:1em;
|
||||
display:inline-block
|
||||
}
|
||||
.button a{
|
||||
text-decoration:none;
|
||||
color:#fafafa;
|
||||
}
|
||||
.button a:hover{
|
||||
text-decoration:none;
|
||||
color:#ffffff;
|
||||
}
|
||||
@ -114,15 +130,17 @@ h3{
|
||||
color: #333;
|
||||
font-size:18px;
|
||||
}
|
||||
.links table td span, .links table td a{font-weight: 400}
|
||||
.border-l{border-left:1px solid #ccc}
|
||||
.links table td span, .links table td a{
|
||||
font-weight: 400
|
||||
}
|
||||
|
||||
.apikey{font-size: 18px; color:#333}
|
||||
.apikey p{border-bottom: 1px solid #dbdbdb; padding: 10px 0 10px 0;margin: 0 0;}
|
||||
.apikey p.last{border-bottom: none}
|
||||
.apikey small{font-size: 80%; font-weight: 300}
|
||||
.twitter{padding: 20px; font-weight: 300;font-size:16px;}
|
||||
.fixedw{width: 80%; margin: 0 auto;}
|
||||
.right{float:right}
|
||||
.left{float:left}
|
||||
.clear{clear: both;}
|
||||
table thead td {font-size: 16px;}
|
||||
|
||||
pre {white-space:pre-wrap;}
|
1
resources/views/vendor/mail/text/subcontent.blade.php
vendored
Normal file
1
resources/views/vendor/mail/text/subcontent.blade.php
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{ $slot }}
|
Loading…
Reference in New Issue
Block a user