stockor 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -4
  3. data/Gemfile.lock +104 -87
  4. data/client/skr/api.js +3 -1
  5. data/client/skr/api/Components/AddressForm.cjsx +1 -1
  6. data/client/skr/api/Components/SingleItemCart.cjsx +1 -1
  7. data/client/skr/api/SingleItemCheckout.cjsx +3 -3
  8. data/client/skr/components/BankAccountFinder.cjsx +1 -1
  9. data/client/skr/components/CreditCardForm.cjsx +1 -1
  10. data/client/skr/components/Currency.cjsx +2 -1
  11. data/client/skr/components/CustomerFinder.cjsx +1 -1
  12. data/client/skr/components/CustomerProjectFinder.cjsx +1 -1
  13. data/client/skr/components/ExpenseCategoryFinder.cjsx +34 -0
  14. data/client/skr/components/GlAccountChooser.cjsx +2 -1
  15. data/client/skr/components/InvoiceFinder.cjsx +1 -1
  16. data/client/skr/components/LatexSnippets.cjsx +3 -0
  17. data/client/skr/components/LocationChooser.cjsx +3 -3
  18. data/client/skr/components/PaymentCategoryFinder.cjsx +1 -1
  19. data/client/skr/components/SalesOrderFinder.cjsx +1 -2
  20. data/client/skr/components/SkuFinder.cjsx +1 -1
  21. data/client/skr/components/SystemSettings.cjsx +4 -1
  22. data/client/skr/components/TermsChooser.cjsx +2 -2
  23. data/client/skr/components/ToolbarButton.cjsx +7 -3
  24. data/client/skr/components/TotalsLine.cjsx +5 -1
  25. data/client/skr/components/UserPreferences.cjsx +1 -1
  26. data/client/skr/components/VendorFinder.cjsx +1 -1
  27. data/client/skr/components/address/Address.cjsx +14 -1
  28. data/client/skr/components/styles.scss +6 -0
  29. data/client/skr/index.js +1 -0
  30. data/client/skr/lib/Remote.coffee +32 -0
  31. data/client/skr/lib/index.js +2 -0
  32. data/client/skr/lib/namespace.coffee +1 -0
  33. data/client/skr/models/CreditCardGateway.coffee +1 -1
  34. data/client/skr/models/ExpenseCategory.coffee +11 -0
  35. data/client/skr/models/ExpenseEntry.coffee +64 -0
  36. data/client/skr/models/ExpenseEntryCategory.coffee +11 -0
  37. data/client/skr/models/Invoice.coffee +4 -1
  38. data/client/skr/models/Payment.coffee +2 -2
  39. data/client/skr/models/SalesOrder.coffee +3 -2
  40. data/client/skr/models/SequentialId.coffee +1 -1
  41. data/client/skr/models/Vendor.coffee +1 -1
  42. data/client/skr/models/mixins/PrintSupport.coffee +1 -1
  43. data/client/skr/screens/bank-maint/BankMaint.cjsx +1 -1
  44. data/client/skr/screens/chart-of-accounts/ChartOfAccounts.cjsx +1 -1
  45. data/client/skr/screens/customer-maint/CustomerMaint.cjsx +1 -1
  46. data/client/skr/screens/customer-projects/CustomerProjects.cjsx +1 -1
  47. data/client/skr/screens/expense-categories/ExpenseCategories.cjsx +31 -0
  48. data/client/skr/screens/expense-categories/index.js +5 -0
  49. data/client/skr/screens/expense-categories/index.scss +9 -0
  50. data/client/skr/screens/expense-entry/ApprovalRequest.coffee +14 -0
  51. data/client/skr/screens/expense-entry/ApproveDialog.cjsx +30 -0
  52. data/client/skr/screens/expense-entry/Categories.cjsx +112 -0
  53. data/client/skr/screens/expense-entry/ExpenseEntry.cjsx +193 -0
  54. data/client/skr/screens/expense-entry/Form.cjsx +54 -0
  55. data/client/skr/screens/expense-entry/Grid.cjsx +51 -0
  56. data/client/skr/screens/expense-entry/ScreenState.coffee +1 -0
  57. data/client/skr/screens/expense-entry/index.js +1 -0
  58. data/client/skr/screens/expense-entry/index.scss +106 -0
  59. data/client/skr/screens/fresh-books-import/ApiInfo.cjsx +3 -3
  60. data/client/skr/screens/fresh-books-import/ChooseRecords.cjsx +6 -4
  61. data/client/skr/screens/fresh-books-import/FreshBooksImport.cjsx +1 -1
  62. data/client/skr/screens/fresh-books-import/ViewRecords.cjsx +2 -2
  63. data/client/skr/screens/fresh-books-import/index.scss +5 -4
  64. data/client/skr/screens/gl-accounts/GlAccounts.cjsx +1 -1
  65. data/client/skr/screens/gl-transactions/GlTransactions.cjsx +1 -1
  66. data/client/skr/screens/invoice/Invoice.cjsx +6 -2
  67. data/client/skr/screens/invoice/Payment.cjsx +1 -1
  68. data/client/skr/screens/invoice/TotalExtraInfo.cjsx +32 -0
  69. data/client/skr/screens/invoice/index.scss +4 -2
  70. data/client/skr/screens/locations/Locations.cjsx +1 -1
  71. data/client/skr/screens/payment-category/PaymentCategory.cjsx +1 -1
  72. data/client/skr/screens/payment-terms/PaymentTerms.cjsx +1 -1
  73. data/client/skr/screens/payments/Payments.cjsx +13 -6
  74. data/client/skr/screens/sale-report/SaleReport.cjsx +1 -1
  75. data/client/skr/screens/sales-order/SalesOrder.cjsx +2 -1
  76. data/client/skr/screens/sku-maint/SkuMaint.cjsx +1 -1
  77. data/client/skr/screens/sku-maint/SkuUomList.cjsx +2 -2
  78. data/client/skr/screens/time-invoicing/TimeInvoicing.cjsx +4 -4
  79. data/client/skr/screens/time-tracking/EditEntry.cjsx +2 -2
  80. data/client/skr/screens/time-tracking/Entries.coffee +6 -4
  81. data/client/skr/screens/time-tracking/Popover.cjsx +11 -6
  82. data/client/skr/screens/time-tracking/TimeTracking.cjsx +12 -5
  83. data/client/skr/screens/vendor-maint/VendorMaint.cjsx +2 -2
  84. data/config/database.yml +2 -0
  85. data/config/puma.rb +0 -4
  86. data/config/routes.rb +4 -0
  87. data/config/screens.rb +17 -0
  88. data/db/migrate/20140323001446_create_so_details_view.rb +2 -2
  89. data/db/migrate/20151121211323_create_customer_project_details_views.rb +1 -1
  90. data/db/migrate/20160216142845_create_gl_account_balances_view.rb +1 -1
  91. data/db/migrate/20160726004411_string_check_numbers.rb +5 -0
  92. data/db/migrate/20160805002717_create_expenses.rb +65 -0
  93. data/db/schema.sql +394 -229
  94. data/db/seed.rb +12 -12
  95. data/lib/skr/access_roles.rb +9 -4
  96. data/lib/skr/concerns/has_gl_transaction.rb +1 -1
  97. data/lib/skr/configuration.rb +3 -1
  98. data/lib/skr/db/migration_helpers.rb +2 -2
  99. data/lib/skr/handlers/approve_expense_entries.rb +16 -0
  100. data/lib/skr/handlers/invoice_from_time_entries.rb +1 -1
  101. data/lib/skr/handlers/sequential_ids.rb +2 -2
  102. data/lib/skr/jobs/fresh_books/import.rb +18 -17
  103. data/lib/skr/model.rb +3 -0
  104. data/lib/skr/models/bank_account.rb +9 -0
  105. data/lib/skr/models/expense_category.rb +27 -0
  106. data/lib/skr/models/expense_entry.rb +76 -0
  107. data/lib/skr/models/expense_entry_category.rb +15 -0
  108. data/lib/skr/models/gl_transaction.rb +2 -2
  109. data/lib/skr/models/inv_line.rb +3 -1
  110. data/lib/skr/models/invoice.rb +9 -5
  111. data/lib/skr/models/payment.rb +1 -1
  112. data/lib/skr/models/purchase_order.rb +4 -4
  113. data/lib/skr/models/uom.rb +2 -2
  114. data/lib/skr/models/voucher.rb +4 -4
  115. data/lib/skr/print/form.rb +17 -14
  116. data/lib/skr/version.rb +1 -1
  117. data/spec/fixtures/skr/expense_category.yml +17 -0
  118. data/spec/fixtures/skr/expense_entries.yml +20 -0
  119. data/spec/fixtures/skr/expense_entry_category.yml +19 -0
  120. data/spec/fixtures/skr/gl_account.yml +10 -0
  121. data/spec/server/handlers/invoice_from_time_entries_spec.rb +2 -2
  122. data/spec/server/handlers/sequential_ids_spec.rb +1 -1
  123. data/spec/server/models/expense_category_spec.rb +17 -0
  124. data/spec/server/models/expense_entry_spec.rb +44 -0
  125. data/spec/server/models/invoice_spec.rb +0 -1
  126. data/spec/server/models/spec_helper_spec.rb +5 -10
  127. data/spec/server/spec_helper.rb +12 -11
  128. data/spec/skr/components/SkuLinesSpec.coffee +11 -9
  129. data/spec/skr/models/CustomerSpec.coffee +1 -1
  130. data/spec/skr/models/ExpenseAccountSpec.coffee +5 -0
  131. data/spec/skr/screens/expense-categories/ExpenseCategoriesSpec.coffee +5 -0
  132. data/spec/skr/screens/expense-entry/ExpenseEntrySpec.coffee +5 -0
  133. data/spec/skr/screens/locations/LocationsSpec.coffee +4 -4
  134. data/spec/skr/screens/time-tracking/TimeTrackingSpec.coffee +4 -4
  135. data/stockor.gemspec +2 -3
  136. data/templates/print/partials/header.tex.erb +1 -1
  137. data/templates/print/partials/skus_table_invoice_footer.tex.erb +22 -19
  138. data/templates/print/partials/skus_table_invoice_info_line.tex.erb +5 -1
  139. data/templates/print/types/payment/default.tex.erb +10 -10
  140. metadata +40 -14
  141. data/client/skr/api/onReady.coffee +0 -23
  142. data/spec/skr/api/SingleItemCheckoutSpec.cjsx +0 -10
  143. data/spec/skr/screens/bank-maint/BankMaintSpec.coffee +0 -5
  144. data/spec/skr/screens/gl-accounts/GlAccountsSpec.coffee +0 -5
  145. data/spec/skr/screens/invoice/InvoiceSpec.coffee +0 -5
  146. data/spec/skr/screens/payment-category/PaymentCategorySpec.coffee +0 -5
  147. data/spec/skr/screens/payments/PaymentsSpec.coffee +0 -5
  148. data/spec/skr/screens/sale-report/SaleReportSpec.coffee +0 -5
