kete_trackable_items 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/.document +5 -0
  2. data/.gitignore +21 -0
  3. data/.specification +146 -0
  4. data/Gemfile +1 -0
  5. data/Gemfile.lock +27 -0
  6. data/LICENSE +20 -0
  7. data/README.rdoc +24 -0
  8. data/Rakefile +53 -0
  9. data/VERSION +1 -0
  10. data/app/controllers/repositories_controller.rb +70 -0
  11. data/app/controllers/shelf_locations_controller.rb +98 -0
  12. data/app/controllers/trackable_item_shelf_locations_controller.rb +64 -0
  13. data/app/controllers/tracked_items_controller.rb +44 -0
  14. data/app/controllers/tracking_lists_controller.rb +88 -0
  15. data/app/helpers/trackable_item_shelf_locations_helper.rb +17 -0
  16. data/app/helpers/trackable_items_helper.rb +52 -0
  17. data/app/models/on_loan_organization.rb +8 -0
  18. data/app/models/repository.rb +11 -0
  19. data/app/models/shelf_location.rb +69 -0
  20. data/app/models/trackable_item_shelf_location.rb +58 -0
  21. data/app/models/tracked_item.rb +18 -0
  22. data/app/models/tracking_list.rb +50 -0
  23. data/app/views/repositories/_form.html.erb +14 -0
  24. data/app/views/repositories/edit.html.erb +9 -0
  25. data/app/views/repositories/index.html.erb +22 -0
  26. data/app/views/repositories/new.html.erb +9 -0
  27. data/app/views/repositories/show.html.erb +30 -0
  28. data/app/views/shelf_locations/_event_button.html.erb +1 -0
  29. data/app/views/shelf_locations/_form.html.erb +34 -0
  30. data/app/views/shelf_locations/_shelf_location.html.erb +17 -0
  31. data/app/views/shelf_locations/_shelf_locations.html.erb +14 -0
  32. data/app/views/shelf_locations/_trackable_item.html.erb +12 -0
  33. data/app/views/shelf_locations/edit.html.erb +9 -0
  34. data/app/views/shelf_locations/index.html.erb +7 -0
  35. data/app/views/shelf_locations/new.html.erb +9 -0
  36. data/app/views/shelf_locations/show.html.erb +48 -0
  37. data/app/views/trackable_item_shelf_locations/new.html.erb +70 -0
  38. data/app/views/tracked_items/_tracked_item.html.erb +18 -0
  39. data/app/views/tracking_lists/_event_button.html.erb +1 -0
  40. data/app/views/tracking_lists/_form.html.erb +27 -0
  41. data/app/views/tracking_lists/_trackable_item_search_form.html.erb +28 -0
  42. data/app/views/tracking_lists/_tracking_list.html.erb +11 -0
  43. data/app/views/tracking_lists/_tracking_lists.html.erb +14 -0
  44. data/app/views/tracking_lists/edit.html.erb +9 -0
  45. data/app/views/tracking_lists/index.html.erb +11 -0
  46. data/app/views/tracking_lists/show.html.erb +45 -0
  47. data/app/views/tracking_lists/show.xls.builder +48 -0
  48. data/config/locales/en.yml +151 -0
  49. data/config/routes.rb +6 -0
  50. data/generators/kete_trackable_items_migrations/USAGE +2 -0
  51. data/generators/kete_trackable_items_migrations/kete_trackable_items_migrations_generator.rb +19 -0
  52. data/generators/kete_trackable_items_migrations/templates/add_trackable_item_columns_to_topics.rb +15 -0
  53. data/generators/kete_trackable_items_migrations/templates/create_on_loan_organizations.rb +14 -0
  54. data/generators/kete_trackable_items_migrations/templates/create_repositories.rb +14 -0
  55. data/generators/kete_trackable_items_migrations/templates/create_shelf_locations.rb +15 -0
  56. data/generators/kete_trackable_items_migrations/templates/create_trackable_item_shelf_locations.rb +16 -0
  57. data/generators/kete_trackable_items_migrations/templates/create_tracked_items.rb +15 -0
  58. data/generators/kete_trackable_items_migrations/templates/create_tracking_lists.rb +15 -0
  59. data/kete_trackable_items.gemspec +25 -0
  60. data/lib/kete_trackable_items.rb +0 -0
  61. data/lib/kete_trackable_items/controller_helpers.rb +7 -0
  62. data/lib/kete_trackable_items/extensions/helpers/application_helper.rb +29 -0
  63. data/lib/kete_trackable_items/extensions/models/basket.rb +4 -0
  64. data/lib/kete_trackable_items/extensions/models/topic.rb +6 -0
  65. data/lib/kete_trackable_items/matching_trackable_items_controller_helpers.rb +42 -0
  66. data/lib/kete_trackable_items/trackable_item.rb +80 -0
  67. data/lib/kete_trackable_items/version.rb +3 -0
  68. data/lib/kete_trackable_items/workflow_utilities.rb +91 -0
  69. data/rails/init.rb +68 -0
  70. metadata +166 -0
