From 5e62d7d2968ae3a481135bbbb721f081b820892c Mon Sep 17 00:00:00 2001 From: Joshua Dwire Date: Thu, 24 Mar 2016 18:15:52 -0400 Subject: [PATCH] Allow documents to be attached to expenses --- app/Http/Controllers/ExpenseController.php | 24 ++-- app/Http/Controllers/InvoiceController.php | 12 +- .../Controllers/PublicClientController.php | 18 +-- app/Models/Document.php | 6 +- app/Models/Expense.php | 19 +++ app/Models/Invoice.php | 35 +++++ app/Ninja/Mailers/ContactMailer.php | 17 ++- app/Ninja/Presenters/ExpensePresenter.php | 7 +- app/Ninja/Repositories/DocumentRepository.php | 12 +- app/Ninja/Repositories/ExpenseRepository.php | 49 ++++++- app/Ninja/Repositories/InvoiceRepository.php | 1 + app/Services/ExpenseService.php | 4 +- public/built.js | 16 ++- public/css/built.css | 15 +- public/css/style.css | 15 +- public/js/pdf.pdfmake.js | 16 ++- resources/lang/en/texts.php | 2 + resources/views/expenses/edit.blade.php | 131 +++++++++++++++++- resources/views/invoices/edit.blade.php | 59 +++++--- resources/views/invoices/history.blade.php | 9 +- resources/views/invoices/knockout.blade.php | 28 ++++ resources/views/invoices/view.blade.php | 16 ++- 22 files changed, 426 insertions(+), 85 deletions(-) diff --git a/app/Http/Controllers/ExpenseController.php b/app/Http/Controllers/ExpenseController.php index b1fd28e41941..7e6b254f9d01 100644 --- a/app/Http/Controllers/ExpenseController.php +++ b/app/Http/Controllers/ExpenseController.php @@ -99,7 +99,7 @@ class ExpenseController extends BaseController public function edit($publicId) { - $expense = Expense::scope($publicId)->firstOrFail(); + $expense = Expense::scope($publicId)->with('documents')->firstOrFail(); if(!$this->checkEditPermission($expense, $response)){ return $response; @@ -163,7 +163,14 @@ class ExpenseController extends BaseController */ public function update(UpdateExpenseRequest $request) { - $expense = $this->expenseService->save($request->input()); + $data = $request->input(); + $data['documents'] = $request->file('documents'); + + if(!$this->checkUpdatePermission($data, $response)){ + return $response; + } + + $expense = $this->expenseService->save($data, true); Session::flash('message', trans('texts.updated_expense')); @@ -195,8 +202,7 @@ class ExpenseController extends BaseController $expenses = Expense::scope($ids)->with('client')->get(); $clientPublicId = null; $currencyId = null; - $data = []; - + // Validate that either all expenses do not have a client or if there is a client, it is the same client foreach ($expenses as $expense) { @@ -220,19 +226,11 @@ class ExpenseController extends BaseController Session::flash('error', trans('texts.expense_error_invoiced')); return Redirect::to('expenses'); } - - $account = Auth::user()->account; - $data[] = [ - 'publicId' => $expense->public_id, - 'description' => $expense->public_notes, - 'qty' => 1, - 'cost' => $expense->present()->converted_amount, - ]; } return Redirect::to("invoices/create/{$clientPublicId}") ->with('expenseCurrencyId', $currencyId) - ->with('expenses', $data); + ->with('expenses', $ids); break; default: diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index 70b8e66fa4f2..93d4a2a2432a 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -17,6 +17,7 @@ use App\Models\Invoice; use App\Models\Client; use App\Models\Account; use App\Models\Product; +use App\Models\Expense; use App\Models\TaxRate; use App\Models\InvoiceDesign; use App\Models\Activity; @@ -91,7 +92,7 @@ class InvoiceController extends BaseController { $account = Auth::user()->account; $invoice = Invoice::scope($publicId) - ->with('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items', 'documents', 'payments') + ->with('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items', 'documents', 'expenses', 'expenses.documents', 'payments') ->withTrashed() ->firstOrFail(); @@ -241,6 +242,12 @@ class InvoiceController extends BaseController $invoice = $account->createInvoice($entityType, $clientId); $invoice->public_id = 0; + + $invoice->expenses = Expense::scope([2])->with('documents')->get(); + if(Session::get('expenses')){ + $invoice->expenses = Expense::scope(Session::get('expenses'))->with('documents')->get(); + } + $clients = Client::scope()->with('contacts', 'country')->orderBy('name'); if(!Auth::user()->hasPermission('view_all')){ @@ -352,7 +359,6 @@ class InvoiceController extends BaseController 'recurringDueDateHelp' => $recurringDueDateHelp, 'invoiceLabels' => Auth::user()->account->getInvoiceLabels(), 'tasks' => Session::get('tasks') ? json_encode(Session::get('tasks')) : null, - 'expenses' => Session::get('expenses') ? json_encode(Session::get('expenses')) : null, 'expenseCurrencyId' => Session::get('expenseCurrencyId') ?: null, ]; @@ -537,7 +543,7 @@ class InvoiceController extends BaseController public function invoiceHistory($publicId) { $invoice = Invoice::withTrashed()->scope($publicId)->firstOrFail(); - $invoice->load('user', 'invoice_items', 'documents', 'account.country', 'client.contacts', 'client.country'); + $invoice->load('user', 'invoice_items', 'documents', 'expenses', 'expenses.documents', 'account.country', 'client.contacts', 'client.country'); $invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date); $invoice->due_date = Utils::fromSqlDate($invoice->due_date); $invoice->is_pro = Auth::user()->isPro(); diff --git a/app/Http/Controllers/PublicClientController.php b/app/Http/Controllers/PublicClientController.php index 2d7f980af2a8..755dbb1ca86a 100644 --- a/app/Http/Controllers/PublicClientController.php +++ b/app/Http/Controllers/PublicClientController.php @@ -179,12 +179,6 @@ class PublicClientController extends BaseController return $paymentTypes; } - - protected function humanFilesize($bytes, $decimals = 2) { - $size = array('B','kB','MB','GB','TB','PB','EB','ZB','YB'); - $factor = floor((strlen($bytes) - 1) / 3); - return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$size[$factor]; - } public function download($invitationKey) { @@ -473,7 +467,13 @@ class PublicClientController extends BaseController } protected function getInvoiceZipDocuments($invoice, &$size=0){ - $documents = $invoice->documents->sortBy('size'); + $documents = $invoice->documents; + + foreach($invoice->expenses as $expense){ + $documents = $documents->merge($expense->documents); + } + + $documents = $documents->sortBy('size'); $size = 0; $maxSize = MAX_ZIP_DOCUMENTS_SIZE * 1000; @@ -520,10 +520,6 @@ class PublicClientController extends BaseController $invoice = $invitation->invoice; - if(!count($invoice->documents)){ - return Response::view('error', array('error'=>'No documents'), 404); - } - $toZip = $this->getInvoiceZipDocuments($invoice); if(!count($toZip)){ diff --git a/app/Models/Document.php b/app/Models/Document.php index 905ea09235c9..0d822ea4d18e 100644 --- a/app/Models/Document.php +++ b/app/Models/Document.php @@ -200,8 +200,10 @@ class Document extends EntityModel public function toArray() { $array = parent::toArray(); - $array['url'] = $this->getUrl(); - $array['preview_url'] = $this->getPreviewUrl(); + + if(empty($this->visible) || in_array('url', $this->visible))$array['url'] = $this->getUrl(); + if(empty($this->visible) || in_array('preview_url', $this->visible))$array['preview_url'] = $this->getPreviewUrl(); + return $array; } diff --git a/app/Models/Expense.php b/app/Models/Expense.php index 2d1b8041d7ee..4da74ca0c4b7 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -53,6 +53,11 @@ class Expense extends EntityModel return $this->belongsTo('App\Models\Invoice')->withTrashed(); } + public function documents() + { + return $this->hasMany('App\Models\Document')->orderBy('id'); + } + public function getName() { if($this->expense_number) @@ -80,6 +85,20 @@ class Expense extends EntityModel { return $this->invoice_currency_id != $this->expense_currency_id; } + + public function convertedAmount() + { + return round($this->amount * $this->exchange_rate, 2); + } + + public function toArray() + { + $array = parent::toArray(); + + if(empty($this->visible) || in_array('converted_amount', $this->visible))$array['previewconverted_amount_url'] = $this->convertedAmount(); + + return $array; + } } Expense::creating(function ($expense) { diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 42706a60b821..f1e943339f7e 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -2,6 +2,7 @@ use Utils; use DateTime; +use URL; use Illuminate\Database\Eloquent\SoftDeletes; use Laracasts\Presenter\PresentableTrait; use App\Models\BalanceAffecting; @@ -391,6 +392,7 @@ class Invoice extends EntityModel implements BalanceAffecting 'balance', 'invoice_items', 'documents', + 'expenses', 'client', 'tax_name', 'tax_rate', @@ -463,6 +465,7 @@ class Invoice extends EntityModel implements BalanceAffecting 'custom_invoice_text_label2', 'custom_invoice_item_label1', 'custom_invoice_item_label2', + 'invoice_embed_documents' ]); foreach ($this->invoice_items as $invoiceItem) { @@ -487,6 +490,26 @@ class Invoice extends EntityModel implements BalanceAffecting ]); } + foreach ($this->documents as $document) { + $document->setVisible([ + 'public_id', + 'name', + ]); + } + + foreach ($this->expenses as $expense) { + $expense->setVisible([ + 'documents', + ]); + + foreach ($expense->documents as $document) { + $document->setVisible([ + 'public_id', + 'name', + ]); + } + } + return $this; } @@ -867,6 +890,18 @@ class Invoice extends EntityModel implements BalanceAffecting return $taxes; } + + public function hasDocuments(){ + if(count($this->documents))return true; + return $this->hasExpenseDocuments(); + } + + public function hasExpenseDocuments(){ + foreach($this->expenses as $expense){ + if(count($expense->documents))return true; + } + return false; + } } Invoice::creating(function ($invoice) { diff --git a/app/Ninja/Mailers/ContactMailer.php b/app/Ninja/Mailers/ContactMailer.php index 7f96efb7da87..229895067e42 100644 --- a/app/Ninja/Mailers/ContactMailer.php +++ b/app/Ninja/Mailers/ContactMailer.php @@ -63,8 +63,14 @@ class ContactMailer extends Mailer } $documentStrings = array(); - if ($account->document_email_attachment && !empty($invoice->documents)) { - $documents = $invoice->documents->sortBy('size'); + if ($account->document_email_attachment && $invoice->hasDocuments()) { + $documents = $invoice->documents; + + foreach($invoice->expenses as $expense){ + $documents = $documents->merge($expense->documents); + } + + $documents = $documents->sortBy('size'); $size = 0; $maxSize = MAX_EMAIL_DOCUMENTS_SIZE * 1000; @@ -285,11 +291,16 @@ class ContactMailer extends Mailer $passwordHTML = isset($data['password'])?'

'.trans('texts.password').': '.$data['password'].'

':false; $documentsHTML = ''; - if($account->isPro() && count($invoice->documents)){ + if($account->isPro() && $invoice->hasDocuments()){ $documentsHTML .= trans('texts.email_documents_header').'

'; } diff --git a/app/Ninja/Presenters/ExpensePresenter.php b/app/Ninja/Presenters/ExpensePresenter.php index 6b66080ded85..1980480a2f53 100644 --- a/app/Ninja/Presenters/ExpensePresenter.php +++ b/app/Ninja/Presenters/ExpensePresenter.php @@ -16,14 +16,9 @@ class ExpensePresenter extends Presenter { return Utils::fromSqlDate($this->entity->expense_date); } - public function converted_amount() - { - return round($this->entity->amount * $this->entity->exchange_rate, 2); - } - public function invoiced_amount() { - return $this->entity->invoice_id ? $this->converted_amount() : 0; + return $this->entity->invoice_id ? $this->entity->convertedAmount() : 0; } public function link() diff --git a/app/Ninja/Repositories/DocumentRepository.php b/app/Ninja/Repositories/DocumentRepository.php index 78be3bf78655..6342fe8eab84 100644 --- a/app/Ninja/Repositories/DocumentRepository.php +++ b/app/Ninja/Repositories/DocumentRepository.php @@ -59,7 +59,7 @@ class DocumentRepository extends BaseRepository public function upload($uploaded, &$doc_array=null) { - $extension = strtolower($uploaded->extension()); + $extension = strtolower($uploaded->getClientOriginalExtension()); if(empty(Document::$types[$extension]) && !empty(Document::$extraExtensions[$extension])){ $documentType = Document::$extraExtensions[$extension]; } @@ -68,7 +68,7 @@ class DocumentRepository extends BaseRepository } if(empty(Document::$types[$documentType])){ - return 'Unsupported extension'; + return 'Unsupported file type'; } $documentTypeData = Document::$types[$documentType]; @@ -180,10 +180,14 @@ class DocumentRepository extends BaseRepository public function getClientDatatable($contactId, $entityType, $search) { - $query = DB::table('invitations') + + $query = DB::table('invitations') ->join('accounts', 'accounts.id', '=', 'invitations.account_id') ->join('invoices', 'invoices.id', '=', 'invitations.invoice_id') - ->join('documents', 'documents.invoice_id', '=', 'invitations.invoice_id') + ->join('expenses', 'expenses.invoice_id', '=', 'invitations.invoice_id') + ->join('documents', function($join){ + $join->on('documents.invoice_id', '=', 'invitations.invoice_id')->orOn('documents.expense_id', '=', 'expenses.id'); + }) ->join('clients', 'clients.id', '=', 'invoices.client_id') ->where('invitations.contact_id', '=', $contactId) ->where('invitations.deleted_at', '=', null) diff --git a/app/Ninja/Repositories/ExpenseRepository.php b/app/Ninja/Repositories/ExpenseRepository.php index 49988435e598..db39857bcf4b 100644 --- a/app/Ninja/Repositories/ExpenseRepository.php +++ b/app/Ninja/Repositories/ExpenseRepository.php @@ -4,17 +4,25 @@ use DB; use Utils; use App\Models\Expense; use App\Models\Vendor; +use App\Models\Document; use App\Ninja\Repositories\BaseRepository; use Session; class ExpenseRepository extends BaseRepository { + protected $documentRepo; + // Expenses public function getClassName() { return 'App\Models\Expense'; } + public function __construct(DocumentRepository $documentRepo) + { + $this->documentRepo = $documentRepo; + } + public function all() { return Expense::scope() @@ -113,7 +121,7 @@ class ExpenseRepository extends BaseRepository return $query; } - public function save($input) + public function save($input, $checkSubPermissions=false) { $publicId = isset($input['public_id']) ? $input['public_id'] : false; @@ -145,6 +153,45 @@ class ExpenseRepository extends BaseRepository $expense->exchange_rate = round($rate, 4); $expense->amount = round(Utils::parseFloat($input['amount']), 2); + // Documents + $document_ids = !empty($input['document_ids'])?array_map('intval', $input['document_ids']):array();; + foreach ($document_ids as $document_id){ + $document = Document::scope($document_id)->first(); + if($document && !$checkSubPermissions || $document->canEdit()){ + $document->invoice_id = null; + $document->expense_id = $expense->id; + $document->save(); + } + } + + if(!empty($input['documents']) && Document::canCreate()){ + // Fallback upload + $doc_errors = array(); + foreach($input['documents'] as $upload){ + $result = $this->documentRepo->upload($upload); + if(is_string($result)){ + $doc_errors[] = $result; + } + else{ + $result->expense_id = $expense->id; + $result->save(); + $document_ids[] = $result->public_id; + } + } + if(!empty($doc_errors)){ + Session::flash('error', implode('
',array_map('htmlentities',$doc_errors))); + } + } + + foreach ($expense->documents as $document){ + if(!in_array($document->public_id, $document_ids)){ + // Removed + if(!$checkSubPermissions || $document->canEdit()){ + $document->delete(); + } + } + } + $expense->save(); return $expense; diff --git a/app/Ninja/Repositories/InvoiceRepository.php b/app/Ninja/Repositories/InvoiceRepository.php index a927cb068c0d..686f9573d12d 100644 --- a/app/Ninja/Repositories/InvoiceRepository.php +++ b/app/Ninja/Repositories/InvoiceRepository.php @@ -415,6 +415,7 @@ class InvoiceRepository extends BaseRepository } $document->invoice_id = $invoice->id; + $document->expense_id = null; $document->save(); } } diff --git a/app/Services/ExpenseService.php b/app/Services/ExpenseService.php index 2fc2afbc84b1..b574aa9983b8 100644 --- a/app/Services/ExpenseService.php +++ b/app/Services/ExpenseService.php @@ -28,7 +28,7 @@ class ExpenseService extends BaseService return $this->expenseRepo; } - public function save($data) + public function save($data, $checkSubPermissions=false) { if (isset($data['client_id']) && $data['client_id']) { $data['client_id'] = Client::getPrivateId($data['client_id']); @@ -38,7 +38,7 @@ class ExpenseService extends BaseService $data['vendor_id'] = Vendor::getPrivateId($data['vendor_id']); } - return $this->expenseRepo->save($data); + return $this->expenseRepo->save($data, $checkSubPermissions); } public function getDatatable($search) diff --git a/public/built.js b/public/built.js index 0b46c5659d41..a883d6a37219 100644 --- a/public/built.js +++ b/public/built.js @@ -31396,13 +31396,19 @@ NINJA.invoiceLines = function(invoice) { } NINJA.invoiceDocuments = function(invoice) { - if(!invoice.documents || !invoice.account.invoice_embed_documents)return[]; + if(!invoice.account.invoice_embed_documents)return[]; var stack = []; var stackItem = null; var j = 0; - for (var i = 0; i < invoice.documents.length; i++) { - var document = invoice.documents[i]; + for (var i = 0; i < invoice.documents.length; i++)addDoc(invoice.documents[i]); + + for (var i = 0; i < invoice.expenses.length; i++) { + var expense = invoice.expenses[i]; + for (var i = 0; i < expense.documents.length; i++)addDoc(expense.documents[i]); + } + + function addDoc(document){ var path = document.base64; if(!path)path = 'docs/'+document.public_id+'/'+document.name; @@ -31415,9 +31421,9 @@ NINJA.invoiceDocuments = function(invoice) { stackItem.columns.push({stack:[{image:path,style:'invoiceDocument',fit:[150,150]}], width:175}) j++; } - } + } - return {stack:stack}; + return stack.length?{stack:stack}:[]; } NINJA.subtotals = function(invoice, hideBalance) diff --git a/public/css/built.css b/public/css/built.css index 7278b9ed4236..559bd1a22c17 100644 --- a/public/css/built.css +++ b/public/css/built.css @@ -3193,10 +3193,21 @@ div.panel-body div.panel-body { } /* Attached Documents */ -.dropzone { +#document-upload { border:1px solid #ebe7e7; background:#f9f9f9 !important; border-radius:3px; + padding:20px; +} + +.invoice-table #document-upload{ + max-width:560px; +} + +#document-upload .dropzone{ + background:none; + border:none; + padding:0; } .dropzone .dz-preview.dz-image-preview{ @@ -3204,8 +3215,6 @@ div.panel-body div.panel-body { } .dropzone .dz-preview .dz-image{ - width:119px; - height:119px; border-radius:5px!important; } diff --git a/public/css/style.css b/public/css/style.css index 1499d26f573a..6514f82ae975 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -1064,10 +1064,21 @@ div.panel-body div.panel-body { } /* Attached Documents */ -.dropzone { +#document-upload { border:1px solid #ebe7e7; background:#f9f9f9 !important; border-radius:3px; + padding:20px; +} + +.invoice-table #document-upload{ + max-width:560px; +} + +#document-upload .dropzone{ + background:none; + border:none; + padding:0; } .dropzone .dz-preview.dz-image-preview{ @@ -1075,8 +1086,6 @@ div.panel-body div.panel-body { } .dropzone .dz-preview .dz-image{ - width:119px; - height:119px; border-radius:5px!important; } diff --git a/public/js/pdf.pdfmake.js b/public/js/pdf.pdfmake.js index 29da491112da..9f38f6e42f3e 100644 --- a/public/js/pdf.pdfmake.js +++ b/public/js/pdf.pdfmake.js @@ -404,13 +404,19 @@ NINJA.invoiceLines = function(invoice) { } NINJA.invoiceDocuments = function(invoice) { - if(!invoice.documents || !invoice.account.invoice_embed_documents)return[]; + if(!invoice.account.invoice_embed_documents)return[]; var stack = []; var stackItem = null; var j = 0; - for (var i = 0; i < invoice.documents.length; i++) { - var document = invoice.documents[i]; + for (var i = 0; i < invoice.documents.length; i++)addDoc(invoice.documents[i]); + + for (var i = 0; i < invoice.expenses.length; i++) { + var expense = invoice.expenses[i]; + for (var i = 0; i < expense.documents.length; i++)addDoc(expense.documents[i]); + } + + function addDoc(document){ var path = document.base64; if(!path)path = 'docs/'+document.public_id+'/'+document.name; @@ -423,9 +429,9 @@ NINJA.invoiceDocuments = function(invoice) { stackItem.columns.push({stack:[{image:path,style:'invoiceDocument',fit:[150,150]}], width:175}) j++; } - } + } - return {stack:stack}; + return stack.length?{stack:stack}:[]; } NINJA.subtotals = function(invoice, hideBalance) diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 4db617943e20..3c7b2dcacc42 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -1103,11 +1103,13 @@ $LANG = array( 'email_documents_example_1' => 'Widgets Receipt.pdf', 'email_documents_example_2' => 'Final Deliverable.zip', 'invoice_documents' => 'Attached Documents', + 'expense_documents' => 'Attached Documents', 'document_upload_message' => 'Drop files here or click to upload.', 'invoice_embed_documents' => 'Embed Documents', 'invoice_embed_documents_help' => 'Include attached images in the invoice.', 'document_email_attachment' => 'Attach Documents', 'download_documents' => 'Download Documents (:size)', + 'documents_from_expenses' => 'From Expenses:', 'documents' => 'Documents', 'document_date' => 'Document Date', 'document_size' => 'Size', diff --git a/resources/views/expenses/edit.blade.php b/resources/views/expenses/edit.blade.php index 589c8d8cda8f..5aaae895fbfa 100644 --- a/resources/views/expenses/edit.blade.php +++ b/resources/views/expenses/edit.blade.php @@ -105,6 +105,27 @@ + @if ($account->isPro()) +
+
{{trans('texts.expense_documents')}}
+
+
+
+
+ +
+
+
+ + + +
+
+
+
+
+
+ @endif @@ -122,6 +143,7 @@ {!! Former::close() !!} @stop \ No newline at end of file diff --git a/resources/views/invoices/edit.blade.php b/resources/views/invoices/edit.blade.php index a383a1b0cb32..c6aaa7230309 100644 --- a/resources/views/invoices/edit.blade.php +++ b/resources/views/invoices/edit.blade.php @@ -38,9 +38,8 @@ {!! Former::open($url) ->method($method) - ->addClass('warn-on-exit') + ->addClass('warn-on-exit main-form') ->autocomplete('off') - ->attributes(array('enctype'=>'multipart/form-data')) ->onsubmit('return onFormSubmit(event)') ->rules(array( 'client' => 'required', @@ -307,17 +306,27 @@ @if ($account->isPro())
-
-
- -
-
-
- - - +
+
+
+ +
+
+
+ + + +
+ @if ($invoice->hasExpenseDocuments()) +

{{trans('texts.documents_from_expenses')}}

+ @foreach($invoice->expenses as $expense) + @foreach($expense->documents as $document) +
{{$document->name}}
+ @endforeach + @endforeach + @endif
@endif @@ -778,24 +787,24 @@ model.invoice().has_tasks(true); @endif - @if (isset($expenses) && $expenses) + if(model.invoice().expenses() && !model.invoice().public_id()){ model.expense_currency_id({{ $expenseCurrencyId }}); // move the blank invoice line item to the end var blank = model.invoice().invoice_items.pop(); - var expenses = {!! $expenses !!}; + var expenses = model.invoice().expenses(); for (var i=0; iaccount->isPro()) + $('.main-form').submit(function(){ + if($('#document-upload .dropzone .fallback input').val())$(this).attr('enctype', 'multipart/form-data') + else $(this).removeAttr('enctype') + }) + // Initialize document upload - dropzone = new Dropzone('#document-upload', { + dropzone = new Dropzone('#document-upload .dropzone', { url:{!! json_encode(url('document')) !!}, params:{ _token:"{{ Session::getToken() }}" @@ -1360,6 +1374,13 @@ @endif @endforeach + @foreach ($invoice->expenses as $expense) + @foreach ($expense->documents as $document) + @if($document->isPDFEmbeddable()) + + @endif + @endforeach + @endforeach @endif @stop diff --git a/resources/views/invoices/history.blade.php b/resources/views/invoices/history.blade.php index 256f541f02e0..baa5c925aadb 100644 --- a/resources/views/invoices/history.blade.php +++ b/resources/views/invoices/history.blade.php @@ -57,11 +57,18 @@ @include('invoices.pdf', ['account' => Auth::user()->account, 'pdfHeight' => 800]) - @if (Auth::user()->account->isPro() && Auth::user()->account->invoice_embed_documents) + @if (Utils::isPro() && $invoice->account->invoice_embed_documents) @foreach ($invoice->documents as $document) @if($document->isPDFEmbeddable()) @endif @endforeach + @foreach ($invoice->expenses as $expense) + @foreach ($expense->documents as $document) + @if($document->isPDFEmbeddable()) + + @endif + @endforeach + @endforeach @endif @stop \ No newline at end of file diff --git a/resources/views/invoices/knockout.blade.php b/resources/views/invoices/knockout.blade.php index 886eb985512e..9db13abe1910 100644 --- a/resources/views/invoices/knockout.blade.php +++ b/resources/views/invoices/knockout.blade.php @@ -227,6 +227,7 @@ function InvoiceModel(data) { self.invoice_status_id = ko.observable(0); self.invoice_items = ko.observableArray(); self.documents = ko.observableArray(); + self.expenses = ko.observableArray(); self.amount = ko.observable(0); self.balance = ko.observable(0); self.invoice_design_id = ko.observable(1); @@ -257,6 +258,11 @@ function InvoiceModel(data) { return new DocumentModel(options.data); } }, + 'expenses': { + create: function(options) { + return new ExpenseModel(options.data); + } + }, 'tax': { create: function(options) { return new TaxRateModel(options.data); @@ -846,6 +852,28 @@ function DocumentModel(data) { self.update(data); } } + +var ExpenseModel = function(data) { + var self = this; + + self.mapping = { + 'documents': { + create: function(options) { + return new DocumentModel(options.data); + } + } + } + + self.description = ko.observable(''); + self.qty = ko.observable(0); + self.public_id = ko.observable(0); + self.amount = ko.observable(); + self.converted_amount = ko.observable(); + + if (data) { + ko.mapping.fromJS(data, self.mapping, this); + } +}; /* Custom binding for product key typeahead */ ko.bindingHandlers.typeahead = { diff --git a/resources/views/invoices/view.blade.php b/resources/views/invoices/view.blade.php index bad07e9e7321..08f5cd9827cd 100644 --- a/resources/views/invoices/view.blade.php +++ b/resources/views/invoices/view.blade.php @@ -49,13 +49,18 @@ @endif

 

- @if ($account->isPro() && count($invoice->documents)) + @if ($account->isPro() && $invoice->hasDocuments())

{{ trans('texts.documents_header') }}

@endif @@ -63,9 +68,16 @@ @if ($account->isPro() && $account->invoice_embed_documents) @foreach ($invoice->documents as $document) @if($document->isPDFEmbeddable()) - + @endif @endforeach + @foreach ($invoice->expenses as $expense) + @foreach ($expense->documents as $document) + @if($document->isPDFEmbeddable()) + + @endif + @endforeach + @endforeach @endif