mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-10-31 12:37:32 -04:00 
			
		
		
		
	Support delivery notes #462
This commit is contained in:
		
							parent
							
								
									ddd60c4d3c
								
							
						
					
					
						commit
						7fbe213146
					
				| @ -590,6 +590,28 @@ class InvoiceController extends BaseController | ||||
|         return View::make('invoices.history', $data); | ||||
|     } | ||||
| 
 | ||||
|     public function deliveryNote(InvoiceRequest $request) | ||||
|     { | ||||
|         $invoice = $request->entity(); | ||||
|         $invoice->load('user', 'invoice_items', 'documents', 'expenses', 'expenses.documents', 'account.country', 'client.contacts', 'client.country', 'client.shipping_country'); | ||||
|         $invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date); | ||||
|         $invoice->due_date = Utils::fromSqlDate($invoice->due_date); | ||||
|         $invoice->features = [ | ||||
|             'customize_invoice_design' => Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN), | ||||
|             'remove_created_by' => Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY), | ||||
|             'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS), | ||||
|         ]; | ||||
|         $invoice->invoice_type_id = intval($invoice->invoice_type_id); | ||||
| 
 | ||||
|         $data = [ | ||||
|             'invoice' => $invoice, | ||||
|             'invoiceDesigns' => InvoiceDesign::getDesigns(), | ||||
|             'invoiceFonts' => Cache::get('fonts'), | ||||
|         ]; | ||||
| 
 | ||||
|         return View::make('invoices.delivery_note', $data); | ||||
|     } | ||||
| 
 | ||||
