stockor 0.1.9 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (313) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +254 -72
  4. data/Guardfile +1 -1
  5. data/README.md +24 -3
  6. data/app.json +28 -0
  7. data/client/skr/Extension.coffee +18 -0
  8. data/client/skr/components/BankAccountFinder.cjsx +34 -0
  9. data/client/skr/components/Currency.cjsx +19 -0
  10. data/client/skr/components/CustomerFinder.cjsx +37 -0
  11. data/client/skr/components/CustomerLink.cjsx +13 -0
  12. data/client/skr/components/CustomerProjectFinder.cjsx +49 -0
  13. data/client/skr/components/GlAccountChooser.cjsx +38 -0
  14. data/client/skr/components/InvoiceFinder.cjsx +37 -0
  15. data/client/skr/components/InvoiceLink.cjsx +13 -0
  16. data/client/skr/components/LocationChooser.cjsx +37 -0
  17. data/client/skr/components/PaymentCategoryFinder.cjsx +34 -0
  18. data/client/skr/components/PrintFormChooser.cjsx +29 -0
  19. data/client/skr/components/SalesOrderFinder.cjsx +38 -0
  20. data/client/skr/components/ScreenControls.cjsx +20 -0
  21. data/client/skr/components/SkuFinder.cjsx +30 -0
  22. data/client/skr/components/SkuLines.cjsx +76 -0
  23. data/client/skr/components/SystemSettings.cjsx +26 -0
  24. data/client/skr/components/TermsChooser.cjsx +40 -0
  25. data/client/skr/components/ToolbarButton.cjsx +7 -0
  26. data/client/skr/components/TotalsLine.cjsx +21 -0
  27. data/client/skr/components/TriStateIcon.cjsx +12 -0
  28. data/client/skr/components/UOMChooser.cjsx +24 -0
  29. data/client/skr/components/UserPreferences.cjsx +30 -0
  30. data/client/skr/components/VendorFinder.cjsx +40 -0
  31. data/client/skr/components/address/Address.cjsx +10 -10
  32. data/client/skr/components/styles.scss +16 -0
  33. data/client/skr/index.js +3 -1
  34. data/client/skr/models/Address.coffee +9 -1
  35. data/client/skr/models/BankAccount.coffee +17 -0
  36. data/client/skr/models/Base.coffee +6 -0
  37. data/client/skr/models/Customer.coffee +17 -10
  38. data/client/skr/models/CustomerProject.coffee +29 -0
  39. data/client/skr/models/GlAccount.coffee +22 -10
  40. data/client/skr/models/GlManualEntry.coffee +4 -2
  41. data/client/skr/models/GlPeriod.coffee +4 -6
  42. data/client/skr/models/GlPosting.coffee +7 -7
  43. data/client/skr/models/GlTransaction.coffee +3 -3
  44. data/client/skr/models/IaLine.coffee +9 -9
  45. data/client/skr/models/IaReason.coffee +4 -4
  46. data/client/skr/models/InvLine.coffee +30 -11
  47. data/client/skr/models/InventoryAdjustment.coffee +8 -6
  48. data/client/skr/models/Invoice.coffee +89 -18
  49. data/client/skr/models/Location.coffee +27 -6
  50. data/client/skr/models/Payment.coffee +36 -0
  51. data/client/skr/models/PaymentCategory.coffee +12 -0
  52. data/client/skr/models/PaymentTerm.coffee +17 -4
  53. data/client/skr/models/PickTicket.coffee +7 -5
  54. data/client/skr/models/PoLine.coffee +15 -15
  55. data/client/skr/models/PoReceipt.coffee +8 -6
  56. data/client/skr/models/PorLine.coffee +11 -11
  57. data/client/skr/models/PricingProvider.coffee +6 -0
  58. data/client/skr/models/PtLine.coffee +13 -13
  59. data/client/skr/models/PurchaseOrder.coffee +11 -9
  60. data/client/skr/models/SalesOrder.coffee +59 -22
  61. data/client/skr/models/Sku.coffee +17 -15
  62. data/client/skr/models/SkuLoc.coffee +14 -9
  63. data/client/skr/models/SkuTran.coffee +10 -10
  64. data/client/skr/models/SkuVendor.coffee +9 -9
  65. data/client/skr/models/SoLine.coffee +27 -20
  66. data/client/skr/models/TimeEntry.coffee +75 -0
  67. data/client/skr/models/Uom.coffee +27 -6
  68. data/client/skr/models/Vendor.coffee +14 -12
  69. data/client/skr/models/VoLine.coffee +11 -11
  70. data/client/skr/models/Voucher.coffee +7 -5
  71. data/client/skr/models/mixins/HasVisibleId.coffee +7 -0
  72. data/client/skr/models/mixins/PrintSupport.coffee +6 -0
  73. data/client/skr/models/mixins/SkuLine.coffee +61 -0
  74. data/client/skr/screens/Commands.coffee +29 -0
  75. data/client/skr/screens/bank-maint/BankMaint.cjsx +43 -0
  76. data/client/skr/screens/bank-maint/index.js +5 -0
  77. data/client/skr/screens/chart-of-accounts/ChartOfAccounts.cjsx +40 -0
  78. data/client/skr/screens/chart-of-accounts/index.js +1 -0
  79. data/client/skr/screens/chart-of-accounts/index.scss +12 -0
  80. data/client/skr/screens/customer-maint/CustomerMaint.cjsx +35 -36
  81. data/client/skr/screens/customer-projects/CustomerProjects.cjsx +70 -0
  82. data/client/skr/screens/customer-projects/index.js +5 -0
  83. data/client/skr/screens/customer-projects/index.scss +25 -0
  84. data/client/skr/screens/fresh-books-import/ApiInfo.cjsx +35 -0
  85. data/client/skr/screens/fresh-books-import/ChooseRecords.cjsx +116 -0
  86. data/client/skr/screens/fresh-books-import/FreshBooksImport.cjsx +31 -0
  87. data/client/skr/screens/fresh-books-import/Import.coffee +52 -0
  88. data/client/skr/screens/fresh-books-import/ViewRecords.cjsx +96 -0
  89. data/client/skr/screens/fresh-books-import/index.js +1 -0
  90. data/client/skr/screens/fresh-books-import/index.scss +39 -0
  91. data/client/skr/screens/gl-accounts/GlAccounts.cjsx +31 -0
  92. data/client/skr/screens/gl-accounts/index.js +5 -0
  93. data/client/skr/screens/gl-transactions/GlTransactions.cjsx +46 -0
  94. data/client/skr/screens/gl-transactions/index.js +1 -0
  95. data/client/skr/screens/gl-transactions/index.scss +12 -0
  96. data/client/skr/screens/invoice/Invoice.cjsx +92 -0
  97. data/client/skr/screens/invoice/Payment.cjsx +28 -0
  98. data/client/skr/screens/invoice/index.js +5 -0
  99. data/client/skr/screens/locations/Locations.cjsx +31 -0
  100. data/client/skr/screens/locations/index.js +5 -0
  101. data/client/skr/screens/payment-category/PaymentCategory.cjsx +28 -0
  102. data/client/skr/screens/payment-category/index.js +5 -0
  103. data/client/skr/screens/payment-category/index.scss +9 -0
  104. data/client/skr/screens/payment-terms/PaymentTerms.cjsx +28 -0
  105. data/client/skr/screens/payment-terms/index.js +5 -0
  106. data/client/skr/screens/payment-terms/index.scss +9 -0
  107. data/client/skr/screens/payments/Payments.cjsx +59 -0
  108. data/client/skr/screens/payments/index.js +5 -0
  109. data/client/skr/screens/sales-order/SalesOrder.cjsx +68 -0
  110. data/client/skr/screens/sales-order/index.js +1 -5
  111. data/client/skr/screens/sku-maint/SkuMaint.cjsx +53 -0
  112. data/client/skr/screens/sku-maint/SkuUomList.cjsx +209 -0
  113. data/client/skr/screens/sku-maint/index.js +2 -5
  114. data/client/skr/screens/sku-maint/index.scss +37 -6
  115. data/client/skr/screens/time-invoicing/TimeInvoicing.cjsx +156 -0
  116. data/client/skr/screens/time-invoicing/index.js +5 -0
  117. data/client/skr/screens/time-invoicing/index.scss +7 -0
  118. data/client/skr/screens/time-tracking/EditEntry.cjsx +54 -0
  119. data/client/skr/screens/time-tracking/Entries.coffee +132 -0
  120. data/client/skr/screens/time-tracking/Header.cjsx +71 -0
  121. data/client/skr/screens/time-tracking/Popover.cjsx +70 -0
  122. data/client/skr/screens/time-tracking/PopoverMiniControls.cjsx +25 -0
  123. data/client/skr/screens/time-tracking/TimeTracking.cjsx +63 -0
  124. data/client/skr/screens/time-tracking/WeekSummary.cjsx +16 -0
  125. data/client/skr/screens/time-tracking/index.js +1 -0
  126. data/client/skr/screens/time-tracking/index.scss +126 -0
  127. data/client/skr/screens/vendor-maint/VendorMaint.cjsx +45 -0
  128. data/client/skr/screens/vendor-maint/index.js +1 -5
  129. data/client/skr/styles.scss +1 -13
  130. data/config/puma.rb +4 -0
  131. data/config/routes.rb +21 -9
  132. data/config/screens.rb +147 -32
  133. data/db/migrate/20140202194700_create_skr_gl_transaction_details.rb +35 -0
  134. data/db/migrate/20140220031800_create_skr_locations.rb +2 -0
  135. data/db/migrate/20140220190836_create_skr_vendors.rb +1 -0
  136. data/db/migrate/20140220203029_create_skr_customers.rb +3 -2
  137. data/db/migrate/20140224034759_create_skr_skus.rb +2 -3
  138. data/db/migrate/20140322223912_create_skr_sales_orders.rb +4 -3
  139. data/db/migrate/20140322223920_create_skr_so_lines.rb +4 -5
  140. data/db/migrate/20140323001446_create_so_details_view.rb +7 -5
  141. data/db/migrate/20140327202209_create_skr_pt_lines.rb +2 -2
  142. data/db/migrate/20140327214000_create_customer_project.rb +16 -0
  143. data/db/migrate/20140327223002_create_time_entries.rb +17 -0
  144. data/db/migrate/20140327224000_create_skr_invoices.rb +5 -1
  145. data/db/migrate/20140327224002_create_skr_inv_lines.rb +3 -1
  146. data/db/migrate/20140422024010_create_skr_inv_details_view.rb +1 -1
  147. data/db/migrate/20151121211323_create_customer_project_details_views.rb +31 -0
  148. data/db/migrate/20160216142845_create_gl_account_balances_view.rb +20 -0
  149. data/db/migrate/20160229002044_create_bank_accounts.rb +18 -0
  150. data/db/migrate/20160229041711_create_payments.rb +33 -0
  151. data/db/migrate/20160307022705_create_create_combined_uom_views.rb +18 -0
  152. data/db/schema.sql +639 -140
  153. data/db/seed/chart_of_accounts.yml +8 -6
  154. data/db/seed/payment_categories.yml +12 -0
  155. data/db/seed/skus.yml +32 -0
  156. data/db/seed.rb +21 -0
  157. data/lib/skr/access_roles.rb +19 -6
  158. data/lib/skr/concerns/has_sku_loc_lines.rb +0 -16
  159. data/lib/skr/concerns/inv_extensions.rb +24 -0
  160. data/lib/skr/concerns/is_sku_loc_line.rb +3 -4
  161. data/lib/skr/concerns/so_extensions.rb +8 -0
  162. data/lib/skr/concerns/visible_id_identifier.rb +1 -1
  163. data/lib/skr/db/migration_helpers.rb +2 -4
  164. data/lib/skr/extension.rb +11 -4
  165. data/lib/skr/handlers/fresh_books_import.rb +20 -0
  166. data/lib/skr/handlers/invoice_from_time_entries.rb +49 -0
  167. data/lib/skr/jobs/fresh_books/base.rb +54 -0
  168. data/lib/skr/jobs/fresh_books/import.rb +151 -0
  169. data/lib/skr/jobs/fresh_books/retrieve.rb +62 -0
  170. data/lib/skr/model.rb +5 -0
  171. data/lib/skr/models/address.rb +1 -1
  172. data/lib/skr/models/bank_account.rb +13 -0
  173. data/lib/skr/models/business_entity.rb +3 -0
  174. data/lib/skr/models/customer.rb +1 -1
  175. data/lib/skr/models/customer_project.rb +22 -0
  176. data/lib/skr/models/gl_account.rb +13 -3
  177. data/lib/skr/models/gl_period.rb +6 -0
  178. data/lib/skr/models/gl_posting.rb +7 -4
  179. data/lib/skr/models/gl_transaction.rb +19 -33
  180. data/lib/skr/models/ia_line.rb +1 -1
  181. data/lib/skr/models/inv_line.rb +33 -15
  182. data/lib/skr/models/invoice.rb +47 -20
  183. data/lib/skr/models/location.rb +7 -1
  184. data/lib/skr/models/payment.rb +49 -0
  185. data/lib/skr/models/payment_category.rb +11 -0
  186. data/lib/skr/models/payment_term.rb +1 -1
  187. data/lib/skr/models/por_line.rb +1 -1
  188. data/lib/skr/models/pt_line.rb +1 -1
  189. data/lib/skr/models/sales_order.rb +9 -9
  190. data/lib/skr/models/sku_loc.rb +1 -1
  191. data/lib/skr/models/sku_tran.rb +6 -11
  192. data/lib/skr/models/so_line.rb +22 -12
  193. data/lib/skr/models/time_entry.rb +36 -0
  194. data/lib/skr/models/uom.rb +11 -10
  195. data/lib/skr/models/user_proxy.rb +1 -1
  196. data/lib/skr/number.rb +25 -0
  197. data/lib/skr/print/form.rb +46 -0
  198. data/lib/skr/print/template.rb +48 -0
  199. data/lib/skr/print.rb +11 -0
  200. data/lib/skr/string.rb +11 -0
  201. data/lib/skr/version.rb +1 -1
  202. data/lib/skr.rb +9 -0
  203. data/spec/fixtures/skr/address.yml +164 -4
  204. data/spec/fixtures/skr/bank_account.yml +8 -0
  205. data/spec/fixtures/skr/customer.yml +30 -4
  206. data/spec/fixtures/skr/customer_project.yml +20 -0
  207. data/spec/fixtures/skr/gl_account.yml +19 -1
  208. data/spec/fixtures/skr/gl_period.yml +3 -0
  209. data/spec/fixtures/skr/gl_posting.yml +22 -1
  210. data/spec/fixtures/skr/gl_transaction.yml +4 -1
  211. data/spec/fixtures/skr/inv_line.yml +35 -0
  212. data/spec/fixtures/skr/invoice.yml +13 -2
  213. data/spec/fixtures/skr/location.yml +5 -0
  214. data/spec/fixtures/skr/payment.yml +10 -0
  215. data/spec/fixtures/skr/payment_category.yml +8 -0
  216. data/spec/fixtures/skr/payment_term.yml +37 -3
  217. data/spec/fixtures/skr/sales_order.yml +12 -1
  218. data/spec/fixtures/skr/sku.yml +78 -1
  219. data/spec/fixtures/skr/sku_loc.yml +42 -1
  220. data/spec/fixtures/skr/sku_tran.yml +24 -1
  221. data/spec/fixtures/skr/so_line.yml +32 -0
  222. data/spec/fixtures/skr/time_entry.yml +82 -0
  223. data/spec/fixtures/skr/uom.yml +52 -1
  224. data/spec/fixtures/skr/vendor.yml +28 -1
  225. data/spec/fixtures/stockor.png +0 -0
  226. data/spec/server/bank_account_spec.rb +10 -0
  227. data/spec/server/customer_project_spec.rb +10 -0
  228. data/spec/server/handlers/invoice_from_time_entries_spec.rb +49 -0
  229. data/spec/server/jobs/fresh_books/import_spec.rb +69 -0
  230. data/spec/server/jobs/fresh_books/retrieve_spec.rb +37 -0
  231. data/spec/server/models/address_spec.rb +4 -3
  232. data/spec/server/models/gl_transaction_spec.rb +3 -3
  233. data/spec/server/models/inv_line_spec.rb +83 -3
  234. data/spec/server/models/invoice_spec.rb +32 -3
  235. data/spec/server/models/payment_spec.rb +40 -0
  236. data/spec/server/models/sales_order_spec.rb +1 -1
  237. data/spec/server/models/so_line_spec.rb +3 -3
  238. data/spec/server/models/spec_helper_spec.rb +1 -1
  239. data/spec/server/payment_spec.rb +10 -0
  240. data/spec/server/print/form_spec.rb +47 -0
  241. data/spec/server/print/template_spec.rb +36 -0
  242. data/spec/server/spec_helper.rb +14 -1
  243. data/spec/server/time_entry_spec.rb +10 -0
  244. data/spec/skr/components/SkuLinesSpec.coffee +61 -0
  245. data/spec/skr/models/BankAccountSpec.coffee +5 -0
  246. data/spec/skr/models/CustomerProjectSpec.coffee +5 -0
  247. data/spec/skr/models/CustomerSpec.coffee +2 -2
  248. data/spec/skr/models/PaymentSpec.coffee +5 -0
  249. data/spec/skr/models/SalesOrderSpec.coffee +21 -5
  250. data/spec/skr/models/SoLineSpec.coffee +7 -2
  251. data/spec/skr/models/TimeEntrySpec.coffee +5 -0
  252. data/spec/skr/screens/bank-maint/BankMaintSpec.coffee +5 -0
  253. data/spec/skr/screens/customer-projects/CustomerProjectsSpec.coffee +5 -0
  254. data/spec/skr/screens/fresh-books-import/FreshBooksImportSpec.coffee +1 -0
  255. data/spec/skr/screens/gl-accounts/GlAccountsSpec.coffee +5 -0
  256. data/spec/skr/screens/invoice/InvoiceSpec.coffee +5 -0
  257. data/spec/skr/screens/locations/LocationsSpec.coffee +5 -0
  258. data/spec/skr/screens/payment-category/PaymentCategorySpec.coffee +5 -0
  259. data/spec/skr/screens/payment-terms/PaymentTermsSpec.coffee +5 -0
  260. data/spec/skr/screens/payments/PaymentsSpec.coffee +5 -0
  261. data/spec/skr/screens/time-invoicing/TimeInvoicingSpec.coffee +5 -0
  262. data/spec/skr/screens/time-tracking/TimeTrackingSpec.coffee +14 -0
  263. data/spec/vcr/freshbooks.yml +698 -0
  264. data/stockor.gemspec +5 -1
  265. data/templates/print/fonts/GnuMICR.otf +0 -0
  266. data/templates/print/layout.tex.erb +39 -0
  267. data/templates/print/packages/booktabs.sty +182 -0
  268. data/templates/print/packages/fancybox.sty +966 -0
  269. data/templates/print/packages/fancyhdr.sty +485 -0
  270. data/templates/print/packages/graphbox.sty +129 -0
  271. data/templates/print/packages/lastpage.sty +283 -0
  272. data/templates/print/packages/lastpage209.sty +70 -0
  273. data/templates/print/packages/marginnote.sty +412 -0
  274. data/templates/print/packages/multirow.sty +159 -0
  275. data/templates/print/packages/rotating.sty +282 -0
  276. data/templates/print/packages/tabu.sty +2557 -0
  277. data/templates/print/packages/textpos.sty +361 -0
  278. data/templates/print/packages/varwidth.sty +318 -0
  279. data/templates/print/partials/address.tex.erb +6 -0
  280. data/templates/print/partials/bill_to_ship_to.tex.erb +13 -0
  281. data/templates/print/partials/header.tex.erb +13 -0
  282. data/templates/print/partials/invoice_paid_state.tex.erb +2 -0
  283. data/templates/print/partials/old/inv_lines_grouping.tex.erb +8 -0
  284. data/templates/print/partials/old/labor_lines_footer.tex.erb +18 -0
  285. data/templates/print/partials/skus_table.tex.erb +32 -0
  286. data/templates/print/partials/skus_table_col_hdr.tex.erb +8 -0
  287. data/templates/print/partials/skus_table_footer.tex.erb +5 -0
  288. data/templates/print/partials/skus_table_group_footer.tex.erb +4 -0
  289. data/templates/print/partials/skus_table_invoice_footer.tex.erb +25 -0
  290. data/templates/print/partials/skus_table_invoice_info_line.tex.erb +16 -0
  291. data/templates/print/partials/skus_table_labor_col_hdr.tex.erb +8 -0
  292. data/templates/print/partials/skus_table_labor_group_footer.tex.erb +7 -0
  293. data/templates/print/partials/skus_table_labor_line.tex.erb +11 -0
  294. data/templates/print/partials/skus_table_line.tex.erb +6 -0
  295. data/templates/print/partials/skus_table_other_charge_lines.tex.erb +7 -0
  296. data/templates/print/partials/so_info_line.tex.erb +14 -0
  297. data/templates/print/types/invoice/default.tex.erb +13 -0
  298. data/templates/print/types/invoice/labor.tex.erb +33 -0
  299. data/templates/print/types/payment/default.tex.erb +64 -0
  300. data/templates/print/types/sales-order/default.tex.erb +8 -0
  301. metadata +252 -15
  302. data/client/skr/components/address/address.html +0 -20
  303. data/client/skr/models/mixins/CodeField.coffee +0 -5
  304. data/client/skr/screens/customer-maint/index.scss +0 -11
  305. data/client/skr/screens/customer-maint/layout.html +0 -32
  306. data/client/skr/screens/sales-order/SalesOrder.coffee +0 -30
  307. data/client/skr/screens/sales-order/index.scss +0 -8
  308. data/client/skr/screens/sales-order/layout.html +0 -30
  309. data/client/skr/screens/sku-maint/SkuMaint.coffee +0 -18
  310. data/client/skr/screens/sku-maint/layout.html +0 -16
  311. data/client/skr/screens/vendor-maint/VendorMaint.coffee +0 -28
  312. data/client/skr/screens/vendor-maint/index.scss +0 -8
  313. data/client/skr/screens/vendor-maint/layout.html +0 -32
