mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-09 20:52:56 +01:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
a8bc3f0663
@ -45,7 +45,7 @@ class SendReminders extends Command
|
||||
|
||||
foreach ($invoices as $invoice) {
|
||||
if ($reminder = $invoice->getReminder()) {
|
||||
$this->info('Send to' . $invoice->id);
|
||||
$this->info('Send to ' . $invoice->id);
|
||||
$this->mailer->sendInvoice($invoice, $reminder);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
<?php namespace App\Http\Controllers;
|
||||
|
||||
use Auth;
|
||||
use Event;
|
||||
use File;
|
||||
use Image;
|
||||
use Input;
|
||||
@ -227,6 +226,17 @@ class AccountController extends BaseController
|
||||
|
||||
private function showCompanyDetails()
|
||||
{
|
||||
// check that logo is less than the max file size
|
||||
$account = Auth::user()->account;
|
||||
if ($account->hasLogo()) {
|
||||
$filename = $account->getLogoPath();
|
||||
$bytes = File::size($filename);
|
||||
if ($bytes > MAX_LOGO_FILE_SIZE * 1000) {
|
||||
$bytes /= 1000;
|
||||
Session::flash('warning', trans('texts.logo_too_large', ['size' => round($bytes) . 'KB']));
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'account' => Account::with('users')->findOrFail(Auth::user()->account_id),
|
||||
'countries' => Cache::get('countries'),
|
||||
@ -842,7 +852,7 @@ class AccountController extends BaseController
|
||||
{
|
||||
$rules = array(
|
||||
'name' => 'required',
|
||||
'logo' => 'sometimes|max:200|mimes:jpeg,gif,png',
|
||||
'logo' => 'sometimes|max:' . MAX_LOGO_FILE_SIZE . '|mimes:jpeg,gif,png',
|
||||
);
|
||||
|
||||
$validator = Validator::make(Input::all(), $rules);
|
||||
@ -905,7 +915,7 @@ class AccountController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
Event::fire(new UserSettingsChanged());
|
||||
event(new UserSettingsChanged());
|
||||
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
return Redirect::to('settings/' . ACCOUNT_COMPANY_DETAILS);
|
||||
@ -940,7 +950,7 @@ class AccountController extends BaseController
|
||||
|
||||
$user->save();
|
||||
|
||||
Event::fire(new UserSettingsChanged());
|
||||
event(new UserSettingsChanged());
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
return Redirect::to('settings/' . ACCOUNT_USER_DETAILS);
|
||||
}
|
||||
@ -957,7 +967,7 @@ class AccountController extends BaseController
|
||||
$account->military_time = Input::get('military_time') ? true : false;
|
||||
$account->save();
|
||||
|
||||
Event::fire(new UserSettingsChanged());
|
||||
event(new UserSettingsChanged());
|
||||
|
||||
Session::flash('message', trans('texts.updated_settings'));
|
||||
return Redirect::to('settings/' . ACCOUNT_LOCALIZATION);
|
||||
|
@ -110,6 +110,7 @@ class DashboardController extends BaseController
|
||||
->leftJoin('invoices', 'invoices.id', '=', 'payments.invoice_id')
|
||||
->where('payments.account_id', '=', Auth::user()->account_id)
|
||||
->where('payments.deleted_at', '=', null)
|
||||
->where('invoices.deleted_at', '=', null)
|
||||
->where('clients.deleted_at', '=', null)
|
||||
->where('contacts.deleted_at', '=', null)
|
||||
->where('contacts.is_primary', '=', true)
|
||||
|
@ -4,6 +4,7 @@ use Auth;
|
||||
use Utils;
|
||||
use Response;
|
||||
use Input;
|
||||
use Validator;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Client;
|
||||
use App\Models\Contact;
|
||||
@ -102,12 +103,18 @@ class InvoiceApiController extends Controller
|
||||
}
|
||||
|
||||
if (isset($data['email'])) {
|
||||
$client = Client::scope()->whereHas('contacts', function($query) use ($data) {
|
||||
$query->where('email', '=', $data['email']);
|
||||
$email = $data['email'];
|
||||
$client = Client::scope()->whereHas('contacts', function($query) use ($email) {
|
||||
$query->where('email', '=', $email);
|
||||
})->first();
|
||||
|
||||
if (!$client) {
|
||||
$clientData = ['contact' => ['email' => $data['email']]];
|
||||
$validator = Validator::make(['email'=>$email], ['email' => 'email']);
|
||||
if ($validator->fails()) {
|
||||
return $validator->message();
|
||||
}
|
||||
|
||||
$clientData = ['contact' => ['email' => $email]];
|
||||
foreach (['name', 'private_notes'] as $field) {
|
||||
if (isset($data[$field])) {
|
||||
$clientData[$field] = $data[$field];
|
||||
@ -118,10 +125,8 @@ class InvoiceApiController extends Controller
|
||||
$clientData[$field] = $data[$field];
|
||||
}
|
||||
}
|
||||
$error = $this->clientRepo->getErrors($clientData);
|
||||
if (!$error) {
|
||||
$client = $this->clientRepo->save($clientData);
|
||||
}
|
||||
|
||||
$client = $this->clientRepo->save($clientData);
|
||||
}
|
||||
} else if (isset($data['client_id'])) {
|
||||
$client = Client::scope($data['client_id'])->first();
|
||||
|
@ -203,7 +203,10 @@ class InvoiceController extends BaseController
|
||||
public function edit($publicId, $clone = false)
|
||||
{
|
||||
$account = Auth::user()->account;
|
||||
$invoice = Invoice::scope($publicId)->withTrashed()->with('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items')->firstOrFail();
|
||||
$invoice = Invoice::scope($publicId)
|
||||
->with('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items')
|
||||
->withTrashed()
|
||||
->firstOrFail();
|
||||
$entityType = $invoice->getEntityType();
|
||||
|
||||
$contactIds = DB::table('invitations')
|
||||
@ -270,6 +273,7 @@ class InvoiceController extends BaseController
|
||||
$lastSent = ($invoice->is_recurring && $invoice->last_sent_date) ? $invoice->recurring_invoices->last() : null;
|
||||
|
||||
$data = array(
|
||||
'clients' => Client::scope()->withTrashed()->with('contacts', 'country')->whereId($invoice->client_id)->get(),
|
||||
'entityType' => $entityType,
|
||||
'showBreadcrumbs' => $clone,
|
||||
'invoice' => $invoice,
|
||||
@ -282,7 +286,7 @@ class InvoiceController extends BaseController
|
||||
'actions' => $actions,
|
||||
'lastSent' => $lastSent);
|
||||
$data = array_merge($data, self::getViewModel());
|
||||
|
||||
|
||||
if ($clone) {
|
||||
$data['formIsChanged'] = true;
|
||||
}
|
||||
@ -327,6 +331,7 @@ class InvoiceController extends BaseController
|
||||
$invoice->public_id = 0;
|
||||
|
||||
$data = [
|
||||
'clients' => Client::scope()->with('contacts', 'country')->orderBy('name')->get(),
|
||||
'entityType' => $invoice->getEntityType(),
|
||||
'invoice' => $invoice,
|
||||
'method' => 'POST',
|
||||
@ -361,7 +366,6 @@ class InvoiceController extends BaseController
|
||||
'account' => Auth::user()->account->load('country'),
|
||||
'products' => Product::scope()->with('default_tax_rate')->orderBy('id')->get(),
|
||||
'countries' => Cache::get('countries'),
|
||||
'clients' => Client::scope()->with('contacts', 'country')->orderBy('name')->get(),
|
||||
'taxRates' => TaxRate::scope()->orderBy('name')->get(),
|
||||
'currencies' => Cache::get('currencies'),
|
||||
'languages' => Cache::get('languages'),
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?php
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Routes
|
||||
@ -334,6 +333,7 @@ if (!defined('CONTACT_EMAIL')) {
|
||||
define('MAX_NUM_USERS', 20);
|
||||
define('MAX_SUBDOMAIN_LENGTH', 30);
|
||||
define('MAX_IFRAME_URL_LENGTH', 250);
|
||||
define('MAX_LOGO_FILE_SIZE', 200); // KB
|
||||
define('DEFAULT_FONT_SIZE', 9);
|
||||
define('DEFAULT_SEND_RECURRING_HOUR', 8);
|
||||
|
||||
@ -535,4 +535,4 @@ if (Auth::check() && Auth::user()->id === 1)
|
||||
{
|
||||
Auth::loginUsingId(1);
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
@ -207,12 +207,12 @@ class Utils
|
||||
$data = [
|
||||
'context' => $context,
|
||||
'user_id' => Auth::check() ? Auth::user()->id : 0,
|
||||
'account_id' => Auth::check() ? Auth::user()->account_id : 0,
|
||||
'user_name' => Auth::check() ? Auth::user()->getDisplayName() : '',
|
||||
'url' => Input::get('url', Request::url()),
|
||||
'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '',
|
||||
'ip' => Request::getClientIp(),
|
||||
'count' => Session::get('error_count', 0),
|
||||
//'input' => Input::all()
|
||||
];
|
||||
|
||||
Log::error($error."\n", $data);
|
||||
|
@ -15,6 +15,7 @@ use App\Events\QuoteInvitationWasEmailed;
|
||||
class Invoice extends EntityModel implements BalanceAffecting
|
||||
{
|
||||
use PresentableTrait;
|
||||
use OwnedByClientTrait;
|
||||
use SoftDeletes {
|
||||
SoftDeletes::trashed as parentTrashed;
|
||||
}
|
||||
|
13
app/Models/OwnedByClientTrait.php
Normal file
13
app/Models/OwnedByClientTrait.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php namespace App\Models;
|
||||
|
||||
trait OwnedByClientTrait
|
||||
{
|
||||
public function isClientTrashed()
|
||||
{
|
||||
if (!$this->client) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->client->trashed();
|
||||
}
|
||||
}
|
@ -23,8 +23,10 @@ class ContactMailer extends Mailer
|
||||
$client = $invoice->client;
|
||||
$account = $invoice->account;
|
||||
|
||||
if ($invoice->trashed() || $client->trashed()) {
|
||||
return false;
|
||||
if ($client->trashed()) {
|
||||
return trans('texts.email_errors.inactive_client');
|
||||
} elseif ($invoice->trashed()) {
|
||||
return trans('texts.email_errors.inactive_invoice');
|
||||
}
|
||||
|
||||
$account->loadLocalizationSettings($client);
|
||||
@ -38,7 +40,8 @@ class ContactMailer extends Mailer
|
||||
}
|
||||
|
||||
foreach ($invoice->invitations as $invitation) {
|
||||
if ($this->sendInvitation($invitation, $invoice, $emailTemplate, $emailSubject, $pdfString)) {
|
||||
$response = $this->sendInvitation($invitation, $invoice, $emailTemplate, $emailSubject, $pdfString);
|
||||
if ($response === true) {
|
||||
$sent = true;
|
||||
}
|
||||
}
|
||||
@ -53,7 +56,7 @@ class ContactMailer extends Mailer
|
||||
}
|
||||
}
|
||||
|
||||
return $sent ?: trans('texts.email_error');
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function sendInvitation($invitation, $invoice, $body, $subject, $pdfString)
|
||||
@ -70,12 +73,14 @@ class ContactMailer extends Mailer
|
||||
}
|
||||
}
|
||||
|
||||
if (!$user->email || !$user->confirmed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$invitation->contact->email || $invitation->contact->trashed()) {
|
||||
return false;
|
||||
if (!$user->email || !$user->registered) {
|
||||
return trans('texts.email_errors.user_unregistered');
|
||||
} elseif (!$user->confirmed) {
|
||||
return trans('texts.email_errors.user_unconfirmed');
|
||||
} elseif (!$invitation->contact->email) {
|
||||
return trans('texts.email_errors.invalid_contact_email');
|
||||
} elseif ($invitation->contact->trashed()) {
|
||||
return trans('texts.email_errors.inactive_contact');
|
||||
}
|
||||
|
||||
$variables = [
|
||||
@ -108,7 +113,7 @@ class ContactMailer extends Mailer
|
||||
if ($response === true) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ class ClientRepository extends BaseRepository
|
||||
$contacts = isset($data['contact']) ? [$data['contact']] : $data['contacts'];
|
||||
$contactIds = [];
|
||||
|
||||
foreach ($data['contacts'] as $contact) {
|
||||
foreach ($contacts as $contact) {
|
||||
$contact = $client->addContact($contact, $first);
|
||||
$contactIds[] = $contact->public_id;
|
||||
$first = false;
|
||||
|
@ -918,4 +918,14 @@ return array(
|
||||
'country' => 'Country',
|
||||
'include' => 'Include',
|
||||
|
||||
'logo_too_large' => 'Your logo is :size, for better performance we suggest uploading an image file less than 200KB',
|
||||
'email_errors' => [
|
||||
'inactive_client' => 'Emails can not be sent to inactive clients',
|
||||
'inactive_contact' => 'Emails can not be sent to inactive contacts',
|
||||
'inactive_invoice' => 'Emails can not be sent to inactive invoices',
|
||||
'user_unregistered' => 'Please register your account to send emails',
|
||||
'user_unconfirmed' => 'Please confirm your account to send emails',
|
||||
'invalid_contact_email' => 'Invalid contact email',
|
||||
]
|
||||
|
||||
);
|
||||
|
@ -22,7 +22,7 @@
|
||||
->addClass('warn-on-exit')
|
||||
->autocomplete('on')
|
||||
->rules([
|
||||
'name' => 'required'
|
||||
'name' => 'required'
|
||||
]) !!}
|
||||
|
||||
{{ Former::populate($account) }}
|
||||
@ -37,24 +37,29 @@
|
||||
<h3 class="panel-title">{!! trans('texts.details') !!}</h3>
|
||||
</div>
|
||||
<div class="panel-body form-padding-right">
|
||||
|
||||
{!! Former::text('name') !!}
|
||||
|
||||
{!! Former::text('name') !!}
|
||||
{!! Former::text('id_number') !!}
|
||||
{!! Former::text('vat_number') !!}
|
||||
{!! Former::text('work_email') !!}
|
||||
{!! Former::text('work_phone') !!}
|
||||
{!! Former::text('work_email') !!}
|
||||
{!! Former::text('work_phone') !!}
|
||||
{!! Former::file('logo')->max(2, 'MB')->accept('image')->inlineHelp(trans('texts.logo_help')) !!}
|
||||
|
||||
|
||||
@if ($account->hasLogo())
|
||||
<center>
|
||||
{!! HTML::image($account->getLogoPath().'?no_cache='.time(), 'Logo', ['width' => 200]) !!}
|
||||
<a href="#" onclick="deleteLogo()">{{ trans('texts.remove_logo') }}</a>
|
||||
</center><br/>
|
||||
@endif
|
||||
@if ($account->hasLogo())
|
||||
<div class="form-group">
|
||||
<div class="col-lg-4 col-sm-4"></div>
|
||||
<div class="col-lg-8 col-sm-8">
|
||||
<a href="/{{ $account->getLogoPath().'?no_cache='.time() }}" target="_blank">
|
||||
{!! HTML::image($account->getLogoPath().'?no_cache='.time(), 'Logo', ['width' => 200]) !!}
|
||||
</a>
|
||||
<a href="#" onclick="deleteLogo()">{{ trans('texts.remove_logo') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{!! Former::select('size_id')->addOption('','')->fromQuery($sizes, 'name', 'id') !!}
|
||||
{!! Former::select('industry_id')->addOption('','')->fromQuery($industries, 'name', 'id') !!}
|
||||
{!! Former::select('size_id')->addOption('','')->fromQuery($sizes, 'name', 'id') !!}
|
||||
{!! Former::select('industry_id')->addOption('','')->fromQuery($industries, 'name', 'id') !!}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
@ -392,19 +392,18 @@
|
||||
|
||||
{!! Button::primary(trans('texts.download_pdf'))->withAttributes(array('onclick' => 'onDownloadClick()'))->appendIcon(Icon::create('download-alt')) !!}
|
||||
|
||||
@if (!$invoice->trashed())
|
||||
|
||||
@if ($invoice->isClientTrashed())
|
||||
<!-- do nothing -->
|
||||
@elseif ($invoice->trashed())
|
||||
{!! Button::success(trans('texts.restore'))->withAttributes(['onclick' => 'submitBulkAction("restore")'])->appendIcon(Icon::create('cloud-download')) !!}
|
||||
@elseif (!$invoice->trashed())
|
||||
{!! Button::success(trans("texts.save_{$entityType}"))->withAttributes(array('id' => 'saveButton', 'onclick' => 'onSaveClick()'))->appendIcon(Icon::create('floppy-disk')) !!}
|
||||
{!! Button::info(trans("texts.email_{$entityType}"))->withAttributes(array('id' => 'emailButton', 'onclick' => 'onEmailClick()'))->appendIcon(Icon::create('send')) !!}
|
||||
|
||||
@if ($invoice->id)
|
||||
{!! DropdownButton::normal(trans('texts.more_actions'))
|
||||
->withContents($actions)
|
||||
->dropup() !!}
|
||||
@endif
|
||||
|
||||
@elseif ($invoice->trashed())
|
||||
{!! Button::success(trans('texts.restore'))->withAttributes(['onclick' => 'submitBulkAction("restore")'])->appendIcon(Icon::create('cloud-download')) !!}
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@ -1007,16 +1006,17 @@
|
||||
}
|
||||
|
||||
function isEmailValid() {
|
||||
var isValid = false;
|
||||
var isValid = true;
|
||||
var sendTo = false;
|
||||
var client = model.invoice().client();
|
||||
for (var i=0; i<client.contacts().length; i++) {
|
||||
var contact = client.contacts()[i];
|
||||
var contact = client.contacts()[i];
|
||||
if ( ! contact.send_invoice()) {
|
||||
continue;
|
||||
}
|
||||
if (isValidEmailAddress(contact.email())) {
|
||||
isValid = true;
|
||||
if (contact.send_invoice() || client.contacts().length == 1) {
|
||||
sendTo = true;
|
||||
}
|
||||
sendTo = true;
|
||||
} else {
|
||||
isValid = false;
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user