Compare commits

...

12 Commits

Author SHA1 Message Date
Bram Senders b31cd03330 Able to enter a location with a time entry 2011-11-23 22:05:51 +01:00
Bram Senders d706e91e9d Able to edit a location in the locations view 2011-11-23 16:27:05 +01:00
Bram Senders 553a919cb1 Add a LocationsN controller 2011-11-23 16:26:41 +01:00
Bram Senders 0ae19e3376 Revert "Redirect to Locations when creating a new location"
This reverts commit 803a8894dc.
2011-11-23 16:12:32 +01:00
Bram Senders 1da6ca6e85 Add a location_form view 2011-11-23 16:11:57 +01:00
Bram Senders 2b4acbdd35 Spacing fix 2011-11-23 16:11:01 +01:00
Bram Senders f8286ba862 Add locations view 2011-11-23 16:01:07 +01:00
Bram Senders 2926b30969 Add LocationsNew controller 2011-11-23 16:00:44 +01:00
Bram Senders 803a8894dc Redirect to Locations when creating a new location
This is instead of redirecting to LocationsN, as we are not going to
provide a view for a specific location at this time.
2011-11-23 15:54:58 +01:00
Bram Senders f9836029c7 Add a locations controller class
This class is directly based on the customers controller class.
2011-11-23 15:34:15 +01:00
Bram Senders 1b00857d62 Add the location class 2011-11-23 15:23:40 +01:00
Bram Senders a4e42d9aca Add LocationSupport migration 2011-11-23 15:00:33 +01:00
1 changed files with 200 additions and 1 deletions

View File

