mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-10-31 18:07:35 -04:00 
			
		
		
		
	Working on manual send reminders #1234
This commit is contained in:
		
							parent
							
								
									3e4528e340
								
							
						
					
					
						commit
						d38101545f
					
				| @ -4,12 +4,20 @@ namespace App\Models; | |||||||
| 
 | 
 | ||||||
| use Auth; | use Auth; | ||||||
| use Eloquent; | use Eloquent; | ||||||
|  | use Laracasts\Presenter\PresentableTrait; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Class Activity. |  * Class Activity. | ||||||
|  */ |  */ | ||||||
| class Activity extends Eloquent | class Activity extends Eloquent | ||||||
| { | { | ||||||
|  |     use PresentableTrait; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     protected $presenter = 'App\Ninja\Presenters\ActivityPresenter'; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * @var bool |      * @var bool | ||||||
|      */ |      */ | ||||||
|  | |||||||
| @ -9,6 +9,7 @@ use App\Events\QuoteInvitationWasEmailed; | |||||||
| use App\Events\QuoteWasCreated; | use App\Events\QuoteWasCreated; | ||||||
| use App\Events\QuoteWasUpdated; | use App\Events\QuoteWasUpdated; | ||||||
| use App\Libraries\CurlUtils; | use App\Libraries\CurlUtils; | ||||||
|  | use App\Models\Activity; | ||||||
| use DateTime; | use DateTime; | ||||||
| use Illuminate\Database\Eloquent\SoftDeletes; | use Illuminate\Database\Eloquent\SoftDeletes; | ||||||
| use Laracasts\Presenter\PresentableTrait; | use Laracasts\Presenter\PresentableTrait; | ||||||
| @ -1441,6 +1442,16 @@ class Invoice extends EntityModel implements BalanceAffecting | |||||||
| 
 | 
 | ||||||
|         return $statuses; |         return $statuses; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     public function emailHistory() | ||||||
|  |     { | ||||||
|  |         return Activity::scope() | ||||||
|  |                 ->with(['contact']) | ||||||
|  |                 ->whereInvoiceId($this->id) | ||||||
|  |                 ->whereIn('activity_type_id', [ACTIVITY_TYPE_EMAIL_INVOICE, ACTIVITY_TYPE_EMAIL_QUOTE]) | ||||||
|  |                 ->orderBy('id', 'desc') | ||||||
|  |                 ->get(); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Invoice::creating(function ($invoice) { | Invoice::creating(function ($invoice) { | ||||||
|  | |||||||
							
								
								
									
										39
									
								
								app/Ninja/Presenters/ActivityPresenter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								app/Ninja/Presenters/ActivityPresenter.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace App\Ninja\Presenters; | ||||||
|  | 
 | ||||||
|  | use Laracasts\Presenter\Presenter; | ||||||
|  | use Utils; | ||||||
|  | 
 | ||||||
|  | class ActivityPresenter extends Presenter | ||||||
|  | { | ||||||
|  |     public function createdAt() | ||||||
|  |     { | ||||||
|  |         return Utils::timestampToDateTimeString(strtotime($this->entity->created_at)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function createdAtDate() | ||||||
|  |     { | ||||||
|  |         return Utils::dateToString($this->entity->created_at); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function user() | ||||||
|  |     { | ||||||
|  |         if ($this->entity->is_system) { | ||||||
|  |             return '<i>' . trans('texts.system') . '</i>'; | ||||||
|  |         } else { | ||||||
|  |             return $this->entity->user->getDisplayName(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public function notes() | ||||||
|  |     { | ||||||
|  |         if ($this->entity->notes) { | ||||||
|  |             return trans('texts.notes_' . $this->entity->notes); | ||||||
|  |         } elseif (in_array($this->entity->activity_type_id, [ACTIVITY_TYPE_EMAIL_INVOICE, ACTIVITY_TYPE_EMAIL_QUOTE])) { | ||||||
|  |             return trans('texts.initial_email'); | ||||||
|  |         } else { | ||||||
|  |             return ''; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -3,6 +3,7 @@ | |||||||
| namespace App\Ninja\Presenters; | namespace App\Ninja\Presenters; | ||||||
| 
 | 
 | ||||||
| use App\Libraries\Skype\InvoiceCard; | use App\Libraries\Skype\InvoiceCard; | ||||||
|  | use App\Models\Activity; | ||||||
| use Carbon; | use Carbon; | ||||||
| use DropdownButton; | use DropdownButton; | ||||||
| use stdClass; | use stdClass; | ||||||
|  | |||||||
| @ -494,7 +494,7 @@ $LANG = array( | |||||||
|     'email_address' => 'Email address', |     'email_address' => 'Email address', | ||||||
|     'lets_go' => 'Let\'s go', |     'lets_go' => 'Let\'s go', | ||||||
|     'password_recovery' => 'Password Recovery', |     'password_recovery' => 'Password Recovery', | ||||||
|     'send_email' => 'Send email', |     'send_email' => 'Send Email', | ||||||
|     'set_password' => 'Set Password', |     'set_password' => 'Set Password', | ||||||
|     'converted' => 'Converted', |     'converted' => 'Converted', | ||||||
|     'email_approved' => 'Email me when a quote is <b>approved</b>', |     'email_approved' => 'Email me when a quote is <b>approved</b>', | ||||||
| @ -2347,6 +2347,13 @@ $LANG = array( | |||||||
|     'inactivity_logout' => 'Due to inactivity, you have been automatically logged out.', |     'inactivity_logout' => 'Due to inactivity, you have been automatically logged out.', | ||||||
|     'mark_active' => 'Mark Active', |     'mark_active' => 'Mark Active', | ||||||
|     'send_automatically' => 'Send Automatically', |     'send_automatically' => 'Send Automatically', | ||||||
|  |     'template' => 'Template', | ||||||
|  |     'initial_email' => 'Initial Email', | ||||||
|  |     'invoice_not_emailed' => 'This invoice hasn\'t been emailed.', | ||||||
|  |     'quote_not_emailed' => 'This quote hasn\'t been emailed.', | ||||||
|  |     'days_ago' => ':count day ago|:count days ago', | ||||||
|  |     'sent_by' => 'Sent by :user', | ||||||
|  |     'recipients' => 'Recipients', | ||||||
| 
 | 
 | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -799,6 +799,8 @@ | |||||||
| 	  </div> | 	  </div> | ||||||
| 	</div> | 	</div> | ||||||
| 
 | 
 | ||||||
|  | 	@include('invoices.email') | ||||||
|  | 
 | ||||||
|     {!! Former::close() !!} |     {!! Former::close() !!} | ||||||
|     </form> |     </form> | ||||||
| 
 | 
 | ||||||
| @ -1284,24 +1286,33 @@ | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 		sweetConfirm(function() { | 		$('#recipients').html(getSendToEmails()); | ||||||
| 			model.invoice().is_public(true); | 		$('#emailModal').modal('show'); | ||||||
|             var accountLanguageId = parseInt({{ $account->language_id ?: '0' }}); |  | ||||||
|             var clientLanguageId = parseInt(model.invoice().client().language_id()) || 0; |  | ||||||
|             var attachPDF = {{ $account->attachPDF() ? 'true' : 'false' }}; |  | ||||||
| 
 |  | ||||||
|             // if they aren't attaching the pdf no need to generate it
 |  | ||||||
|             if ( ! attachPDF) { |  | ||||||
|                 submitAction('email'); |  | ||||||
|             // if the client's language is different then we can't use the browser version of the PDF
 |  | ||||||
|             } else if (clientLanguageId && clientLanguageId != accountLanguageId) { |  | ||||||
|                 submitAction('email'); |  | ||||||
|             } else { |  | ||||||
|                 preparePdfData('email'); |  | ||||||
|             } |  | ||||||
| 		}, getSendToEmails()); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	function onConfirmEmailClick() { | ||||||
|  | 		model.invoice().is_public(true); | ||||||
|  | 		var accountLanguageId = parseInt({{ $account->language_id ?: '0' }}); | ||||||
|  | 		var clientLanguageId = parseInt(model.invoice().client().language_id()) || 0; | ||||||
|  | 		var attachPDF = {{ $account->attachPDF() ? 'true' : 'false' }}; | ||||||
|  | 
 | ||||||
|  | 		// if they aren't attaching the pdf no need to generate it
 | ||||||
|  | 		if ( ! attachPDF) { | ||||||
|  | 			submitAction('email'); | ||||||
|  | 		// if the client's language is different then we can't use the browser version of the PDF
 | ||||||
|  | 		} else if (clientLanguageId && clientLanguageId != accountLanguageId) { | ||||||
|  | 			submitAction('email'); | ||||||
|  | 		} else { | ||||||
|  | 			preparePdfData('email'); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@if (Utils::isNinjaDev()) | ||||||
|  | 		$(function() { | ||||||
|  | 			onEmailClick(); | ||||||
|  | 		}) | ||||||
|  | 	@endif | ||||||
|  | 
 | ||||||
| 	function onSaveDraftClick() { | 	function onSaveDraftClick() { | ||||||
| 		model.invoice().is_public(false); | 		model.invoice().is_public(false); | ||||||
| 		onSaveClick(); | 		onSaveClick(); | ||||||
| @ -1310,7 +1321,7 @@ | |||||||
| 	function onMarkSentClick() { | 	function onMarkSentClick() { | ||||||
| 		if (model.invoice().is_recurring()) { | 		if (model.invoice().is_recurring()) { | ||||||
|             // warn invoice will be emailed when saving new recurring invoice
 |             // warn invoice will be emailed when saving new recurring invoice
 | ||||||
|             var text = getSendToEmails() + '\n' + "{!! trans("texts.confirm_recurring_timing") !!}"; |             var text = '\n' + getSendToEmails() + '\n\n' + "{!! trans("texts.confirm_recurring_timing") !!}"; | ||||||
|             var title = "{!! trans("texts.confirm_recurring_email_$entityType") !!}"; |             var title = "{!! trans("texts.confirm_recurring_email_$entityType") !!}"; | ||||||
|             sweetConfirm(function() { |             sweetConfirm(function() { | ||||||
| 				model.invoice().is_public(true); | 				model.invoice().is_public(true); | ||||||
|  | |||||||
							
								
								
									
										93
									
								
								resources/views/invoices/email.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								resources/views/invoices/email.blade.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | |||||||
|  | <div class="modal fade" id="emailModal" tabindex="-1" role="dialog" aria-labelledby="emailModalLabel" 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">×</button> | ||||||
|  |                 <h4 class="modal-title" id="emailModalLabel">{{ trans('texts.email_invoice') }}</h4> | ||||||
|  |             </div> | ||||||
|  | 
 | ||||||
|  |             <div class="modal-body"> | ||||||
|  |             <div class="panel-body"> | ||||||
|  | 
 | ||||||
|  |                 {!! Former::plaintext('recipients') | ||||||
|  |                         ->value('') !!} | ||||||
|  | 
 | ||||||
|  |                 {!! Former::select('template') | ||||||
|  |                         ->options([ | ||||||
|  |                             'initial' => trans('texts.initial_email'), | ||||||
|  |                             'reminder1' => trans('texts.first_reminder'), | ||||||
|  |                             'reminder2' => trans('texts.second_reminder'), | ||||||
|  |                             'reminder3' => trans('texts.third_reminder'), | ||||||
|  |                         ]) !!} | ||||||
|  | 
 | ||||||
|  |                 <br/> | ||||||
|  |                 <div role="tabpanel"> | ||||||
|  |                     <ul class="nav nav-tabs" role="tablist" style="border: none"> | ||||||
|  |                         <li role="presentation" class="active"> | ||||||
|  |                             <a href="#preview" aria-controls="preview" role="tab" data-toggle="tab">{{ trans('texts.preview') }}</a> | ||||||
|  |                         </li> | ||||||
|  |                         <li role="presentation"> | ||||||
|  |                             <a href="#customize" aria-controls="customize" role="tab" data-toggle="tab">{{ trans('texts.customize') }}</a> | ||||||
|  |                         </li> | ||||||
|  |                         <li role="presentation"> | ||||||
|  |                             <a href="#history" aria-controls="history" role="tab" data-toggle="tab">{{ trans('texts.history') }}</a> | ||||||
|  |                         </li> | ||||||
|  |                     </ul> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="tab-content"> | ||||||
|  |                     <div role="tabpanel" class="tab-pane active" id="preview"> | ||||||
|  |                         <div id="emailSubject"></div> | ||||||
|  |                         <div id="emailBody"></div> | ||||||
|  |                     </div> | ||||||
|  |                     <div role="tabpanel" class="tab-pane" id="customize"> | ||||||
|  | 
 | ||||||
|  |                     </div> | ||||||
|  |                     <div role="tabpanel" class="tab-pane" id="history"> | ||||||
|  |                         <br/> | ||||||
|  |                         @if (count($activities = $invoice->emailHistory())) | ||||||
|  |                         <table class="table table-striped data-table"> | ||||||
|  |                             <tr> | ||||||
|  |                                 <th>{{ trans('texts.template')}}</th> | ||||||
|  |                                 <th>{{ trans('texts.contact')}}</th> | ||||||
|  |                                 <th>{{ trans('texts.date')}}</th> | ||||||
|  |                             </tr> | ||||||
|  |                             @foreach ($activities as $activity) | ||||||
|  |                             <tr> | ||||||
|  |                                 <td>{{ $activity->present()->notes }}</td> | ||||||
|  |                                 <td> | ||||||
|  |                                     <span title="{{ trans('texts.sent_by', ['user' => $activity->present()->user]) }}"> | ||||||
|  |                                         {{ $activity->contact->getDisplayName() }} | ||||||
|  |                                     </span> | ||||||
|  |                                 </td> | ||||||
|  |                                 <td> | ||||||
|  |                                     <span title="{{ $activity->present()->createdAt }}"> | ||||||
|  |                                         {{ $activity->present()->createdAtDate }} - {{ trans_choice('texts.days_ago', $activity->created_at->diffInDays()) }} | ||||||
|  |                                     </span> | ||||||
|  |                                 </td> | ||||||
|  |                             </tr> | ||||||
|  |                             @endforeach | ||||||
|  |                         </table> | ||||||
|  |                         @else | ||||||
|  |                             <center style="font-size:16px;color:#888888;padding-top:20px;"> | ||||||
|  |                                 {{ trans("texts.{$invoice->getEntityType()}_not_emailed") }} | ||||||
|  |                             </center> | ||||||
|  |                         @endif | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  | 
 | ||||||
|  |             </div> | ||||||
|  |             </div> | ||||||
|  | 
 | ||||||
|  |             <div class="modal-footer" style="margin-top: 0px"> | ||||||
|  |                 <button type="button" class="btn btn-default" data-dismiss="modal">{{ trans('texts.cancel') }}</button> | ||||||
|  |                 <button type="button" class="btn btn-info" onclick="onConfirmEmailClick()">{{ trans('texts.send_email') }}</button> | ||||||
|  |             </div> | ||||||
|  | 
 | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | <script type="text/javascript"> | ||||||
|  | 
 | ||||||
|  | </script> | ||||||
| @ -641,13 +641,13 @@ function ContactModel(data) { | |||||||
|     self.displayName = ko.computed(function() { |     self.displayName = ko.computed(function() { | ||||||
|         var str = ''; |         var str = ''; | ||||||
|         if (self.first_name() || self.last_name()) { |         if (self.first_name() || self.last_name()) { | ||||||
|             str += (self.first_name() || '') + ' ' + (self.last_name() || '') + '\n'; |             str += (self.first_name() || '') + ' ' + (self.last_name() || '') + ' '; | ||||||
|         } |         } | ||||||
|         if (self.email()) { |         if (self.email()) { | ||||||
|             str += self.email() + '\n'; |             str += '<' + self.email() + '>'; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return str; |         return str + '<br/>'; | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     self.email.display = ko.computed(function() { |     self.email.display = ko.computed(function() { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user