eboshi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +28 -0
  3. data/Rakefile +8 -0
  4. data/app/assets/config/eboshi_manifest.js +1 -0
  5. data/app/assets/stylesheets/eboshi/application.css +15 -0
  6. data/app/controllers/eboshi/adjustments_controller.rb +77 -0
  7. data/app/controllers/eboshi/application_controller.rb +62 -0
  8. data/app/controllers/eboshi/assignments_controller.rb +31 -0
  9. data/app/controllers/eboshi/budgets_controller.rb +43 -0
  10. data/app/controllers/eboshi/calendar_controller.rb +12 -0
  11. data/app/controllers/eboshi/clients_controller.rb +41 -0
  12. data/app/controllers/eboshi/invoices_controller.rb +69 -0
  13. data/app/controllers/eboshi/line_items_controller.rb +28 -0
  14. data/app/controllers/eboshi/payments_controller.rb +31 -0
  15. data/app/controllers/eboshi/user_sessions_controller.rb +25 -0
  16. data/app/controllers/eboshi/users_controller.rb +41 -0
  17. data/app/controllers/eboshi/works_controller.rb +83 -0
  18. data/app/helpers/eboshi/application_helper.rb +15 -0
  19. data/app/helpers/eboshi/calendar_helper.rb +80 -0
  20. data/app/helpers/eboshi/shallow_route_helper.rb +68 -0
  21. data/app/jobs/eboshi/application_job.rb +4 -0
  22. data/app/mailers/eboshi/application_mailer.rb +6 -0
  23. data/app/models/eboshi/adjustment.rb +37 -0
  24. data/app/models/eboshi/application_record.rb +5 -0
  25. data/app/models/eboshi/assignment.rb +20 -0
  26. data/app/models/eboshi/budget.rb +33 -0
  27. data/app/models/eboshi/client.rb +85 -0
  28. data/app/models/eboshi/invoice.rb +87 -0
  29. data/app/models/eboshi/line_item.rb +94 -0
  30. data/app/models/eboshi/payment.rb +20 -0
  31. data/app/models/eboshi/user.rb +128 -0
  32. data/app/models/eboshi/user_session.rb +6 -0
  33. data/app/models/eboshi/work.rb +66 -0
  34. data/app/views/eboshi/adjustments/_adjustment.html.slim +15 -0
  35. data/app/views/eboshi/adjustments/_form.html.haml +27 -0
  36. data/app/views/eboshi/adjustments/edit.html.haml +7 -0
  37. data/app/views/eboshi/adjustments/new.html.haml +8 -0
  38. data/app/views/eboshi/assignments/new.html.haml +18 -0
  39. data/app/views/eboshi/budgets/form.html.haml +22 -0
  40. data/app/views/eboshi/calendar/index.html.slim +32 -0
  41. data/app/views/eboshi/clients/_form.html.haml +34 -0
  42. data/app/views/eboshi/clients/edit.html.haml +4 -0
  43. data/app/views/eboshi/clients/index.html.haml +19 -0
  44. data/app/views/eboshi/clients/new.html.haml +4 -0
  45. data/app/views/eboshi/invoices/_form.html.slim +68 -0
  46. data/app/views/eboshi/invoices/_full.html.haml +76 -0
  47. data/app/views/eboshi/invoices/_invoice.html.haml +2 -0
  48. data/app/views/eboshi/invoices/_mini.html.haml +21 -0
  49. data/app/views/eboshi/invoices/edit.html.haml +14 -0
  50. data/app/views/eboshi/invoices/index.html.haml +46 -0
  51. data/app/views/eboshi/invoices/new.html.haml +11 -0
  52. data/app/views/eboshi/invoices/show.pdf.haml +118 -0
  53. data/app/views/eboshi/layouts/application.html.haml +120 -0
  54. data/app/views/eboshi/payments/_form.html.haml +10 -0
  55. data/app/views/eboshi/payments/new.html.haml +9 -0
  56. data/app/views/eboshi/user_sessions/new.html.haml +19 -0
  57. data/app/views/eboshi/users/_form.html.haml +65 -0
  58. data/app/views/eboshi/users/edit.html.haml +16 -0
  59. data/app/views/eboshi/users/index.html.haml +11 -0
  60. data/app/views/eboshi/users/new.html.haml +13 -0
  61. data/app/views/eboshi/users/show.html.haml +39 -0
  62. data/app/views/eboshi/works/_form.html.slim +25 -0
  63. data/app/views/eboshi/works/_work.html.slim +27 -0
  64. data/app/views/eboshi/works/edit.html.haml +9 -0
  65. data/app/views/eboshi/works/new.html.haml +8 -0
  66. data/app/views/layouts/eboshi/application.html.haml +120 -0
  67. data/config/routes.rb +35 -0
  68. data/lib/eboshi/engine.rb +15 -0
  69. data/lib/eboshi/version.rb +3 -0
  70. data/lib/eboshi.rb +6 -0
  71. data/lib/tasks/eboshi_tasks.rake +4 -0
  72. metadata +253 -0