@@ -0,0 +1,64 @@
1
+ class TrackableItemShelfLocationsController < ApplicationController
2
+ # Prevents the following error from showing up, common in Rails engines
3
+ # A copy of ApplicationController has been removed from the module tree but is still active!
4
+ unloadable
5
+
6
+ def new
7
+ if params[:trackable_item].present?
8
+ @trackable_item = params[:trackable_item][:type].constantize.find(params[:trackable_item][:id])
9
+ end
10
+
11
+ @repositories = appropriate_repositories_for_basket
12
+
13
+ @trackable_item_shelf_location = @trackable_item ? @trackable_item.trackable_item_shelf_locations.build : TrackableItemShelfLocation.new
14
+ end
15
+
16
+ def create
17
+ repository_id = params[:trackable_item_shelf_location].delete(:repository_id)
18
+ code = params[:trackable_item_shelf_location].delete(:code)
19
+
20
+ if repository_id.present?
21
+ @repository = Repository.find(repository_id)
22
+ @repositories = [@repository]
23
+ end
24
+
25
+ if @repository.present? && code.present?
26
+ @shelf_location = @repository.shelf_locations.find_by_code(code)
27
+ params[:trackable_item_shelf_location][:shelf_location_id] = @shelf_location ? @shelf_location.id : nil
28
+ end
29
+
30
+ @trackable_item_shelf_location = TrackableItemShelfLocation.new(params[:trackable_item_shelf_location])
31
+ @trackable_item = @trackable_item_shelf_location.trackable_item
32
+
33
+ if @trackable_item_shelf_location.save
34
+ redirect_to url_for_dc_identifier(@trackable_item)
35
+ else
36
+ render :action => 'new'
37
+ end
38
+ end
39
+
40
+ def update
41
+ @trackable_item_shelf_location = TrackableItemShelfLocation.find(params[:id])
42
+
43
+ if params[:event]
44
+ original_state = @trackable_item_shelf_location.current_state
45
+ event_method = params[:event] + '!'
46
+ @trackable_item_shelf_location.send(event_method)
47
+ @successful = @trackable_item_shelf_location.current_state != original_state
48
+ @state_change_failed = @succesful
49
+ else
50
+ @successful = @trackable_item_shelf_location.update_attributes(params[:shelf_location])
51
+ end
52
+
53
+ if @successful || @state_change_failed
54
+ flash[:notice] = t('shelf_locations.update.state_change_failed', :event_transition => params[:event].humanize) if @state_change_failed
55
+
56
+ url = repository_shelf_location_url(:id => @trackable_item_shelf_location.shelf_location,
57
+ :repository_id => @trackable_item_shelf_location.shelf_location.repository)
58
+ redirect_to url
59
+ else
60
+ render :action => 'edit'
61
+ end
62
+ end
63
+
64
+ end
@@ -0,0 +1,44 @@
1
+ class TrackedItemsController < ApplicationController
2
+ # Prevents the following error from showing up, common in Rails engines
3
+ # A copy of ApplicationController has been removed from the module tree but is still active!
4
+ unloadable
5
+
6
+ before_filter :get_tracked_item, :except => [:create]
7
+ before_filter :get_trackable_item
8
+ before_filter :get_tracking_list
9
+
10
+ def create
11
+ tracked_item = @trackable_item.tracked_items.build(@tracking_list)
12
+
13
+ if tracked_item.save
14
+ redirect_to tracking_list_url(:id => @tracking_list)
15
+ end
16
+ end
17
+
18
+ def destroy
19
+ tracked_item = @trackable_item.tracked_items.find(@tracked_item)
20
+ tracked_item.destroy unless tracked_item.nil?
21
+
22
+ # TODO: this redirect may need to redirect a different place in some contexts
23
+ redirect_to repository_tracking_list_url(:id => @tracking_list, :repository_id => @tracking_list.repository)
24
+ end
25
+
26
+ private
27
+
28
+ def get_tracked_item
29
+ @tracked_item = TrackedItem.find(params[:id])
30
+ end
31
+
32
+ def get_trackable_item
33
+ if @tracked_item
34
+ @trackable_item = @tracked_item.trackable_item
35
+ else
36
+ type = params[:tracked_item_type]
37
+ @trackable_item ||= type.classify.constantize.find(params[:tracked_item_id])
38
+ end
39
+ end
40
+
41
+ def get_tracking_list
42
+ @tracking_list ||= TrackingList.find(params[:tracking_list_id])
43
+ end
44
+ end
@@ -0,0 +1,88 @@
1
+ class TrackingListsController < ApplicationController
2
+ # Prevents the following error from showing up, common in Rails engines
3
+ # A copy of ApplicationController has been removed from the module tree but is still active!
4
+ unloadable
5
+
6
+ include KeteTrackableItems::MatchingTrackableItemsControllerHelpers
7
+
8
+ before_filter :set_repository
9
+ before_filter :set_tracking_list, :except => [:index, :create]
10
+
11
+ def index
12
+ @tracking_lists = TrackingList.all
13
+ end
14
+
15
+ def show
16
+ unless params[:format] == 'xls'
17
+ @possible_events = @tracking_list.current_state.events.keys.collect(&:to_s).sort
18
+ end
19
+
20
+ # xls support as outlined in http://www.arydjmal.com/blog/export-to-excel-in-rails-2
21
+ respond_to do |format|
22
+ format.html # index.html.erb
23
+ format.xls { render :layout => false } if params[:format] == 'xls' # blog post noted that otherwise always interpretted as xls
24
+ end
25
+ end
26
+
27
+ # unused at this point
28
+ def new
29
+ set_matching_trackable_items
30
+
31
+ build_items_for_matching_trackable_items_for(@tracking_list, :tracked_items)
32
+ end
33
+
34
+ def create
35
+ @tracking_list = @repository.tracking_lists.build(params[:tracking_list])
36
+
37
+ if @tracking_list.save
38
+ redirect_to repository_tracking_list_url(:id => @tracking_list,
39
+ :repository_id => @repository)
40
+ end
41
+ end
42
+
43
+ def edit
44
+ set_matching_trackable_items
45
+
46
+ build_items_for_matching_trackable_items_for(@tracking_list, :tracked_items)
47
+ end
48
+
49
+ # update tracked_items (i.e. add them based on a search)
50
+ # or run state change
51
+ def update
52
+ if params[:event]
53
+ original_state = @tracking_list.current_state
54
+ event_method = params[:event] + '!'
55
+ @tracking_list.send(event_method)
56
+ @successful = @tracking_list.current_state != original_state
57
+ @state_change_failed = @succesful
58
+ else
59
+ @successful = @tracking_list.update_attributes(params[:tracking_list])
60
+ end
61
+
62
+ if @successful || @state_change_failed
63
+ flash[:notice] = t('tracking_lists.update.state_change_failed', :event_transition => params[:event].humanize) if @state_change_failed
64
+
65
+ redirect_to repository_tracking_list_url(:id => @tracking_list,
66
+ :repository_id => @repository)
67
+ else
68
+ render :action => 'edit'
69
+ end
70
+ end
71
+
72
+ def destroy
73
+ @tracking_list.destroy
74
+
75
+ # TODO: may need to redirect a different place in some contexts
76
+ redirect_to repository_tracking_lists_url(:repository_id => @repository)
77
+ end
78
+
79
+ private
80
+
81
+ def set_repository
82
+ @repository = Repository.find(params[:repository_id])
83
+ end
84
+
85
+ def set_tracking_list
86
+ @tracking_list = @repository.tracking_lists.find(params[:id])
87
+ end
88
+ end
@@ -0,0 +1,17 @@
1
+ module TrackableItemShelfLocationsHelper
2
+ def javascript_repository_id_observer_and_adjust_code_autocomplete(urlified_name)
3
+ javascript_tag("jQuery(document).ready(function(){
4
+ jQuery(\"#trackable_item_shelf_location_repository_id\").change(
5
+ function() {
6
+ jQuery(\"#trackable_item_shelf_location_code\").val('');
7
+
8
+ var repository_id = jQuery(\"#trackable_item_shelf_location_repository_id\").val();
9
+ var new_shelf_locations_url = \"/#{urlified_name}/repositories/\" + repository_id + \"/shelf_locations.json\";
10
+
11
+ trackable_item_shelf_location_code_auto_completer.url = new_shelf_locations_url;
12
+
13
+ });
14
+
15
+ });")
16
+ end
17
+ end
@@ -0,0 +1,52 @@
1
+ module TrackableItemsHelper
2
+ # wrapped in a div to allow for styling the form to be inline
3
+ def button_to_place_in_shelf_location(trackable_item, additional = false)
4
+ # whether we should redirect to site basket or not
5
+ # if no repositories are associated with this basket, specify site
6
+
7
+ options = { :trackable_item => { :id => trackable_item.id,
8
+ :type => trackable_item.class.name } }
9
+
10
+ options[:urlified_name] = @site_basket.urlified_name if @current_basket.repositories.count < 1
11
+
12
+ button_text = if additional
13
+ button_text = t('trackable_items_helper.add_to_additional_shelf_location')
14
+ else
15
+ button_text = t('trackable_items_helper.add_to_shelf_location')
16
+ end
17
+ "<div class=\"add-to-shelf-location\">" +
18
+ button_to(button_text,
19
+ new_trackable_item_shelf_location_url(options)) +
20
+ "</div>"
21
+ end
22
+
23
+ def shelf_locations_or_appropriate_action(trackable_item)
24
+ html = String.new
25
+
26
+ additional = false
27
+ if trackable_item.has_shelf_locations?
28
+ additional = true
29
+
30
+ html += '<ul class="shelf-locations">'
31
+ shelf_locations_count = 1
32
+ trackable_item.shelf_locations.each do |shelf_location|
33
+ html += '<li'
34
+ html += ' class="first"'if shelf_locations_count == 1
35
+ html += '>'
36
+
37
+ html += link_to(shelf_location.code, repository_shelf_location_url(:repository_id => shelf_location.repository_id,
38
+ :id => shelf_location,
39
+ :urlified_name => shelf_location.repository.basket.urlified_name))
40
+ html += '</li>'
41
+ shelf_locations_count += 1
42
+ end
43
+
44
+ html += '</ul>'
45
+ end
46
+
47
+ html += button_to_place_in_shelf_location(trackable_item, additional)
48
+
49
+ html
50
+ end
51
+
52
+ end
@@ -0,0 +1,8 @@
1
+ # -*- coding: utf-8 -*-
2
+ # name
3
+ # address, contact details?
4
+ # used in Item when current_location is on_loan
5
+
6
+ # quote from spec: When archives are tracked to “On Loan” additional information is required i.e. to what organization / office they will be loaned to. This is a list that will need to be maintained by Staff as it could be continually added to. This list may need to be separate for each Archives Repository as to prevent clutter for the other councils.
7
+ class OnLoanOrganization < ActiveRecord::Base
8
+ end
@@ -0,0 +1,11 @@
1
+ # name Archives Central, PNCC, WDC
2
+ # other contact details?
3
+ class Repository < ActiveRecord::Base
4
+ # we inherit security from our basket
5
+ # site basket == can see all repositories
6
+ # otherwise must be associated to the basket we are within
7
+ belongs_to :basket
8
+
9
+ has_many :shelf_locations, :dependent => :destroy
10
+ has_many :tracking_lists, :dependent => :destroy
11
+ end
@@ -0,0 +1,69 @@
1
+ class ShelfLocation < ActiveRecord::Base
2
+ include KeteTrackableItems::WorkflowUtilities
3
+
4
+ belongs_to :repository
5
+ has_many :trackable_item_shelf_locations, :dependent => :destroy
6
+
7
+ validates_uniqueness_of :code, :case_sensitive => false, :scope => :repository_id
8
+
9
+ workflow do
10
+ state :available do
11
+ event :allocate, :transitions_to => :allocated
12
+ event :deactivate, :transitions_to => :deactivated
13
+ end
14
+
15
+ state :allocated do
16
+ # probably want to create an instance method for clear_out
17
+ # that deactivates all trackable_item_shelf_locations
18
+ event :clear_out, :transitions_to => :available
19
+ event :deallocate, :transitions_to => :available
20
+ end
21
+
22
+ state :deactivated do
23
+ event :reactivate, :transitions_to => :available
24
+ end
25
+ end
26
+
27
+ set_up_workflow_named_scopes.call
28
+
29
+ # returns a hash with trackable_item_type as key
30
+ # and array of ids for that type as value
31
+ def trackable_items_types_and_ids
32
+ @trackable_items_types_and_ids = trackable_item_shelf_locations.with_state_active.inject(Hash.new) do |result, mapping_object|
33
+ type_key = mapping_object.trackable_item_type
34
+ item_id = mapping_object.trackable_item_id
35
+
36
+ values = result[type_key] || Array.new
37
+ values << item_id
38
+
39
+ result[type_key] = values
40
+ result
41
+ end
42
+ end
43
+
44
+ # good enough for our purposes
45
+ # WARNING: this is not a full association, but a hacked together collection
46
+ def trackable_items
47
+ @trackable_items = Array.new
48
+
49
+ trackable_items_types_and_ids.each do |k,v|
50
+ @trackable_items += k.constantize.find(v)
51
+ end
52
+
53
+ @trackable_items
54
+ end
55
+
56
+ def new_allocation
57
+ allocate!
58
+ end
59
+
60
+ def mapping_deactivated_or_destroyed
61
+ deallocate! if allocated? && trackable_items.size == 0
62
+ end
63
+
64
+ def clear_out
65
+ trackable_item_shelf_locations.each do |mapping|
66
+ mapping.make_deactivated
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,58 @@
1
+ class TrackableItemShelfLocation < ActiveRecord::Base
2
+ include KeteTrackableItems::WorkflowUtilities
3
+
4
+ after_create :update_state_of_shelf_location_and_trackable_item
5
+
6
+ # after destroy, change state of trackable_item and shelf_location
7
+ after_destroy :send_deactivated_to_associations
8
+
9
+ belongs_to :shelf_location
10
+ belongs_to :trackable_item, :polymorphic => true
11
+
12
+ validates_presence_of :shelf_location, :message => lambda { I18n.t('trackable_item_shelf_location.shelf_location_blank_or_does_not_match') }
13
+ validates_presence_of :trackable_item, :message => lambda { I18n.t('trackable_item_shelf_location.trackable_item_blank_or_does_not_match') }
14
+
15
+ # needs to be unique to shelf_location to trackable_item
16
+ validates_uniqueness_of :shelf_location_id, :scope => [:trackable_item_type, :trackable_item_id], :message => lambda { I18n.t('trackable_item_shelf_location.previously_allocated_reactivate_instead') }
17
+
18
+ delegate :repository, :to => :shelf_location, :allow_nil => true
19
+ delegate :repository_id, :to => :shelf_location, :allow_nil => true
20
+ delegate :code, :to => :shelf_location, :allow_nil => true
21
+ delegate :description_for_tracked_item, :to => :trackable_item, :allow_nil => true
22
+
23
+ workflow do
24
+ state :active do
25
+ event :deactivate, :transitions_to => :deactivated
26
+ end
27
+
28
+ state :deactivated do
29
+ event :reactivate, :transitions_to => :active
30
+ end
31
+ end
32
+
33
+ set_up_workflow_named_scopes.call
34
+
35
+ def tell_associations_deactivated_or_destroyed
36
+ shelf_location.mapping_deactivated_or_destroyed
37
+ trackable_item.mapping_deactivated_or_destroyed
38
+ end
39
+
40
+ def deactivate
41
+ tell_associations_deactivated_or_destroyed
42
+ end
43
+
44
+ def make_deactivated
45
+ deactivate!
46
+ end
47
+
48
+ private
49
+
50
+ def update_state_of_shelf_location_and_trackable_item
51
+ shelf_location.new_allocation
52
+ trackable_item.new_allocation
53
+ end
54
+
55
+ def send_deactivated_to_associations
56
+ tell_associations_deactivated_or_destroyed
57
+ end
58
+ end
@@ -0,0 +1,18 @@
1
+ class TrackedItem < ActiveRecord::Base
2
+ belongs_to :tracking_list
3
+ belongs_to :trackable_item, :polymorphic => true
4
+
5
+ delegate :description_for_tracked_item, :to => :trackable_item
6
+
7
+ validates_presence_of :tracking_list, :message => lambda { I18n.t('tracked_item.tracking_list_blank_or_does_not_match') }
8
+ validates_presence_of :trackable_item, :message => lambda { I18n.t('tracked_item.trackable_item_blank_or_does_not_match') }
9
+
10
+ # needs to be unique to tracking_list
11
+ validates_uniqueness_of :tracking_list_id, :scope => [:trackable_item_type, :trackable_item_id]
12
+
13
+ private
14
+
15
+ def validate
16
+ errors.add(:tracking_list, I18n.t('tracked_item.already_in_tracking_list')) if tracking_list.tracked_items.include?(self)
17
+ end
18
+ end
@@ -0,0 +1,50 @@
1
+ class TrackingList < ActiveRecord::Base
2
+ include Workflow
3
+ include KeteTrackableItems::WorkflowUtilities
4
+
5
+ belongs_to :repository
6
+
7
+ has_many :tracked_items, :dependent => :destroy
8
+ accepts_nested_attributes_for :tracked_items, :allow_destroy => true
9
+
10
+ # set up workflow states, some are shared with trackable_items
11
+ shared_code_as_string = shared_tracking_workflow_specs_as_string
12
+
13
+ specification = Proc.new {
14
+ state :new do
15
+ event :display, :transitions_to => :displayed
16
+ event :hold_out, :transitions_to => :held_out
17
+ event :loan, :transitions_to => :on_loan_to_organization
18
+ event :queue_for_refiling, :transitions_to => :to_be_refiled
19
+ event :cancel, :transitions_to => :cancelled
20
+ end
21
+
22
+ eval(shared_code_as_string)
23
+
24
+ # we replace to_be_refiled transitions with complete event only
25
+ state :to_be_refiled do
26
+ event :refile, :transitions_to => :completed
27
+ end
28
+
29
+ state :cancelled
30
+ state :completed
31
+ }
32
+
33
+ workflow(&specification)
34
+
35
+ set_up_workflow_named_scopes.call
36
+
37
+ # send workflow event, except cancel, to tracked_items
38
+ # upon event being called on tracking_list
39
+ workflow_event_names.each do |event_name|
40
+ unless event_name == 'cancel'
41
+ code = Proc.new {
42
+ tracked_items.each do |tracked_item|
43
+ tracked_item.trackable_item.send("#{event_name}!")
44
+ end
45
+ }
46
+
47
+ define_method(event_name, &code)
48
+ end
49
+ end
50
+ end