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,80 @@
1
+ require 'date'
2
+
3
+ module Eboshi
4
+ module CalendarHelper
5
+ def calendar(options = {}, &block)
6
+ defaults = {
7
+ year: Date.today.year,
8
+ month: Date.today.month,
9
+ previous_month_text: nil,
10
+ next_month_text: nil
11
+ }
12
+ options.reverse_merge! defaults
13
+
14
+ first = Date.civil(options[:year], options[:month], 1)
15
+ last = first.end_of_month
16
+
17
+ build first, last, options, &block
18
+ end
19
+
20
+ private
21
+
22
+ def build(first, last, _options, &block)
23
+ content_tag :tbody do
24
+ content_tag :tr do
25
+ concat last_month_days(first) # start out the week with last month's days
26
+ concat this_month_days(first, last, &block)
27
+ concat next_month_days(last) # finish out the week with next month's days
28
+ "".html_safe
29
+ end
30
+ end
31
+ end
32
+
33
+ def last_month_days(first)
34
+ first.beginning_of_week(:sunday).upto(first - 1.day).map do |d|
35
+ content_tag :td, class: "otherMonth" do
36
+ concat d.day
37
+ end
38
+ end.join("\n").html_safe
39
+ end
40
+
41
+ def this_month_days(first, last, &block)
42
+ first.upto(last).map do |date|
43
+ out = content_tag :td, id: "day_#{date.day}", class: "#{date.today? && "today"}" do
44
+ date.mday.to_s.html_safe + capture(date, &block).to_s.html_safe
45
+ end
46
+ unless date == last || !date.saturday?
47
+ out << raw("</tr><tr>")
48
+ end
49
+ out.html_safe
50
+ end.join("\n").html_safe
51
+ end
52
+
53
+ def next_month_days(last)
54
+ unless last.saturday?
55
+ (last + 1).upto(last.end_of_week(:sunday)) do |d|
56
+ content_tag :td, class: "otherMonth" do
57
+ concat d.day
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ module CalendarHelper
65
+ def link_to_previous_month(date, options = {})
66
+ link_to_month(:prev, date, options)
67
+ end
68
+
69
+ def link_to_next_month(date, options = {})
70
+ link_to_month(:next, date, options)
71
+ end
72
+
73
+ private
74
+
75
+ def link_to_month(direction, date, options = {})
76
+ date += (direction == :next ? 1 : -1).month
77
+ link_to direction, "/calendar/#{date.year}/#{date.month}", options
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,68 @@
1
+ module Eboshi
2
+ module ShallowRouteHelper
3
+ def invoices_path(client, options = {})
4
+ client_invoices_path(client, options)
5
+ end
6
+
7
+ def invoice_path(invoice, options = {})
8
+ client_invoice_path(invoice.client, invoice, options)
9
+ end
10
+
11
+ def new_invoice_path(client, options = {})
12
+ new_client_invoice_path(client, options)
13
+ end
14
+
15
+ def edit_invoice_path(invoice, options = {})
16
+ edit_client_invoice_path(invoice.client, invoice, options)
17
+ end
18
+
19
+ def payments_path(invoice, options = {})
20
+ client_invoice_payments_path(invoice.client, invoice, options)
21
+ end
22
+
23
+ def new_payment_path(invoice, options = {})
24
+ new_client_invoice_payment_path(invoice.client, invoice, options)
25
+ end
26
+
27
+ def new_adjustment_path(adjustment, options = {})
28
+ new_client_adjustment_path(adjustment.client, adjustment, options)
29
+ end
30
+
31
+ def edit_adjustment_path(adjustment, options = {})
32
+ edit_client_adjustment_path(adjustment.client, adjustment, options)
33
+ end
34
+
35
+ def work_path(work, options = {})
36
+ client_work_path(work.client, work, options)
37
+ end
38
+
39
+ def edit_work_path(work, options = {})
40
+ edit_client_work_path(work.client, work, options)
41
+ end
42
+
43
+ def merge_works_path(client, options = {})
44
+ merge_client_works_path(client, options)
45
+ end
46
+
47
+ def convert_work_path(work, options = {})
48
+ convert_client_work_path(work.client, work, options)
49
+ end
50
+
51
+ def line_item_path(work, options = {})
52
+ client_line_item_path(work.client, work, options)
53
+ end
54
+
55
+ def assignments_path(client, options = {})
56
+ client_assignments_path(client, options)
57
+ end
58
+
59
+ def assignment_path(assignment, options = {})
60
+ client_assignment_path(assignment.client, assignment, options)
61
+ end
62
+
63
+ def new_assignment_path(client, options = {})
64
+ new_client_assignment_path(client, options)
65
+ end
66
+ end
67
+ end
68
+
@@ -0,0 +1,4 @@
1
+ module Eboshi
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module Eboshi
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: "from@example.com"
4
+ layout "mailer"
5
+ end
6
+ end
@@ -0,0 +1,37 @@
1
+ # == Schema Information
2
+ # Schema version: 20081222015211
3
+ #
4
+ # Table name: line_items
5
+ #
6
+ # id :integer(4) not null, primary key
7
+ # client_id :integer(4)
8
+ # user_id :integer(4)
9
+ # start :datetime
10
+ # finish :datetime
11
+ # rate :decimal(10, 2)
12
+ # notes :text
13
+ # created_at :datetime
14
+ # updated_at :datetime
15
+ # invoice_id :integer(4)
16
+ # type :string(255)
17
+ #
18
+
19
+ module Eboshi
20
+ class Adjustment < LineItem
21
+ def total
22
+ rate
23
+ end
24
+
25
+ def total=(value)
26
+ self.rate = value
27
+ end
28
+
29
+ def no_user
30
+ user.nil? && !new_record?
31
+ end
32
+
33
+ def no_date
34
+ start.nil? && !new_record?
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,5 @@
1
+ module Eboshi
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,20 @@
1
+ # == Schema Information
2
+ # Schema version: 20090412030221
3
+ #
4
+ # Table name: assignments
5
+ #
6
+ # id :integer(4) not null, primary key
7
+ # user_id :integer(4)
8
+ # client_id :integer(4)
9
+ # created_at :datetime
10
+ # updated_at :datetime
11
+ #
12
+
13
+ module Eboshi
14
+ class Assignment < ApplicationRecord
15
+ self.table_name = "assignments"
16
+
17
+ belongs_to :user, required: false
18
+ belongs_to :client, required: false
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ module Eboshi
2
+ class Budget < ApplicationRecord
3
+ self.table_name = "budgets"
4
+
5
+ belongs_to :client, touch: true, required: false
6
+ has_many :invoices
7
+
8
+ validates_presence_of :total
9
+
10
+ attr_accessor :unbilled_invoice
11
+
12
+ def used
13
+ invoices.to_a.sum(&:total) + unbilled_invoice.try(:total).to_f
14
+ end
15
+
16
+ def remaining
17
+ total - used
18
+ end
19
+
20
+ def name_and_total
21
+ [name, total.to_s].join(" - $")
22
+ end
23
+
24
+ def under?
25
+ used < total
26
+ end
27
+
28
+ def over?
29
+ used > total
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,85 @@
1
+ # == Schema Information
2
+ # Schema version: 20081222015211
3
+ #
4
+ # Table name: clients
5
+ #
6
+ # id :integer(4) not null, primary key
7
+ # name :string(255)
8
+ # address :string(255)
9
+ # city :string(255)
10
+ # state :string(255)
11
+ # zip :string(255)
12
+ # country :string(255)
13
+ # email :string(255)
14
+ # contact :string(255)
15
+ # phone :string(255)
16
+ # created_at :datetime
17
+ # updated_at :datetime
18
+ #
19
+
20
+ module Eboshi
21
+ class Client < ApplicationRecord
22
+ self.table_name = "clients"
23
+
24
+ default_scope -> { order(:name) }
25
+
26
+ has_many :line_items, dependent: :destroy
27
+ has_many :works
28
+ has_many :adjustments
29
+ has_many :invoices, -> { includes(:line_items, :payments).order(date: :desc) }, dependent: :destroy
30
+ has_many :payments, through: :invoices
31
+ has_many :budgets
32
+ has_many :assignments, dependent: :destroy
33
+ has_many :users, through: :assignments
34
+
35
+ validates_presence_of :name
36
+
37
+ def build_invoice_from_unbilled(line_items_ids = nil)
38
+ lis = line_items_ids ? LineItem.find(line_items_ids) : line_items.unbilled
39
+ budget = budgets.order(:created_at).last
40
+ invoice = invoices.build line_items: lis, budget: budget
41
+ budget.unbilled_invoice = invoice if budget
42
+ invoice
43
+ end
44
+
45
+ def invoices_with_unbilled
46
+ new_invoices = invoices.to_a
47
+ new_invoices.unshift build_invoice_from_unbilled
48
+ new_invoices
49
+ end
50
+
51
+ def balance
52
+ credits - debits
53
+ end
54
+
55
+ def unbilled_balance
56
+ return 0.0 if line_items.empty?
57
+ line_items.to_a.select(&:unbilled?).sum(&:total)
58
+ end
59
+
60
+ def overdue_balance
61
+ balance - unbilled_balance
62
+ end
63
+
64
+ def credits
65
+ line_items.to_a.sum(&:total)
66
+ end
67
+
68
+ def debits
69
+ payments.to_a.sum(&:total)
70
+ end
71
+
72
+ def clock_in(user)
73
+ Work.new.tap do |line_item|
74
+ now = Time.now
75
+ line_item.attributes = { start: now, finish: now, user: user, rate: user.default_rate_for(self) }
76
+ line_items << line_item
77
+ end
78
+ end
79
+
80
+ def default_project_name
81
+ invoices.last.try(:project_name)
82
+ end
83
+ end
84
+ end
85
+
@@ -0,0 +1,87 @@
1
+ # == Schema Information
2
+ # Schema version: 20081222015211
3
+ #
4
+ # Table name: invoices
5
+ #
6
+ # id :integer(4) not null, primary key
7
+ # client_id :integer(4)
8
+ # date :datetime
9
+ # project_name :string(255)
10
+ #
11
+
12
+ module Eboshi
13
+ class Invoice < ApplicationRecord
14
+ self.table_name = "invoices"
15
+
16
+ belongs_to :client, touch: true, required: false
17
+ has_many :line_items, dependent: :nullify
18
+ has_many :payments, -> { order(created_at: :desc) }, dependent: :destroy
19
+ belongs_to :budget, touch: true, required: false
20
+
21
+ validates_presence_of :client, :date
22
+
23
+ default_value_for(:date) { Time.zone.today.midnight }
24
+
25
+ def self.unpaid
26
+ order(date: :desc).reject(&:paid?)
27
+ end
28
+
29
+ def self.paid
30
+ order(date: :desc).select(&:paid?)
31
+ end
32
+
33
+ def works
34
+ line_items.where(type: "Eboshi::Work")
35
+ end
36
+
37
+ def adjustments
38
+ line_items.where(type: "Eboshi::Adjustment")
39
+ end
40
+
41
+ def total
42
+ line_items.to_a.sum(&:total)
43
+ end
44
+
45
+ def total_for_user(user)
46
+ line_items.to_a.select { |li| li.user == user }.sum(&:total)
47
+ end
48
+
49
+ def total=(value)
50
+ difference = value.to_f - total
51
+ return total if difference.abs < 0.01
52
+ line_items << Adjustment.new(total: difference, client_id: client_id)
53
+ end
54
+
55
+ def balance
56
+ total - payments.to_a.sum(&:total)
57
+ end
58
+
59
+ def status
60
+ return 'unbilled' if new_record?
61
+ paid? ? 'paid' : 'unpaid'
62
+ end
63
+
64
+ def paid?
65
+ !line_items.empty? && !payments.empty? && balance == 0
66
+ end
67
+
68
+ def total_hours
69
+ line_items.to_a.sum(&:hours)
70
+ end
71
+
72
+ def total_hours_for_user(user)
73
+ line_items.to_a.select { |li| li.user == user }.sum(&:hours)
74
+ end
75
+
76
+ def consistant_rate
77
+ return true if works.empty?
78
+ rates = works.collect(&:rate).uniq
79
+ rates.length == 1 ? rates.first : false
80
+ end
81
+
82
+ def users
83
+ line_items.collect(&:user).uniq.sort_by { |user| user ? user.name : "" }
84
+ end
85
+ end
86
+ end
87
+
@@ -0,0 +1,94 @@
1
+ # == Schema Information
2
+ # Schema version: 20081222015211
3
+ #
4
+ # Table name: line_items
5
+ #
6
+ # id :integer(4) not null, primary key
7
+ # client_id :integer(4)
8
+ # user_id :integer(4)
9
+ # start :datetime
10
+ # finish :datetime
11
+ # rate :decimal(10, 2)
12
+ # notes :text
13
+ # created_at :datetime
14
+ # updated_at :datetime
15
+ # invoice_id :integer(4)
16
+ # type :string(255)
17
+ #
18
+
19
+ module Eboshi
20
+ class LineItem < ApplicationRecord
21
+ self.table_name = "line_items"
22
+
23
+ include Comparable
24
+
25
+ belongs_to :client, touch: true, required: false
26
+ belongs_to :user, required: false
27
+ belongs_to :invoice, touch: true, required: false
28
+
29
+ validates_presence_of :client, :rate
30
+
31
+ def self.unbilled
32
+ where(invoice_id: nil).order(start: :desc)
33
+ end
34
+
35
+ def self.on_date(date)
36
+ start = date.beginning_of_day
37
+ finish = date.end_of_day
38
+ where(start: start..finish)
39
+ end
40
+
41
+ def self.on_week(date)
42
+ start = date.beginning_of_week(:sunday).beginning_of_day
43
+ finish = date.end_of_week(:sunday).end_of_day
44
+ where(start: start..finish)
45
+ end
46
+
47
+ def self.on_month(date)
48
+ start = date.beginning_of_month.beginning_of_day
49
+ finish = date.end_of_month.end_of_day
50
+ where(start: start..finish)
51
+ end
52
+
53
+ def self.on_year(date)
54
+ start = date.beginning_of_year.beginning_of_day
55
+ finish = date.end_of_year.end_of_day
56
+ where(start: start..finish)
57
+ end
58
+
59
+ def total
60
+ 0
61
+ end
62
+
63
+ def hours
64
+ return 0 unless finish && start
65
+ seconds = BigDecimal((finish - start).to_s)
66
+ seconds / 60 / 60
67
+ end
68
+
69
+ def ==(target)
70
+ target == id
71
+ end
72
+
73
+ def unbilled?
74
+ invoice_id.nil?
75
+ end
76
+
77
+ def checked?
78
+ unbilled?
79
+ end
80
+
81
+ def user_name=(name)
82
+ self.user = User.find_by_name!(name) unless name.nil?
83
+ end
84
+
85
+ def invoice_total
86
+ invoice.try(:total) || client.unbilled_balance
87
+ end
88
+
89
+ def <=>(target)
90
+ (target.start || Time.zone.parse("0000-01-01")) <=> (start || Time.zone.parse("0000-01-01"))
91
+ end
92
+ end
93
+ end
94
+
@@ -0,0 +1,20 @@
1
+ # == Schema Information
2
+ # Schema version: 20081222015211
3
+ #
4
+ # Table name: payments
5
+ #
6
+ # id :integer(4) not null, primary key
7
+ # invoice_id :integer(4)
8
+ # total :decimal(10, 2)
9
+ # created_at :datetime
10
+ # updated_at :datetime
11
+ #
12
+
13
+ module Eboshi
14
+ class Payment < ApplicationRecord
15
+ self.table_name = "payments"
16
+
17
+ belongs_to :invoice, touch: true, required: false
18
+ end
19
+ end
20
+
@@ -0,0 +1,128 @@
1
+ # == Schema Information
2
+ # Schema version: 20090412030221
3
+ #
4
+ # Table name: users
5
+ #
6
+ # id :integer(4) not null, primary key
7
+ # name :string(255)
8
+ # email :string(255)
9
+ # crypted_password :string(255)
10
+ # password_salt :string(255)
11
+ # created_at :datetime
12
+ # updated_at :datetime
13
+ # rate :decimal(10, 2)
14
+ # color :string(255)
15
+ # persistence_token :string(255)
16
+ # login_count :integer(4)
17
+ # last_request_at :datetime
18
+ # last_login_at :datetime
19
+ # current_login_at :datetime
20
+ # last_login_ip :string(255)
21
+ # current_login_ip :string(255)
22
+ # last_client_id :integer(4)
23
+ # admin :boolean(1)
24
+ # logo_file_name :string(255)
25
+ # logo_content_type :string(255)
26
+ # logo_file_size :integer(4)
27
+ # logo_updated_at :datetime
28
+ # signature_file_name :string(255)
29
+ # signature_content_type :string(255)
30
+ # signature_file_size :integer(4)
31
+ # signature_updated_at :datetime
32
+ #
33
+
34
+ module Eboshi
35
+ class User < ApplicationRecord
36
+ self.table_name = "eboshi_users"
37
+
38
+ acts_as_authentic do |config|
39
+ config.crypto_provider = Authlogic::CryptoProviders::SCrypt
40
+ config.transition_from_crypto_providers = [Authlogic::CryptoProviders::Sha512]
41
+ end
42
+
43
+ validates_uniqueness_of :email, case_sensitive: false
44
+ validates_email_format_of :email
45
+ validates_presence_of :password, :on => :create
46
+ validates_confirmation_of :password, if: proc { |user| user.password.present? }
47
+ validates_length_of :password, minimum: 4, allow_blank: true, message: "must be at least five characters long"
48
+ validates_length_of :password_confirmation, minimum: 4, allow_blank: true, message: "must be at least five characters long"
49
+
50
+ belongs_to :last_client, class_name: "Client", required: false
51
+ has_many :assignments, dependent: :destroy
52
+ has_many :clients, through: :assignments
53
+ has_many :works
54
+
55
+ has_attached_file :logo,
56
+ styles: { pdf: "200x200>" },
57
+ path: ":rails_root/public/:attachment/:id/:style.:extension",
58
+ url: "/:attachment/:id/:style.:extension"
59
+ has_attached_file :signature,
60
+ styles: { pdf: "450x100>" },
61
+ path: ":rails_root/public/:attachment/:id/:style.:extension",
62
+ url: "/:attachment/:id/:style.:extension"
63
+ validates_attachment_content_type :logo, content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"]
64
+ validates_attachment_content_type :signature, content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"]
65
+
66
+ def default_rate_for(client)
67
+ last_work = client.works.complete.where(user: self).order(start: :desc).first
68
+ last_work.try(:rate) || rate
69
+ end
70
+
71
+ def related_users
72
+ clients.collect(&:users).flatten.uniq - [self]
73
+ end
74
+
75
+ def authorized?(object)
76
+ return if object.is_a?(Client) && clients.include?(object)
77
+ return if object.is_a?(Invoice) && clients.include?(object.client)
78
+ return if object.is_a?(Assignment) && object.client.users.include?(self)
79
+ raise ActiveRecord::RecordNotFound
80
+ end
81
+
82
+ def city_state_zip
83
+ return nil if city.blank? || state.blank? || zip.blank?
84
+ "#{city}, #{state} #{zip}"
85
+ end
86
+
87
+ def business_name_or_name
88
+ business_name.blank? ? name : business_name
89
+ end
90
+
91
+ def business_email_or_email
92
+ business_email.blank? ? email : business_email
93
+ end
94
+
95
+ def hours_by_date(date)
96
+ works.on_date(date).to_a.sum(&:hours)
97
+ end
98
+
99
+ def total_by_date(date)
100
+ works.on_date(date).to_a.sum(&:total)
101
+ end
102
+
103
+ def hours_by_week(date)
104
+ works.on_week(date).to_a.sum(&:hours)
105
+ end
106
+
107
+ def total_by_week(date)
108
+ works.on_week(date).to_a.sum(&:total)
109
+ end
110
+
111
+ def hours_by_month(date)
112
+ works.on_month(date).to_a.sum(&:hours)
113
+ end
114
+
115
+ def total_by_month(date)
116
+ works.on_month(date).to_a.sum(&:total)
117
+ end
118
+
119
+ def hours_by_year(date)
120
+ works.on_year(date).to_a.sum(&:hours)
121
+ end
122
+
123
+ def total_by_year(date)
124
+ works.on_year(date).to_a.sum(&:total)
125
+ end
126
+ end
127
+ end
128
+
@@ -0,0 +1,6 @@
1
+ module Eboshi
2
+ class UserSession < Authlogic::Session::Base
3
+ authenticate_with Eboshi::User
4
+ end
5
+ end
6
+