2013-11-26 13:45:07 +01:00
@ extends ( 'header' )
2013-12-08 14:32:49 +01:00
@ section ( 'head' )
@ parent
2014-01-05 15:03:29 +01:00
< script src = " { { asset('js/pdf_viewer.js') }} " type = " text/javascript " ></ script >
< script src = " { { asset('js/compatibility.js') }} " type = " text/javascript " ></ script >
2013-12-08 14:32:49 +01:00
@ stop
2013-11-26 13:45:07 +01:00
@ section ( 'content' )
2013-12-07 19:45:00 +01:00
2014-01-01 16:23:32 +01:00
2013-11-26 22:45:10 +01:00
{{ Former :: open ( $url ) -> method ( $method ) -> addClass ( 'main_form' ) -> rules ( array (
2013-12-08 14:32:49 +01:00
'client' => 'required' ,
2013-12-30 21:17:45 +01:00
'email' => 'required' ,
2013-12-10 23:10:43 +01:00
'product_key' => 'max:14' ,
2014-01-01 16:23:32 +01:00
)); }}
2013-12-31 20:49:54 +01:00
2014-01-01 16:23:32 +01:00
< div data - bind = " with: invoice " >
2013-12-13 10:13:57 +01:00
< div class = " row " style = " min-height:195px " onkeypress = " formEnterClick(event) " >
2013-12-24 07:22:16 +01:00
< div class = " col-md-5 " id = " col_1 " >
2013-12-31 00:19:17 +01:00
@ if ( $invoice && $invoice -> isSent ())
< div class = " form-group " >
< label for = " client " class = " control-label col-lg-4 col-sm-4 " > Client </ label >
< div class = " col-lg-8 col-sm-8 " style = " padding-top: 7px " >
2014-01-01 16:23:32 +01:00
< a href = " # " data - bind = " click: $root .showClientForm " > {{ $client -> getDisplayName () }} </ a >
2013-12-31 00:19:17 +01:00
</ div >
</ div >
< div style = " display:none " >
@ endif
2014-01-01 18:34:37 +01:00
{{ Former :: select ( 'client' ) -> addOption ( '' , '' ) -> data_bind ( " dropdown: client " ) -> addGroupClass ( 'client_select closer-row' ) }}
2013-12-13 10:13:57 +01:00
< div class = " form-group " style = " margin-bottom: 8px " >
2013-12-15 13:55:50 +01:00
< div class = " col-lg-8 col-sm-8 col-lg-offset-4 col-sm-offset-4 " >
2014-01-02 00:12:33 +01:00
< a href = " # " data - bind = " click: $root .showClientForm, text: $root .clientLinkText " ></ a >
2013-12-13 10:13:57 +01:00
</ div >
</ div >
2013-12-31 00:19:17 +01:00
@ if ( $invoice && $invoice -> isSent ())
</ div >
@ endif
2013-12-13 10:13:57 +01:00
< div data - bind = " with: client " >
< div class = " form-group " data - bind = " visible: contacts().length > 1, foreach: contacts " >
< div class = " col-lg-8 col-lg-offset-4 " >
< label for = " test " class = " checkbox " data - bind = " attr: { for: $index () + '_check'} " >
< input type = " checkbox " value = " 1 " data - bind = " checked: send_invoice, attr: { id: $index () + '_check'} " >
2014-01-02 09:27:48 +01:00
< span data - bind = " text: first_name() + ' ' + last_name() + ' - ' + email() " />
2013-12-13 10:13:57 +01:00
</ label >
</ div >
</ div >
</ div >
2013-12-11 21:33:44 +01:00
2013-11-26 22:45:10 +01:00
</ div >
2013-12-11 21:33:44 +01:00
< div class = " col-md-4 " id = " col_2 " >
2013-12-13 10:13:57 +01:00
< div data - bind = " visible: !is_recurring() " >
{{ Former :: text ( 'invoice_number' ) -> label ( 'Invoice #' ) -> data_bind ( " value: invoice_number, valueUpdate: 'afterkeydown' " ) }}
2014-01-02 14:21:15 +01:00
{{ Former :: text ( 'invoice_date' ) -> data_bind ( " datePicker: invoice_date, valueUpdate: 'afterkeydown' " ) -> data_date_format ( Session :: get ( SESSION_DATE_PICKER_FORMAT )) }}
{{ Former :: text ( 'due_date' ) -> data_bind ( " datePicker: due_date, valueUpdate: 'afterkeydown' " ) -> data_date_format ( Session :: get ( SESSION_DATE_PICKER_FORMAT )) }}
2013-12-10 23:10:43 +01:00
</ div >
2013-12-13 10:13:57 +01:00
< div data - bind = " visible: is_recurring " >
{{ Former :: select ( 'frequency_id' ) -> label ( 'How often' ) -> options ( $frequencies ) -> data_bind ( " value: frequency_id " ) }}
2014-01-02 14:21:15 +01:00
{{ Former :: text ( 'start_date' ) -> data_bind ( " datePicker: start_date, valueUpdate: 'afterkeydown' " ) -> data_date_format ( Session :: get ( SESSION_DATE_PICKER_FORMAT )) }}
{{ Former :: text ( 'end_date' ) -> data_bind ( " datePicker: end_date, valueUpdate: 'afterkeydown' " ) -> data_date_format ( Session :: get ( SESSION_DATE_PICKER_FORMAT )) }}
2013-12-10 23:10:43 +01:00
</ div >
2013-12-24 07:22:16 +01:00
@ if ( $invoice && $invoice -> recurring_invoice_id )
2013-12-30 21:17:45 +01:00
< div class = " pull-right " style = " padding-top: 6px " >
2013-12-24 07:22:16 +01:00
Created by a {{ link_to ( '/invoices/' . $invoice -> recurring_invoice_id , 'recurring invoice' ) }}
</ div >
2013-12-30 21:17:45 +01:00
@ else
< div data - bind = " visible: invoice_status_id() < CONSTS.INVOICE_STATUS_SENT " >
{{ Former :: checkbox ( 'recurring' ) -> text ( 'Enable | <a href="#" rel="tooltip" data-toggle="tooltip" title="Recurring invoices are automatically sent. Use :MONTH, :QUARTER or :YEAR for dynamic dates. Basic math works as well. ie, :MONTH-1.">Learn more</a>' ) -> data_bind ( " checked: is_recurring " )
-> inlineHelp ( $invoice && $invoice -> last_sent_date ? 'Last invoice sent ' . Utils :: dateToString ( $invoice -> last_sent_date ) : '' ) }}
</ div >
2013-12-24 07:22:16 +01:00
@ endif
2013-12-11 21:33:44 +01:00
2013-11-26 22:45:10 +01:00
</ div >
2013-12-24 07:22:16 +01:00
< div class = " col-md-3 " id = " col_2 " >
{{ Former :: text ( 'po_number' ) -> label ( 'PO number' ) -> data_bind ( " value: po_number, valueUpdate: 'afterkeydown' " ) }}
{{ Former :: text ( 'discount' ) -> data_bind ( " value: discount, valueUpdate: 'afterkeydown' " ) }}
2014-01-02 18:16:00 +01:00
{{ Former :: select ( 'currency_id' ) -> label ( 'Currency' ) -> addOption ( '' , '' ) -> fromQuery ( $currencies , 'name' , 'id' ) -> data_bind ( " value: currency_id " ) }}
2013-12-27 10:10:32 +01:00
< div class = " form-group " style = " margin-bottom: 8px " >
< label for = " recurring " class = " control-label col-lg-4 col-sm-4 " > Taxes </ label >
< div class = " col-lg-8 col-sm-8 " style = " padding-top: 7px " >
2014-01-06 07:48:11 +01:00
< a href = " # " data - bind = " click: $root .showTaxesForm " > Manage rates </ a >
2013-12-27 10:10:32 +01:00
</ div >
</ div >
2013-12-24 07:22:16 +01:00
</ div >
2013-11-26 22:45:10 +01:00
</ div >
2013-11-26 13:45:07 +01:00
2013-11-26 22:45:10 +01:00
< p >& nbsp ; </ p >
2013-11-26 13:45:07 +01:00
2014-01-01 16:23:32 +01:00
{{ Former :: hidden ( 'data' ) -> data_bind ( " value: ko.mapping.toJSON(model) " ) }}
2013-11-28 13:15:34 +01:00
2013-11-27 08:38:37 +01:00
< table class = " table invoice-table " style = " margin-bottom: 0px !important " >
2013-11-26 22:45:10 +01:00
< thead >
< tr >
< th class = " hide-border " ></ th >
< th > Item </ th >
< th > Description </ th >
2013-12-13 10:13:57 +01:00
< th > Unit Cost </ th >
< th > Quantity </ th >
2014-01-01 16:23:32 +01:00
< th data - bind = " visible: $root .invoice_item_taxes.show " > Tax </ th >
2013-11-26 22:45:10 +01:00
< th > Line & nbsp ; Total </ th >
< th class = " hide-border " ></ th >
</ tr >
</ thead >
2013-12-13 10:13:57 +01:00
< tbody data - bind = " sortable: { data: invoice_items, afterMove: onDragged } " >
2013-11-26 22:45:10 +01:00
< tr data - bind = " event: { mouseover: showActions, mouseout: hideActions } " class = " sortable-row " >
2013-12-31 20:49:54 +01:00
< td style = " min-width:20px; " class = " hide-border td-icon " >
2013-12-13 10:13:57 +01:00
< i data - bind = " visible: actionsVisible() && $parent .invoice_items().length > 1 " class = " fa fa-sort " ></ i >
2013-11-26 22:45:10 +01:00
</ td >
2013-12-31 20:49:54 +01:00
< td style = " min-width:120px " >
2013-12-27 10:10:32 +01:00
{{ Former :: text ( 'product_key' ) -> useDatalist ( Product :: getProductKeys ( $products ), 'key' ) -> onkeyup ( 'onItemChange()' )
2013-11-28 13:15:34 +01:00
-> raw () -> data_bind ( " value: product_key, valueUpdate: 'afterkeydown' " ) -> addClass ( 'datalist' ) }}
2013-11-26 22:45:10 +01:00
</ td >
2013-12-31 20:49:54 +01:00
< td style = " width:100% " >
2013-12-31 10:43:39 +01:00
< textarea data - bind = " value: wrapped_notes, valueUpdate: 'afterkeydown' " rows = " 1 " cols = " 60 " style = " resize: none; " class = " form-control word-wrap " ></ textarea >
2013-11-26 22:45:10 +01:00
</ td >
2013-12-31 20:49:54 +01:00
< td style = " min-width:120px " >
2013-12-31 10:43:39 +01:00
< input onkeyup = " onItemChange() " data - bind = " value: prettyCost, valueUpdate: 'afterkeydown' " style = " text-align: right " class = " form-control " //>
2013-11-26 22:45:10 +01:00
</ td >
2013-12-31 20:49:54 +01:00
< td style = " min-width:120px " >
2013-12-31 10:43:39 +01:00
< input onkeyup = " onItemChange() " data - bind = " value: prettyQty, valueUpdate: 'afterkeydown' " style = " text-align: right " class = " form-control " //>
2013-11-26 22:45:10 +01:00
</ td >
2014-01-01 16:23:32 +01:00
< td style = " min-width:120px; vertical-align:middle " data - bind = " visible: $root .invoice_item_taxes.show " >
< select class = " form-control " style = " width:100% " data - bind = " value: tax, options: $root .tax_rates, optionsText: 'displayName' " ></ select >
2013-11-26 22:45:10 +01:00
</ td >
2013-12-31 20:49:54 +01:00
< td style = " min-width:120px;text-align: right;padding-top:9px !important " >
2014-01-01 16:23:32 +01:00
< span data - bind = " text: totals.total " ></ span >
2013-11-26 22:45:10 +01:00
</ td >
2013-12-31 20:49:54 +01:00
< td style = " min-width:20px; cursor:pointer " class = " hide-border td-icon " >
2013-12-13 10:13:57 +01:00
& nbsp ; < i data - bind = " click: $parent .removeItem, visible: actionsVisible() && $parent .invoice_items().length > 1 " class = " fa fa-minus-circle " title = " Remove item " />
2013-11-26 22:45:10 +01:00
</ td >
</ tr >
</ tbody >
2013-12-31 20:49:54 +01:00
< tfoot >
< tr >
2013-12-29 00:33:48 +01:00
< td class = " hide-border " />
2014-01-02 18:16:00 +01:00
< td colspan = " 2 " rowspan = " 5 " >
< br />
{{ Former :: textarea ( 'public_notes' ) -> data_bind ( " value: wrapped_notes, valueUpdate: 'afterkeydown' " )
-> label ( false ) -> placeholder ( 'Note to client' ) -> style ( 'width: 520px; resize: none' ) }}
{{ Former :: textarea ( 'terms' ) -> data_bind ( " value: wrapped_terms, valueUpdate: 'afterkeydown' " )
-> label ( false ) -> placeholder ( 'Invoice terms' ) -> style ( 'width: 520px; resize: none' ) }}
</ td >
2014-01-01 16:23:32 +01:00
< td data - bind = " visible: $root .invoice_item_taxes.show " />
2013-11-26 22:45:10 +01:00
< td colspan = " 2 " > Subtotal </ td >
2014-01-01 16:23:32 +01:00
< td style = " text-align: right " >< span data - bind = " text: totals.subtotal " /></ td >
2013-11-26 22:45:10 +01:00
</ tr >
< tr data - bind = " visible: discount() > 0 " >
2013-12-31 20:49:54 +01:00
< td class = " hide-border " colspan = " 3 " />
2014-01-01 16:23:32 +01:00
< td class = " hide-border " data - bind = " visible: $root .invoice_item_taxes.show " />
2013-11-26 22:45:10 +01:00
< td colspan = " 2 " > Discount </ td >
2014-01-01 16:23:32 +01:00
< td style = " text-align: right " >< span data - bind = " text: totals.discounted " /></ td >
2013-11-26 22:45:10 +01:00
</ tr >
2014-01-01 16:23:32 +01:00
< tr data - bind = " visible: $root .invoice_taxes.show " >
2013-12-31 20:49:54 +01:00
< td class = " hide-border " colspan = " 3 " />
2014-01-01 16:23:32 +01:00
< td class = " hide-border " data - bind = " visible: $root .invoice_item_taxes.show " />
2013-12-31 20:49:54 +01:00
< td style = " vertical-align: middle " > Tax </ td >
2014-01-01 16:23:32 +01:00
< td >< select class = " form-control " style = " width:100% " data - bind = " value: tax, options: $root .tax_rates, optionsText: 'displayName' " ></ select ></ td >
< td style = " vertical-align: middle; text-align: right " >< span data - bind = " text: totals.taxAmount " /></ td >
2013-12-31 20:49:54 +01:00
</ tr >
2013-12-30 21:17:45 +01:00
< tr >
2013-12-31 20:49:54 +01:00
< td class = " hide-border " colspan = " 3 " />
2014-01-01 16:23:32 +01:00
< td class = " hide-border " data - bind = " visible: $root .invoice_item_taxes.show " />
2013-12-30 21:17:45 +01:00
< td colspan = " 2 " > Paid to Date </ td >
2014-01-08 00:59:06 +01:00
< td style = " text-align: right " data - bind = " text: totals.paidToDate " ></ td >
2013-12-30 21:17:45 +01:00
</ tr >
2013-11-26 22:45:10 +01:00
< tr >
2013-12-31 20:49:54 +01:00
< td class = " hide-border " colspan = " 3 " />
2014-01-01 16:23:32 +01:00
< td class = " hide-border " data - bind = " visible: $root .invoice_item_taxes.show " />
2013-12-11 21:33:44 +01:00
< td colspan = " 2 " >< b > Balance Due </ b ></ td >
2014-01-01 16:23:32 +01:00
< td style = " text-align: right " >< span data - bind = " text: totals.total " /></ td >
2013-11-26 22:45:10 +01:00
</ tr >
</ tfoot >
</ table >
2013-11-26 13:45:07 +01:00
2013-11-26 22:45:10 +01:00
< p >& nbsp ; </ p >
< div class = " form-actions " >
2013-12-03 18:32:33 +01:00
2013-12-07 19:45:00 +01:00
< div style = " display:none " >
{{ Former :: text ( 'action' ) }}
2014-01-01 16:23:32 +01:00
@ if ( $invoice )
2013-12-05 21:25:20 +01:00
{{ Former :: text ( 'id' ) }}
2014-01-01 16:23:32 +01:00
{{ Former :: populateField ( 'id' , $invoice -> id ) }}
2013-12-07 19:45:00 +01:00
@ endif
</ div >
2013-12-11 21:33:44 +01:00
2013-12-07 19:45:00 +01:00
@ if ( $invoice )
2014-01-06 19:03:00 +01:00
< div id = " relatedActions " style = " text-align:left " class = " btn-group " >
< button class = " btn-default btn " type = " button " > Download PDF </ button >
< button class = " btn-default btn dropdown-toggle " type = " button " data - toggle = " dropdown " >
< span class = " caret " ></ span >
</ button >
< ul class = " dropdown-menu " >
< li >< a href = " javascript:onDownloadClick() " > Download PDF </ a ></ li >
< li class = " divider " ></ li >
< li >< a href = " javascript:onPaymentClick() " > Create Payment </ a ></ li >
< li >< a href = " javascript:onCreditClick() " > Create Credit </ a ></ li >
</ ul >
</ div >
< div id = " primaryActions " style = " text-align:left " data - bind = " css: $root .enable.save " class = " btn-group " >
< button class = " btn-primary btn " type = " button " data - bind = " css: $root .enable.save " > Save Invoice </ button >
< button class = " btn-primary btn dropdown-toggle " type = " button " data - toggle = " dropdown " data - bind = " css: $root .enable.save " >
< span class = " caret " ></ span >
</ button >
< ul class = " dropdown-menu " >
< li >< a href = " javascript:onSaveClick() " > Save Invoice </ a ></ li >
< li >< a href = " javascript:onCloneClick() " > Clone Invoice </ a ></ li >
< li class = " divider " ></ li >
< li >< a href = " javascript:onArchiveClick() " > Archive Invoice </ a ></ li >
< li >< a href = " javascript:onDeleteClick() " > Delete Invoice </ a ></ li >
</ ul >
</ div >
{{ -- DropdownButton :: normal ( 'Download PDF' ,
2014-01-02 14:21:15 +01:00
Navigation :: links (
array (
array ( 'Download PDF' , " javascript:onDownloadClick() " ),
array ( Navigation :: DIVIDER ),
array ( 'Create Payment' , " javascript:onPaymentClick() " ),
array ( 'Create Credit' , " javascript:onCreditClick() " ),
)
)
2014-01-06 19:03:00 +01:00
, array ( 'id' => 'relatedActions' , 'style' => 'text-align:left' )) -> split (); -- }}
2014-01-02 14:21:15 +01:00
2014-01-06 19:03:00 +01:00
{{ -- DropdownButton :: primary ( 'Save Invoice' ,
2013-12-03 18:32:33 +01:00
Navigation :: links (
array (
2013-12-11 21:33:44 +01:00
array ( 'Save Invoice' , " javascript:onSaveClick() " ),
array ( 'Clone Invoice' , " javascript:onCloneClick() " ),
2013-12-03 18:32:33 +01:00
array ( Navigation :: DIVIDER ),
array ( 'Archive Invoice' , " javascript:onArchiveClick() " ),
array ( 'Delete Invoice' , " javascript:onDeleteClick() " ),
)
)
2014-01-06 19:03:00 +01:00
, array ( 'id' => 'primaryActions' , 'style' => 'text-align:left' , 'data-bind' => 'css: $root.enable.save' )) -> split (); -- }}
2013-12-03 18:32:33 +01:00
@ else
2014-01-02 14:21:15 +01:00
{{ Button :: normal ( 'Download PDF' , array ( 'onclick' => 'onDownloadClick()' )) }}
2014-01-02 00:12:33 +01:00
{{ Button :: primary_submit ( 'Save Invoice' , array ( 'data-bind' => 'css: $root.enable.save' )) }}
2013-12-03 18:32:33 +01:00
@ endif
2014-01-02 00:12:33 +01:00
{{ Button :: primary ( 'Send Email' , array ( 'id' => 'email_button' , 'onclick' => 'onEmailClick()' , 'data-bind' => 'css: $root.enable.email' )) }}
2013-11-26 13:45:07 +01:00
</ div >
2013-11-26 22:45:10 +01:00
< p >& nbsp ; </ p >
<!-- < textarea rows = " 20 " cols = " 120 " id = " pdfText " onkeyup = " runCode() " ></ textarea > -->
2013-11-27 08:38:37 +01:00
<!-- < iframe frameborder = " 1 " width = " 100% " height = " 600 " style = " display:block;margin: 0 auto " ></ iframe > -->
2013-12-31 00:19:17 +01:00
< iframe id = " theFrame " style = " display:none " frameborder = " 1 " width = " 100% " height = " 500 " ></ iframe >
2013-12-11 21:33:44 +01:00
< canvas id = " theCanvas " style = " display:none;width:100%;border:solid 1px #CCCCCC; " ></ canvas >
2013-11-26 13:45:07 +01:00
2013-12-27 10:10:32 +01:00
< div class = " modal fade " id = " clientModal " tabindex = " -1 " role = " dialog " aria - labelledby = " clientModalLabel " aria - hidden = " true " >
2013-12-05 21:25:20 +01:00
< div class = " modal-dialog " style = " min-width:1000px " >
2013-11-26 13:45:07 +01:00
< div class = " modal-content " >
< div class = " modal-header " >
< button type = " button " class = " close " data - dismiss = " modal " aria - hidden = " true " >& times ; </ button >
2013-12-31 00:19:17 +01:00
< h4 class = " modal-title " id = " clientModalLabel " > Client </ h4 >
2013-11-26 13:45:07 +01:00
</ div >
2013-12-05 21:25:20 +01:00
2013-12-27 10:10:32 +01:00
< div class = " container " style = " width: 100% " >
< div style = " background-color: #F6F6F6 " class = " row " data - bind = " with: client " onkeypress = " clientModalEnterClick(event) " >
< div class = " col-md-6 " style = " margin-left:0px;margin-right:0px " >
2013-12-05 21:25:20 +01:00
2014-01-02 09:27:48 +01:00
{{ Former :: legend ( 'Organization' ) }}
{{ Former :: text ( 'name' ) -> data_bind ( " value: name, valueUpdate: 'afterkeydown', attr { placeholder: name.placeholder } " ) }}
{{ Former :: text ( 'website' ) -> data_bind ( " value: website, valueUpdate: 'afterkeydown' " ) }}
{{ Former :: text ( 'work_phone' ) -> data_bind ( " value: work_phone, valueUpdate: 'afterkeydown' " ) -> label ( 'Phone' ) }}
{{ Former :: legend ( 'Address' ) }}
{{ Former :: text ( 'address1' ) -> label ( 'Street' ) -> data_bind ( " value: address1, valueUpdate: 'afterkeydown' " ) }}
2014-01-02 18:16:00 +01:00
{{ Former :: text ( 'address2' ) -> label ( 'Apt/Suite' ) -> data_bind ( " value: address2, valueUpdate: 'afterkeydown' " ) }}
2014-01-02 09:27:48 +01:00
{{ Former :: text ( 'city' ) -> data_bind ( " value: city, valueUpdate: 'afterkeydown' " ) }}
2014-01-02 18:16:00 +01:00
{{ Former :: text ( 'state' ) -> label ( 'State/Province' ) -> data_bind ( " value: state, valueUpdate: 'afterkeydown' " ) }}
2014-01-02 09:27:48 +01:00
{{ Former :: text ( 'postal_code' ) -> data_bind ( " value: postal_code, valueUpdate: 'afterkeydown' " ) }}
{{ Former :: select ( 'country_id' ) -> addOption ( '' , '' ) -> label ( 'Country' ) -> addGroupClass ( 'country_select' )
-> fromQuery ( $countries , 'name' , 'id' ) -> data_bind ( " dropdown: country_id " ) }}
</ div >
< div class = " col-md-6 " style = " margin-left:0px;margin-right:0px " >
2013-12-13 10:13:57 +01:00
{{ Former :: legend ( 'Contacts' ) }}
< div data - bind = ' template : { foreach : contacts ,
beforeRemove : hideContact ,
afterAdd : showContact } ' >
{{ Former :: hidden ( 'public_id' ) -> data_bind ( " value: public_id, valueUpdate: 'afterkeydown' " ) }}
{{ Former :: text ( 'first_name' ) -> data_bind ( " value: first_name, valueUpdate: 'afterkeydown' " ) }}
{{ Former :: text ( 'last_name' ) -> data_bind ( " value: last_name, valueUpdate: 'afterkeydown' " ) }}
{{ Former :: text ( 'email' ) -> data_bind ( " value: email, valueUpdate: 'afterkeydown' " ) }}
{{ Former :: text ( 'phone' ) -> data_bind ( " value: phone, valueUpdate: 'afterkeydown' " ) }}
< div class = " form-group " >
< div class = " col-lg-8 col-lg-offset-4 " >
< span data - bind = " visible: $parent .contacts().length > 1 " >
{{ link_to ( '#' , 'Remove contact' , array ( 'data-bind' => 'click: $parent.removeContact' )) }}
</ span >
< span data - bind = " visible: $index () === ( $parent .contacts().length - 1) " class = " pull-right " >
{{ link_to ( '#' , 'Add contact' , array ( 'data-bind' => 'click: $parent.addContact' )) }}
</ span >
</ div >
</ div >
</ div >
{{ Former :: legend ( 'Additional Info' ) }}
2014-01-01 16:23:32 +01:00
{{ Former :: select ( 'payment_terms' ) -> addOption ( '' , '0' ) -> data_bind ( 'value: payment_terms' )
2013-12-31 10:43:39 +01:00
-> fromQuery ( $paymentTerms , 'name' , 'num_days' ) }}
2013-12-29 18:40:11 +01:00
{{ Former :: select ( 'currency_id' ) -> addOption ( '' , '' ) -> label ( 'Currency' ) -> data_bind ( 'value: currency_id' )
-> fromQuery ( $currencies , 'name' , 'id' ) }}
2014-01-06 19:03:00 +01:00
{{ Former :: select ( 'size_id' ) -> addOption ( '' , '' ) -> label ( 'Size' ) -> data_bind ( 'value: size_id' )
-> fromQuery ( $sizes , 'name' , 'id' ) }}
{{ Former :: select ( 'industry_id' ) -> addOption ( '' , '' ) -> label ( 'Industry' ) -> data_bind ( 'value: industry_id' )
-> fromQuery ( $industries , 'name' , 'id' ) }}
2013-12-30 21:17:45 +01:00
{{ Former :: textarea ( 'private_notes' ) -> data_bind ( 'value: private_notes' ) }}
2013-12-13 10:13:57 +01:00
2013-12-05 21:25:20 +01:00
</ div >
</ div >
2013-12-27 10:10:32 +01:00
</ div >
2013-12-05 21:25:20 +01:00
2013-12-27 10:10:32 +01:00
< div class = " modal-footer " style = " margin-top: 0px " >
2013-12-31 10:43:39 +01:00
< span class = " error-block " id = " emailError " style = " display:none;float:left;font-weight:bold " > Please provide a valid email address .</ span >< span >& nbsp ; </ span >
2013-12-05 21:25:20 +01:00
< button type = " button " class = " btn btn-default " data - dismiss = " modal " > Cancel </ button >
2014-01-01 16:23:32 +01:00
< button type = " button " class = " btn btn-primary " data - bind = " click: $root .clientFormComplete " > Done </ button >
2013-12-27 10:10:32 +01:00
</ div >
</ div >
</ div >
</ div >
< div class = " modal fade " id = " taxModal " tabindex = " -1 " role = " dialog " aria - labelledby = " taxModalLabel " aria - hidden = " true " >
< div class = " modal-dialog " style = " min-width:150px " >
< div class = " modal-content " >
< div class = " modal-header " >
< button type = " button " class = " close " data - dismiss = " modal " aria - hidden = " true " >& times ; </ button >
< h4 class = " modal-title " id = " taxModalLabel " > Tax Rates </ h4 >
2013-11-26 13:45:07 +01:00
</ div >
2013-12-27 10:10:32 +01:00
< div style = " background-color: #F6F6F6 " onkeypress = " taxModalEnterClick(event) " >
< table class = " table invoice-table sides-padded " style = " margin-bottom: 0px !important " >
< thead >
< tr >
< th class = " hide-border " ></ th >
< th class = " hide-border " > Name </ th >
< th class = " hide-border " > Rate </ th >
< th class = " hide-border " ></ th >
</ tr >
</ thead >
2014-01-01 16:23:32 +01:00
< tbody data - bind = " foreach: $root .tax_rates.filtered " >
2013-12-27 10:10:32 +01:00
< tr data - bind = " event: { mouseover: showActions, mouseout: hideActions } " >
< td style = " width:10px " class = " hide-border " ></ td >
< td style = " width:60px " >
< input onkeyup = " onTaxRateChange() " data - bind = " value: name, valueUpdate: 'afterkeydown' " class = " form-control " onchange = " refreshPDF() " //>
</ td >
< td style = " width:60px " >
2013-12-29 12:28:44 +01:00
< input onkeyup = " onTaxRateChange() " data - bind = " value: prettyRate, valueUpdate: 'afterkeydown' " style = " text-align: right " class = " form-control " onchange = " refreshPDF() " //>
2013-12-27 10:10:32 +01:00
</ td >
< td style = " width:10px; cursor:pointer " class = " hide-border td-icon " >
2014-01-02 00:12:33 +01:00
& nbsp ; < i data - bind = " click: $root .removeTaxRate, visible: actionsVisible() && !isEmpty() " class = " fa fa-minus-circle " title = " Remove item " />
2013-12-27 10:10:32 +01:00
</ td >
</ tr >
</ tbody >
</ table >
& nbsp ;
2013-12-31 20:49:54 +01:00
{{ Former :: checkbox ( 'invoice_taxes' ) -> text ( 'Enable specifying an <b>invoice tax</b>' )
2014-01-01 16:23:32 +01:00
-> label ( 'Settings' ) -> data_bind ( 'checked: $root.invoice_taxes, enable: $root.tax_rates().length > 1' ) }}
2014-01-06 07:48:11 +01:00
{{ Former :: checkbox ( 'invoice_item_taxes' ) -> text ( 'Enable specifying <b>line item taxes</b>' ) -> addOnGroupClass ( 'no-space-bottom' )
2014-01-01 16:23:32 +01:00
-> label ( ' ' ) -> data_bind ( 'checked: $root.invoice_item_taxes, enable: $root.tax_rates().length > 1' ) }}
2013-12-31 20:49:54 +01:00
2014-01-06 07:48:11 +01:00
< br />
2013-12-27 10:10:32 +01:00
</ div >
< div class = " modal-footer " style = " margin-top: 0px " >
2013-12-29 12:28:44 +01:00
<!-- < button type = " button " class = " btn btn-default " data - dismiss = " modal " > Cancel </ button > -->
2014-01-01 16:23:32 +01:00
< button type = " button " class = " btn btn-primary " data - bind = " click: $root .taxFormComplete " > Done </ button >
2013-12-27 10:10:32 +01:00
</ div >
2013-12-05 21:25:20 +01:00
2013-11-26 13:45:07 +01:00
</ div >
</ div >
</ div >
2013-12-27 10:10:32 +01:00
2013-11-26 13:45:07 +01:00
{{ Former :: close () }}
2014-01-01 16:23:32 +01:00
</ div >
2013-11-26 13:45:07 +01:00
< script type = " text/javascript " >
2013-11-27 08:38:37 +01:00
2013-11-26 13:45:07 +01:00
$ ( function () {
2013-12-05 21:25:20 +01:00
$ ( '#country_id' ) . combobox ();
2013-12-24 22:27:36 +01:00
$ ( '[rel=tooltip]' ) . tooltip ();
2013-12-05 21:25:20 +01:00
2014-01-02 14:21:15 +01:00
$ ( '#invoice_date, #due_date, #start_date, #end_date' ) . datepicker ();
2013-11-28 17:40:13 +01:00
2013-12-29 18:40:11 +01:00
@ if ( $client && ! $invoice )
$ ( 'input[name=client]' ) . val ({{ $client -> public_id }});
@ endif
2013-11-26 13:45:07 +01:00
var $input = $ ( 'select#client' );
2013-12-31 17:38:49 +01:00
$input . combobox () . on ( 'change' , function ( e ) {
2014-01-01 18:34:37 +01:00
var clientId = parseInt ( $ ( 'input[name=client]' ) . val (), 10 );
2013-12-17 14:14:47 +01:00
if ( clientId > 0 ) {
model . loadClient ( clientMap [ clientId ]);
2013-12-13 10:13:57 +01:00
} else {
2014-01-02 09:27:48 +01:00
model . loadClient ( $ . parseJSON ( ko . toJSON ( new ClientModel ())));
2013-12-08 14:32:49 +01:00
}
2013-12-30 21:17:45 +01:00
refreshPDF ();
2014-01-06 19:03:00 +01:00
}); //.trigger('change');
2013-11-26 13:45:07 +01:00
2013-12-30 21:17:45 +01:00
$ ( '#terms, #public_notes, #invoice_number, #invoice_date, #due_date, #po_number, #discout, #currency_id' ) . change ( function () {
refreshPDF ();
});
2013-12-24 22:27:36 +01:00
$ ( '.country_select input.form-control' ) . on ( 'change' , function ( e ) {
var countryId = parseInt ( $ ( 'input[name=country_id]' ) . val (), 10 );
2014-01-01 18:34:37 +01:00
model . invoice () . client () . country_id ( countryId );
2013-12-24 22:27:36 +01:00
});
2014-01-06 19:03:00 +01:00
2014-01-02 09:27:48 +01:00
@ if ( $client || $invoice )
2013-12-08 20:08:17 +01:00
$ ( '#invoice_number' ) . focus ();
2013-11-26 13:45:07 +01:00
@ else
2013-12-31 00:19:17 +01:00
$ ( '.client_select input.form-control' ) . focus ();
2013-11-26 13:45:07 +01:00
@ endif
2013-12-29 00:33:48 +01:00
$ ( '#clientModal' ) . on ( 'shown.bs.modal' , function () {
2014-01-06 07:48:11 +01:00
$ ( '#name' ) . focus ();
2013-12-29 00:33:48 +01:00
}) . on ( 'hidden.bs.modal' , function () {
2013-12-17 14:14:47 +01:00
if ( model . clientBackup ) {
model . loadClient ( model . clientBackup );
refreshPDF ();
}
2013-11-26 13:45:07 +01:00
})
2013-12-17 14:14:47 +01:00
2013-12-27 10:10:32 +01:00
$ ( '#taxModal' ) . on ( 'shown.bs.modal' , function () {
$ ( '#taxModal input:first' ) . focus ();
2013-12-29 00:33:48 +01:00
}) . on ( 'hidden.bs.modal' , function () {
2014-01-02 00:12:33 +01:00
// if the user changed the tax rates we need to trigger the
// change event on the selects for the model to get updated
$ ( 'table.invoice-table select' ) . trigger ( 'change' );
2013-12-29 00:33:48 +01:00
})
2013-12-27 10:10:32 +01:00
2014-01-02 18:16:00 +01:00
$ ( '#relatedActions > button:first' ) . click ( function () {
onDownloadClick ();
});
$ ( '#primaryActions > button:first' ) . click ( function () {
2013-12-11 21:33:44 +01:00
onSaveClick ();
2013-12-03 18:32:33 +01:00
});
2013-12-10 23:10:43 +01:00
$ ( 'label.radio' ) . addClass ( 'radio-inline' );
2014-01-06 19:03:00 +01:00
applyComboboxListeners ();
@ if ( $client )
$input . trigger ( 'change' );
@ else
refreshPDF ();
@ endif
2014-01-02 00:12:33 +01:00
var client = model . invoice () . client ();
setComboboxValue ( $ ( '.client_select' ),
client . public_id (),
client . name . display ());
2014-01-06 19:03:00 +01:00
2013-12-17 14:14:47 +01:00
});
2013-11-26 13:45:07 +01:00
2013-11-27 08:38:37 +01:00
function applyComboboxListeners () {
2013-12-31 10:43:39 +01:00
$ ( '.invoice-table input, .invoice-table select, .invoice-table textarea' ) . on ( 'blur' , function () {
//if (value != $(this).val()) refreshPDF();
refreshPDF ();
});
var value ;
2013-11-27 08:38:37 +01:00
$ ( '.datalist' ) . on ( 'focus' , function () {
value = $ ( this ) . val ();
}) . on ( 'blur' , function () {
if ( value != $ ( this ) . val ()) refreshPDF ();
2013-12-03 18:32:33 +01:00
}) . on ( 'input' , function () {
2013-11-27 08:38:37 +01:00
var key = $ ( this ) . val ();
for ( var i = 0 ; i < products . length ; i ++ ) {
var product = products [ i ];
2013-12-04 17:20:14 +01:00
if ( product . product_key == key ) {
2013-11-27 08:38:37 +01:00
var model = ko . dataFor ( this );
2013-12-29 12:28:44 +01:00
//model.notes(product.notes);
//model.cost(product.cost);
//model.qty(product.qty);
2013-11-27 08:38:37 +01:00
break ;
}
}
});
}
2013-11-26 13:45:07 +01:00
function createInvoiceModel () {
2014-01-06 19:03:00 +01:00
var invoice = ko . toJS ( model ) . invoice ;
2013-12-13 10:13:57 +01:00
@ if ( file_exists ( $account -> getLogoPath ()))
invoice . image = " { { HTML::image_data( $account->getLogoPath ()) }} " ;
invoice . imageWidth = {{ $account -> getLogoWidth () }};
invoice . imageHeight = {{ $account -> getLogoHeight () }};
@ endif
2013-11-26 13:45:07 +01:00
return invoice ;
}
2014-01-01 00:50:13 +01:00
/*
2013-11-26 13:45:07 +01:00
function refreshPDF () {
2013-12-07 19:45:00 +01:00
setTimeout ( function () {
_refreshPDF ();
}, 100 );
}
2014-01-01 00:50:13 +01:00
*/
2013-12-07 19:45:00 +01:00
2014-01-01 00:50:13 +01:00
function refreshPDF () {
2013-11-26 13:45:07 +01:00
var invoice = createInvoiceModel ();
2013-12-11 21:33:44 +01:00
var doc = generatePDF ( invoice );
var string = doc . output ( 'datauristring' );
2013-12-31 00:19:17 +01:00
if ( isFirefox || isChrome ) {
$ ( '#theFrame' ) . attr ( 'src' , string ) . show ();
} else {
var pdfAsArray = convertDataURIToBinary ( string );
PDFJS . getDocument ( pdfAsArray ) . then ( function getPdfHelloWorld ( pdf ) {
pdf . getPage ( 1 ) . then ( function getPageHelloWorld ( page ) {
var scale = 1.5 ;
var viewport = page . getViewport ( scale );
var canvas = document . getElementById ( 'theCanvas' );
var context = canvas . getContext ( '2d' );
canvas . height = viewport . height ;
canvas . width = viewport . width ;
page . render ({ canvasContext : context , viewport : viewport });
$ ( '#theCanvas' ) . show ();
});
});
}
2013-12-07 19:45:00 +01:00
}
2013-11-26 13:45:07 +01:00
function onDownloadClick () {
var invoice = createInvoiceModel ();
var doc = generatePDF ( invoice );
2013-12-08 20:08:17 +01:00
doc . save ( 'Invoice-' + $ ( '#invoice_number' ) . val () + '.pdf' );
2013-11-26 13:45:07 +01:00
}
function onEmailClick () {
if ( confirm ( 'Are you sure you want to email this invoice?' )) {
2013-12-03 18:32:33 +01:00
$ ( '#action' ) . val ( 'email' );
2013-11-26 13:45:07 +01:00
$ ( '.main_form' ) . submit ();
}
}
2013-12-11 21:33:44 +01:00
function onSaveClick () {
$ ( '.main_form' ) . submit ();
}
function onCloneClick () {
$ ( '#action' ) . val ( 'clone' );
$ ( '.main_form' ) . submit ();
}
2014-01-02 14:21:15 +01:00
@ if ( $client && $invoice )
function onPaymentClick () {
window . location = '{{ URL::to(' payments / create / ' . $client->public_id . ' / ' . $invoice->public_id ) }}' ;
}
function onCreditClick () {
window . location = '{{ URL::to(' credits / create / ' . $client->public_id . ' / ' . $invoice->public_id ) }}' ;
}
@ endif
2013-12-03 18:32:33 +01:00
function onArchiveClick () {
$ ( '#action' ) . val ( 'archive' );
$ ( '.main_form' ) . submit ();
}
function onDeleteClick () {
if ( confirm ( 'Are you sure you want to delete this invoice?' )) {
$ ( '#action' ) . val ( 'delete' );
$ ( '.main_form' ) . submit ();
}
}
2013-12-13 10:13:57 +01:00
function formEnterClick ( event ) {
if ( event . keyCode === 13 ){
if ( event . target . type == 'textarea' ) {
return ;
2013-12-11 21:33:44 +01:00
}
2013-12-13 10:13:57 +01:00
event . preventDefault ();
2014-01-02 00:12:33 +01:00
if ( model . enable . save () != 'enabled' ) {
return ;
}
2013-12-13 10:13:57 +01:00
$ ( '.main_form' ) . submit ();
return false ;
2013-11-26 13:45:07 +01:00
}
2013-12-13 10:13:57 +01:00
}
2013-12-05 21:25:20 +01:00
2013-12-27 10:10:32 +01:00
function clientModalEnterClick ( event ) {
2013-11-26 13:45:07 +01:00
if ( event . keyCode === 13 ){
event . preventDefault ();
2013-12-13 10:13:57 +01:00
model . clientFormComplete ();
2013-11-26 13:45:07 +01:00
return false ;
}
}
2013-12-27 10:10:32 +01:00
function taxModalEnterClick ( event ) {
if ( event . keyCode === 13 ){
event . preventDefault ();
model . taxFormComplete ();
return false ;
}
}
2014-01-01 18:34:37 +01:00
function ViewModel ( data ) {
2014-01-01 16:23:32 +01:00
var self = this ;
2014-01-01 18:34:37 +01:00
//self.invoice = data ? false : new InvoiceModel();
self . invoice = ko . observable ( data ? false : new InvoiceModel ());
2014-01-01 16:23:32 +01:00
self . tax_rates = ko . observableArray ();
self . loadClient = function ( client ) {
2014-01-01 18:34:37 +01:00
ko . mapping . fromJS ( client , model . invoice () . client () . mapping , model . invoice () . client );
2014-01-08 00:59:06 +01:00
self . setDueDate ();
}
self . setDueDate = function () {
var paymentTerms = parseInt ( self . invoice () . client () . payment_terms ());
if ( paymentTerms && ! self . invoice () . due_date ())
{
var dueDate = $ ( '#invoice_date' ) . datepicker ( 'getDate' );
dueDate . setDate ( dueDate . getDate () + paymentTerms );
self . invoice () . due_date ( dueDate );
}
2014-01-01 16:23:32 +01:00
}
self . invoice_taxes = ko . observable ({{ Auth :: user () -> account -> invoice_taxes ? 'true' : 'false' }});
self . invoice_item_taxes = ko . observable ({{ Auth :: user () -> account -> invoice_item_taxes ? 'true' : 'false' }});
2014-01-01 18:34:37 +01:00
2014-01-01 16:23:32 +01:00
self . mapping = {
'invoice' : {
create : function ( options ) {
return new InvoiceModel ( options . data );
}
},
'tax_rates' : {
create : function ( options ) {
return new TaxRateModel ( options . data );
}
},
2014-01-01 18:34:37 +01:00
}
if ( data ) {
ko . mapping . fromJS ( data , self . mapping , self );
2014-01-01 16:23:32 +01:00
}
self . invoice_taxes . show = ko . computed ( function () {
if ( self . tax_rates () . length > 2 && self . invoice_taxes ()) {
return true ;
}
2014-01-01 18:34:37 +01:00
if ( self . invoice () . tax_rate () > 0 ) {
2014-01-01 16:23:32 +01:00
return true ;
}
return false ;
});
self . invoice_item_taxes . show = ko . computed ( function () {
if ( self . tax_rates () . length > 2 && self . invoice_item_taxes ()) {
return true ;
}
2014-01-01 18:34:37 +01:00
for ( var i = 0 ; i < self . invoice () . invoice_items () . length ; i ++ ) {
var item = self . invoice () . invoice_items ()[ i ];
2014-01-01 16:23:32 +01:00
if ( item . tax_rate () > 0 ) {
return true ;
}
}
return false ;
});
self . tax_rates . filtered = ko . computed ( function () {
2014-01-02 00:12:33 +01:00
var i = 0 ;
for ( i ; i < self . tax_rates () . length ; i ++ ) {
var taxRate = self . tax_rates ()[ i ];
if ( taxRate . isEmpty ()) {
break ;
}
}
2014-01-01 16:23:32 +01:00
2014-01-02 00:12:33 +01:00
var rates = self . tax_rates () . concat ();
rates . splice ( i , 1 );
return rates ;
});
2014-01-01 16:23:32 +01:00
self . removeTaxRate = function ( taxRate ) {
self . tax_rates . remove ( taxRate );
//refreshPDF();
}
self . addTaxRate = function ( data ) {
var itemModel = new TaxRateModel ( data );
self . tax_rates . push ( itemModel );
applyComboboxListeners ();
2014-01-02 00:12:33 +01:00
}
2014-01-01 16:23:32 +01:00
2014-01-02 00:12:33 +01:00
/*
2014-01-01 16:23:32 +01:00
self . getBlankTaxRate = function () {
for ( var i = 0 ; i < self . tax_rates () . length ; i ++ ) {
var taxRate = self . tax_rates ()[ i ];
if ( ! taxRate . name ()) {
return taxRate ;
}
}
}
2014-01-02 00:12:33 +01:00
*/
2014-01-01 16:23:32 +01:00
self . getTaxRate = function ( name , rate ) {
for ( var i = 0 ; i < self . tax_rates () . length ; i ++ ) {
var taxRate = self . tax_rates ()[ i ];
if ( taxRate . name () == name && taxRate . rate () == parseFloat ( rate )) {
return taxRate ;
}
}
2014-01-02 00:12:33 +01:00
2014-01-01 16:23:32 +01:00
var taxRate = new TaxRateModel ();
taxRate . name ( name );
taxRate . rate ( parseFloat ( rate ));
2014-01-02 00:12:33 +01:00
if ( parseFloat ( rate ) > 0 ) taxRate . is_deleted ( true );
2014-01-01 18:34:37 +01:00
self . tax_rates . push ( taxRate );
2014-01-01 16:23:32 +01:00
return taxRate ;
}
self . showTaxesForm = function () {
self . taxBackup = ko . mapping . toJS ( self . tax_rates );
$ ( '#taxModal' ) . modal ( 'show' );
}
self . taxFormComplete = function () {
model . taxBackup = false ;
$ ( '#taxModal' ) . modal ( 'hide' );
}
self . showClientForm = function () {
2014-01-01 18:34:37 +01:00
self . clientBackup = ko . mapping . toJS ( self . invoice () . client );
2014-01-01 16:23:32 +01:00
$ ( '#emailError' ) . css ( " display " , " none " );
$ ( '#clientModal' ) . modal ( 'show' );
}
self . clientFormComplete = function () {
2014-01-02 09:27:48 +01:00
var isValid = true ;
$ ( " input[id='email'] " ) . each ( function ( item , value ) {
var email = $ ( value ) . val ();
if ( ! email || ! isValidEmailAddress ( email )) {
isValid = false ;
}
});
if ( ! isValid ) {
$ ( '#emailError' ) . css ( " display " , " inline " );
return ;
}
2014-01-01 16:23:32 +01:00
var email = $ ( '#email' ) . val ();
var firstName = $ ( '#first_name' ) . val ();
var lastName = $ ( '#last_name' ) . val ();
var name = $ ( '#name' ) . val ();
2014-01-01 18:34:37 +01:00
if ( self . invoice () . client () . public_id () == 0 ) {
self . invoice () . client () . public_id ( - 1 );
2014-01-01 16:23:32 +01:00
}
2014-01-08 00:59:06 +01:00
model . setDueDate ();
2014-01-01 16:23:32 +01:00
if ( name ) {
//
} else if ( firstName || lastName ) {
name = firstName + ' ' + lastName ;
} else {
name = email ;
}
2014-01-02 00:12:33 +01:00
setComboboxValue ( $ ( '.client_select' ), - 1 , name );
//$('.client_select select').combobox('setSelected');
//$('.client_select input.form-control').val(name);
//$('.client_select .combobox-container').addClass('combobox-selected');
2014-01-01 16:23:32 +01:00
$ ( '#emailError' ) . css ( " display " , " none " );
//$('.client_select input.form-control').focus();
$ ( '#invoice_number' ) . focus ();
refreshPDF ();
model . clientBackup = false ;
$ ( '#clientModal' ) . modal ( 'hide' );
}
2014-01-02 00:12:33 +01:00
self . enable = {};
self . enable . save = ko . computed ( function () {
var isValid = false ;
for ( var i = 0 ; i < self . invoice () . client () . contacts () . length ; i ++ ) {
var contact = self . invoice () . client () . contacts ()[ i ];
if ( isValidEmailAddress ( contact . email ())) {
isValid = true ;
} else {
isValid = false ;
break ;
}
}
return isValid ? " enabled " : " disabled " ;
});
self . enable . email = ko . computed ( function () {
var isValid = false ;
var sendTo = false ;
2014-01-06 19:03:00 +01:00
var client = self . invoice () . client ();
for ( var i = 0 ; i < client . contacts () . length ; i ++ ) {
var contact = client . contacts ()[ i ];
2014-01-02 00:12:33 +01:00
if ( isValidEmailAddress ( contact . email ())) {
isValid = true ;
2014-01-06 19:03:00 +01:00
if ( contact . send_invoice () || client . contacts () . length == 1 ) {
2014-01-02 00:12:33 +01:00
sendTo = true ;
}
} else {
isValid = false ;
break ;
}
}
return isValid && sendTo ? " enabled " : " disabled " ;
});
self . clientLinkText = ko . computed ( function () {
return self . invoice () . client () . public_id () ? 'Edit client details' : 'Create new client' ;
});
2014-01-01 16:23:32 +01:00
}
2014-01-01 00:50:13 +01:00
function InvoiceModel ( data ) {
2013-12-13 10:13:57 +01:00
var self = this ;
2014-01-01 18:34:37 +01:00
this . client = ko . observable ( data ? false : new ClientModel ());
2014-01-06 19:03:00 +01:00
self . account = {{ $account }};
2014-01-01 16:23:32 +01:00
this . id = ko . observable ( '' );
2013-12-13 10:13:57 +01:00
self . discount = ko . observable ( '' );
self . frequency_id = ko . observable ( '' );
2014-01-02 18:16:00 +01:00
//self.currency_id = ko.observable({{ Session::get(SESSION_CURRENCY) }});
self . currency_id = ko . observable ({{ $client && $client -> currency_id ? $client -> currency_id : Session :: get ( SESSION_CURRENCY ) }});
2014-01-01 16:23:32 +01:00
self . terms = ko . observable ( wordWrapText ( '{{ $account->invoice_terms }}' , 340 ));
2013-12-30 21:17:45 +01:00
self . public_notes = ko . observable ( '' );
2013-12-13 10:13:57 +01:00
self . po_number = ko . observable ( '' );
2014-01-01 16:23:32 +01:00
self . invoice_date = ko . observable ( '{{ Utils::today() }}' );
self . invoice_number = ko . observable ( '{{ isset($invoiceNumber) ? $invoiceNumber : ' ' }}' );
2013-12-13 10:13:57 +01:00
self . due_date = ko . observable ( '' );
2014-01-01 16:23:32 +01:00
self . start_date = ko . observable ( '{{ Utils::today() }}' );
2013-12-13 10:13:57 +01:00
self . end_date = ko . observable ( '' );
2014-01-01 16:23:32 +01:00
self . tax_name = ko . observable ();
self . tax_rate = ko . observable ();
2013-12-13 10:13:57 +01:00
self . is_recurring = ko . observable ( false );
self . invoice_status_id = ko . observable ( 0 );
self . invoice_items = ko . observableArray ();
2014-01-08 00:59:06 +01:00
self . amount = ko . observable ( 0 );
self . balance = ko . observable ( 0 );
2013-12-31 20:49:54 +01:00
2013-12-13 10:13:57 +01:00
self . mapping = {
2014-01-01 18:34:37 +01:00
'client' : {
create : function ( options ) {
return new ClientModel ( options . data );
}
},
2013-12-13 10:13:57 +01:00
'invoice_items' : {
create : function ( options ) {
return new ItemModel ( options . data );
}
2014-01-01 16:23:32 +01:00
},
'tax' : {
create : function ( options ) {
return new TaxRateModel ( options . data );
}
},
2013-12-17 14:14:47 +01:00
}
2014-01-01 18:34:37 +01:00
self . addItem = function () {
var itemModel = new ItemModel ();
self . invoice_items . push ( itemModel );
applyComboboxListeners ();
}
if ( data ) {
ko . mapping . fromJS ( data , self . mapping , self );
} else {
self . addItem ();
}
2014-01-01 16:23:32 +01:00
self . _tax = ko . observable ();
this . tax = ko . computed ({
read : function () {
return self . _tax ();
},
write : function ( value ) {
if ( value ) {
self . _tax ( value );
self . tax_name ( value . name ());
self . tax_rate ( value . rate ());
} else {
self . _tax ( false );
self . tax_name ( '' );
self . tax_rate ( 0 );
}
}
})
2013-12-15 13:55:50 +01:00
self . wrapped_terms = ko . computed ({
read : function () {
2013-12-30 21:17:45 +01:00
$ ( '#terms' ) . height ( this . terms () . split ( '\n' ) . length * 36 );
2013-12-15 13:55:50 +01:00
return this . terms ();
},
write : function ( value ) {
2013-12-30 21:17:45 +01:00
value = wordWrapText ( value , 340 );
2013-12-15 13:55:50 +01:00
self . terms ( value );
2013-12-30 21:17:45 +01:00
$ ( '#terms' ) . height ( value . split ( '\n' ) . length * 36 );
},
owner : this
});
2013-12-31 20:49:54 +01:00
2013-12-30 21:17:45 +01:00
self . wrapped_notes = ko . computed ({
read : function () {
$ ( '#public_notes' ) . height ( this . public_notes () . split ( '\n' ) . length * 36 );
return this . public_notes ();
},
write : function ( value ) {
value = wordWrapText ( value , 340 );
self . public_notes ( value );
$ ( '#public_notes' ) . height ( value . split ( '\n' ) . length * 36 );
2013-12-15 13:55:50 +01:00
},
owner : this
});
2014-01-01 00:50:13 +01:00
2013-11-26 13:45:07 +01:00
self . removeItem = function ( item ) {
2013-12-13 10:13:57 +01:00
self . invoice_items . remove ( item );
2013-11-26 13:45:07 +01:00
refreshPDF ();
}
2014-01-01 16:23:32 +01:00
this . totals = ko . observable ();
2013-12-31 20:49:54 +01:00
2014-01-01 16:23:32 +01:00
this . totals . rawSubtotal = ko . computed ( function () {
2013-11-26 13:45:07 +01:00
var total = 0 ;
2014-01-01 18:34:37 +01:00
for ( var p = 0 ; p < self . invoice_items () . length ; ++ p ) {
var item = self . invoice_items ()[ p ];
total += item . totals . rawTotal ();
2013-11-26 13:45:07 +01:00
}
return total ;
});
2014-01-01 16:23:32 +01:00
this . totals . subtotal = ko . computed ( function () {
var total = self . totals . rawSubtotal ();
2013-12-29 18:40:11 +01:00
return total > 0 ? formatMoney ( total , self . currency_id ()) : '' ;
2013-11-26 13:45:07 +01:00
});
2014-01-01 16:23:32 +01:00
this . totals . rawDiscounted = ko . computed ( function () {
return self . totals . rawSubtotal () * ( self . discount () / 100 );
2013-12-31 20:49:54 +01:00
});
2013-11-26 13:45:07 +01:00
2014-01-01 16:23:32 +01:00
this . totals . discounted = ko . computed ( function () {
return formatMoney ( self . totals . rawDiscounted (), self . currency_id ());
2013-11-26 13:45:07 +01:00
});
2014-01-01 16:23:32 +01:00
self . totals . taxAmount = ko . computed ( function () {
var total = self . totals . rawSubtotal ();
2013-12-31 20:49:54 +01:00
var discount = parseFloat ( self . discount ());
if ( discount > 0 ) {
total = total * (( 100 - discount ) / 100 );
}
2014-01-01 16:23:32 +01:00
var taxRate = parseFloat ( self . tax_rate ());
2013-12-31 20:49:54 +01:00
if ( taxRate > 0 ) {
var tax = total * ( taxRate / 100 );
return formatMoney ( tax , self . currency_id ());
} else {
return formatMoney ( 0 );
}
});
2014-01-08 00:59:06 +01:00
this . totals . rawPaidToDate = ko . computed ( function () {
return self . amount () - self . balance ();
});
this . totals . paidToDate = ko . computed ( function () {
var total = self . totals . rawPaidToDate ();
return total > 0 ? formatMoney ( total , self . currency_id ()) : '' ;
});
2013-12-31 20:49:54 +01:00
2014-01-01 16:23:32 +01:00
this . totals . total = ko . computed ( function () {
var total = self . totals . rawSubtotal ();
2013-11-26 13:45:07 +01:00
2013-12-11 21:33:44 +01:00
var discount = parseFloat ( self . discount ());
2013-11-26 13:45:07 +01:00
if ( discount > 0 ) {
total = total * (( 100 - discount ) / 100 );
}
2014-01-01 16:23:32 +01:00
var taxRate = parseFloat ( self . tax_rate ());
2013-12-31 20:49:54 +01:00
if ( taxRate > 0 ) {
total = parseFloat ( total ) + ( total * ( taxRate / 100 ));
}
2014-01-08 00:59:06 +01:00
var paid = self . totals . rawPaidToDate ();
if ( paid > 0 ) {
total -= paid ;
}
return total != 0 ? formatMoney ( total , self . currency_id ()) : '' ;
2013-11-26 13:45:07 +01:00
});
self . onDragged = function ( item ) {
refreshPDF ();
2014-01-01 00:50:13 +01:00
}
2013-11-26 13:45:07 +01:00
}
2013-12-13 10:13:57 +01:00
function ClientModel ( data ) {
var self = this ;
self . public_id = ko . observable ( 0 );
self . name = ko . observable ( '' );
self . work_phone = ko . observable ( '' );
2013-12-30 21:17:45 +01:00
self . private_notes = ko . observable ( '' );
2013-12-13 10:13:57 +01:00
self . address1 = ko . observable ( '' );
self . address2 = ko . observable ( '' );
self . city = ko . observable ( '' );
self . state = ko . observable ( '' );
self . postal_code = ko . observable ( '' );
self . country_id = ko . observable ( '' );
2014-01-06 19:03:00 +01:00
self . size_id = ko . observable ( '' );
self . industry_id = ko . observable ( '' );
2013-12-29 18:40:11 +01:00
self . currency_id = ko . observable ( '' );
2013-12-15 13:55:50 +01:00
self . website = ko . observable ( '' );
2014-01-01 16:23:32 +01:00
self . payment_terms = ko . observable ( 0 );
2013-12-13 10:13:57 +01:00
self . contacts = ko . observableArray ();
self . mapping = {
'contacts' : {
create : function ( options ) {
return new ContactModel ( options . data );
}
}
}
2014-01-02 00:12:33 +01:00
2013-12-13 10:13:57 +01:00
self . showContact = function ( elem ) { if ( elem . nodeType === 1 ) $ ( elem ) . hide () . slideDown () }
self . hideContact = function ( elem ) { if ( elem . nodeType === 1 ) $ ( elem ) . slideUp ( function () { $ ( elem ) . remove (); }) }
self . addContact = function () {
var contact = new ContactModel ();
if ( self . contacts () . length == 0 ) {
contact . send_invoice ( true );
}
self . contacts . push ( contact );
return false ;
}
self . removeContact = function () {
self . contacts . remove ( this );
}
2014-01-02 00:12:33 +01:00
self . name . display = ko . computed ( function () {
if ( self . name ()) {
return self . name ();
}
2013-12-30 21:17:45 +01:00
if ( self . contacts () . length == 0 ) return ;
2014-01-02 00:12:33 +01:00
var contact = self . contacts ()[ 0 ];
2013-12-30 21:17:45 +01:00
if ( contact . first_name () || contact . last_name ()) {
2014-01-02 00:12:33 +01:00
return contact . first_name () + ' ' + contact . last_name ();
2013-12-30 21:17:45 +01:00
} else {
2014-01-02 00:12:33 +01:00
return contact . email ();
2013-12-30 21:17:45 +01:00
}
2014-01-02 00:12:33 +01:00
});
2014-01-02 09:27:48 +01:00
self . name . placeholder = ko . computed ( function () {
if ( self . contacts () . length == 0 ) return '' ;
var contact = self . contacts ()[ 0 ];
if ( contact . first_name () || contact . last_name ()) {
return contact . first_name () + ' ' + contact . last_name ();
} else {
return contact . email ();
}
});
2013-12-30 21:17:45 +01:00
2013-12-13 10:13:57 +01:00
if ( data ) {
ko . mapping . fromJS ( data , {}, this );
} else {
self . addContact ();
}
}
function ContactModel ( data ) {
2013-11-26 13:45:07 +01:00
var self = this ;
2013-12-13 10:13:57 +01:00
self . public_id = ko . observable ( '' );
self . first_name = ko . observable ( '' );
self . last_name = ko . observable ( '' );
self . email = ko . observable ( '' );
self . phone = ko . observable ( '' );
self . send_invoice = ko . observable ( false );
2014-01-02 09:27:48 +01:00
/*
self . displayName = ko . computed ( function () {
return self . first_name () + ' ' + self . last_name () + ' - ' + self . email ();
});
*/
2013-12-13 10:13:57 +01:00
if ( data ) {
ko . mapping . fromJS ( data , {}, this );
}
}
2013-12-27 10:10:32 +01:00
function TaxRateModel ( data ) {
var self = this ;
2013-12-29 00:33:48 +01:00
self . public_id = ko . observable ( '' );
2014-01-01 16:23:32 +01:00
self . rate = ko . observable ( 0 );
2013-12-29 00:33:48 +01:00
self . name = ko . observable ( '' );
2013-12-29 12:28:44 +01:00
self . is_deleted = ko . observable ( false );
2014-01-02 00:12:33 +01:00
self . is_blank = ko . observable ( false );
2013-12-29 00:33:48 +01:00
self . actionsVisible = ko . observable ( false );
2013-12-27 10:10:32 +01:00
2013-12-29 00:33:48 +01:00
if ( data ) {
ko . mapping . fromJS ( data , {}, this );
}
2013-12-29 12:28:44 +01:00
this . prettyRate = ko . computed ({
read : function () {
return this . rate () ? parseFloat ( this . rate ()) : '' ;
},
write : function ( value ) {
this . rate ( value );
},
owner : this
});
2014-01-01 16:23:32 +01:00
self . displayName = ko . computed ({
read : function () {
var name = self . name () ? self . name () : '' ;
2014-01-02 00:12:33 +01:00
var rate = self . rate () ? parseFloat ( self . rate ()) + '% ' : '' ;
2014-01-01 16:23:32 +01:00
return rate + name ;
},
write : function ( value ) {
// do nothing
},
owner : this
2013-12-29 00:33:48 +01:00
});
self . hideActions = function () {
self . actionsVisible ( false );
2013-12-27 10:10:32 +01:00
}
2013-12-29 00:33:48 +01:00
self . showActions = function () {
self . actionsVisible ( true );
2013-12-27 10:10:32 +01:00
}
2013-12-29 00:33:48 +01:00
self . isEmpty = function () {
2013-12-27 10:10:32 +01:00
return ! self . rate () && ! self . name ();
}
}
2013-12-13 10:13:57 +01:00
function ItemModel ( data ) {
var self = this ;
2013-11-26 13:45:07 +01:00
this . product_key = ko . observable ( '' );
this . notes = ko . observable ( '' );
2013-12-31 00:19:17 +01:00
this . cost = ko . observable ( 0 );
this . qty = ko . observable ( 0 );
2014-01-01 16:23:32 +01:00
self . tax_name = ko . observable ( '' );
self . tax_rate = ko . observable ( 0 );
2013-11-26 13:45:07 +01:00
this . actionsVisible = ko . observable ( false );
2013-12-29 18:40:11 +01:00
2014-01-01 16:23:32 +01:00
self . _tax = ko . observable ();
this . tax = ko . computed ({
read : function () {
return self . _tax ();
},
write : function ( value ) {
self . _tax ( value );
self . tax_name ( value . name ());
self . tax_rate ( value . rate ());
}
})
2013-12-29 12:28:44 +01:00
this . prettyQty = ko . computed ({
read : function () {
2014-01-08 09:35:35 +01:00
return parseFloat ( this . qty ()) ? parseFloat ( this . qty ()) : '' ;
2013-12-29 12:28:44 +01:00
},
write : function ( value ) {
this . qty ( value );
},
owner : this
});
2013-12-31 00:19:17 +01:00
this . prettyCost = ko . computed ({
read : function () {
return this . cost () ? this . cost () : '' ;
},
write : function ( value ) {
this . cost ( value );
},
owner : this
});
2014-01-01 16:23:32 +01:00
self . mapping = {
'tax' : {
create : function ( options ) {
return new TaxRateModel ( options . data );
}
}
}
2013-12-13 10:13:57 +01:00
if ( data ) {
2014-01-01 16:23:32 +01:00
ko . mapping . fromJS ( data , self . mapping , this );
2014-01-02 00:12:33 +01:00
//if (this.cost()) this.cost(formatMoney(this.cost(), model ? model.invoice().currency_id() : 1, true));
2013-12-29 00:33:48 +01:00
}
2013-12-15 13:55:50 +01:00
self . wrapped_notes = ko . computed ({
read : function () {
return this . notes ();
},
write : function ( value ) {
value = wordWrapText ( value );
self . notes ( value );
2013-12-27 10:10:32 +01:00
onItemChange ();
2013-12-15 13:55:50 +01:00
},
owner : this
});
2014-01-01 16:23:32 +01:00
this . totals = ko . observable ();
this . totals . rawTotal = ko . computed ( function () {
2013-11-26 13:45:07 +01:00
var cost = parseFloat ( self . cost ());
2013-12-08 14:32:49 +01:00
var qty = parseFloat ( self . qty ());
2014-01-01 16:23:32 +01:00
var taxRate = parseFloat ( self . tax_rate ());
2013-12-29 00:33:48 +01:00
var value = cost * qty ;
if ( taxRate > 0 ) {
value += value * ( taxRate / 100 );
}
2013-11-26 13:45:07 +01:00
return value ? value : '' ;
2013-12-29 00:33:48 +01:00
});
2013-11-26 13:45:07 +01:00
2014-01-01 16:23:32 +01:00
this . totals . total = ko . computed ( function () {
var total = self . totals . rawTotal ();
2014-01-01 18:34:37 +01:00
//return total ? formatMoney(total, model.invoice.currency_id()) : '';
return total ? formatMoney ( total , 1 ) : '' ; // TODO_FIX
2013-11-26 13:45:07 +01:00
});
this . hideActions = function () {
this . actionsVisible ( false );
}
this . showActions = function () {
this . actionsVisible ( true );
}
2013-12-01 13:22:08 +01:00
this . isEmpty = function () {
2013-12-29 00:33:48 +01:00
return ! self . product_key () && ! self . notes () && ! self . cost () && ! self . qty ();
2013-12-01 13:22:08 +01:00
}
2013-12-29 00:33:48 +01:00
2014-01-01 18:34:37 +01:00
this . onSelect = function (){
2013-12-29 00:33:48 +01:00
}
2013-12-01 13:22:08 +01:00
}
2013-12-27 10:10:32 +01:00
function onItemChange ()
2013-12-01 13:22:08 +01:00
{
var hasEmpty = false ;
2014-01-01 18:34:37 +01:00
for ( var i = 0 ; i < model . invoice () . invoice_items () . length ; i ++ ) {
var item = model . invoice () . invoice_items ()[ i ];
2013-12-01 13:22:08 +01:00
if ( item . isEmpty ()) {
hasEmpty = true ;
}
}
2013-12-27 10:10:32 +01:00
2013-12-01 13:22:08 +01:00
if ( ! hasEmpty ) {
2014-01-01 18:34:37 +01:00
model . invoice () . addItem ();
2013-12-01 13:22:08 +01:00
}
2013-12-15 13:55:50 +01:00
$ ( '.word-wrap' ) . each ( function ( index , input ) {
$ ( input ) . height ( $ ( input ) . val () . split ( '\n' ) . length * 22 );
});
2013-11-26 13:45:07 +01:00
}
2013-12-27 10:10:32 +01:00
function onTaxRateChange ()
{
2014-01-01 16:23:32 +01:00
var emptyCount = 0 ;
2014-01-02 00:12:33 +01:00
2013-12-27 10:10:32 +01:00
for ( var i = 0 ; i < model . tax_rates () . length ; i ++ ) {
var taxRate = model . tax_rates ()[ i ];
if ( taxRate . isEmpty ()) {
2014-01-01 16:23:32 +01:00
emptyCount ++ ;
2013-12-27 10:10:32 +01:00
}
}
2014-01-02 00:12:33 +01:00
for ( var i = 0 ; i < 2 - emptyCount ; i ++ ) {
2013-12-27 10:10:32 +01:00
model . addTaxRate ();
}
}
2013-11-27 08:38:37 +01:00
var products = {{ $products }};
2013-12-07 19:45:00 +01:00
var clients = {{ $clients }};
var clientMap = {};
2013-12-30 21:17:45 +01:00
var $clientSelect = $ ( 'select#client' );
2013-12-07 19:45:00 +01:00
for ( var i = 0 ; i < clients . length ; i ++ ) {
var client = clients [ i ];
2013-12-15 13:55:50 +01:00
for ( var j = 0 ; j < client . contacts . length ; j ++ ) {
var contact = client . contacts [ j ];
2013-12-13 10:13:57 +01:00
contact . send_invoice = contact . is_primary ;
}
2013-12-07 19:45:00 +01:00
clientMap [ client . public_id ] = client ;
2013-12-30 21:17:45 +01:00
$clientSelect . append ( new Option ( getClientDisplayName ( client ), client . public_id ));
2013-12-07 19:45:00 +01:00
}
2013-11-27 08:38:37 +01:00
2014-01-01 18:34:37 +01:00
@ if ( $data )
2014-01-02 00:12:33 +01:00
window . model = new ViewModel ({{ $data }});
2014-01-01 18:34:37 +01:00
@ else
window . model = new ViewModel ();
2014-01-01 16:23:32 +01:00
model . addTaxRate ();
@ foreach ( $taxRates as $taxRate )
2014-01-02 00:12:33 +01:00
model . addTaxRate ({{ $taxRate }});
2014-01-01 18:34:37 +01:00
@ endforeach
2014-01-01 16:23:32 +01:00
@ if ( $invoice )
2014-01-01 18:34:37 +01:00
var invoice = {{ $invoice }};
ko . mapping . fromJS ( invoice , model . invoice () . mapping , model . invoice );
2014-01-01 16:23:32 +01:00
var invitationContactIds = {{ json_encode ( $invitationContactIds ) }};
var client = clientMap [ invoice . client . public_id ];
for ( var i = 0 ; i < client . contacts . length ; i ++ ) {
var contact = client . contacts [ i ];
contact . send_invoice = invitationContactIds . indexOf ( contact . public_id ) >= 0 ;
2014-01-01 18:34:37 +01:00
}
2014-01-02 00:12:33 +01:00
model . invoice () . addItem ();
//model.addTaxRate();
2014-01-01 16:23:32 +01:00
@ endif
2013-12-29 00:33:48 +01:00
@ endif
2014-01-01 18:34:37 +01:00
model . invoice () . tax ( model . getTaxRate ( model . invoice () . tax_name (), model . invoice () . tax_rate ()));
for ( var i = 0 ; i < model . invoice () . invoice_items () . length ; i ++ ) {
var item = model . invoice () . invoice_items ()[ i ];
item . tax ( model . getTaxRate ( item . tax_name (), item . tax_rate ()));
2014-01-02 00:12:33 +01:00
item . cost ( parseFloat ( item . cost ()) > 0 ? formatMoney ( item . cost (), model . invoice () . currency_id (), true ) : '' );
2014-01-01 18:34:37 +01:00
}
2014-01-02 00:12:33 +01:00
onTaxRateChange ();
2014-01-01 18:34:37 +01:00
if ( ! model . invoice () . discount ()) model . invoice () . discount ( '' );
ko . applyBindings ( model );
2013-11-26 13:45:07 +01:00
</ script >
@ stop