|     public function checkInvoiceNumber($invoicePublicId = false) | ||||
|     { | ||||
|         $invoiceNumber = request()->invoice_number; | ||||
|  | ||||
| @ -106,11 +106,20 @@ class InvoiceDatatable extends EntityDatatable | ||||
|                 }, | ||||
|             ], | ||||
|             [ | ||||
|                 trans('texts.view_history'), | ||||
|                 trans("texts.{$entityType}_history"), | ||||
|                 function ($model) use ($entityType) { | ||||
|                     return URL::to("{$entityType}s/{$entityType}_history/{$model->public_id}"); | ||||
|                 }, | ||||
|             ], | ||||
|             [ | ||||
|                 trans('texts.delivery_note'), | ||||
|                 function ($model) use ($entityType) { | ||||
|                     return url("invoices/delivery_note/{$model->public_id}"); | ||||
|                 }, | ||||
|                 function ($model) use ($entityType) { | ||||
|                     return $entityType == ENTITY_INVOICE; | ||||
|                 }, | ||||
|             ], | ||||
|             [ | ||||
|                 '--divider--', function () { | ||||
|                     return false; | ||||
|  | ||||
| @ -242,6 +242,11 @@ class InvoicePresenter extends EntityPresenter | ||||
|         } | ||||
| 
 | ||||
|         $actions[] = ['url' => url("{$entityType}s/{$entityType}_history/{$invoice->public_id}"), 'label' => trans('texts.view_history')]; | ||||
| 
 | ||||
|         if ($entityType == ENTITY_INVOICE) { | ||||
|             $actions[] = ['url' => url("invoices/delivery_note/{$invoice->public_id}"), 'label' => trans('texts.delivery_note')]; | ||||
|         } | ||||
| 
 | ||||
|         $actions[] = DropdownButton::DIVIDER; | ||||
| 
 | ||||
|         if ($entityType == ENTITY_QUOTE) { | ||||
|  | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -417,6 +417,18 @@ NINJA.invoiceColumns = function(invoice, design, isTasks) | ||||
|         var field = fields[i]; | ||||
|         var width = 0; | ||||
| 
 | ||||
|         if (invoice.is_delivery_note) { | ||||
|             var skipFields = [ | ||||
|                 'product.unit_cost', | ||||
|                 'product.rate', | ||||
|                 'product.tax', | ||||
|                 'product.line_total', | ||||
|             ]; | ||||
|             if (skipFields.indexOf(field) >= 0) { | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (field == 'product.custom_value1') { | ||||
|             if (invoice.has_custom_item_value1) { | ||||
|                 width = 10; | ||||
| @ -529,6 +541,12 @@ NINJA.invoiceLines = function(invoice, isSecondTable) { | ||||
|     var isTasks = isSecondTable || (invoice.hasTasks && !invoice.hasStandard); | ||||
|     var grid = [[]]; | ||||
|     var styles = ['tableHeader']; | ||||
|     var skipFields = [ | ||||
|         'product.unit_cost', | ||||
|         'product.rate', | ||||
|         'product.tax', | ||||
|         'product.line_total', | ||||
|     ]; | ||||
| 
 | ||||
|     if (isSecondTable) { | ||||
|         styles.push('secondTableHeader'); | ||||
| @ -539,6 +557,11 @@ NINJA.invoiceLines = function(invoice, isSecondTable) { | ||||
| 
 | ||||
|     for (var i=0; i<fields.length; i++) { | ||||
|         var field = fields[i].split('.')[1]; // split to remove 'product.'
 | ||||
| 
 | ||||
|         if (invoice.is_delivery_note && skipFields.indexOf(fields[i]) >= 0) { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         var headerStyles = styles.concat([snakeToCamel(field), snakeToCamel(field) + 'TableHeader']); | ||||
|         var value = invoiceLabels[field]; | ||||
| 
 | ||||
| @ -633,6 +656,11 @@ NINJA.invoiceLines = function(invoice, isSecondTable) { | ||||
| 
 | ||||
|         for (var j=0; j<fields.length; j++) { | ||||
|             var field = fields[j].split('.')[1]; // split to remove 'product.'
 | ||||
| 
 | ||||
|             if (invoice.is_delivery_note && skipFields.indexOf(fields[j]) >= 0) { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             var value = item[field]; | ||||
|             var styles = [snakeToCamel(field), rowStyle]; | ||||
| 
 | ||||
| @ -742,8 +770,8 @@ NINJA.statementSubtotals = function(invoice) | ||||
| 
 | ||||
| NINJA.subtotals = function(invoice, hideBalance) | ||||
| { | ||||
|     if (!invoice) { | ||||
|         return; | ||||
|     if (! invoice || invoice.is_delivery_note) { | ||||
|         return [[]]; | ||||
|     } | ||||
| 
 | ||||
|     var account = invoice.account; | ||||
| @ -818,6 +846,10 @@ NINJA.subtotals = function(invoice, hideBalance) | ||||
| } | ||||
| 
 | ||||
| NINJA.subtotalsBalance = function(invoice) { | ||||
|     if (invoice.is_delivery_note) { | ||||
|         return [[]]; | ||||
|     } | ||||
| 
 | ||||
|     var isPartial = NINJA.parseFloat(invoice.partial); | ||||
|     return [[ | ||||
|         {text: isPartial ? invoiceLabels.partial_due : (invoice.is_quote || invoice.balance_amount < 0 ? invoiceLabels.total : invoiceLabels.balance_due), style:['subtotalsLabel', 'subtotalsBalanceDueLabel']}, | ||||
| @ -913,6 +945,17 @@ NINJA.invoiceDetails = function(invoice) { | ||||
| 
 | ||||
| 
 | ||||
| NINJA.renderField = function(invoice, field, twoColumn) { | ||||
|     if (invoice.is_delivery_note) { | ||||
|         var skipFields = [ | ||||
|             'invoice.due_date', | ||||
|             'invoice.balance_due', | ||||
|             'invoice.partial_due', | ||||
|         ]; | ||||
|         if (skipFields.indexOf(field) >= 0) { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     var client = invoice.client; | ||||
|     if (!client) { | ||||
|         return false; | ||||
| @ -939,24 +982,49 @@ NINJA.renderField = function(invoice, field, twoColumn) { | ||||
|             label = invoiceLabels.vat_number; | ||||
|         } | ||||
|     } else if (field == 'client.address1') { | ||||
|         if (invoice.is_delivery_note && client.shipping_address1) { | ||||
|             value = client.shipping_address1; | ||||
|         } else { | ||||
|             value = client.address1; | ||||
|         } | ||||
|     } else if (field == 'client.address2') { | ||||
|         if (invoice.is_delivery_note && client.shipping_address1) { | ||||
|             value = client.shipping_address2; | ||||
|         } else { | ||||
|             value = client.address2; | ||||
|         } | ||||
|     } else if (field == 'client.city_state_postal') { | ||||
|         var cityStatePostal = ''; | ||||
|         if (invoice.is_delivery_note && client.shipping_address1) { | ||||
|             if (client.shipping_city || client.shipping_state || client.shipping_postal_code) { | ||||
|                 var swap = client.shipping_country && client.shipping_country.swap_postal_code; | ||||
|                 cityStatePostal = formatAddress(client.shipping_city, client.shipping_state, client.shipping_postal_code, swap); | ||||
|             } | ||||
|         } else { | ||||
|             if (client.city || client.state || client.postal_code) { | ||||
|                 var swap = client.country && client.country.swap_postal_code; | ||||
|                 cityStatePostal = formatAddress(client.city, client.state, client.postal_code, swap); | ||||
|             } | ||||
|         } | ||||
|         value = cityStatePostal; | ||||
|     } else if (field == 'client.postal_city_state') { | ||||
|         var postalCityState = ''; | ||||
|         if (invoice.is_delivery_note && client.shipping_address1) { | ||||
|             if (client.shipping_city || client.shipping_state || client.shipping_postal_code) { | ||||
|                 postalCityState = formatAddress(client.shipping_city, client.shipping_state, client.shipping_postal_code, true); | ||||
|             } | ||||
|         } else { | ||||
|             if (client.city || client.state || client.postal_code) { | ||||
|                 postalCityState = formatAddress(client.city, client.state, client.postal_code, true); | ||||
|             } | ||||
|         } | ||||
|         value = postalCityState; | ||||
|     } else if (field == 'client.country') { | ||||
|         if (invoice.is_delivery_note && client.shipping_address1) { | ||||
|             value = client.shipping_country ? client.shipping_country.name : ''; | ||||
|         } else { | ||||
|             value = client.country ? client.country.name : ''; | ||||
|         } | ||||
|     } else if (field == 'client.email') { | ||||
|         value = contact.email == clientName ? '' : contact.email; | ||||
|     } else if (field == 'client.phone') { | ||||
|  | ||||
| @ -2543,6 +2543,7 @@ $LANG = array( | ||||
|     'classify' => 'Classify', | ||||
|     'show_shipping_address_help' => 'Require client to provide their shipping address', | ||||
|     'ship_to_billing_address' => 'Ship to billing address', | ||||
|     'delivery_note' => 'Delivery Note', | ||||
| 
 | ||||
| ); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										75
									
								
								resources/views/invoices/delivery_note.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								resources/views/invoices/delivery_note.blade.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | ||||
| @extends('header') | ||||
| 
 | ||||
| @section('head') | ||||
|     @parent | ||||
| 
 | ||||
|     @include('money_script') | ||||
|     @foreach (Auth::user()->account->getFontFolders() as $font) | ||||
|         <script src="{{ asset('js/vfs_fonts/'.$font.'.js') }}" type="text/javascript"></script> | ||||
|     @endforeach | ||||
|     <script src="{{ asset('pdf.built.js') }}?no_cache={{ NINJA_VERSION }}" type="text/javascript"></script> | ||||
| 
 | ||||
|   <script> | ||||
| 
 | ||||
|     var invoice = {!! $invoice !!}; | ||||
|     var invoiceDesign = false; | ||||
|     var invoiceDesigns = {!! $invoiceDesigns !!}; | ||||
|     var invoiceFonts = {!! $invoiceFonts !!}; | ||||
| 
 | ||||
|     function getPDFString(cb) { | ||||
|         invoice.image = window.accountLogo; | ||||
|         invoice.is_delivery_note = true; | ||||
|         var invoiceDesignId = parseInt(invoice.invoice_design_id); | ||||
|         invoiceDesign = _.findWhere(invoiceDesigns, {id: invoiceDesignId}); | ||||
|         if (!invoiceDesign) { | ||||
|             invoiceDesign = invoiceDesigns[0]; | ||||
|         } | ||||
|         generatePDF(invoice, invoiceDesign.javascript, true, cb); | ||||
|     } | ||||
| 
 | ||||
|     function onDownloadClick() { | ||||
| 		trackEvent('/activity', '/download_pdf'); | ||||
| 		var doc = generatePDF(invoice, invoiceDesign.javascript, true); | ||||
|         doc.save('{{ str_replace(' ', '_', trans('texts.delivery_note')) }}-{{ $invoice->invoice_number }}.pdf'); | ||||
| 	} | ||||
| 
 | ||||
|     $(function() { | ||||
|         refreshPDF(); | ||||
|     }); | ||||
| 
 | ||||
|   </script> | ||||
| 
 | ||||
| @stop | ||||
| 
 | ||||
| @section('top-right') | ||||
|     <div class="pull-right"> | ||||
|         {!! Button::normal(trans('texts.download_pdf')) | ||||
|                 ->withAttributes(['onclick' => 'onDownloadClick()', 'id' => 'downloadPdfButton']) | ||||
|                 ->appendIcon(Icon::create('download-alt')) !!} | ||||
| 
 | ||||
|         {!! Button::primary(trans('texts.edit_' . $invoice->getEntityType())) | ||||
|                 ->asLinkTo(url('/' . $invoice->getEntityType() . 's/' . $invoice->public_id . '/edit')) | ||||
|                 ->appendIcon(Icon::create('edit')) !!} | ||||
|     </div> | ||||
| @stop | ||||
| 
 | ||||
| @section('content') | ||||
| 
 | ||||
| 
 | ||||
|     @include('invoices.pdf', ['account' => Auth::user()->account, 'pdfHeight' => 800]) | ||||
| 
 | ||||
|     @if (Utils::hasFeature(FEATURE_DOCUMENTS) && $invoice->account->invoice_embed_documents) | ||||
|         @foreach ($invoice->documents as $document) | ||||
|             @if($document->isPDFEmbeddable()) | ||||
|                 <script src="{{ $document->getVFSJSUrl() }}" type="text/javascript" async></script> | ||||
|             @endif | ||||
|         @endforeach | ||||
|         @foreach ($invoice->expenses as $expense) | ||||
|             @foreach ($expense->documents as $document) | ||||
|                 @if($document->isPDFEmbeddable()) | ||||
|                     <script src="{{ $document->getVFSJSUrl() }}" type="text/javascript" async></script> | ||||
|                 @endif | ||||
|             @endforeach | ||||
|         @endforeach | ||||
|     @endif | ||||
| @stop | ||||
| @ -61,7 +61,10 @@ | ||||
|                 ->style('background-color: white !important') !!} | ||||
|     @endif | ||||
| 
 | ||||
|     {!! Button::primary(trans('texts.edit_' . $invoice->getEntityType()))->asLinkTo(URL::to('/' . $invoice->getEntityType() . 's/' . $invoice->public_id . '/edit'))->withAttributes(array('class' => 'pull-right')) !!} | ||||
|     {!! Button::primary(trans('texts.edit_' . $invoice->getEntityType())) | ||||
|             ->asLinkTo(URL::to('/' . $invoice->getEntityType() . 's/' . $invoice->public_id . '/edit')) | ||||
|             ->appendIcon(Icon::create('edit')) | ||||
|             ->withAttributes(array('class' => 'pull-right')) !!} | ||||
|     {!! Former::close() !!} | ||||
| 
 | ||||
|     <br/> <br/> | ||||
|  | ||||
| @ -155,6 +155,7 @@ Route::group(['middleware' => ['lookup:user', 'auth:user']], function () { | ||||
| 
 | ||||
|     Route::get('api/recurring_invoices/{client_id?}', 'InvoiceController@getRecurringDatatable'); | ||||
| 
 | ||||
|     Route::get('invoices/delivery_note/{invoice_id}', 'InvoiceController@deliveryNote'); | ||||
|     Route::get('invoices/invoice_history/{invoice_id}', 'InvoiceController@invoiceHistory'); | ||||
|     Route::get('quotes/quote_history/{invoice_id}', 'InvoiceController@invoiceHistory'); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user