@@ -0,0 +1,54 @@
1
+ class Attachments extends Lanes.React.Component
2
+ modelBindings:
3
+ attachments: 'props'
4
+
5
+ render: ->
6
+ <LC.FieldSet
7
+ title={"Attachments (#{@attachments.length-1})"}
8
+ >
9
+ <LC.AssetsListing assets={@attachments}
10
+ name='attachments' size="thumb" />
11
+ </LC.FieldSet>
12
+
13
+ class Skr.Screens.ExpenseEntry.Form extends Lanes.React.Component
14
+
15
+ propTypes:
16
+ onEntrySave: React.PropTypes.func.isRequired
17
+
18
+ modelBindings:
19
+ entry: 'props'
20
+
21
+ getInitialState: ->
22
+ isEditing: true
23
+
24
+ mixins: [
25
+ Lanes.React.Mixins.RelayEditingState
26
+ ]
27
+
28
+ focus: ->
29
+ _.defer => @refs.name.focus()
30
+
31
+ render: ->
32
+ <div className="form">
33
+ <LC.NetworkActivityOverlay model={@entry} />
34
+ <BS.Row>
35
+ <LC.Input sm=8 name='name' ref="name" model={@entry} />
36
+ <Skr.Screens.ExpenseEntry.Categories
37
+ categories={@props.categories}
38
+ entry={@entry} sm={4} />
39
+ </BS.Row>
40
+
41
+ <BS.Row>
42
+ <Attachments attachments={@entry.attachments} />
43
+ </BS.Row>
44
+
45
+ <BS.Row>
46
+ <LC.Input sm=10 name='memo' model={@entry} />
47
+ <LC.FormGroup className='controls' sm=2>
48
+ <BS.ButtonGroup>
49
+ <BS.Button tabIndex={-1} onClick={@props.onEntryReset}>Reset</BS.Button>
50
+ <BS.Button onClick={@props.onEntrySave}>Save</BS.Button>
51
+ </BS.ButtonGroup>
52
+ </LC.FormGroup>
53
+ </BS.Row>
54
+ </div>
@@ -0,0 +1,51 @@
1
+ class Skr.Screens.ExpenseEntry.Grid extends Lanes.React.Component
2
+
3
+ propTypes:
4
+ onRecordSelect: React.PropTypes.func.isRequired
5
+
6
+ modelBindings:
7
+ categories: 'props'
8
+ query: 'props'
9
+
10
+ getInitialState: ->
11
+ category: new Skr.Models.ExpenseCategory
12
+
13
+ getCurrentCategory: -> @state.category
14
+
15
+ renderReviewCheckbox: ->
16
+ return null unless Lanes.current_user.roles.includes('accounting')
17
+ <BS.Checkbox className="all-users" checked={!!@query.syncOptions.queryParams?.review}
18
+ onChange={(ev) => @props.setReviewState(ev.target.checked)}
19
+ > Review</BS.Checkbox>
20
+
21
+ renderApproveToggle: ->
22
+ return null unless @props.isReviewing
23
+ <span className="approved-toggle">
24
+ <LC.IndeterminateCheckbox checked={@props.isConfirmationChecked}
25
+ onChange={(ev) => @props.onConfirmationToggle(ev.target.checked)}
26
+ />
27
+ </span>
28
+
29
+ toolbarControls: ->
30
+ <BS.Navbar.Form className="controls">
31
+ {@renderApproveToggle()}
32
+ <div className="spacer" />
33
+ <div className="right">
34
+ {@renderReviewCheckbox()}
35
+ <SC.ExpenseCategoryFinder
36
+ choices={@categories.models} fetchOnSelect={false}
37
+ withClearBtn fieldOnly editOnly selectField unlabeled
38
+ model={@state.category} getSelection={@getCurrentCategory}
39
+ setSelection={@props.onCategorySelect} />
40
+ </div>
41
+ </BS.Navbar.Form>
42
+
43
+ render: ->
44
+ <LC.Grid
45
+ expandY={true}
46
+ onColumnClick={@onColumnSort}
47
+ isRowFocused={@props.isRowFocused}
48
+ query={@query} height=200 autoLoadQuery
49
+ onSelectionChange={@props.onRecordSelect}
50
+ toolbarChildren={@toolbarControls()}
51
+ />
@@ -0,0 +1 @@
1
+ class Skr.Screens.ExpenseEntry.ScreenState extends Lanes.Models.State
@@ -0,0 +1 @@
1
+ //= require ./ExpenseEntry
@@ -0,0 +1,106 @@
1
+ /*
2
+ You should remove this file if your screen does not use any custom styles
3
+
4
+ Otherwise Lanes will continue to fetch an empty file whenever
5
+ the screen is displayed
6
+ */
7
+ .expense-entry {
8
+ $first-column-width: 90px;
9
+ .footer {
10
+ display: none;
11
+ button {
12
+ width: $first-column-width;
13
+ border-top-left-radius: 0;
14
+ border-top-right-radius: 0;
15
+ }
16
+ }
17
+ &.is-reviewing {
18
+ .footer { display: block; }
19
+ }
20
+
21
+ .selection {
22
+ //margin: 5px;
23
+ }
24
+
25
+ .form {
26
+ .controls {
27
+ text-align: center;
28
+ }
29
+
30
+ }
31
+
32
+ .grid-component .toolbar .controls {
33
+ display: flex;
34
+ justify-content: space-around;
35
+ align-items: center;
36
+ .approved-toggle {
37
+ width: $first-column-width;
38
+ text-align: center;
39
+ }
40
+ .all-users {
41
+ margin-right: 20px;
42
+ }
43
+ .spacer { flex: 1; }
44
+ }
45
+
46
+
47
+ .categories {
48
+ display: flex;
49
+ align-items: flex-end;
50
+ position: relative;
51
+ .add { margin-left: 5px; }
52
+ .multiple {
53
+ .controls {
54
+ display: flex;
55
+ align-items: center;
56
+ justify-content: flex-end;
57
+ p {
58
+ flex: 1;
59
+ .pair + .pair { margin-left: 0.5em; }
60
+ }
61
+ .btn.view {
62
+ margin-right: 1em;
63
+ }
64
+ }
65
+ .form-control-static { padding-top: 0; padding-bottom: 0; }
66
+ .pair {
67
+ max-width: 100px;
68
+ display: inline-block;
69
+ text-overflow: ellipsis;
70
+ overflow: hidden;
71
+ white-space: nowrap;
72
+ max-height: 35px;
73
+ }
74
+ }
75
+
76
+ .category {
77
+ display: flex;
78
+ align-items: center;
79
+ margin-bottom: 15px;
80
+ .form-group { margin-bottom: 0; }
81
+ .lanes-field { flex: 1; }
82
+ .btn {
83
+ margin-left: 0.5rem;
84
+ &.delete { display: none; }
85
+ }
86
+ }
87
+
88
+ .popover-content {
89
+ width: 320px;
90
+ .category {
91
+ label { display: none; }
92
+ .btn.delete { display: block; }
93
+ }
94
+ }
95
+ }
96
+
97
+ #choose-bank-account {
98
+ .popover-content {
99
+ display: flex;
100
+ button { margin-left: 0.5rem; }
101
+ }
102
+
103
+ //height: 200px;
104
+
105
+ }
106
+ }
@@ -1,6 +1,6 @@
1
1
  class Skr.Screens.FreshBooksImport.ApiInfo extends Lanes.React.Component
