eboshi 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/README.md +28 -0
 - data/Rakefile +8 -0
 - data/app/assets/config/eboshi_manifest.js +1 -0
 - data/app/assets/stylesheets/eboshi/application.css +15 -0
 - data/app/controllers/eboshi/adjustments_controller.rb +77 -0
 - data/app/controllers/eboshi/application_controller.rb +62 -0
 - data/app/controllers/eboshi/assignments_controller.rb +31 -0
 - data/app/controllers/eboshi/budgets_controller.rb +43 -0
 - data/app/controllers/eboshi/calendar_controller.rb +12 -0
 - data/app/controllers/eboshi/clients_controller.rb +41 -0
 - data/app/controllers/eboshi/invoices_controller.rb +69 -0
 - data/app/controllers/eboshi/line_items_controller.rb +28 -0
 - data/app/controllers/eboshi/payments_controller.rb +31 -0
 - data/app/controllers/eboshi/user_sessions_controller.rb +25 -0
 - data/app/controllers/eboshi/users_controller.rb +41 -0
 - data/app/controllers/eboshi/works_controller.rb +83 -0
 - data/app/helpers/eboshi/application_helper.rb +15 -0
 - data/app/helpers/eboshi/calendar_helper.rb +80 -0
 - data/app/helpers/eboshi/shallow_route_helper.rb +68 -0
 - data/app/jobs/eboshi/application_job.rb +4 -0
 - data/app/mailers/eboshi/application_mailer.rb +6 -0
 - data/app/models/eboshi/adjustment.rb +37 -0
 - data/app/models/eboshi/application_record.rb +5 -0
 - data/app/models/eboshi/assignment.rb +20 -0
 - data/app/models/eboshi/budget.rb +33 -0
 - data/app/models/eboshi/client.rb +85 -0
 - data/app/models/eboshi/invoice.rb +87 -0
 - data/app/models/eboshi/line_item.rb +94 -0
 - data/app/models/eboshi/payment.rb +20 -0
 - data/app/models/eboshi/user.rb +128 -0
 - data/app/models/eboshi/user_session.rb +6 -0
 - data/app/models/eboshi/work.rb +66 -0
 - data/app/views/eboshi/adjustments/_adjustment.html.slim +15 -0
 - data/app/views/eboshi/adjustments/_form.html.haml +27 -0
 - data/app/views/eboshi/adjustments/edit.html.haml +7 -0
 - data/app/views/eboshi/adjustments/new.html.haml +8 -0
 - data/app/views/eboshi/assignments/new.html.haml +18 -0
 - data/app/views/eboshi/budgets/form.html.haml +22 -0
 - data/app/views/eboshi/calendar/index.html.slim +32 -0
 - data/app/views/eboshi/clients/_form.html.haml +34 -0
 - data/app/views/eboshi/clients/edit.html.haml +4 -0
 - data/app/views/eboshi/clients/index.html.haml +19 -0
 - data/app/views/eboshi/clients/new.html.haml +4 -0
 - data/app/views/eboshi/invoices/_form.html.slim +68 -0
 - data/app/views/eboshi/invoices/_full.html.haml +76 -0
 - data/app/views/eboshi/invoices/_invoice.html.haml +2 -0
 - data/app/views/eboshi/invoices/_mini.html.haml +21 -0
 - data/app/views/eboshi/invoices/edit.html.haml +14 -0
 - data/app/views/eboshi/invoices/index.html.haml +46 -0
 - data/app/views/eboshi/invoices/new.html.haml +11 -0
 - data/app/views/eboshi/invoices/show.pdf.haml +118 -0
 - data/app/views/eboshi/layouts/application.html.haml +120 -0
 - data/app/views/eboshi/payments/_form.html.haml +10 -0
 - data/app/views/eboshi/payments/new.html.haml +9 -0
 - data/app/views/eboshi/user_sessions/new.html.haml +19 -0
 - data/app/views/eboshi/users/_form.html.haml +65 -0
 - data/app/views/eboshi/users/edit.html.haml +16 -0
 - data/app/views/eboshi/users/index.html.haml +11 -0
 - data/app/views/eboshi/users/new.html.haml +13 -0
 - data/app/views/eboshi/users/show.html.haml +39 -0
 - data/app/views/eboshi/works/_form.html.slim +25 -0
 - data/app/views/eboshi/works/_work.html.slim +27 -0
 - data/app/views/eboshi/works/edit.html.haml +9 -0
 - data/app/views/eboshi/works/new.html.haml +8 -0
 - data/app/views/layouts/eboshi/application.html.haml +120 -0
 - data/config/routes.rb +35 -0
 - data/lib/eboshi/engine.rb +15 -0
 - data/lib/eboshi/version.rb +3 -0
 - data/lib/eboshi.rb +6 -0
 - data/lib/tasks/eboshi_tasks.rake +4 -0
 - 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,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,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 
     | 
    
         
            +
             
     |