@ -156,6 +156,7 @@ module StopTime::Models
# task.
class TimeEntry < Base
belongs_to :task
belongs_to :location
has_one :customer, :through => :task
# Returns the total amount of time, the duration, in hours.
@ -170,6 +171,7 @@ module StopTime::Models
# tasks and through the tasks registered time.
class Invoice < Base
has_many :tasks
has_many :locations
has_many :time_entries, :through => :tasks
belongs_to :customer
@ -203,6 +205,22 @@ module StopTime::Models
class CompanyInfo < Base
end
# == The location class
#
# This class represents a specific location where work can be done.
# Each location has a name, a distance (in kilometres, from the user's
# home) and travel time (in minutes, also from the user's home). Each
# time entry can be associated with a location.
class Location < Base
has_many :time_entries
belongs_to :invoice
# Returns whether the location is billed, i.e. included in an invoice.
def billed?
not invoice.nil?
end
end
class StopTimeTables < V 1.0 # :nodoc:
def self.up
create_table Customer.table_name do |t|
@ -341,6 +359,23 @@ module StopTime::Models
end
end
class LocationSupport < V 1.9 # :nodoc:
def self.up
create_table Location.table_name do |t|
t.string :name
t.float :distance, :travel_time
t.integer :invoice_id
t.timestamps
end
add_column(TimeEntry.table_name, :location_id, :integer)
end
def self.down
drop_table Location.table_name
remove_column(TimeEntry.table_name, :location_id)
end
end
end # StopTime::Models
# = The Stop… Camping Time! controllers
@ -792,6 +827,9 @@ module StopTime::Controllers
@task_list = Task.all.reject { |t| t.billed? }.map do |t|
[t.id, t.name]
end
@location_list = Location.all.reject { |l| l.billed? }.map do |l|
[l.id, l.name]
end
@input["bill"] = true # Bill by default.
render :time_entries
end
@ -802,6 +840,7 @@ module StopTime::Controllers
if @input.has_key? "enter"
@time_entry = TimeEntry.create(
:task_id => @input.task,
:location_id => @input.location,
:date => @input.date,
:start => "#{@input.date} #{@input.start}",
:end => "#{@input.date} #{@input.end}",
@ -858,6 +897,7 @@ module StopTime::Controllers
@input = @time_entry.attributes
@input["customer"] = @time_entry.task.customer.id
@input["task"] = @time_entry.task.id
@input["location"] = @time_entry.location.id
@input["date"] = @time_entry.date.to_date
@input["start"] = @time_entry.start.to_formatted_s(:time_only)
@input["end"] = @time_entry.end.to_formatted_s(:time_only)
@ -890,6 +930,7 @@ module StopTime::Controllers
@time_entry.start = "#{@input["date"]} #{@input["start"]}"
@time_entry.end = "#{@input["date"]} #{@input["end"]}"
@time_entry.task = Task.find(@input.task)
@time_entry.location = Location.find(@input.location)
@time_entry.bill = @input.has_key? "bill"
@time_entry.save
if @time_entry.invalid?
@ -975,6 +1016,102 @@ module StopTime::Controllers
end
end
# == The locations controller
#
# Controller for viewing a list of existing locations or creating a new
# one.
#
# path:: /locations
# view:: Views#locations and Views#location_form
class Locations
# Gets the list of locations and displays them via Views#locations.
def get
@locations = Location.all
render :locations
end
# Creates a new location object (Models::Location) if the input is
# valid and redirects to LocationsN.
# If the provided information is invalid, the errors are retrieved
# and shown in the initial form (Views#location_form).
def post
return redirect R(Locations) if @input.cancel
@location = Location.create(
:name => @input.name,
:distance => @input.distance,
:travel_time => @input.travel_time)
@location.save
if @location.invalid?
@errors = @location.errors
@target = [Location]
@button = "create"
return render :location_form
end
redirect R(LocationsN, @location.id)
end
end
# == The location creation controller
#
# Controller for filling in the information to create a new location.
#
# path:: /locations/new
# view:: Views#location_form
class LocationsNew
# Generates the form to create a new location object
# (Models::Location) using Views#location_form.
def get
@location = Location.new
@input = @location.attributes
@target = [Locations]
@button = "create"
render :location_form
end
end
# == The location controller
#
# Controller for viewing and updating information of a location.
#
# path:: /locations/_location_id_
# view:: Views#location_form
class LocationsN
# Finds the specific location for the given _location_id_ and shows
# a form for updating via Views#location_form.
def get(location_id)
@location = Location.find(location_id)
@input = @location.attributes
@target = [LocationsN, @location.id]
@button = "update"
render :location_form
end
# Updates or deletes the location with the given _location_id_ if the
# input is valid and redirects to LocationsN.
# If the provided information is invalid, the errors are retrieved
# and shown in the initial form (Views#location_form).
def post(location_id)
return redirect R(Locations) if @input.cancel
@location = Location.find(location_id)
if @input.has_key? "delete"
@location.delete
elsif @input.has_key? "update"
attrs = ["name", "distance", "travel_time"]
attrs.each do |attr|
@location[attr] = @input[attr]
end
@location.save
if @location.invalid?
@errors = @location.errors
return render :location_form
end
end
redirect R(Locations)
end
end
# == The static data controller
#
# Controller for serving static data information available in the
@ -1031,7 +1168,8 @@ module StopTime::Views
["Timeline", Timeline],
["Customers", Customers],
["Invoices", Invoices],
["Company", Company]].each { |label, ctrl| _menu_link(label, ctrl) }
["Company", Company],
["Locations", Locations]].each { |label, ctrl| _menu_link(label, ctrl) }
end
end
@ -1095,6 +1233,7 @@ module StopTime::Views
h2 "Timeline"
table.timeline do
col.task {}
col.location {}
col.date {}
col.start_time {}
col.end_time {}
@ -1103,6 +1242,7 @@ module StopTime::Views
col.flag {}
tr do
th "Project/Task"
th "Location"
th "Date"
th "Start time"
th "End time"
@ -1113,6 +1253,7 @@ module StopTime::Views
form :action => R(Timeline), :method => :post do
tr do
td { _form_select("task", @task_list) }
td { _form_select("location", @location_list) }
td { input :type => :text, :name => "date",
:value => DateTime.now.to_date.to_formatted_s }
td { input :type => :text, :name => "start",
@ -1131,6 +1272,12 @@ module StopTime::Views
tr do
td { a entry.task.name,
:href => R(CustomersNTasksN, entry.customer.id, entry.task.id) }
if entry.location
td { a entry.location.name,
:href => R(LocationsN, entry.location.id) }
else
td { "unspecified" }
end
td { a entry.date.to_date,
:href => R(TimelineN, entry.id) }
td { entry.start.to_formatted_s(:time_only) }
@ -1564,6 +1711,58 @@ module StopTime::Views
end
end
# The main overview of the list of locations.
def locations
h2 "Locations"
if @locations.empty?
p do
text "None found! You can create one "
a "here", :href => R(LocationsNew)
text "."
end
else
table.locations do
col.name {}
col.distance {}
col.travel_time {}
tr do
th "Name"
th "Distance (km)"
th "Travel time (min)"
end
@locations.each do |location|
tr do
td { a location.name, :href => R(LocationsN, location.id) }
td { location.distance }
td { location.travel_time }
td do
form :action => R(LocationsN, location.id), :method => :post do
input :type => :submit, :name => "delete", :value => "Delete"
end
end
end
end
end
a "Add a new location", :href => R(LocationsNew)
end
end
# Form for editing the properties of a location (Models::Location)
def location_form
form.float_left :action => R(*@target), :method => :post do
h2 "Location Information"
ol do
li { _form_input_with_label("Name", "name", :text) }
li { _form_input_with_label("Distance (km)", "distance", :text) }
li { _form_input_with_label("Travel time (min)", "travel_time", :text) }
end
input :type => "submit", :name => @button, :value => @button.capitalize
input :type => "submit", :name => "cancel", :value => "Cancel"
end
div.clear {}
end
# Partial view that generates a form label with the given _label_name_
# and a form input with the given _input_name_ and _type_, such that the
# label is linked to the input.