2
2
  listenNetworkEvents: true
3
- dataObjects:
3
+ modelBindings:
4
4
  import: 'props'
5
5
  startImport: ->
6
6
  @import.save()
@@ -20,10 +20,10 @@ class Skr.Screens.FreshBooksImport.ApiInfo extends Lanes.React.Component
20
20
  <p>Your access information will not be stored and is only used to download records</p>
21
21
  </BS.Col>
22
22
  </BS.Row>
23
- <BS.Row>
23
+ <BS.Row className="api-info">
24
24
  <LC.Input name='api_key' label='API Key' sm=7 model={@import} />
25
25
  <LC.Input name='domain' label='Company' sm=3 model={@import} />
26
- <BS.FormGroup className='domain' sm=2 label=''>.freshbooks.com</BS.FormGroup>
26
+ <BS.Col sm=2 className="domain">.freshbooks.com</BS.Col>
27
27
  </BS.Row>
28
28
  <BS.Row>
29
29
  <BS.Col smOffset=9 sm=2>
@@ -11,7 +11,7 @@ class TextInput extends Lanes.React.Component
11
11
  <input value={@props.row.customer_code || ''} onChange={@setCode} />
12
12
 
13
13
  class UserSelect extends Lanes.React.Component
14
- dataObjects:
14
+ modelBindings:
15
15
  user: -> new Lanes.Models.User