@@ -0,0 +1,120 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %meta(http-equiv="Content-Type" content="text/html; charset=utf-8")
5
+ %title
6
+ Eboshi »
7
+ = yield :title
8
+ = csrf_meta_tags
9
+
10
+ = stylesheet_link_tag "application"
11
+ = yield :css
12
+
13
+ - if current_user
14
+ %style
15
+ :plain
16
+ a:hover, input.button:hover {color: ##{current_user.color};}
17
+ .button:hover, input.button:hover {border-color:##{current_user.color};}
18
+ .line_item_selected {background-color:##{current_user.color};}
19
+
20
+ = javascript_importmap_tags
21
+
22
+ %link{rel: "shortcut icon", href: image_path("/favicon.png"), type: "image/x-icon"}
23
+
24
+ %body
25
+ #flash_notice= flash.notice
26
+ #flash_error= flash.alert
27
+
28
+ #wrapper
29
+ #header_container
30
+ #header
31
+ #login
32
+ #account.right
33
+ - if current_user
34
+ = link_to 'Logout', logout_path, method: :delete, class: "button right"
35
+ - if current_user.admin?
36
+ = link_to 'All Users', users_path, class: "button right"
37
+ = link_to 'My Account', edit_user_path(current_user), class: "button right"
38
+ .user_name.right.sm_pad{style: "color: ##{current_user.color}"}
39
+ %span Welcome, #{current_user.name}!
40
+ .clear
41
+ .clear
42
+ #title
43
+ %h1
44
+ %a(href="/") EBO$HI
45
+ %p a simple rails invoicing application
46
+ .clear
47
+ .clear
48
+
49
+ #breadcrumbs_container
50
+ #breadcrumbs
51
+ %h2= yield :title
52
+ = yield :header
53
+
54
+ #actions= yield :actions
55
+
56
+ #all_content
57
+ #sidebar
58
+ - if current_user
59
+ %h2#summaries_control Activity Summary
60
+ %table#summaries(width="100%" border="0" cellspacing="0" cellpadding="0")
61
+ %col(width="60%")
62
+ %col(width="20%")
63
+ %col(width="20%")
64
+ %tr
65
+ %td Year
66
+ %td= pluralize number_with_precision(current_user.hours_by_year(Date.today), precision: 0), 'hour'
67
+ %td= currency_or_empty current_user.total_by_year(Date.today)
68
+ %tr
69
+ %td Month
70
+ %td= pluralize number_with_precision(current_user.hours_by_month(Date.today), precision: 0), 'hour'
71
+ %td= currency_or_empty current_user.total_by_month(Date.today)
72
+ %tr
73
+ %td Week
74
+ %td= pluralize number_with_precision(current_user.hours_by_week(Date.today), precision: 0), 'hour'
75
+ %td= currency_or_empty current_user.total_by_week(Date.today)
76
+ %tr
77
+ %td Day
78
+ %td= pluralize number_with_precision(current_user.hours_by_date(Date.today), precision: 0), 'hour'
79
+ %td= currency_or_empty current_user.total_by_date(Date.today)
80
+
81
+ %p= link_to "details", "/calendar"
82
+ %br
83
+
84
+ - if @client and !@client.new_record?
85
+ %h2 Collaborators
86
+ %ul#collaborators
87
+ - @client.assignments.each do |assignment|
88
+ - next if assignment.new_record?
89
+ %li
90
+ %span= assignment.user.name
91
+ = link_to "delete", assignment, :method => :delete
92
+ = link_to '+ Invite collaborator', new_assignment_path(@client), :class=>"button right"
93
+ .clear
94
+
95
+ - if current_user
96
+ %h2= link_to "Clients", clients_path
97
+ %table#clients_summary(width="100%" border="0" cellspacing="0" cellpadding="0")
98
+ %col(width="60%")
99
+ %col(width="20%")
100
+ %col(width="20%")
101
+ - current_user.clients.each do |client|
102
+ = cache client do
103
+ %tr
104
+ %td= link_to client.name, [client, :invoices], class: "inline"
105
+ %td= currency_or_empty client.unbilled_balance
106
+ %td.red= currency_or_empty client.overdue_balance
107
+
108
+ = link_to '+ Add Client', new_client_path, :class=>"button right"
109
+ .clear
110
+
111
+
112
+ #content
113
+ = yield
114
+ .clear
115
+ .clear
116
+
117
+ #footer_container
118
+ #footer
119
+ = yield :footer
120
+
@@ -0,0 +1,10 @@
1
+ - f = form
2
+ %p
3
+ = f.label :create_at, "Date"
4
+ = f.date_select :created_at
5
+
6
+ %p
7
+ = f.label :total
8
+ = f.text_field :total
9
+
10
+ %p= f.submit @payment.new_record? ? "Create" : "Update"
@@ -0,0 +1,9 @@
1
+ - content_for :title do
2
+ New payment
3
+
4
+ = error_messages_for :payment
5
+
6
+ = form_for @payment, :url => payments_path(@invoice) do |f|
7
+ = render :partial => 'form', :object => f
8
+
9
+ = link_to 'Cancel', invoices_path(@invoice.client)
@@ -0,0 +1,19 @@
1
+ - content_for :title do
2
+ Login
3
+
4
+ %h2 Login
5
+
6
+ = form_for @user_session, :url => user_session_path do |f|
7
+ = f.error_messages
8
+ %p
9
+ = f.label :email
10
+ = f.text_field :email
11
+ %p
12
+ = f.label :password
13
+ = f.password_field :password
14
+ %p
15
+ = f.label :remember_me
16
+ = f.check_box :remember_me
17
+ %hr
18
+ %p.center_align
19
+ = f.submit "Login", :class=>"button lg"
@@ -0,0 +1,65 @@
1
+ %p
2
+ = form.label :name
3
+ = form.text_field :name
4
+
5
+ %p
6
+ = form.label :email, "Email Address"
7
+ = form.text_field :email
8
+
9
+ %p
10
+ = form.label :password, form.object.new_record? ? nil : "Change password"
11
+ = form.password_field :password
12
+
13
+ %p
14
+ = form.label :password_confirmation
15
+ = form.password_field :password_confirmation
16
+
17
+ %p
18
+ = form.label :rate, "Default Rate"
19
+ == $#{form.text_field :rate}
20
+
21
+ %p
22
+ = form.label :color
23
+ = form.text_field :color
24
+
25
+ %h1 invoice details
26
+
27
+ %p
28
+ = form.label :business_name
29
+ = form.text_field :business_name
30
+
31
+ %p
32
+ = form.label :business_email
33
+ = form.text_field :business_email
34
+
35
+ %p
36
+ = form.label :address
37
+ = form.text_field :address
38
+
39
+ %p
40
+ = form.label :address2, ""
41
+ = form.text_field :address2
42
+
43
+ %p
44
+ = form.label :city
45
+ = form.text_field :city
46
+
47
+ %p
48
+ = form.label :state
49
+ = form.text_field :state
50
+
51
+ %p
52
+ = form.label :zip, "Zipcode"
53
+ = form.text_field :zip
54
+
55
+ %p
56
+ = form.label :logo
57
+ = image_tag @user.logo.url(:pdf) if @user.logo.exists?
58
+ = form.file_field :logo
59
+
60
+ %p
61
+ = form.label :signature
62
+ = image_tag @user.signature.url(:pdf) if @user.signature.exists?
63
+ = form.file_field :signature
64
+
65
+
@@ -0,0 +1,16 @@
1
+ - content_for :title do
2
+ Users » edit
3
+ = @user.name
4
+
5
+ %h2
6
+ .user_name{:style => "color: \##{current_user.color}"}
7
+ %span Users » edit
8
+ = @user.name
9
+
10
+ = form_for @user, :html => { :multipart => true } do |f|
11
+ = f.error_messages
12
+ = render :partial => "form", :object => f
13
+ = f.submit "Update", :class=>"right"
14
+
15
+ = link_to "cancel", current_user.admin? ? users_path : root_path, :class=>"button right"
16
+ .clear
@@ -0,0 +1,11 @@
1
+ - content_for :title do
2
+ users » all
3
+
4
+ %h2 users » all
5
+ %ul
6
+ - @users.each do |user|
7
+ %li.user
8
+ = link_to h(user.name), edit_user_path(user), :style => "color: \##{user.color}"
9
+ %span= number_to_per_hour user.rate
10
+
11
+ .add= link_to '+add user', new_user_path, :class=>"button right clear"
@@ -0,0 +1,13 @@
1
+ - content_for :title do
2
+ Users » new
3
+
4
+ %h2
5
+ Users » new
6
+
7
+ = form_for @user, :html => { :multipart => true } do |f|
8
+ = f.error_messages
9
+ = render :partial => "form", :object => f
10
+ = f.submit "Register"
11
+
12
+ %br
13
+ = link_to "cancel", users_path
@@ -0,0 +1,39 @@
1
+ - content_for :title do
2
+ Users »
3
+ = @user.name
4
+
5
+ %h2
6
+ .user_name{:style => "color: \##{current_user.color}"}
7
+ %span Users »
8
+ = @user.name
9
+
10
+ %p
11
+ %b Email:
12
+ = @user.email
13
+
14
+
15
+ %p
16
+ %b Login count:
17
+ =h @user.login_count
18
+
19
+ %p
20
+ %b Last request at:
21
+ =h @user.last_request_at
22
+
23
+ %p
24
+ %b Last login at:
25
+ =h @user.last_login_at
26
+
27
+ %p
28
+ %b Current login at:
29
+ =h @user.current_login_at
30
+
31
+ %p
32
+ %b Last login ip:
33
+ =h @user.last_login_ip
34
+
35
+ %p
36
+ %b Current login ip:
37
+ =h @user.current_login_ip
38
+
39
+ = link_to 'Edit', edit_user_path, :class=>"button"
@@ -0,0 +1,25 @@
1
+ = error_messages_for :work
2
+
3
+ = form_for [@client, @work] do |form|
4
+ = form.hidden_field :type
5
+
6
+ p
7
+ = form.label :start
8
+ |  
9
+ = form.datetime_field :start
10
+ p
11
+ = form.label :finish, "End"
12
+ |  
13
+ = form.datetime_field :finish
14
+ p
15
+ = form.label :rate
16
+ |  
17
+ | $
18
+ = form.text_field :rate
19
+ p
20
+ = form.label :notes
21
+ |  
22
+ = form.text_area :notes
23
+
24
+ p = form.submit form.object.new_record? ? "Create" : "Update"
25
+
@@ -0,0 +1,27 @@
1
+ tr.line_item.work id="line_item_#{work.id}_tr" class=cycle('even','') data-controller="line-item"
2
+ td = check_box_tag 'line_item_ids[]', work.id, nil, id: "line_item_ids_#{work.id}", data: { line_item_target: "checkbox" }
3
+ td.name.user_name style="color: ##{work.user&.color}" = work.user&.name
4
+ td.time colspan=(work.incomplete? ? 4 : 1)
5
+ = work.start.to_fs(:slash)
6
+ br
7
+ = work.start.to_fs(:time)
8
+ br
9
+ - if work.incomplete?
10
+ = link_to 'Clock Out', clock_out_path(@client, work), class: "clock_out",
11
+ data: { turbo_frame: dom_id(work.invoice || Eboshi::Invoice.new), turbo: true }
12
+ - else
13
+ = work.finish.to_fs(:time)
14
+ - unless work.incomplete?
15
+ td.hours = number_with_precision work.hours, precision: 2
16
+ td.rate = number_to_per_hour work.rate
17
+ td.total = number_to_currency work.total
18
+ td.notes
19
+ textarea.dummy id="notes_#{work.id}" autocomplete="off" data-controller="live-textarea" data-live-textarea-url-value=line_item_path(work)
20
+ = work.notes
21
+
22
+ td
23
+ = link_to image_tag("edit.png", size: "12x13"), edit_work_path(work), title: "Edit"
24
+ = link_to image_tag("delete.png", size: "11x10"), work, class: "delete",
25
+ data: { confirm: "Are you sure you want to delete this line item? This cannot be undone!",
26
+ turbo_frame: dom_id(work.invoice || Eboshi::Invoice.new), turbo_method: "delete", turbo: true }
27
+
@@ -0,0 +1,9 @@
1
+ - content_for :title do
2
+ =h @client.name
3
+ » Editing Time Item
4
+
5
+ = render "form"
6
+
7
+ = link_to 'Back', invoices_path(@client)
8
+
9
+ = button_to "Convert to Flat fee", convert_work_path(@work)
@@ -0,0 +1,8 @@
1
+ - content_for :title do
2
+ =h @client.name
3
+ » New Time Item
4
+
5
+ = render "form"
6
+
7
+ = link_to 'Back', invoices_path(@client)
8
+
@@ -0,0 +1,120 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %meta(http-equiv="Content-Type" content="text/html; charset=utf-8")
5
+ %title
6
+ Eboshi »
7
+ = yield :title
8
+ = csrf_meta_tags
9
+
10
+ = stylesheet_link_tag "application"
11
+ = yield :css
12
+
13
+ - if current_user
14
+ %style
15
+ :plain
16
+ a:hover, input.button:hover {color: ##{current_user.color};}
17
+ .button:hover, input.button:hover {border-color:##{current_user.color};}
18
+ .line_item_selected {background-color:##{current_user.color};}
19
+
20
+ = javascript_importmap_tags
21
+
22
+ %link{rel: "shortcut icon", href: image_path("/favicon.png"), type: "image/x-icon"}
23
+
24
+ %body
25
+ #flash_notice= flash.notice
26
+ #flash_error= flash.alert
27
+
28
+ #wrapper
29
+ #header_container
30
+ #header
31
+ #login
32
+ #account.right
33
+ - if current_user
34
+ = link_to 'Logout', logout_path, method: :delete, class: "button right"
35
+ - if current_user.admin?
36
+ = link_to 'All Users', users_path, class: "button right"
37
+ = link_to 'My Account', edit_user_path(current_user), class: "button right"
38
+ .user_name.right.sm_pad{style: "color: ##{current_user.color}"}
39
+ %span Welcome, #{current_user.name}!
40
+ .clear
41
+ .clear
42
+ #title
43
+ %h1
44
+ %a(href="/") EBO$HI
45
+ %p a simple rails invoicing application
46
+ .clear
47
+ .clear
48
+
49
+ #breadcrumbs_container
50
+ #breadcrumbs
51
+ %h2= yield :title
52
+ = yield :header
53
+
54
+ #actions= yield :actions
55
+
56
+ #all_content
57
+ #sidebar
58
+ - if current_user
59
+ %h2#summaries_control Activity Summary
60
+ %table#summaries(width="100%" border="0" cellspacing="0" cellpadding="0")
61
+ %col(width="60%")
62
+ %col(width="20%")
63
+ %col(width="20%")
64
+ %tr
65
+ %td Year
66
+ %td= pluralize number_with_precision(current_user.hours_by_year(Date.today), precision: 0), 'hour'
67
+ %td= currency_or_empty current_user.total_by_year(Date.today)
68
+ %tr
69
+ %td Month
70
+ %td= pluralize number_with_precision(current_user.hours_by_month(Date.today), precision: 0), 'hour'
71
+ %td= currency_or_empty current_user.total_by_month(Date.today)
72
+ %tr
73
+ %td Week
74
+ %td= pluralize number_with_precision(current_user.hours_by_week(Date.today), precision: 0), 'hour'
75
+ %td= currency_or_empty current_user.total_by_week(Date.today)
76
+ %tr
77
+ %td Day
78
+ %td= pluralize number_with_precision(current_user.hours_by_date(Date.today), precision: 0), 'hour'
79
+ %td= currency_or_empty current_user.total_by_date(Date.today)
80
+
81
+ %p= link_to "details", "/calendar"
82
+ %br
83
+
84
+ - if @client and !@client.new_record?
85
+ %h2 Collaborators
86
+ %ul#collaborators
87
+ - @client.assignments.each do |assignment|
88
+ - next if assignment.new_record?
89
+ %li
90
+ %span= assignment.user.name
91
+ = link_to "delete", assignment, :method => :delete
92
+ = link_to '+ Invite collaborator', new_assignment_path(@client), :class=>"button right"
93
+ .clear
94
+
95
+ - if current_user
96
+ %h2= link_to "Clients", clients_path
97
+ %table#clients_summary(width="100%" border="0" cellspacing="0" cellpadding="0")
98
+ %col(width="60%")
99
+ %col(width="20%")
100
+ %col(width="20%")
101
+ - current_user.clients.each do |client|
102
+ = cache client do
103
+ %tr
104
+ %td= link_to client.name, [client, :invoices], class: "inline"
105
+ %td= currency_or_empty client.unbilled_balance
106
+ %td.red= currency_or_empty client.overdue_balance
107
+
108
+ = link_to '+ Add Client', new_client_path, :class=>"button right"
109
+ .clear
110
+
111
+
112
+ #content
113
+ = yield
114
+ .clear
115
+ .clear
116
+
117
+ #footer_container
118
+ #footer
119
+ = yield :footer
120
+
data/config/routes.rb ADDED
@@ -0,0 +1,35 @@
1
+ Eboshi::Engine.routes.draw do
2
+ root to: "clients#index"
3
+
4
+ resources :clients do
5
+ resources :invoices do
6
+ resources :payments
7
+ end
8
+ resources :budgets
9
+
10
+ resources :line_items, only: [:update]
11
+ resources :works, except: [:index, :show] do
12
+ post :merge, on: :collection
13
+ post :convert, on: :member
14
+ end
15
+ resources :adjustments, except: [:index, :show]
16
+ resources :assignments, only: [:new, :create, :destroy]
17
+ end
18
+
19
+ resources :payments
20
+ resources :adjustments, except: [:index, :show]
21
+ resources :assignments, only: [:new, :create, :destroy]
22
+ resources :works, except: [:index, :show]
23
+
24
+ match "/clients/:client_id/clock_in(.:format)" => "works#clock_in", :as => "clock_in", :via => [:get, :post]
25
+ match "/clients/:client_id/works/:id/clock_out(.:format)" => "works#clock_out", :as => "clock_out", :via => [:get, :post]
26
+
27
+ get "/calendar(/:year(/:month))" => "calendar#index", :as => "calendar"
28
+
29
+ resources :users
30
+ resource :account, controller: "users"
31
+ resource :user_session
32
+
33
+ get "login" => "user_sessions#new"
34
+ delete "logout" => "user_sessions#destroy"
35
+ end
@@ -0,0 +1,15 @@
1
+ require "authlogic"
2
+ require "scrypt"
3
+ require "validates_email_format_of"
4
+ require "kt-paperclip"
5
+ require "haml-rails"
6
+ require "dynamic_form"
7
+ require "default_value_for"
8
+ require "wicked_pdf"
9
+ # require "wkhtmltopdf-binary"
10
+
11
+ module Eboshi
12
+ class Engine < ::Rails::Engine
13
+ isolate_namespace Eboshi
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module Eboshi
2
+ VERSION = "0.1.0"
3
+ end
data/lib/eboshi.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "eboshi/version"
2
+ require "eboshi/engine"
3
+
4
+ module Eboshi
5
+ # Your code goes here...
6
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :eboshi do
3
+ # # Task goes here
4
+ # end