mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-10-31 01:17:33 -04:00 
			
		
		
		
	Merge remote-tracking branch 'upstream/develop' into develop
This commit is contained in:
		
						commit
						1bef3b0791
					
				| @ -1301,4 +1301,37 @@ class AccountController extends BaseController | |||||||
| 
 | 
 | ||||||
|         return Redirect::to("/settings/$section/", 301); |         return Redirect::to("/settings/$section/", 301); | ||||||
|     } |     } | ||||||
|  |      | ||||||
|  |     public function previewEmail(\App\Services\TemplateService $templateService) | ||||||
|  |     { | ||||||
|  |         $template = Input::get('template'); | ||||||
|  |         $invoice = Invoice::scope() | ||||||
|  |                     ->invoices() | ||||||
|  |                     ->withTrashed() | ||||||
|  |                     ->first(); | ||||||
|  |          | ||||||
|  |         if ( ! $invoice) { | ||||||
|  |             return trans('texts.create_invoice_for_sample'); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         $account = Auth::user()->account; | ||||||
|  |          | ||||||
|  |         // replace the variables with sample data
 | ||||||
|  |         $data = [ | ||||||
|  |             'account' => $account, | ||||||
|  |             'invoice' => $invoice, | ||||||
|  |             'invitation' => $invoice->invitations->first(), | ||||||
|  |             'client' => $invoice->client, | ||||||
|  |             'amount' => $invoice->amount  | ||||||
|  |         ]; | ||||||
|  |          | ||||||
|  |         // create the email view 
 | ||||||
|  |         $view = 'emails.' . $account->getTemplateView(ENTITY_INVOICE) . '_html'; | ||||||
|  |         $data = array_merge($data, [ | ||||||
|  |             'body' => $templateService->processVariables($template, $data), | ||||||
|  |             'entityType' => ENTITY_INVOICE, | ||||||
|  |         ]); | ||||||
|  |          | ||||||
|  |         return Response::view($view, $data); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -266,18 +266,7 @@ class AppController extends BaseController | |||||||
|                 Cache::flush(); |                 Cache::flush(); | ||||||
|                 Session::flush(); |                 Session::flush(); | ||||||
|                 Artisan::call('migrate', array('--force' => true)); |                 Artisan::call('migrate', array('--force' => true)); | ||||||
|                 foreach ([ |                 Artisan::call('db:seed', array('--force' => true, '--class' => "UpdateSeeder")); | ||||||
|                     'PaymentLibraries', |  | ||||||
|                     'Fonts', |  | ||||||
|                     'Banks', |  | ||||||
|                     'InvoiceStatus', |  | ||||||
|                     'Currencies', |  | ||||||
|                     'DateFormats', |  | ||||||
|                     'InvoiceDesigns', |  | ||||||
|                     'PaymentTerms', |  | ||||||
|                 ] as $seeder) { |  | ||||||
|                     Artisan::call('db:seed', array('--force' => true, '--class' => "{$seeder}Seeder")); |  | ||||||
|                 } |  | ||||||
|                 Event::fire(new UserSettingsChanged()); |                 Event::fire(new UserSettingsChanged()); | ||||||
|                 Session::flash('message', trans('texts.processed_updates')); |                 Session::flash('message', trans('texts.processed_updates')); | ||||||
|             } catch (Exception $e) { |             } catch (Exception $e) { | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ class ClientRequest extends EntityRequest { | |||||||
|         $client = parent::entity(); |         $client = parent::entity(); | ||||||
|          |          | ||||||
|         // eager load the contacts
 |         // eager load the contacts
 | ||||||
|         if ($client && ! count($client->contacts)) { |         if ($client && ! $client->relationLoaded('contacts')) { | ||||||
|             $client->load('contacts'); |             $client->load('contacts'); | ||||||
|         } |         } | ||||||
|           |           | ||||||
|  | |||||||
| @ -8,8 +8,8 @@ class ExpenseRequest extends EntityRequest { | |||||||
|     { |     { | ||||||
|         $expense = parent::entity(); |         $expense = parent::entity(); | ||||||
|          |          | ||||||
|         // eager load the contacts
 |         // eager load the documents
 | ||||||
|         if ($expense && ! count($expense->documents)) { |         if ($expense && ! $expense->relationLoaded('documents')) { | ||||||
|             $expense->load('documents'); |             $expense->load('documents'); | ||||||
|         } |         } | ||||||
|          |          | ||||||
|  | |||||||
| @ -8,8 +8,8 @@ class InvoiceRequest extends EntityRequest { | |||||||
|     { |     { | ||||||
|         $invoice = parent::entity(); |         $invoice = parent::entity(); | ||||||
|          |          | ||||||
|         // eager load the contacts
 |         // eager load the invoice items
 | ||||||
|         if ($invoice && ! count($invoice->invoice_items)) { |         if ($invoice && ! $invoice->relationLoaded('invoice_items')) { | ||||||
|             $invoice->load('invoice_items'); |             $invoice->load('invoice_items'); | ||||||
|         } |         } | ||||||
|           |           | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ class VendorRequest extends EntityRequest { | |||||||
|         $vendor = parent::entity(); |         $vendor = parent::entity(); | ||||||
|          |          | ||||||
|         // eager load the contacts
 |         // eager load the contacts
 | ||||||
|         if ($vendor && ! count($vendor->vendor_contacts)) { |         if ($vendor && ! $vendor->relationLoaded('vendor_contacts')) { | ||||||
|             $vendor->load('vendor_contacts'); |             $vendor->load('vendor_contacts'); | ||||||
|         } |         } | ||||||
|           |           | ||||||
|  | |||||||
| @ -208,6 +208,7 @@ Route::group([ | |||||||
|     Route::resource('tax_rates', 'TaxRateController'); |     Route::resource('tax_rates', 'TaxRateController'); | ||||||
|     Route::post('tax_rates/bulk', 'TaxRateController@bulk'); |     Route::post('tax_rates/bulk', 'TaxRateController@bulk'); | ||||||
| 
 | 
 | ||||||
|  |     Route::get('settings/email_preview', 'AccountController@previewEmail'); | ||||||
|     Route::get('company/{section}/{subSection?}', 'AccountController@redirectLegacy'); |     Route::get('company/{section}/{subSection?}', 'AccountController@redirectLegacy'); | ||||||
|     Route::get('settings/data_visualizations', 'ReportController@d3'); |     Route::get('settings/data_visualizations', 'ReportController@d3'); | ||||||
|     Route::get('settings/charts_and_reports', 'ReportController@showReports'); |     Route::get('settings/charts_and_reports', 'ReportController@showReports'); | ||||||
|  | |||||||
| @ -341,6 +341,7 @@ class Utils | |||||||
|         $currency = self::getFromCache($currencyId, 'currencies'); |         $currency = self::getFromCache($currencyId, 'currencies'); | ||||||
|         $thousand = $currency->thousand_separator; |         $thousand = $currency->thousand_separator; | ||||||
|         $decimal = $currency->decimal_separator; |         $decimal = $currency->decimal_separator; | ||||||
|  |         $precision = $currency->precision; | ||||||
|         $code = $currency->code; |         $code = $currency->code; | ||||||
|         $swapSymbol = false; |         $swapSymbol = false; | ||||||
| 
 | 
 | ||||||
| @ -355,7 +356,7 @@ class Utils | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $value = number_format($value, $currency->precision, $decimal, $thousand); |         $value = number_format($value, $precision, $decimal, $thousand); | ||||||
|         $symbol = $currency->symbol; |         $symbol = $currency->symbol; | ||||||
| 
 | 
 | ||||||
|         if ($showCode || !$symbol) { |         if ($showCode || !$symbol) { | ||||||
|  | |||||||
| @ -212,7 +212,9 @@ class Account extends Eloquent | |||||||
| 
 | 
 | ||||||
|     public function isGatewayConfigured($gatewayId = 0) |     public function isGatewayConfigured($gatewayId = 0) | ||||||
|     { |     { | ||||||
|         $this->load('account_gateways'); |         if ( ! $this->relationLoaded('account_gateways')) { | ||||||
|  |             $this->load('account_gateways'); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         if ($gatewayId) { |         if ($gatewayId) { | ||||||
|             return $this->getGatewayConfig($gatewayId) != false; |             return $this->getGatewayConfig($gatewayId) != false; | ||||||
| @ -241,7 +243,7 @@ class Account extends Eloquent | |||||||
|             return $this->name; |             return $this->name; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $this->load('users'); |         //$this->load('users');
 | ||||||
|         $user = $this->users()->first(); |         $user = $this->users()->first(); | ||||||
| 
 | 
 | ||||||
|         return $user->getDisplayName(); |         return $user->getDisplayName(); | ||||||
| @ -1167,6 +1169,11 @@ class Account extends Eloquent | |||||||
|         return str_replace('/>', ' />', $template); |         return str_replace('/>', ' />', $template); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function getTemplateView($view = '') | ||||||
|  |     { | ||||||
|  |         return $this->getEmailDesignId() == EMAIL_DESIGN_PLAIN ? $view : 'design' . $this->getEmailDesignId(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function getEmailFooter() |     public function getEmailFooter() | ||||||
|     { |     { | ||||||
|         if ($this->email_footer) { |         if ($this->email_footer) { | ||||||
|  | |||||||
| @ -256,13 +256,17 @@ class Client extends EntityModel | |||||||
| 
 | 
 | ||||||
|     public function getGatewayToken() |     public function getGatewayToken() | ||||||
|     { |     { | ||||||
|         $this->account->load('account_gateways'); |         $account = $this->account; | ||||||
|          |          | ||||||
|         if (!count($this->account->account_gateways)) { |         if ( ! $account->relationLoaded('account_gateways')) { | ||||||
|  |             $account->load('account_gateways'); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (!count($account->account_gateways)) { | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $accountGateway = $this->account->getGatewayConfig(GATEWAY_STRIPE); |         $accountGateway = $account->getGatewayConfig(GATEWAY_STRIPE); | ||||||
|          |          | ||||||
|         if (!$accountGateway) { |         if (!$accountGateway) { | ||||||
|             return false; |             return false; | ||||||
|  | |||||||
| @ -228,6 +228,12 @@ class Invoice extends EntityModel implements BalanceAffecting | |||||||
|         return $this->hasMany('App\Models\Expense','invoice_id','id')->withTrashed(); |         return $this->hasMany('App\Models\Expense','invoice_id','id')->withTrashed(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public function scopeInvoices($query) | ||||||
|  |     { | ||||||
|  |         return $query->where('is_quote', '=', false) | ||||||
|  |                      ->where('is_recurring', '=', false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function markInvitationsSent($notify = false) |     public function markInvitationsSent($notify = false) | ||||||
|     { |     { | ||||||
|         foreach ($this->invitations as $invitation) { |         foreach ($this->invitations as $invitation) { | ||||||
|  | |||||||
| @ -1,17 +1,13 @@ | |||||||
| <?php namespace App\Ninja\Mailers; | <?php namespace App\Ninja\Mailers; | ||||||
| 
 | 
 | ||||||
| use Form; |  | ||||||
| use HTML; |  | ||||||
| use Utils; | use Utils; | ||||||
| use Event; | use Event; | ||||||
| use URL; | use URL; | ||||||
| use Auth; | use Auth; | ||||||
| 
 | use App\Services\TemplateService; | ||||||
| use App\Models\Invoice; | use App\Models\Invoice; | ||||||
| use App\Models\Payment; | use App\Models\Payment; | ||||||
| use App\Models\Activity; | use App\Models\Activity; | ||||||
| use App\Models\Gateway; |  | ||||||
| 
 |  | ||||||
| use App\Events\InvoiceWasEmailed; | use App\Events\InvoiceWasEmailed; | ||||||
| use App\Events\QuoteWasEmailed; | use App\Events\QuoteWasEmailed; | ||||||
| 
 | 
 | ||||||
| @ -36,6 +32,11 @@ class ContactMailer extends Mailer | |||||||
|         'paymentButton', |         'paymentButton', | ||||||
|     ]; |     ]; | ||||||
| 
 | 
 | ||||||
|  |     public function __construct(TemplateService $templateService) | ||||||
|  |     { | ||||||
|  |         $this->templateService = $templateService; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public function sendInvoice(Invoice $invoice, $reminder = false, $pdfString = false) |     public function sendInvoice(Invoice $invoice, $reminder = false, $pdfString = false) | ||||||
|     { |     { | ||||||
|         $invoice->load('invitations', 'client.language', 'account'); |         $invoice->load('invitations', 'client.language', 'account'); | ||||||
| @ -144,7 +145,7 @@ class ContactMailer extends Mailer | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $data = [ |         $data = [ | ||||||
|             'body' => $this->processVariables($body, $variables), |             'body' => $this->templateService->processVariables($body, $variables), | ||||||
|             'link' => $invitation->getLink(), |             'link' => $invitation->getLink(), | ||||||
|             'entityType' => $invoice->getEntityType(), |             'entityType' => $invoice->getEntityType(), | ||||||
|             'invoiceId' => $invoice->id, |             'invoiceId' => $invoice->id, | ||||||
| @ -160,14 +161,9 @@ class ContactMailer extends Mailer | |||||||
|             $data['pdfFileName'] = $invoice->getFileName(); |             $data['pdfFileName'] = $invoice->getFileName(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $subject = $this->processVariables($subject, $variables); |         $subject = $this->templateService->processVariables($subject, $variables); | ||||||
|         $fromEmail = $user->email; |         $fromEmail = $user->email; | ||||||
| 
 |         $view = $account->getTemplateView(ENTITY_INVOICE); | ||||||
|         if ($account->getEmailDesignId() == EMAIL_DESIGN_PLAIN) { |  | ||||||
|             $view = ENTITY_INVOICE; |  | ||||||
|         } else { |  | ||||||
|             $view = 'design' . ($account->getEmailDesignId() - 1); |  | ||||||
|         } |  | ||||||
|          |          | ||||||
|         $response = $this->sendTo($invitation->contact->email, $fromEmail, $account->getDisplayName(), $subject, $view, $data); |         $response = $this->sendTo($invitation->contact->email, $fromEmail, $account->getDisplayName(), $subject, $view, $data); | ||||||
| 
 | 
 | ||||||
| @ -230,7 +226,7 @@ class ContactMailer extends Mailer | |||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|         $data = [ |         $data = [ | ||||||
|             'body' => $this->processVariables($emailTemplate, $variables), |             'body' => $this->templateService->processVariables($emailTemplate, $variables), | ||||||
|             'link' => $invitation->getLink(), |             'link' => $invitation->getLink(), | ||||||
|             'invoice' => $invoice, |             'invoice' => $invoice, | ||||||
|             'client' => $client, |             'client' => $client, | ||||||
| @ -244,14 +240,10 @@ class ContactMailer extends Mailer | |||||||
|             $data['pdfFileName'] = $invoice->getFileName(); |             $data['pdfFileName'] = $invoice->getFileName(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $subject = $this->processVariables($emailSubject, $variables); |         $subject = $this->templateService->processVariables($emailSubject, $variables); | ||||||
|         $data['invoice_id'] = $payment->invoice->id; |         $data['invoice_id'] = $payment->invoice->id; | ||||||
| 
 | 
 | ||||||
|         if ($account->getEmailDesignId() == EMAIL_DESIGN_PLAIN) { |         $view = $account->getTemplateView('payment_confirmation'); | ||||||
|             $view = 'payment_confirmation'; |  | ||||||
|         } else { |  | ||||||
|             $view = 'design' . ($account->getEmailDesignId() - 1); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if ($user->email && $contact->email) { |         if ($user->email && $contact->email) { | ||||||
|             $this->sendTo($contact->email, $user->email, $accountName, $subject, $view, $data); |             $this->sendTo($contact->email, $user->email, $accountName, $subject, $view, $data); | ||||||
| @ -281,75 +273,4 @@ class ContactMailer extends Mailer | |||||||
|          |          | ||||||
|         $this->sendTo($email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data); |         $this->sendTo($email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     private function processVariables($template, $data) |  | ||||||
|     { |  | ||||||
|         $account = $data['account']; |  | ||||||
|         $client = $data['client']; |  | ||||||
|         $invitation = $data['invitation']; |  | ||||||
|         $invoice = $invitation->invoice; |  | ||||||
|         $passwordHTML = isset($data['password'])?'<p>'.trans('texts.password').': '.$data['password'].'<p>':false; |  | ||||||
|         $documentsHTML = ''; |  | ||||||
| 
 |  | ||||||
|         if($account->hasFeature(FEATURE_DOCUMENTS) && $invoice->hasDocuments()){ |  | ||||||
|             $documentsHTML .= trans('texts.email_documents_header').'<ul>'; |  | ||||||
|             foreach($invoice->documents as $document){ |  | ||||||
|                 $documentsHTML .= '<li><a href="'.HTML::entities($document->getClientUrl($invitation)).'">'.HTML::entities($document->name).'</a></li>'; |  | ||||||
|             } |  | ||||||
|             foreach($invoice->expenses as $expense){ |  | ||||||
|                 foreach($expense->documents as $document){ |  | ||||||
|                     $documentsHTML .= '<li><a href="'.HTML::entities($document->getClientUrl($invitation)).'">'.HTML::entities($document->name).'</a></li>'; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             $documentsHTML .= '</ul>'; |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         $variables = [ |  | ||||||
|             '$footer' => $account->getEmailFooter(), |  | ||||||
|             '$client' => $client->getDisplayName(), |  | ||||||
|             '$account' => $account->getDisplayName(), |  | ||||||
|             '$dueDate' => $account->formatDate($invoice->due_date), |  | ||||||
|             '$invoiceDate' => $account->formatDate($invoice->invoice_date), |  | ||||||
|             '$contact' => $invitation->contact->getDisplayName(), |  | ||||||
|             '$firstName' => $invitation->contact->first_name, |  | ||||||
|             '$amount' => $account->formatMoney($data['amount'], $client), |  | ||||||
|             '$invoice' => $invoice->invoice_number, |  | ||||||
|             '$quote' => $invoice->invoice_number, |  | ||||||
|             '$link' => $invitation->getLink(), |  | ||||||
|             '$password' => $passwordHTML, |  | ||||||
|             '$viewLink' => $invitation->getLink().'$password', |  | ||||||
|             '$viewButton' => Form::emailViewButton($invitation->getLink(), $invoice->getEntityType()).'$password', |  | ||||||
|             '$paymentLink' => $invitation->getLink('payment').'$password', |  | ||||||
|             '$paymentButton' => Form::emailPaymentButton($invitation->getLink('payment')).'$password', |  | ||||||
|             '$customClient1' => $account->custom_client_label1, |  | ||||||
|             '$customClient2' => $account->custom_client_label2, |  | ||||||
|             '$customInvoice1' => $account->custom_invoice_text_label1, |  | ||||||
|             '$customInvoice2' => $account->custom_invoice_text_label2, |  | ||||||
|             '$documents' => $documentsHTML, |  | ||||||
|         ]; |  | ||||||
| 
 |  | ||||||
|         // Add variables for available payment types
 |  | ||||||
|         foreach (Gateway::$paymentTypes as $type) { |  | ||||||
|             $camelType = Gateway::getPaymentTypeName($type); |  | ||||||
|             $type = Utils::toSnakeCase($camelType); |  | ||||||
|             $variables["\${$camelType}Link"] = $invitation->getLink('payment') . "/{$type}"; |  | ||||||
|             $variables["\${$camelType}Button"] = Form::emailPaymentButton($invitation->getLink('payment')  . "/{$type}"); |  | ||||||
|         } |  | ||||||
|          |  | ||||||
|         $includesPasswordPlaceholder = strpos($template, '$password') !== false; |  | ||||||
|                  |  | ||||||
|         $str = str_replace(array_keys($variables), array_values($variables), $template); |  | ||||||
| 
 |  | ||||||
|         if(!$includesPasswordPlaceholder && $passwordHTML){ |  | ||||||
|             $pos = strrpos($str, '$password'); |  | ||||||
|             if($pos !== false) |  | ||||||
|             { |  | ||||||
|                 $str = substr_replace($str, $passwordHTML, $pos, 9/* length of "$password" */); |  | ||||||
|             } |  | ||||||
|         }         |  | ||||||
|         $str = str_replace('$password', '', $str); |  | ||||||
|         $str = autolink($str, 100); |  | ||||||
|          |  | ||||||
|         return $str; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -18,7 +18,7 @@ class InvoicePresenter extends Presenter { | |||||||
| 
 | 
 | ||||||
|     public function balanceDueLabel() |     public function balanceDueLabel() | ||||||
|     { |     { | ||||||
|         if ($this->entity->partial) { |         if ($this->entity->partial > 0) { | ||||||
|             return 'partial_due'; |             return 'partial_due'; | ||||||
|         } elseif ($this->entity->is_quote) { |         } elseif ($this->entity->is_quote) { | ||||||
|             return 'total'; |             return 'total'; | ||||||
|  | |||||||
| @ -167,6 +167,7 @@ class AccountRepository | |||||||
|             ENTITY_QUOTE, |             ENTITY_QUOTE, | ||||||
|             ENTITY_TASK, |             ENTITY_TASK, | ||||||
|             ENTITY_EXPENSE, |             ENTITY_EXPENSE, | ||||||
|  |             ENTITY_VENDOR, | ||||||
|             ENTITY_RECURRING_INVOICE, |             ENTITY_RECURRING_INVOICE, | ||||||
|             ENTITY_PAYMENT, |             ENTITY_PAYMENT, | ||||||
|             ENTITY_CREDIT |             ENTITY_CREDIT | ||||||
| @ -183,15 +184,22 @@ class AccountRepository | |||||||
|             ]; |             ]; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $features[] = ['dashboard', '/dashboard']; |         $features = array_merge($features, [ | ||||||
|         $features[] = ['customize_design', '/settings/customize_design']; |             ['dashboard', '/dashboard'], | ||||||
|         $features[] = ['new_tax_rate', '/tax_rates/create']; |             ['customize_design', '/settings/customize_design'], | ||||||
|         $features[] = ['new_product', '/products/create']; |             ['new_tax_rate', '/tax_rates/create'], | ||||||
|         $features[] = ['new_user', '/users/create']; |             ['new_product', '/products/create'], | ||||||
|         $features[] = ['custom_fields', '/settings/invoice_settings'];	 |             ['new_user', '/users/create'], | ||||||
|  |             ['custom_fields', '/settings/invoice_settings'], | ||||||
|  |             ['invoice_number', '/settings/invoice_settings'], | ||||||
|  |         ]); | ||||||
| 
 | 
 | ||||||
|         $settings = array_merge(Account::$basicSettings, Account::$advancedSettings); |         $settings = array_merge(Account::$basicSettings, Account::$advancedSettings); | ||||||
| 
 | 
 | ||||||
|  |         if ( ! Utils::isNinjaProd()) { | ||||||
|  |             $settings[] = ACCOUNT_SYSTEM_SETTINGS; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         foreach ($settings as $setting) { |         foreach ($settings as $setting) { | ||||||
|             $features[] = [ |             $features[] = [ | ||||||
|                 $setting, |                 $setting, | ||||||
| @ -332,7 +340,7 @@ class AccountRepository | |||||||
|             $client->public_id = $account->id; |             $client->public_id = $account->id; | ||||||
|             $client->user_id = $ninjaAccount->users()->first()->id; |             $client->user_id = $ninjaAccount->users()->first()->id; | ||||||
|             $client->currency_id = 1; |             $client->currency_id = 1; | ||||||
|             foreach (['name', 'address1', 'address2', 'city', 'state', 'postal_code', 'country_id', 'work_phone', 'language_id'] as $field) { |             foreach (['name', 'address1', 'address2', 'city', 'state', 'postal_code', 'country_id', 'work_phone', 'language_id', 'vat_number'] as $field) { | ||||||
|                 $client->$field = $account->$field; |                 $client->$field = $account->$field; | ||||||
|             } |             } | ||||||
|             $ninjaAccount->clients()->save($client); |             $ninjaAccount->clients()->save($client); | ||||||
|  | |||||||
| @ -105,7 +105,7 @@ class ClientRepository extends BaseRepository | |||||||
| 
 | 
 | ||||||
|         // If the primary is set ensure it's listed first
 |         // If the primary is set ensure it's listed first
 | ||||||
|         usort($contacts, function ($left, $right) { |         usort($contacts, function ($left, $right) { | ||||||
|             return (isset($right['is_primary']) ? $right['is_primary'] : 0) - (isset($left['is_primary']) ? $left['is_primary'] : 0); |             return (isset($right['is_primary']) ? $right['is_primary'] : 1) - (isset($left['is_primary']) ? $left['is_primary'] : 0); | ||||||
|         }); |         }); | ||||||
|          |          | ||||||
|         foreach ($contacts as $contact) { |         foreach ($contacts as $contact) { | ||||||
|  | |||||||
							
								
								
									
										80
									
								
								app/Services/TemplateService.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								app/Services/TemplateService.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,80 @@ | |||||||
|  | <?php namespace App\Services; | ||||||
|  | 
 | ||||||
|  | use Form; | ||||||
|  | use HTML; | ||||||
|  | use Utils; | ||||||
|  | use App\Models\Gateway; | ||||||
|  | 
 | ||||||
|  | class TemplateService | ||||||
|  | { | ||||||
|  |     public function processVariables($template, $data) | ||||||
|  |     { | ||||||
|  |         $account = $data['account']; | ||||||
|  |         $client = $data['client']; | ||||||
|  |         $invitation = $data['invitation']; | ||||||
|  |         $invoice = $invitation->invoice; | ||||||
|  |         $passwordHTML = isset($data['password'])?'<p>'.trans('texts.password').': '.$data['password'].'<p>':false; | ||||||
|  |         $documentsHTML = ''; | ||||||
|  | 
 | ||||||
|  |         if ($account->hasFeature(FEATURE_DOCUMENTS) && $invoice->hasDocuments()) { | ||||||
|  |             $documentsHTML .= trans('texts.email_documents_header').'<ul>'; | ||||||
|  |             foreach($invoice->documents as $document){ | ||||||
|  |                 $documentsHTML .= '<li><a href="'.HTML::entities($document->getClientUrl($invitation)).'">'.HTML::entities($document->name).'</a></li>'; | ||||||
|  |             } | ||||||
|  |             foreach($invoice->expenses as $expense){ | ||||||
|  |                 foreach($expense->documents as $document){ | ||||||
|  |                     $documentsHTML .= '<li><a href="'.HTML::entities($document->getClientUrl($invitation)).'">'.HTML::entities($document->name).'</a></li>'; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             $documentsHTML .= '</ul>'; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         $variables = [ | ||||||
|  |             '$footer' => $account->getEmailFooter(), | ||||||
|  |             '$client' => $client->getDisplayName(), | ||||||
|  |             '$account' => $account->getDisplayName(), | ||||||
|  |             '$dueDate' => $account->formatDate($invoice->due_date), | ||||||
|  |             '$invoiceDate' => $account->formatDate($invoice->invoice_date), | ||||||
|  |             '$contact' => $invitation->contact->getDisplayName(), | ||||||
|  |             '$firstName' => $invitation->contact->first_name, | ||||||
|  |             '$amount' => $account->formatMoney($data['amount'], $client), | ||||||
|  |             '$invoice' => $invoice->invoice_number, | ||||||
|  |             '$quote' => $invoice->invoice_number, | ||||||
|  |             '$link' => $invitation->getLink(), | ||||||
|  |             '$password' => $passwordHTML, | ||||||
|  |             '$viewLink' => $invitation->getLink().'$password', | ||||||
|  |             '$viewButton' => Form::emailViewButton($invitation->getLink(), $invoice->getEntityType()).'$password', | ||||||
|  |             '$paymentLink' => $invitation->getLink('payment').'$password', | ||||||
|  |             '$paymentButton' => Form::emailPaymentButton($invitation->getLink('payment')).'$password', | ||||||
|  |             '$customClient1' => $account->custom_client_label1, | ||||||
|  |             '$customClient2' => $account->custom_client_label2, | ||||||
|  |             '$customInvoice1' => $account->custom_invoice_text_label1, | ||||||
|  |             '$customInvoice2' => $account->custom_invoice_text_label2, | ||||||
|  |             '$documents' => $documentsHTML, | ||||||
|  |         ]; | ||||||
|  | 
 | ||||||
|  |         // Add variables for available payment types
 | ||||||
|  |         foreach (Gateway::$paymentTypes as $type) { | ||||||
|  |             $camelType = Gateway::getPaymentTypeName($type); | ||||||
|  |             $type = Utils::toSnakeCase($camelType); | ||||||
|  |             $variables["\${$camelType}Link"] = $invitation->getLink('payment') . "/{$type}"; | ||||||
|  |             $variables["\${$camelType}Button"] = Form::emailPaymentButton($invitation->getLink('payment')  . "/{$type}"); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         $includesPasswordPlaceholder = strpos($template, '$password') !== false; | ||||||
|  |                  | ||||||
|  |         $str = str_replace(array_keys($variables), array_values($variables), $template); | ||||||
|  | 
 | ||||||
|  |         if (!$includesPasswordPlaceholder && $passwordHTML) { | ||||||
|  |             $pos = strrpos($str, '$password'); | ||||||
|  |             if ($pos !== false) | ||||||
|  |             { | ||||||
|  |                 $str = substr_replace($str, $passwordHTML, $pos, 9/* length of "$password" */); | ||||||
|  |             } | ||||||
|  |         }         | ||||||
|  |         $str = str_replace('$password', '', $str); | ||||||
|  |         $str = autolink($str, 100); | ||||||
|  |          | ||||||
|  |         return $str; | ||||||
|  |     }     | ||||||
|  | } | ||||||
| @ -8,6 +8,7 @@ class CurrenciesSeeder extends Seeder | |||||||
|     { |     { | ||||||
|         Eloquent::unguard(); |         Eloquent::unguard(); | ||||||
| 
 | 
 | ||||||
|  |         // http://www.localeplanet.com/icu/currency.html
 | ||||||
|         $currencies = [ |         $currencies = [ | ||||||
|             ['name' => 'US Dollar', 'code' => 'USD', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], |             ['name' => 'US Dollar', 'code' => 'USD', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], | ||||||
|             ['name' => 'Pound Sterling', 'code' => 'GBP', 'symbol' => '£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], |             ['name' => 'Pound Sterling', 'code' => 'GBP', 'symbol' => '£', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], | ||||||
| @ -56,6 +57,7 @@ class CurrenciesSeeder extends Seeder | |||||||
|             ['name' => 'Japanese Yen', 'code' => 'JPY', 'symbol' => '¥', 'precision' => '0', 'thousand_separator' => ',', 'decimal_separator' => '.'], |             ['name' => 'Japanese Yen', 'code' => 'JPY', 'symbol' => '¥', 'precision' => '0', 'thousand_separator' => ',', 'decimal_separator' => '.'], | ||||||
|             ['name' => 'Maldivian Rufiyaa', 'code' => 'MVR', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], |             ['name' => 'Maldivian Rufiyaa', 'code' => 'MVR', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], | ||||||
|             ['name' => 'Costa Rican Colón', 'code' => 'CRC', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], |             ['name' => 'Costa Rican Colón', 'code' => 'CRC', 'symbol' => '', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], | ||||||
|  |             ['name' => 'Pakistani Rupee', 'code' => 'PKR', 'symbol' => 'Rs ', 'precision' => '0', 'thousand_separator' => ',', 'decimal_separator' => '.'], | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|         foreach ($currencies as $currency) { |         foreach ($currencies as $currency) { | ||||||
|  | |||||||
| @ -23,5 +23,6 @@ class DatabaseSeeder extends Seeder | |||||||
|         $this->call('DateFormatsSeeder'); |         $this->call('DateFormatsSeeder'); | ||||||
|         $this->call('InvoiceDesignsSeeder'); |         $this->call('InvoiceDesignsSeeder'); | ||||||
|         $this->call('PaymentTermsSeeder'); |         $this->call('PaymentTermsSeeder'); | ||||||
|  |         $this->call('LanguageSeeder'); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										41
									
								
								database/seeds/LanguageSeeder.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								database/seeds/LanguageSeeder.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | use App\Models\Language; | ||||||
|  | 
 | ||||||
|  | class LanguageSeeder extends Seeder | ||||||
|  | { | ||||||
|  |     public function run() | ||||||
|  |     { | ||||||
|  |         Eloquent::unguard(); | ||||||
|  | 
 | ||||||
|  |         $languages = [ | ||||||
|  |             ['name' => 'English', 'locale' => 'en'], | ||||||
|  |             ['name' => 'Italian', 'locale' => 'it'], | ||||||
|  |             ['name' => 'German', 'locale' => 'de'], | ||||||
|  |             ['name' => 'French', 'locale' => 'fr'], | ||||||
|  |             ['name' => 'Brazilian Portuguese', 'locale' => 'pt_BR'], | ||||||
|  |             ['name' => 'Dutch', 'locale' => 'nl'], | ||||||
|  |             ['name' => 'Spanish', 'locale' => 'es'], | ||||||
|  |             ['name' => 'Norwegian', 'locale' => 'nb_NO'], | ||||||
|  |             ['name' => 'Danish', 'locale' => 'da'], | ||||||
|  |             ['name' => 'Japanese', 'locale' => 'ja'], | ||||||
|  |             ['name' => 'Swedish', 'locale' => 'sv'], | ||||||
|  |             ['name' => 'Spanish - Spain', 'locale' => 'es_ES'], | ||||||
|  |             ['name' => 'French - Canada', 'locale' => 'fr_CA'], | ||||||
|  |             ['name' => 'Lithuanian', 'locale' => 'lt'],   | ||||||
|  |             ['name' => 'Polish', 'locale' => 'pl'], | ||||||
|  |         ]; | ||||||
|  | 
 | ||||||
|  |         foreach ($languages as $language) { | ||||||
|  |             $record = Language::whereLocale($language['locale'])->first(); | ||||||
|  |             if ($record) { | ||||||
|  |                 $record->name = $language['name']; | ||||||
|  |                 $record->save(); | ||||||
|  |             } else { | ||||||
|  |                 Language::create($language); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Eloquent::reguard(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -19,5 +19,6 @@ class UpdateSeeder extends Seeder | |||||||
|         $this->call('DateFormatsSeeder'); |         $this->call('DateFormatsSeeder'); | ||||||
|         $this->call('InvoiceDesignsSeeder'); |         $this->call('InvoiceDesignsSeeder'); | ||||||
|         $this->call('PaymentTermsSeeder'); |         $this->call('PaymentTermsSeeder'); | ||||||
|  |         $this->call('LanguageSeeder'); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,9 +1,13 @@ | |||||||
| <?php | <?php | ||||||
| 
 | 
 | ||||||
| use App\Models\User; | use App\Models\User; | ||||||
|  | use App\Models\Font; | ||||||
| use App\Models\Account; | use App\Models\Account; | ||||||
| use App\Models\Company; | use App\Models\Company; | ||||||
| use App\Models\Affiliate; | use App\Models\Affiliate; | ||||||
|  | use App\Models\Country; | ||||||
|  | use App\Models\InvoiceDesign; | ||||||
|  | use Faker\Factory; | ||||||
| 
 | 
 | ||||||
| class UserTableSeeder extends Seeder | class UserTableSeeder extends Seeder | ||||||
| { | { | ||||||
| @ -14,11 +18,25 @@ class UserTableSeeder extends Seeder | |||||||
| 
 | 
 | ||||||
|         Eloquent::unguard(); |         Eloquent::unguard(); | ||||||
| 
 | 
 | ||||||
|  |         $faker = Faker\Factory::create(); | ||||||
|         $company = Company::create(); |         $company = Company::create(); | ||||||
|          |          | ||||||
|         $account = Account::create([ |         $account = Account::create([ | ||||||
|             //'name' => 'Test Account',
 |             'name' => $faker->name, | ||||||
|  |             'address1' => $faker->streetAddress, | ||||||
|  |             'address2' => $faker->secondaryAddress, | ||||||
|  |             'city' => $faker->city, | ||||||
|  |             'state' => $faker->state, | ||||||
|  |             'postal_code' => $faker->postcode, | ||||||
|  |             'country_id' => Country::all()->random()->id,  | ||||||
|             'account_key' => str_random(RANDOM_KEY_LENGTH), |             'account_key' => str_random(RANDOM_KEY_LENGTH), | ||||||
|  |             'invoice_terms' => $faker->text($faker->numberBetween(50, 300)), | ||||||
|  |             'work_phone' => $faker->phoneNumber, | ||||||
|  |             'work_email' => $faker->safeEmail, | ||||||
|  |             'invoice_design_id' => min(InvoiceDesign::all()->random()->id, 10), | ||||||
|  |             'header_font_id' => min(Font::all()->random()->id, 17), | ||||||
|  |             'body_font_id' => min(Font::all()->random()->id, 17), | ||||||
|  |             'primary_color' => $faker->hexcolor, | ||||||
|             'timezone_id' => 1, |             'timezone_id' => 1, | ||||||
|             'company_id' => $company->id, |             'company_id' => $company->id, | ||||||
|         ]); |         ]); | ||||||
| @ -30,6 +48,8 @@ class UserTableSeeder extends Seeder | |||||||
|             'password' => Hash::make(TEST_PASSWORD), |             'password' => Hash::make(TEST_PASSWORD), | ||||||
|             'registered' => true, |             'registered' => true, | ||||||
|             'confirmed' => true, |             'confirmed' => true, | ||||||
|  |             'notify_sent' => false, | ||||||
|  |             'notify_paid' => false, | ||||||
|         ]); |         ]); | ||||||
| 
 | 
 | ||||||
|         Affiliate::create([ |         Affiliate::create([ | ||||||
|  | |||||||
| @ -31196,7 +31196,7 @@ NINJA.decodeJavascript = function(invoice, javascript) | |||||||
|             field = toSnakeCase(field); |             field = toSnakeCase(field); | ||||||
|             var value = getDescendantProp(invoice, field); |             var value = getDescendantProp(invoice, field); | ||||||
|             if (match.indexOf('?') < 0 || value) { |             if (match.indexOf('?') < 0 || value) { | ||||||
|                 if (invoice.partial && field == 'balance_due') { |                 if (invoice.partial > 0 && field == 'balance_due') { | ||||||
|                     field = 'partial_due'; |                     field = 'partial_due'; | ||||||
|                 } else if (invoice.is_quote) { |                 } else if (invoice.is_quote) { | ||||||
|                     field = field.replace('invoice', 'quote'); |                     field = field.replace('invoice', 'quote'); | ||||||
| @ -31584,7 +31584,7 @@ NINJA.invoiceDetails = function(invoice) { | |||||||
|     ], |     ], | ||||||
|     [ |     [ | ||||||
|         {text: (invoice.is_quote ? invoiceLabels.valid_until : invoiceLabels.due_date)},  |         {text: (invoice.is_quote ? invoiceLabels.valid_until : invoiceLabels.due_date)},  | ||||||
|         {text: invoice.due_date} |         {text: invoice.is_recurring ? false : invoice.due_date} | ||||||
|     ] |     ] | ||||||
|     ]; |     ]; | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								public/css/built.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								public/css/built.css
									
									
									
									
										vendored
									
									
								
							| @ -2539,6 +2539,10 @@ ul.dropdown-menu, | |||||||
|     box-shadow: 0 0 10px 2px rgba(0,0,0,.05); |     box-shadow: 0 0 10px 2px rgba(0,0,0,.05); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .twitter-typeahead .tt-menu { | ||||||
|  |     overflow-x: hidden; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .panel-default, | .panel-default, | ||||||
| canvas { | canvas { | ||||||
|     border: 1px solid; |     border: 1px solid; | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								public/css/style.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								public/css/style.css
									
									
									
									
										vendored
									
									
								
							| @ -410,6 +410,10 @@ ul.dropdown-menu, | |||||||
|     box-shadow: 0 0 10px 2px rgba(0,0,0,.05); |     box-shadow: 0 0 10px 2px rgba(0,0,0,.05); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .twitter-typeahead .tt-menu { | ||||||
|  |     overflow-x: hidden; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .panel-default, | .panel-default, | ||||||
| canvas { | canvas { | ||||||
|     border: 1px solid; |     border: 1px solid; | ||||||
|  | |||||||
| @ -192,7 +192,7 @@ NINJA.decodeJavascript = function(invoice, javascript) | |||||||
|             field = toSnakeCase(field); |             field = toSnakeCase(field); | ||||||
|             var value = getDescendantProp(invoice, field); |             var value = getDescendantProp(invoice, field); | ||||||
|             if (match.indexOf('?') < 0 || value) { |             if (match.indexOf('?') < 0 || value) { | ||||||
|                 if (invoice.partial && field == 'balance_due') { |                 if (invoice.partial > 0 && field == 'balance_due') { | ||||||
|                     field = 'partial_due'; |                     field = 'partial_due'; | ||||||
|                 } else if (invoice.is_quote) { |                 } else if (invoice.is_quote) { | ||||||
|                     field = field.replace('invoice', 'quote'); |                     field = field.replace('invoice', 'quote'); | ||||||
| @ -580,7 +580,7 @@ NINJA.invoiceDetails = function(invoice) { | |||||||
|     ], |     ], | ||||||
|     [ |     [ | ||||||
|         {text: (invoice.is_quote ? invoiceLabels.valid_until : invoiceLabels.due_date)},  |         {text: (invoice.is_quote ? invoiceLabels.valid_until : invoiceLabels.due_date)},  | ||||||
|         {text: invoice.due_date} |         {text: invoice.is_recurring ? false : invoice.due_date} | ||||||
|     ] |     ] | ||||||
|     ]; |     ]; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1176,6 +1176,8 @@ $LANG = array( | |||||||
|     'page_size' => 'Page Size', |     'page_size' => 'Page Size', | ||||||
|     'live_preview_disabled' => 'Live preview has been disabled to support selected font', |     'live_preview_disabled' => 'Live preview has been disabled to support selected font', | ||||||
|     'invoice_number_padding' => 'Padding', |     'invoice_number_padding' => 'Padding', | ||||||
|  |     'preview' => 'Preview', | ||||||
|  |     'list_vendors' => 'List Vendors', | ||||||
| 
 | 
 | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -94,9 +94,9 @@ | |||||||
| 						</div> | 						</div> | ||||||
| 					@endif | 					@endif | ||||||
| 					@if (Utils::isNinjaProd()) | 					@if (Utils::isNinjaProd()) | ||||||
| 					{!! Former::actions( Button::success(trans('texts.plan_upgrade'))->large()->withAttributes(['onclick' => 'showChangePlan()'])->appendIcon(Icon::create('plus-sign'))) !!} | 					   {!! Former::actions( Button::success(trans('texts.plan_upgrade'))->large()->withAttributes(['onclick' => 'showChangePlan()'])->appendIcon(Icon::create('plus-sign'))) !!} | ||||||
| 					@else | 					@elseif (!$account->hasFeature(FEATURE_WHITE_LABEL)) | ||||||
| 					{!! Former::actions( Button::success(trans('texts.white_label_button'))->large()->withAttributes(['onclick' => 'loadImages("#whiteLabelModal");$("#whiteLabelModal").modal("show");'])->appendIcon(Icon::create('plus-sign'))) !!} | 					   {!! Former::actions( Button::success(trans('texts.white_label_button'))->large()->withAttributes(['onclick' => 'loadImages("#whiteLabelModal");$("#whiteLabelModal").modal("show");'])->appendIcon(Icon::create('plus-sign'))) !!} | ||||||
| 					@endif | 					@endif | ||||||
| 				@endif | 				@endif | ||||||
| 			</div> | 			</div> | ||||||
|  | |||||||
| @ -62,11 +62,14 @@ | |||||||
|                 <div id="{{ $field }}_template_preview"></div> |                 <div id="{{ $field }}_template_preview"></div> | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|  |         <p> <p/> | ||||||
|         <div class="row"> |         <div class="row"> | ||||||
|             <div class="col-md-12"> |             <div class="col-md-10"> | ||||||
|                 <p> <p/> |  | ||||||
|                 @include('partials/quill_toolbar', ['name' => $field]) |                 @include('partials/quill_toolbar', ['name' => $field]) | ||||||
|             </div> |             </div> | ||||||
|  |             <div class="col-md-2" style="padding-top:10px"> | ||||||
|  |                 {!! Button::primary(trans('texts.preview'))->withAttributes(['onclick' => 'serverPreview("'.$field.'")'])->small() !!} | ||||||
|  |             </div> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
| </div> | </div> | ||||||
|  | |||||||
| @ -25,11 +25,16 @@ | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     {!! Former::vertical_open()->addClass('warn-on-exit') !!} |     {!! Former::vertical_open()->addClass('warn-on-exit') !!} | ||||||
|     {!! Former::populate($account) !!} |  | ||||||
| 
 | 
 | ||||||
|     @foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_PAYMENT, REMINDER1, REMINDER2, REMINDER3] as $type) |     @foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_PAYMENT, REMINDER1, REMINDER2, REMINDER3] as $type) | ||||||
|         @foreach (['subject', 'template'] as $field) |         @foreach (['subject', 'template'] as $field) | ||||||
|             {!! Former::populateField("email_{$field}_{$type}", $templates[$type][$field]) !!} |             {{ Former::populateField("email_{$field}_{$type}", $templates[$type][$field]) }} | ||||||
|  |         @endforeach | ||||||
|  |     @endforeach | ||||||
|  | 
 | ||||||
|  |     @foreach ([REMINDER1, REMINDER2, REMINDER3] as $type) | ||||||
|  |         @foreach (['enable', 'num_days', 'direction', 'field'] as $field) | ||||||
|  |             {{ Former::populateField("{$field}_{$type}", $account->{"{$field}_{$type}"}) }} | ||||||
|         @endforeach |         @endforeach | ||||||
|     @endforeach |     @endforeach | ||||||
| 
 | 
 | ||||||
| @ -80,6 +85,26 @@ | |||||||
|     </div> |     </div> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |     <div class="modal fade" id="templatePreviewModal" tabindex="-1" role="dialog" aria-labelledby="templatePreviewModalLabel" aria-hidden="true"> | ||||||
|  |         <div class="modal-dialog" style="width:800px"> | ||||||
|  |             <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="templatePreviewModalLabel">{{ trans('texts.preview') }}</h4> | ||||||
|  |                 </div> | ||||||
|  | 
 | ||||||
|  |                 <div class="modal-body"> | ||||||
|  |                     <iframe id="server-preview" frameborder="1" width="100%" height="500px"/></iframe> | ||||||
|  |                 </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> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     <div class="modal fade" id="templateHelpModal" tabindex="-1" role="dialog" aria-labelledby="templateHelpModalLabel" aria-hidden="true"> |     <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-dialog" style="min-width:150px"> | ||||||
|             <div class="modal-content"> |             <div class="modal-content"> | ||||||
| @ -158,6 +183,22 @@ | |||||||
|             }             |             }             | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         function serverPreview(field) { | ||||||
|  |             console.log(field); | ||||||
|  |             $('#templatePreviewModal').modal('show'); | ||||||
|  |             var template = $('#email_template_' + field).val(); | ||||||
|  |             var url = '{{ URL::to('settings/email_preview') }}?template=' + template; | ||||||
|  |             $('#server-preview').attr('src', url).load(function() { | ||||||
|  |                 // disable links in the preview 
 | ||||||
|  |                 $('iframe').contents().find('a').each(function(index) { | ||||||
|  |                     $(this).on('click', function(event) { | ||||||
|  |                         event.preventDefault(); | ||||||
|  |                         event.stopPropagation(); | ||||||
|  |                     }); | ||||||
|  |                 }); | ||||||
|  |             });             | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         $(function() { |         $(function() { | ||||||
|             for (var i=0; i<entityTypes.length; i++) { |             for (var i=0; i<entityTypes.length; i++) { | ||||||
|                 var entityType = entityTypes[i]; |                 var entityType = entityTypes[i]; | ||||||
|  | |||||||
| @ -12,30 +12,30 @@ | |||||||
|     </tr> |     </tr> | ||||||
|     <tr> |     <tr> | ||||||
|         <td style="border-collapse: collapse;"> |         <td style="border-collapse: collapse;"> | ||||||
|             <table cellpadding="10" cellspacing="0" border="0" bgcolor="{{ $account->primary_color ?: '#2E2B2B' }}" width="580" align="center" class="header"  |             <table cellpadding="10" cellspacing="0" border="0" bgcolor="#F4F5F5" width="600" align="center"  | ||||||
|                 style="border-bottom-width: 6px; border-bottom-color: {{ $account->primary_color ?: '#2E2B2B' }}; border-bottom-style: solid;"> |                 class="header" style="border-top-width: 6px; border-top-color: {{ $account->primary_color ?: '#2E2B2B' }}; border-top-style: solid;"> | ||||||
|                 <tr> |                 <tr> | ||||||
|                     <td class="logo" width="205" style="border-collapse: collapse; vertical-align: middle; line-height: 16px;" valign="middle"> |                     <td class="logo" width="208" style="border-collapse: collapse; vertical-align: middle;" valign="middle"> | ||||||
|                         @include('emails.partials.account_logo') |                         @include('emails.partials.account_logo') | ||||||
|                     </td> |                     </td> | ||||||
|                     <td width="183" style="border-collapse: collapse; vertical-align: middle; line-height: 16px;" valign="middle"> |                     <td width="183" style="border-collapse: collapse; vertical-align: middle;" valign="middle"> | ||||||
|                         <p class="left" style="line-height: 22px; margin: 3px 0 0; padding: 0;"> |                         <p class="left" style="line-height: 22px; margin: 0; padding: 2px 0 0;"> | ||||||
|                             @if ($invoice->due_date) |                             @if ($invoice->due_date) | ||||||
|                                 <span style="font-size: 11px; color: #8f8d8e;"> |                                 <span style="font-size: 11px; color: #8f8d8e;"> | ||||||
|                                     {{ strtoupper(trans('texts.due_by', ['date' => $account->formatDate($invoice->due_date)])) }} |                                     {{ strtoupper(trans('texts.due_by', ['date' => $account->formatDate($invoice->due_date)])) }} | ||||||
|                                 </span><br /> |                                 </span><br /> | ||||||
|                             @endif |                             @endif | ||||||
|                             <span style="font-size: 19px; color: #FFFFFF;"> |                             <span style="font-size: 18px;"> | ||||||
|                                 {{ trans("texts.{$entityType}") }} {{ $invoice->invoice_number }} |                                 {{ trans("texts.{$entityType}") }} {{ $invoice->invoice_number }} | ||||||
|                             </span> |                             </span> | ||||||
|                         </p> |                         </p> | ||||||
|                     </td> |                     </td> | ||||||
|                     <td style="border-collapse: collapse; vertical-align: middle; line-height: 16px;" valign="middle"> |                     <td style="border-collapse: collapse; vertical-align: middle;" valign="middle"> | ||||||
|                         <p style="margin: 0; padding: 0;"> |                         <p class="right" style="line-height: 14px; margin: 0; padding: 0;"> | ||||||
|                             <span style="font-size: 12px; color: #8f8d8e;"> |                             <span style="font-size: 15px; color: #231F20;"> | ||||||
|                                 {{ strtoupper(trans('texts.' . $invoice->present()->balanceDueLabel)) }}: |                                 {{ trans('texts.' . $invoice->present()->balanceDueLabel) }}: | ||||||
|                             </span><br /> |                             </span><br /> | ||||||
|                             <span class="total" style="font-size: 27px; color: #FFFFFF; margin-top: 5px;display: block;"> |                             <span class="total" style="font-size: 26px; display: block;margin-top: 5px;"> | ||||||
|                                 {{ $account->formatMoney($invoice->getRequestedAmount(), $client) }} |                                 {{ $account->formatMoney($invoice->getRequestedAmount(), $client) }} | ||||||
|                             </span> |                             </span> | ||||||
|                         </p> |                         </p> | ||||||
|  | |||||||
| @ -12,30 +12,30 @@ | |||||||
|     </tr> |     </tr> | ||||||
|     <tr> |     <tr> | ||||||
|         <td style="border-collapse: collapse;"> |         <td style="border-collapse: collapse;"> | ||||||
|             <table cellpadding="10" cellspacing="0" border="0" bgcolor="#F4F5F5" width="580" align="center"  |             <table cellpadding="10" cellspacing="0" border="0" bgcolor="{{ $account->primary_color ?: '#2E2B2B' }}" width="600" align="center" class="header"  | ||||||
|                 class="header" style="border-top-width: 6px; border-top-color: {{ $account->primary_color ?: '#2E2B2B' }}; border-top-style: solid;"> |                 style="border-bottom-width: 6px; border-bottom-color: {{ $account->primary_color ?: '#2E2B2B' }}; border-bottom-style: solid;"> | ||||||
|                 <tr> |                 <tr> | ||||||
|                     <td class="logo" width="208" style="border-collapse: collapse; vertical-align: middle;" valign="middle"> |                     <td class="logo" width="205" style="border-collapse: collapse; vertical-align: middle; line-height: 16px;" valign="middle"> | ||||||
|                         @include('emails.partials.account_logo') |                         @include('emails.partials.account_logo') | ||||||
|                     </td> |                     </td> | ||||||
|                     <td width="183" style="border-collapse: collapse; vertical-align: middle;" valign="middle"> |                     <td width="183" style="border-collapse: collapse; vertical-align: middle; line-height: 16px;" valign="middle"> | ||||||
|                         <p class="left" style="line-height: 22px; margin: 0; padding: 2px 0 0;"> |                         <p class="left" style="line-height: 22px; margin: 3px 0 0; padding: 0;"> | ||||||
|                             @if ($invoice->due_date) |                             @if ($invoice->due_date) | ||||||
|                                 <span style="font-size: 11px; color: #8f8d8e;"> |                                 <span style="font-size: 11px; color: #8f8d8e;"> | ||||||
|                                     {{ strtoupper(trans('texts.due_by', ['date' => $account->formatDate($invoice->due_date)])) }} |                                     {{ strtoupper(trans('texts.due_by', ['date' => $account->formatDate($invoice->due_date)])) }} | ||||||
|                                 </span><br /> |                                 </span><br /> | ||||||
|                             @endif |                             @endif | ||||||
|                             <span style="font-size: 18px;"> |                             <span style="font-size: 19px; color: #FFFFFF;"> | ||||||
|                                 {{ trans("texts.{$entityType}") }} {{ $invoice->invoice_number }} |                                 {{ trans("texts.{$entityType}") }} {{ $invoice->invoice_number }} | ||||||
|                             </span> |                             </span> | ||||||
|                         </p> |                         </p> | ||||||
|                     </td> |                     </td> | ||||||
|                     <td style="border-collapse: collapse; vertical-align: middle;" valign="middle"> |                     <td style="border-collapse: collapse; vertical-align: middle; line-height: 16px;" valign="middle"> | ||||||
|                         <p class="right" style="line-height: 14px; margin: 0; padding: 0;"> |                         <p style="margin: 0; padding: 0;"> | ||||||
|                             <span style="font-size: 15px; color: #231F20;"> |                             <span style="font-size: 12px; color: #8f8d8e;"> | ||||||
|                                 {{ trans('texts.' . $invoice->present()->balanceDueLabel) }}: |                                 {{ strtoupper(trans('texts.' . $invoice->present()->balanceDueLabel)) }}: | ||||||
|                             </span><br /> |                             </span><br /> | ||||||
|                             <span class="total" style="font-size: 26px; display: block;margin-top: 5px;"> |                             <span class="total" style="font-size: 27px; color: #FFFFFF; margin-top: 5px;display: block;"> | ||||||
|                                 {{ $account->formatMoney($invoice->getRequestedAmount(), $client) }} |                                 {{ $account->formatMoney($invoice->getRequestedAmount(), $client) }} | ||||||
|                             </span> |                             </span> | ||||||
|                         </p> |                         </p> | ||||||
| @ -3,7 +3,7 @@ | |||||||
|         <a href="{{ $account->website }}" style="color: #19BB40; text-decoration: underline;"> |         <a href="{{ $account->website }}" style="color: #19BB40; text-decoration: underline;"> | ||||||
|     @endif |     @endif | ||||||
| 
 | 
 | ||||||
|     <img src="{{ $message->embed($account->getLogoURL()) }}" style="max-height:50px; max-width:140px; margin-left: 33px;" /> |     <img src="{{ isset($message) ? $message->embed($account->getLogoURL()) : $account->getLogoURL() }}" style="max-height:50px; max-width:140px; margin-left: 33px;" /> | ||||||
| 
 | 
 | ||||||
|     @if ($account->website) |     @if ($account->website) | ||||||
|         </a> |         </a> | ||||||
|  | |||||||
| @ -93,14 +93,14 @@ | |||||||
|     <div class="container main-container"> |     <div class="container main-container"> | ||||||
| 
 | 
 | ||||||
|         <div class="row"> |         <div class="row"> | ||||||
|             <div class="col-md-3 logo"> |             <div class="col-md-6 logo"> | ||||||
|                 @if ($account->hasLogo()) |                 @if ($account->hasLogo()) | ||||||
|                     {!! HTML::image($account->getLogoURL()) !!} |                     {!! HTML::image($account->getLogoURL()) !!} | ||||||
|                 @else |                 @else | ||||||
|                     <h2>{{ $account->name}}</h2> |                     <h2>{{ $account->name}}</h2> | ||||||
|                 @endif |                 @endif | ||||||
|             </div> |             </div> | ||||||
|             <div class="col-md-3 col-md-offset-3 address-details"> |             <div class="col-md-3 address-details"> | ||||||
|                 @if ($account->address1) |                 @if ($account->address1) | ||||||
|                     {{ $account->address1 }}<br/> |                     {{ $account->address1 }}<br/> | ||||||
|                 @endif |                 @endif | ||||||
|  | |||||||
| @ -73,7 +73,12 @@ | |||||||
| 				<div class="form-group"> | 				<div class="form-group"> | ||||||
| 					<label for="client" class="control-label col-lg-4 col-sm-4">{{ trans('texts.client') }}</label> | 					<label for="client" class="control-label col-lg-4 col-sm-4">{{ trans('texts.client') }}</label> | ||||||
| 					<div class="col-lg-8 col-sm-8"> | 					<div class="col-lg-8 col-sm-8"> | ||||||
|                         <h4><div data-bind="text: getClientDisplayName(ko.toJS(client()))"></div></h4> |                         <h4> | ||||||
|  |                             <span data-bind="text: getClientDisplayName(ko.toJS(client()))"></span> | ||||||
|  |                             @if ($invoice->client->is_deleted) | ||||||
|  |                                   <div class="label label-danger">{{ trans('texts.deleted') }}</div> | ||||||
|  |                             @endif | ||||||
|  |                         </h4> | ||||||
|                          |                          | ||||||
|                         @can('view', $invoice->client) |                         @can('view', $invoice->client) | ||||||
|                             @can('edit', $invoice->client) |                             @can('edit', $invoice->client) | ||||||
| @ -109,6 +114,7 @@ | |||||||
| 							<input type="checkbox" value="1" data-bind="checked: send_invoice, attr: {id: $index() + '_check', name: 'client[contacts][' + $index() + '][send_invoice]'}"> | 							<input type="checkbox" value="1" data-bind="checked: send_invoice, attr: {id: $index() + '_check', name: 'client[contacts][' + $index() + '][send_invoice]'}"> | ||||||
| 							<span data-bind="html: email.display"></span> | 							<span data-bind="html: email.display"></span> | ||||||
|                         </label> |                         </label> | ||||||
|  |                         @if ( ! $invoice->is_deleted && ! $invoice->client->is_deleted) | ||||||
|                         <span data-bind="visible: !$root.invoice().is_recurring()"> |                         <span data-bind="visible: !$root.invoice().is_recurring()"> | ||||||
|                             <span data-bind="html: $data.view_as_recipient"></span>   |                             <span data-bind="html: $data.view_as_recipient"></span>   | ||||||
|                             @if (Utils::isConfirmed()) |                             @if (Utils::isConfirmed()) | ||||||
| @ -119,6 +125,7 @@ | |||||||
|                                     style: {color: $data.info_color}"></span>
 |                                     style: {color: $data.info_color}"></span>
 | ||||||
|                             @endif |                             @endif | ||||||
|                         </span> |                         </span> | ||||||
|  |                         @endif | ||||||
| 					</div> | 					</div> | ||||||
| 				</div> | 				</div> | ||||||
| 			</div> | 			</div> | ||||||
|  | |||||||
| @ -66,6 +66,7 @@ | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         var currency = currencyMap[currencyId]; |         var currency = currencyMap[currencyId]; | ||||||
|  |         var precision = currency.precision; | ||||||
|         var thousand = currency.thousand_separator; |         var thousand = currency.thousand_separator; | ||||||
|         var decimal = currency.decimal_separator; |         var decimal = currency.decimal_separator; | ||||||
|         var code = currency.code; |         var code = currency.code; | ||||||
| @ -82,7 +83,7 @@ | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         value = accounting.formatMoney(value, '', 2, thousand, decimal); |         value = accounting.formatMoney(value, '', precision, thousand, decimal); | ||||||
|         var symbol = currency.symbol; |         var symbol = currency.symbol; | ||||||
| 
 | 
 | ||||||
|         if (hideSymbol) { |         if (hideSymbol) { | ||||||
|  | |||||||
| @ -96,7 +96,7 @@ class OnlinePaymentCest | |||||||
|         $I->click('table.invoice-table tbody tr:nth-child(1) .tt-selectable'); |         $I->click('table.invoice-table tbody tr:nth-child(1) .tt-selectable'); | ||||||
|         $I->checkOption('#auto_bill'); |         $I->checkOption('#auto_bill'); | ||||||
|         $I->executeJS('preparePdfData(\'email\')'); |         $I->executeJS('preparePdfData(\'email\')'); | ||||||
|         $I->wait(2); |         $I->wait(3); | ||||||
|         $I->see("$0.00"); |         $I->see("$0.00"); | ||||||
| 
 | 
 | ||||||
|    } |    } | ||||||
|  | |||||||
| @ -84,6 +84,7 @@ class TaxRatesCest | |||||||
|         // check total is right after saving
 |         // check total is right after saving
 | ||||||
|         $I->see("\${$total}"); |         $I->see("\${$total}"); | ||||||
|         $I->amOnPage('/invoices'); |         $I->amOnPage('/invoices'); | ||||||
|  |         $I->wait(2); | ||||||
|          |          | ||||||
|         // check total is right in list view
 |         // check total is right in list view
 | ||||||
|         $I->see("\${$total}"); |         $I->see("\${$total}"); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user