16
16
 
17
17
  getUser: ->
@@ -58,7 +58,7 @@ class RecordRow extends Lanes.React.BaseComponent
58
58
 
59
59
  class Skr.Screens.FreshBooksImport.ChooseRecords extends Lanes.React.Component
60
60
  listenNetworkEvents: true
61
- dataObjects:
61
+ modelBindings:
62
62
  import: 'props'
63
63
  job: -> @props.import.job
64
64
 
@@ -107,9 +107,11 @@ class Skr.Screens.FreshBooksImport.ChooseRecords extends Lanes.React.Component
107
107
  return null unless @import.hasPendingRecords()
108
108
  <div className="import-records">
109
109
  {@renderHeader()}
110
- <BS.Tabs animation={false} defaultActiveKey={0}>
110
+ <BS.Tabs id='choose-records'>
111
111
  {for type, i in @import.recordTypes when @import.recordsForType(type)
112
- <BS.Tab eventKey={i} key={i} title={_.titleize(type)} animation={false}>
112
+ <BS.Tab eventKey={i} key={i}
113
+ title={_.titleize(type)} animation={false}
114
+ >
113
115
  <@RecordTable type={type} />
114
116
  </BS.Tab>}
115
117
  </BS.Tabs>
@@ -7,7 +7,7 @@
7
7
  class Skr.Screens.FreshBooksImport extends Skr.Screens.Base