@@ -0,0 +1,132 @@
1
+ class TimeEntries extends Skr.Models.TimeEntry.Collection
2
+
3
+ constructor: (@projects) ->
4
+ super()
5
+
6
+ projectForEntry: (entry) ->
7
+ @projects.get( entry.customer_project_id )
8
+
9
+ loadEntries: (range, query = {}) ->
10
+ query.end_at = { op: 'gt', value: range.start.toISOString() }
11
+ query.start_at = { op: 'lt', value: range.end.toISOString() }
12
+ @fetch({query, reset: true})
13
+
14
+ resetEntries: (projectId, range) ->
15
+ @projectId = projectId
16
+ query = if @projectId and @projectId isnt -1
17
+ {customer_project_id: @projectId}
18
+ else {}
19
+ @loadEntries(range, query)
20
+
21
+ class Skr.Screens.TimeTracking.Entries extends Lanes.Models.Base
22
+
23
+ session:
24
+ date: { type: 'object', 'required': true, default: -> _.moment() }
25
+ display: { type: 'string', values: ['day', 'week', 'month'], default: 'week' }
26
+ isLoading: { type: 'boolean', default: false }
27
+ customer_project_id: 'integer'
28
+ editing: 'any'
29
+
30
+ derived:
31
+ project:
32
+ deps: ['customer_project_id'], fn: ->
33
+ @available_projects.get(@customer_project_id)
34
+ isMonth:
35
+ deps: ['display'], fn: -> 'month' == @display
36
+ range:
37
+ deps: ['date', 'isMonth'], fn: ->
38
+ _.moment.range(
39
+ @date.clone().startOf( @display ), @date.clone().endOf( @display )
40
+ )
41
+
42
+ calLegend:
43
+ deps: ['range', 'display'], fn: ->
44
+ if @display is 'month'
45
+ @date.format('MMMM YYYY')
46
+ else if @display is 'week'
47
+ "#{@range.start.format('MMM Do')} - #{@range.end.format('MMM Do')}"
48
+ else if @display is 'day'
49
+ @date.format('MMMM Do YYYY')
50
+
51
+ events:
52
+ 'change:range': 'fetchEvents'
53
+ 'change:display': 'onDisplayChange'
54
+ 'change:customer_project_id': 'fetchEvents'
55
+
56
+ constructor: ->
57
+ super
58
+ @available_projects = new Skr.Models.CustomerProject.Collection
59
+ @listenTo(@available_projects, 'sync', @onProjectsRequest)
60
+ @available_projects.ensureLoaded()
61
+ @entries = new TimeEntries(@available_projects)
62
+ @listenTo(@entries, 'request', @onRequest)
63
+ @listenTo(@entries, 'sync', @onLoad)
64
+
65
+ onProjectsRequest: ->
66
+ @available_projects.add({id:-1, code: 'ALL', options:{color: 1}}, at: 0)
67
+ @set(customer_project_id: Lanes.current_user.options.project_id or -1 )
68
+ @trigger('change', @)
69
+
70
+ startEditing: (editingEvent) ->
71
+ for event in @calEvents().events
72
+ event.setEditing(event is editingEvent)
73
+
74
+ stopEditing: ->
75
+ for event in @calEvents().events when event.isEditing()
76
+ entry = event.get('entry')
77
+ if entry.isNew()
78
+ event.remove()
79
+ else
80
+ entry.setEditing(false)
81
+
82
+ addEvent: (date) ->
83
+ date = date.clone()
84
+ rounded = Math.round( date.minute() / 15 ) * 15
85
+ date.minute(rounded).second(0)
86
+ entry = @entries.add({
87
+ start_at: date.subtract(1, 'hour'), end_at: date.clone().add(2, 'hour')
88
+ customer_project: @project unless @project.id is -1
89
+ })
90
+ @calEvents().add( entry.toCalEvent() )
91
+
92
+ onRequest: ->
93
+ @isLoading = !!@entries.requestInProgress
94
+ @trigger('change', @)
95
+
96
+ onLoad: ->
97
+ delete @_cachedEvents unless @entries.requestInProgress
98
+ @isLoading = !!@entries.requestInProgress
99
+ @trigger('change', @)
100
+
101
+ reset: ->
102
+ @entries.loadEntries(@range.clone())
103
+
104
+ fetchEvents: ->
105
+ @entries.resetEntries(@customer_project_id, @range)
106
+
107
+ calEvents: ->
108
+ @_cachedEvents ||= new LC.Calendar.Events( @entries.invoke('toCalEvent') )
109
+
110
+ back: ->
111
+ @set(editing: false, date: @date.clone().subtract(1, @display) )
112
+
113
+ forward: ->
114
+ @set(editing: false, date: @date.clone().add(1, @display) )
115
+
116
+ onDisplayChange: ->
117
+ @editing = false
118
+
119
+ totalHours: ->
120
+ @entries.reduce( (sum, entry) =>
121
+ sum.add( entry.lengthInRange(@range, 'hours') )
122
+ , _.bigDecimal('0') )
123
+
124
+ totalsForWeek: (week) ->
125
+ start = @range.start.clone().add(week - 1, 'week').startOf('week')
126
+ days = _.moment.range( start, start.clone().endOf('week') )
127
+ entries = @entries.filter (entry) -> days.overlaps( entry.range )
128
+ byProject = _.groupBy entries, (entry) -> entry.customer_project_id
129
+ _.mapValues byProject, (entries, projectId) ->
130
+ _.reduce( entries, (total, entry) ->
131
+ total.plus(entry.lengthInRange(days, 'hours'))
132
+ , _.bigDecimal('0'))
@@ -0,0 +1,71 @@
1
+ class Skr.Screens.TimeTracking.Header extends Lanes.React.BaseComponent
2
+
3
+ back: ->
4
+ @props.entries.back()
5
+ forward: ->
6
+ @props.entries.forward()
7
+ changeDisplay: (ev) ->
8
+ @props.entries.display = ev.target.value
9
+ setProject: (project) ->
10
+ @props.entries.set(customer_project_id: project.id)
11
+ ProjectOption: (props) ->
12
+ color = props.item.options?.color || 0
13
+ <div className={"color-#{color}"}>{props.item.code}</div>
14
+ getProjects: ->
15
+ @props.entries.available_projects.models
16
+
17
+ onProjectsToggle: (isOpen) ->
18
+ if isOpen and not @props.entries.available_projects.requestInProgress
19
+ @props.entries.available_projects.fetch()
20
+ @forceUpdate()
21
+
22
+ render: ->
23
+ <BS.Row className='calendar-header'>
24
+
25
+ <div className="paging">
26
+
27
+ <span className="legend">
28
+ {@props.entries.calLegend}
29
+ </span>
30
+
31
+ <BS.ButtonGroup>
32
+ <BS.Button bsSize="small" onClick={@back}>
33
+ <LC.Icon size='2x' type="caret-left" />
34
+ </BS.Button>
35
+ <BS.Button bsSize="small" onClick={@forward}>
36
+ <LC.Icon size='2x' type="caret-right" />
37
+ </BS.Button>
38
+ </BS.ButtonGroup>
39
+
40
+ </div>
41
+
42
+ <div className="display">
43
+ <BS.ButtonGroup>
44
+ <BS.Button
45
+ value='month' onClick={@changeDisplay}
46
+ active={@props.entries.display == 'month'}>Month</BS.Button>
47
+
48
+ <BS.Button
49
+ value='week' onClick={@changeDisplay}
50
+ active={@props.entries.display == 'week'}>Week</BS.Button>
51
+
52
+ <BS.Button
53
+ value='day' onClick={@changeDisplay}
54
+ active={@props.entries.display == 'day'}>Day</BS.Button>
55
+ </BS.ButtonGroup>
56
+ </div>
57
+
58
+ <div className="select">
59
+ <Lanes.Vendor.ReactWidgets.DropdownList
60
+ data={@getProjects()}
61
+ busy={!!@props.entries.available_projects.requestInProgress}
62
+ onToggle={@onProjectsToggle}
63
+ valueField='id' textField='code'
64
+ value={@props.entries.project}
65
+ onChange={@setProject}
66
+ valueComponent={@ProjectOption}
67
+ itemComponent={@ProjectOption}
68
+ />
69
+ </div>
70
+
71
+ </BS.Row>
@@ -0,0 +1,70 @@
1
+ ##= require ./PopoverMiniControls
2
+ ##= require ./EditEntry
3
+
4
+ class Skr.Screens.TimeTracking.Popover extends Lanes.React.Component
5
+
6
+ componentWillReceiveProps: (nextProps) ->
7
+ if @state.editing and nextProps.editing is false
8
+ @onCancel()
9
+ else
10
+ @setState(isCanceled: false)
11
+
12
+ onCancel: ->
13
+ if @state.editing?.get('entry').isNew()
14
+ @state.editing.remove()
15
+ @props.entries.stopEditing()
16
+ @setState(isCanceled: true, editing: null)
17
+
18
+ onAddEntry: ->
19
+ event = @props.entries.addEvent(@props.date)
20
+ @setState(editing: event)
21
+
22
+ onEditEvent: (event) ->
23
+ @setState(editing: event)
24
+
25
+ EditEntry: ->
26
+ return null unless @state.editing
27
+ <Skr.Screens.TimeTracking.EditEntry
28
+ event={@state.editing}
29
+ entries={@props.entries}
30
+ date={@props.date}
31
+ onCancel={@onCancel}
32
+ />
33
+
34
+ MiniControls: ->
35
+ return null if @state.editing
36
+ <Skr.Screens.TimeTracking.MiniControls
37
+ date={@props.date}
38
+ event={@props.event}
39
+ onCancel={@onCancel}
40
+ onAddEntry={@onAddEntry}
41
+ onEditEvent={@onEditEvent}
42
+ />
43
+
44
+ render: ->
45
+ return null if @state.isCanceled or not @props.date
46
+
47
+ classes = _.classnames('edit-control', 'in')
48
+ {x, y} = @props.position
49
+ [width, height] = if @state.editing
50
+ [320, 400]
51
+ else
52
+ [175, 60]
53
+
54
+ # expand to show edit button
55
+ width += 60 if @props.event and not @state.editing
56
+
57
+ placement = if x > (this.props.bounds.width / 2) then 'left' else 'right'
58
+
59
+ x -= width if placement is 'left'
60
+
61
+ <BS.Popover className={classes}
62
+ style={{width, height}}
63
+ id='edit-controls'
64
+ placement={placement}
65
+ positionLeft={x}
66
+ positionTop={y - (height / 2)}
67
+ >
68
+ <@MiniControls />
69
+ <@EditEntry />
70
+ </BS.Popover>
@@ -0,0 +1,25 @@
1
+ class Skr.Screens.TimeTracking.MiniControls extends Lanes.React.Component
2
+
3
+ onEditEvent: ->
4
+ @props.onEditEvent(@props.event)
5
+
6
+ EditButton: ->
7
+ return null unless @props.event
8
+ <BS.Button onClick={@onEditEvent} title="Edit Time Entry">
9
+ <LC.Icon type='pencil-square-o' 2x flush />
10
+ </BS.Button>
11
+
12
+ render: ->
13
+ <div className="mini-controls">
14
+ <div className='l'>
15
+ {@props.date.format('MMM')}
16
+ {@props.date.format('Do')}
17
+ </div>
18
+ <BS.Button onClick={@props.onCancel} title="Hide Controls">
19
+ <LC.Icon type='ban' 2x flush />
20
+ </BS.Button>
21
+ <@EditButton />
22
+ <BS.Button onClick={@props.onAddEntry} title="Create Time Entry">
23
+ <LC.Icon type='plus-square' 2x flush />
24
+ </BS.Button>
25
+ </div>
@@ -0,0 +1,63 @@
1
+ ##= require_self
2
+ ##= require ./Popover
3
+ ##= require ./WeekSummary
4
+ ##= require ./Entries
5
+ ##= require ./Header
6
+
7
+ class Skr.Screens.TimeTracking extends Skr.Screens.Base
8
+
9
+ dataObjects:
10
+ entries: ->
11
+ new Skr.Screens.TimeTracking.Entries
12
+
13
+ onDayClick: (ev, date) ->
14
+ @showPopup(ev, date)
15
+
16
+ showPopup: (ev, date, eventEditing = false) ->
17
+ rect = _.dom(this).el.getBoundingClientRect()
18
+ @entries.editing = {
19
+ event: eventEditing,
20
+ date: date, bounds: rect,
21
+ position: {x: ev.clientX - rect.left, y: ev.clientY - rect.top}
22
+ }
23
+
24
+ onEventClick: (ev, event) ->
25
+ @showPopup(ev, event.start(), event)
26
+
27
+ stopEdit: ->
28
+ @entries.editing = false
29
+
30
+ onEventResize: (ev, event) ->
31
+ entry = event.get('entry')
32
+ entry.fromCalEvent(event)
33
+ entry.save() unless entry.isNew()
34
+
35
+ renderSummaryDays: ->
36
+ return null unless @entries.isMonth
37
+ for week in [1..5]
38
+ <Skr.Screens.TimeTracking.WeekSummary
39
+ key={week} week={week} entries={@entries} />
40
+
41
+ renderTotals: ->
42
+ return null unless @entries.isMonth
43
+ <div className="monthly-totals">{@entries.totalHours().toFixed(2)}</div>
44
+
45
+ render: ->
46
+ <LC.ScreenWrapper identifier="time-tracking" flexVertical>
47
+ <Skr.Screens.TimeTracking.Popover entries={@entries} {...@entries.editing} />
48
+ <LC.NetworkActivityOverlay visible={@entries.isLoading} model={@entries}/>
49
+ <Skr.Screens.TimeTracking.Header entries={@entries} />
50
+ <BS.Row className="calendar-panel">
51
+ {@renderTotals()}
52
+ <LC.Calendar ref='calendar'
53
+ onDayClick={@onDayClick}
54
+ onEventResize={@onEventResize}
55
+ onEventClick={@onEventClick}
56
+ date={@entries.date}
57
+ events={@entries.calEvents()}
58
+ display={@entries.display}
59
+ >
60
+ {@renderSummaryDays()}
61
+ </LC.Calendar>
62
+ </BS.Row>
63
+ </LC.ScreenWrapper>
@@ -0,0 +1,16 @@
1
+ class Skr.Screens.TimeTracking.WeekSummary extends Lanes.React.BaseComponent
2
+
3
+ color: (projectId) ->
4
+ project = @props.entries.available_projects.get(projectId)
5
+ project?.options?.color || 0
6
+
7
+ render: ->
8
+ order = (@props.week * 7) - 1
9
+ totals = @props.entries.totalsForWeek(@props.week)
10
+
11
+ <div className="day summary" style={order: order}>
12
+ {for projectId, total of totals
13
+ <div key={projectId} className="color-#{@color(projectId)}">
14
+ {Lanes.u.format.currency(total)}
15
+ </div>}
16
+ </div>
@@ -0,0 +1 @@
1
+ //= require ./TimeTracking
@@ -0,0 +1,126 @@
1
+ @import "lanes/screens/styles";
2
+
3
+ .time-tracking {
4
+ position: relative;
5
+
6
+ .edit-control {
7
+
8
+ .mini-controls {
9
+ display: flex;
10
+ flex-direction: row;
11
+ justify-content: space-between;
12
+ .l {
13
+ display: flex;
14
+ flex-direction: column;
15
+ align-items: flex-end;
16
+ }
17
+ }
18
+ &.left {
19
+ .mini-controls {
20
+ flex-direction: row-reverse;
21
+ }
22
+ }
23
+ }
24
+
25
+ .calendar-header {
26
+ display: flex;
27
+ flex-direction: row;
28
+ justify-content: space-around;
29
+ flex-wrap: wrap;
30
+ align-items: center;
31
+ .display label+label {
32
+ padding-left: 1rem;
33
+ }
34
+ .paging {
35
+ display: flex;
36
+ flex-direction: row;
37
+ align-items: center;
38
+ .legend{
39
+ font-size: 1.4rem;
40
+ margin-right: 1rem;
41
+ }
42
+ i {
43
+ margin: 0 0.5em;
44
+ }
45
+ }
46
+ .select {
47
+ width: 200px;
48
+ @include lanes-unpadded-dropdown();
49
+ }
50
+ }
51
+
52
+ .calendar-panel {
53
+ margin: 5px 20px 20px 20px;
54
+ @include flexbox();
55
+ @include flex-grow(1);
56
+ @include flex-direction(column);
57
+ }
58
+
59
+ .monthly-totals {
60
+ align-self: flex-end;
61
+ display: inline;
62
+ width: 52px;
63
+ position: relative;
64
+ top: 18px;
65
+
66
+ text-align: right;
67
+ border-top-right-radius: 8px;
68
+ border: 1px solid lightgrey;
69
+ border-top-left-radius: 8px;
70
+ border-bottom: 0;
71
+ padding-right: 3px;
72
+
73
+ }
74
+
75
+ @each $current-color in $lanes-color-selections {
76
+ $i: index($lanes-color-selections, $current-color);
77
+ .calendar-header .select .color-#{$i} {
78
+ background: $current-color;
79
+ color: nth($lanes-text-color-selections, $i);
80
+ }
81
+ .day.summary .color-#{$i} {
82
+ background: $current-color;
83
+ color: nth($lanes-text-color-selections, $i);
84
+ }
85
+ }
86
+
87
+ .dayz {
88
+ flex: 1;
89
+ &.month {
90
+ .x-labels {
91
+ width: 94.5%;
92
+ .day-label {
93
+ width: (100%/7);
94
+ }
95
+ }
96
+ .days {
97
+ .day {
98
+ width: 13.5%;
99
+ }
100
+ .summary {
101
+ width: 5.5%;
102
+ flex-direction: column;
103
+ display: flex;
104
+ justify-content: center;
105
+ text-align: right;
106
+ }
107
+ }
108
+ }
109
+ }
110
+
111
+ .popover {
112
+ .controls {
113
+ border-top: 2px solid lightgrey;
114
+ padding-top: 1rem;
115
+ display: flex;
116
+ flex-direction: row;
117
+ justify-content: space-between;
118
+ button { width: 6rem; }
119
+ }
120
+ }
121
+
122
+ .dayz .label {
123
+ font-size: 1rem;
124
+ color: darkgrey;
125
+ }
126
+ }
@@ -0,0 +1,45 @@
1
+ class Skr.Screens.VendorMaint extends Lanes.React.Screen
2
+
3
+ syncOptions:
4
+ include: ['billing_address', 'shipping_address']
5
+
6
+ dataObjects:
7
+ vendor: ->
8
+ @loadOrCreateModel({
9
+ syncOptions: @syncOptions, klass: Skr.Models.Vendor,
10
+ prop: 'vendor', attribute: 'code'
11
+ })
12
+
13
+ getInitialState: ->
14
+ commands: new Skr.Screens.Commands(this, modelName: 'vendor')
15
+
16
+ modelForAccess: 'vendor'
17
+
18
+ render: ->
19
+ <LC.ScreenWrapper identifier="vendor-maint">
20
+ <SC.ScreenControls commands={@state.commands} />
21
+ <BS.Row>
22
+ <SC.VendorFinder model={@vendor} sm=4 editOnly autofocus
23
+ syncOptions={@syncOptions}
24
+ model={@vendor} name='code'
25
+ commands={@state.commands} />
26
+ <LC.Input sm=8 name="name" model={@vendor} />
27
+ </BS.Row>
28
+ <BS.Row>
29
+ <LC.Input sm=12 type='textarea' name="notes" model={@vendor} />
30
+ </BS.Row>
31
+ <BS.Row>
32
+ <SC.GlAccountChooser sm=4 label="Payables Account"
33
+ name="gl_payables_account" model={@vendor} />
34
+ <SC.GlAccountChooser sm=4 label="Freight Account"
35
+ name="gl_freight_account" model={@vendor} />
36
+ <SC.TermsChooser sm=4 model={@vendor} />
37
+ </BS.Row>
38
+ <BS.Row>
39
+ <LC.FieldSet sm=12 title="Address">
40
+ <SC.Address lg=6 title="Billing" model={@vendor.billing_address} />
41
+ <SC.Address lg=6 title="Shipping" model={@vendor.shipping_address} />
42
+ </LC.FieldSet>
43
+ </BS.Row>
44
+
45
+ </LC.ScreenWrapper>
@@ -1,5 +1 @@
1
- // require_tree .
2
-
3
- /*
4
- Add additional requirement statements for other files that the screen uses
5
- */
1
+ //=require ./VendorMaint
@@ -1,17 +1,5 @@
1
1
  /* Enter styles for your application in scss format here */