8
8
  modelForAccess: 'invoice'
9
9
  getInitialState: -> isEditing: true
10
- dataObjects:
10
+ modelBindings:
11
11
  import: ->
12
12
  new Skr.Screens.FreshBooksImport.Import
13
13
 
@@ -1,7 +1,7 @@
1
1
  # coffeelint: disable=max_line_length
2
2
  class Skr.Screens.FreshBooksImport.ViewRecords extends Lanes.React.Component
3
3
  listenNetworkEvents: true
4
- dataObjects:
4
+ modelBindings:
5
5
  import: 'props'
6
6
  job: -> @props.import.job
7
7
 
@@ -87,7 +87,7 @@ class Skr.Screens.FreshBooksImport.ViewRecords extends Lanes.React.Component
87
87
  return null unless @import.hasImportedRecords()
88
88
 
89
89
  <h3>Import Success!</h3>
90
- <BS.Tabs animation={false} defaultActiveKey={0}>
90
+ <BS.Tabs id='view-records'>
91
91
  {for type, i in @import.recordTypes
92
92
  TableType = @[_.capitalize(type)] || @BlankTable
93
93
  <BS.Tab eventKey={i} key={i} title={_.titleize(type)} animation={false}>
@@ -1,12 +1,13 @@
1
1
  .fresh-books-import {
2
- .domain .value {
3
- margin-top: 15px;
4
- }
5
2
  .job-executing {
6
3
  width: 80%;
7
4
  margin: 80px auto;
8
5
  }
9
-
6
+ .api-info {
7
+ .domain {
8
+ padding-top: 35px;
9
+ }
10
+ }
10
11
  .import-records {
11
12
  .clients tbody tr td:last-child {
12
13
  width: 130px;
@@ -1,6 +1,6 @@
1
1
  class Skr.Screens.GlAccounts extends Skr.Screens.Base
2
2
 
3
- dataObjects:
3
+ modelBindings:
4
4
  account: ->
5
5
  @loadOrCreateModel({
6
6
  klass: Skr.Models.GlAccount,
@@ -35,7 +35,7 @@ class Skr.Screens.GlTransactions extends Skr.Screens.Base
35
35
 
36
36
  modelForAccess: 'gl-transaction'
37
37
 
38
- dataObjects:
38
+ modelBindings:
39
39
  transactions: -> new Transactions(account: @props.account)
40
40
 
41
41
  render: ->
@@ -1,5 +1,6 @@
1
1
  ##= require_self
2
2
  ##= require ./Payment
3
+ ##= require ./TotalExtraInfo
3
4
 
4
5
  class Skr.Screens.Invoice extends Skr.Screens.Base
5
6
 
@@ -7,7 +8,7 @@ class Skr.Screens.Invoice extends Skr.Screens.Base
7
8
  with: [ 'with_details' ]
8
9
  include: [ 'sales_order', 'billing_address', 'shipping_address', 'lines', 'payments' ]
9
10
 
10
- dataObjects:
11
+ modelBindings:
11
12
  invoice: ->
12
13
  @loadOrCreateModel({
13
14
  syncOptions: @syncOptions, klass: Skr.Models.Invoice,
@@ -49,6 +50,7 @@ class Skr.Screens.Invoice extends Skr.Screens.Base
49
50
  parentModel={@invoice} />
50
51
 
51
52
  <SC.CustomerFinder
53
+ fallBackValue={@invoice.customer_code}
52
54
  syncOptions={ include: ['billing_address', 'shipping_address' ] }
53
55
  selectField sm=3 xs=6 model={@invoice} />
54
56
 
@@ -87,5 +89,7 @@ class Skr.Screens.Invoice extends Skr.Screens.Base
87
89
  saveImmediately={@shouldSaveLinesImmediately}
88
90
  commands={@state.commands} lines={@invoice.lines} />
89
91
 
90
- <SC.TotalsLine model={@invoice} />
92
+ <SC.TotalsLine model={@invoice} extraInfo={
93
+ <Skr.Screens.Invoice.TotalExtraInfo invoice={@invoice} />
94
+ } />
91
95
  </LC.ScreenWrapper>
@@ -23,7 +23,7 @@ class Skr.Screens.Invoice.Payment extends Lanes.React.Component
23
23
  getInitialState: ->
24
24
  type: 'credit-card'
25
25
 
26
- dataObjects:
26
+ modelBindings:
27
27
  invoice: 'props'
28
28
  payment: ->
29
29
  payment = @props.invoice.payments.find (pymnt) -> pymnt.isNew()
@@ -0,0 +1,32 @@
1
+ class Skr.Screens.Invoice.TotalExtraInfo extends Lanes.React.Component
2
+
3
+ modelBindings:
4
+ invoice: 'props'
5
+
6
+ checkLoading: ->
7
+ unless @invoice.total_hours
8
+ @invoice.fetch({
9
+ fields: ['total_hours']
10
+ })
11
+
12
+ TotalHours: ->
13
+ body = if @invoice.total_hours
14
+ <span>Hours: {Lanes.u.format.currency(@invoice.total_hours)}</span>
15
+ else
16
+ [
17
+ <LC.Icon key="icon" type='spinner' />,
18
+ <span key='msg'> Loading...</span>
19
+ ]
20
+ <div className="invoice-total-hours-tooltip">
21
+ {body}
22
+ </div>
23
+
24
+
25
+ render: ->
26
+ return null if @invoice.form isnt 'labor' or @invoice.isNew()
27
+
28
+ <LC.Icon
29
+ className='total-hours'
30
+ tooltipProps={onEntering: @checkLoading}
31
+ type='clock-o' tooltip={<@TotalHours />}
32
+ />
@@ -1,7 +1,9 @@
1
1
  .invoice {
2
+ .total-hours { margin-right: 0.5rem; }
3
+ }
2
4
 
3
-
4
-
5
+ .invoice-total-hours-tooltip {
6
+ width: 100px;
5
7
  }
6
8
 
7
9
  .invoice-payment {
@@ -3,7 +3,7 @@ class Skr.Screens.Locations extends Skr.Screens.Base
3
3
  syncOptions:
4
4
  include: [ 'address', 'logo' ]
5
5
 
6
- dataObjects:
6
+ modelBindings:
7
7
  location: ->
8
8
  @loadOrCreateModel({
9
9
  syncOptions: @syncOptions, klass: Skr.Models.Location
@@ -1,6 +1,6 @@
1
1
  class Skr.Screens.PaymentCategory extends Skr.Screens.Base
2
2
 
3
- dataObjects:
3
+ modelBindings:
4
4
  category: ->
5
5
  @loadOrCreateModel({
6
6
  klass: Skr.Models.PaymentCategory
@@ -1,6 +1,6 @@
1
1
  class Skr.Screens.PaymentTerms extends Skr.Screens.Base
2
2
 
3
- dataObjects:
3
+ modelBindings:
4
4
  term: ->
5
5
  @loadOrCreateModel({
6
6
  klass: Skr.Models.PaymentTerm