2
2
 
3
- .header-top {
4
- .logo {
5
- display: inline-block;
6
- height: 48px;
7
- width: 150px;
8
- margin: 2px;
9
- text-indent: -9999px;
10
- background: url(asset_path('images/skr/logo-sm.png')) no-repeat;
11
- }
12
- }
13
-
14
-
15
3
  .record-finder-dialog {
16
4
  min-height: 250px;
17
5
  .clause {
@@ -31,4 +19,4 @@
31
19
  }
32
20
  }
33
21
 
34
- @import "components/address/styles.scss";
22
+ @import "components/styles";
data/config/puma.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'message_bus'
2
+ on_worker_boot do
3
+ MessageBus.after_fork
4
+ end
data/config/routes.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  require 'stockor'
2
2
 
3
- Lanes::API.routes.draw do
3
+ Lanes::API.routes.for_extension 'skr' do
4
+
5
+ resources Skr::CustomerProject
6
+ resources Skr::TimeEntry
4
7
  resources Skr::Customer
5
8
  resources Skr::Address
6
9
  resources Skr::GlAccount
@@ -8,11 +11,14 @@ Lanes::API.routes.draw do
8
11
  resources Skr::GlPeriod
9
12
  resources Skr::GlPosting
10
13
  resources Skr::GlTransaction
14
+ resources Skr::BankAccount
15
+ resources Skr::PaymentCategory
16
+ resources Skr::Payment
11
17
  resources Skr::IaLine
12
18
  resources Skr::IaReason
13
- resources Skr::InvLine
19
+ resources Skr::InvLine, indestructible: true
14
20
  resources Skr::InventoryAdjustment
15
- resources Skr::Invoice
21
+ resources Skr::Invoice, indestructible: true
16
22
  resources Skr::Location
17
23
  resources Skr::PaymentTerm
18
24
  resources Skr::Sku
@@ -20,22 +26,28 @@ Lanes::API.routes.draw do
20
26
  resources Skr::SkuTran
21
27
  resources Skr::Uom
22
28
  resources Skr::Vendor
23
-
24
-
25
29
  resources Skr::PickTicket
26
30
  resources Skr::PtLine
27
-
28
31
  resources Skr::PoReceipt
29
32
  resources Skr::PorLine
30
-
31
33
  resources Skr::PurchaseOrder
32
34
  resources Skr::PoLine
33
-
34
35
  resources Skr::Voucher
35
36
  resources Skr::VoLine
36
-
37
37
  resources Skr::SalesOrder
38
38
  resources Skr::SoLine
39
39
 
40
+ post 'invoices/from-time-entries.json',
41
+ &Skr::Handlers::InvoiceFromTimeEntries.handler
42
+
43
+ get 'print/:type/:id.pdf' do
44
+ content_type 'application/pdf'
45
+ form = Skr::Print::Form.new(params[:type], params[:id])
46
+ form.as_pdf
47
+ end
48
+
49
+ post 'fresh-books-imports.json',
50
+ &Skr::Handlers::FreshBooksImport.handler
51
+
40
52
 
41
53
  end