enju_standalone_interface 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +35 -0
- data/app/assets/javascripts/enju_standalone_interface/application.js +15 -0
- data/app/assets/javascripts/enju_standalone_interface/batch_action.js +2 -0
- data/app/assets/stylesheets/enju_standalone_interface/application.css +13 -0
- data/app/assets/stylesheets/enju_standalone_interface/batch_action.css +4 -0
- data/app/controllers/application_controller.rb +4 -0
- data/app/controllers/batch_action_controller.rb +9 -0
- data/app/helpers/enju_standalone_interface/application_helper.rb +4 -0
- data/app/helpers/enju_standalone_interface/batch_action_helper.rb +4 -0
- data/app/views/enju_standalone_interface/batch_action/recept.html.erb +1 -0
- data/app/views/layouts/enju_standalone_interface/application.html.erb +14 -0
- data/config/routes.rb +3 -0
- data/lib/enju_standalone_interface.rb +233 -0
- data/lib/enju_standalone_interface/engine.rb +5 -0
- data/lib/enju_standalone_interface/version.rb +3 -0
- data/lib/tasks/enju_standalone_interface_tasks.rake +4 -0
- data/spec/controllers/enju_standalone_interface/batch_action_controller_spec.rb +21 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/helpers/users_helper.rb +36 -0
- data/spec/dummy/app/models/basket.rb +70 -0
- data/spec/dummy/app/models/carrier_type.rb +33 -0
- data/spec/dummy/app/models/checked_item.rb +177 -0
- data/spec/dummy/app/models/checkout.rb +307 -0
- data/spec/dummy/app/models/checkout_type.rb +33 -0
- data/spec/dummy/app/models/circulation_status.rb +23 -0
- data/spec/dummy/app/models/event.rb +124 -0
- data/spec/dummy/app/models/item.rb +1234 -0
- data/spec/dummy/app/models/item_has_use_restriction.rb +23 -0
- data/spec/dummy/app/models/lending_policy.rb +32 -0
- data/spec/dummy/app/models/library.rb +105 -0
- data/spec/dummy/app/models/library_group.rb +88 -0
- data/spec/dummy/app/models/manifestation.rb +698 -0
- data/spec/dummy/app/models/patron.rb +342 -0
- data/spec/dummy/app/models/role.rb +47 -0
- data/spec/dummy/app/models/shelf.rb +83 -0
- data/spec/dummy/app/models/use_restriction.rb +22 -0
- data/spec/dummy/app/models/user.rb +580 -0
- data/spec/dummy/app/models/user_group.rb +43 -0
- data/spec/dummy/app/models/user_group_has_checkout_type.rb +80 -0
- data/spec/dummy/app/models/user_has_role.rb +4 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +57 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/locales/translation_en.yml +1724 -0
- data/spec/dummy/config/locales/validates_timeliness.en.yml +16 -0
- data/spec/dummy/config/routes.rb +4 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20120322223037_create_users.rb +71 -0
- data/spec/dummy/db/migrate/20120323053037_create_roles.rb +15 -0
- data/spec/dummy/db/migrate/20120323060718_create_user_has_roles.rb +10 -0
- data/spec/dummy/db/migrate/20120323062239_create_libraries.rb +37 -0
- data/spec/dummy/db/migrate/20120323063602_create_items.rb +33 -0
- data/spec/dummy/db/migrate/20120323064619_craete_circulation_statuses.rb +13 -0
- data/spec/dummy/db/migrate/20120323065157_craete_checkout_types.rb +13 -0
- data/spec/dummy/db/migrate/20120323070102_craete_shelves.rb +17 -0
- data/spec/dummy/db/migrate/20120323071616_craete_library_groups.rb +24 -0
- data/spec/dummy/db/migrate/20120323073022_craete_patrons.rb +72 -0
- data/spec/dummy/db/migrate/20120323141030_create_manifestations.rb +97 -0
- data/spec/dummy/db/migrate/20120323142330_create_carrier_types.rb +12 -0
- data/spec/dummy/db/migrate/20120324132708_create_baskets.rb +20 -0
- data/spec/dummy/db/migrate/20120324135409_checked_items.rb +16 -0
- data/spec/dummy/db/migrate/20120324141007_create_user_groups.rb +22 -0
- data/spec/dummy/db/migrate/20120324141950_create_user_group_has_checkout_type.rb +26 -0
- data/spec/dummy/db/migrate/20120324151951_create_lending_policies.rb +22 -0
- data/spec/dummy/db/migrate/20120324153756_create_use_restrictions.rb +15 -0
- data/spec/dummy/db/migrate/20120324154009_create_item_has_use_restrictions.rb +16 -0
- data/spec/dummy/db/migrate/20120324164815_create_checkouts.rb +26 -0
- data/spec/dummy/db/migrate/20120325160112_create_events.rb +23 -0
- data/spec/dummy/db/schema.rb +518 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/lib/enju_leaf.rb +6 -0
- data/spec/dummy/lib/enju_leaf/master_model.rb +41 -0
- data/spec/dummy/lib/enju_leaf/url_validator.rb +10 -0
- data/spec/dummy/log/development.log +116 -0
- data/spec/dummy/log/test.log +17849 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/factories/item.rb +9 -0
- data/spec/factories/manifestation.rb +6 -0
- data/spec/factories/user.rb +27 -0
- data/spec/fixtures/carrier_types.yml +38 -0
- data/spec/fixtures/checkout_types.yml +34 -0
- data/spec/fixtures/circulation_statuses.yml +135 -0
- data/spec/fixtures/libraries.yml +40 -0
- data/spec/fixtures/roles.yml +21 -0
- data/spec/fixtures/shelves.yml +53 -0
- data/spec/fixtures/user_group_has_checkout_types.yml +14 -0
- data/spec/fixtures/user_groups.yml +7 -0
- data/spec/libs/enju_standalone_interface_spec.rb +133 -0
- data/spec/spec_helper.rb +36 -0
- metadata +358 -0
data/spec/dummy/Rakefile
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
3
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
4
|
+
|
5
|
+
require File.expand_path('../config/application', __FILE__)
|
6
|
+
|
7
|
+
Dummy::Application.load_tasks
|
@@ -0,0 +1,15 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// the compiled file.
|
9
|
+
//
|
10
|
+
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
11
|
+
// GO AFTER THE REQUIRES BELOW.
|
12
|
+
//
|
13
|
+
//= require jquery
|
14
|
+
//= require jquery_ujs
|
15
|
+
//= require_tree .
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require_self
|
12
|
+
*= require_tree .
|
13
|
+
*/
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module UsersHelper
|
2
|
+
def enumrate_user_name(family)
|
3
|
+
v = ""
|
4
|
+
family.users.each do |u|
|
5
|
+
v.concat("#{u.patron.full_name if u.patron} (#{u.username}) ")
|
6
|
+
end
|
7
|
+
return v
|
8
|
+
end
|
9
|
+
|
10
|
+
def family_radio_check?(btn_value, family)
|
11
|
+
#logger.info "family_radio_check v=[#{btn_value}] f=[#{family}]"
|
12
|
+
#logger.info "family_radio_check v=[#{btn_value.class}] f=[#{family.class}]"
|
13
|
+
if family.empty? && btn_value == 0
|
14
|
+
return true
|
15
|
+
end
|
16
|
+
if btn_value.to_s == family
|
17
|
+
#logger.info "true"
|
18
|
+
return true
|
19
|
+
end
|
20
|
+
#logger.info "false"
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
|
24
|
+
def i18n_telephone_type(type)
|
25
|
+
case type
|
26
|
+
when 1
|
27
|
+
t('activerecord.attributes.patron.home_phone')
|
28
|
+
when 2
|
29
|
+
t('activerecord.attributes.patron.fax')
|
30
|
+
when 3
|
31
|
+
t('activerecord.attributes.patron.mobile_phone')
|
32
|
+
when 4
|
33
|
+
t('activerecord.attributes.patron.company_phone')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
class Basket < ActiveRecord::Base
|
2
|
+
default_scope :order => 'id DESC'
|
3
|
+
scope :will_expire, lambda {|date| {:conditions => ['created_at < ?', date]}}
|
4
|
+
belongs_to :user, :validate => true
|
5
|
+
has_many :checked_items, :dependent => :destroy
|
6
|
+
has_many :items, :through => :checked_items
|
7
|
+
has_many :checkouts
|
8
|
+
has_many :checkins
|
9
|
+
#acts_as_paranoid
|
10
|
+
|
11
|
+
validates_associated :user, :on => :create
|
12
|
+
# 貸出完了後にかごのユーザidは破棄する
|
13
|
+
validates_presence_of :user, :on => :create
|
14
|
+
validate :check_suspended
|
15
|
+
|
16
|
+
attr_accessor :user_number
|
17
|
+
|
18
|
+
def check_suspended
|
19
|
+
if self.user
|
20
|
+
errors[:base] << I18n.t('basket.this_account_is_suspended') unless self.user.active_for_authentication?
|
21
|
+
else
|
22
|
+
errors[:base] << I18n.t('user.not_found')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def basket_checkout(librarian)
|
27
|
+
return nil if self.checked_items.size == 0
|
28
|
+
begin
|
29
|
+
Item.transaction do
|
30
|
+
self.checked_items.each do |checked_item|
|
31
|
+
checked_item.ignore_restriction = '1'
|
32
|
+
if checked_item.available_for_checkout?
|
33
|
+
checkout = self.user.checkouts.new(:librarian_id => librarian.id, :item_id => checked_item.item.id, :basket_id => self.id, :due_date => checked_item.due_date)
|
34
|
+
checked_item.item.checkout!(self.user, librarian)
|
35
|
+
checkout.save!
|
36
|
+
else
|
37
|
+
#errors[:base] << I18n.t('activerecord.errors.messages.checked_item.not_available_for_checkout')
|
38
|
+
errors[:base] << 'checked_item.not_available_for_checkout'
|
39
|
+
return false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
CheckedItem.destroy_all(:basket_id => self.id)
|
43
|
+
self.destroy
|
44
|
+
end
|
45
|
+
rescue Exception => e
|
46
|
+
logger.error "Failed to checkout: #{e}"
|
47
|
+
return false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.expire
|
52
|
+
Basket.will_expire(Time.zone.now.beginning_of_day).destroy_all
|
53
|
+
logger.info "#{Time.zone.now} baskets expired!"
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
# == Schema Information
|
59
|
+
#
|
60
|
+
# Table name: baskets
|
61
|
+
#
|
62
|
+
# id :integer not null, primary key
|
63
|
+
# user_id :integer
|
64
|
+
# note :text
|
65
|
+
# type :string(255)
|
66
|
+
# lock_version :integer default(0), not null
|
67
|
+
# created_at :datetime
|
68
|
+
# updated_at :datetime
|
69
|
+
#
|
70
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class CarrierType < ActiveRecord::Base
|
2
|
+
include MasterModel
|
3
|
+
default_scope :order => "position"
|
4
|
+
scope :audio, where(:name => ["CD", "DVD", "AV"])
|
5
|
+
scope :not_audio, where(["name NOT IN (?)", ["CD", "DVD", "AV"]])
|
6
|
+
has_many :manifestation
|
7
|
+
has_many :carrier_type_has_checkout_types, :dependent => :destroy
|
8
|
+
has_many :checkout_types, :through => :carrier_type_has_checkout_types
|
9
|
+
|
10
|
+
def mods_type
|
11
|
+
case name
|
12
|
+
when 'print'
|
13
|
+
'text'
|
14
|
+
else
|
15
|
+
# TODO: その他のタイプ
|
16
|
+
'software, multimedia'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# == Schema Information
|
22
|
+
#
|
23
|
+
# Table name: carrier_types
|
24
|
+
#
|
25
|
+
# id :integer not null, primary key
|
26
|
+
# name :string(255) not null
|
27
|
+
# display_name :text
|
28
|
+
# note :text
|
29
|
+
# position :integer
|
30
|
+
# created_at :datetime
|
31
|
+
# updated_at :datetime
|
32
|
+
#
|
33
|
+
|
@@ -0,0 +1,177 @@
|
|
1
|
+
class CheckedItem < ActiveRecord::Base
|
2
|
+
belongs_to :item #, :validate => true
|
3
|
+
belongs_to :basket #, :validate => true
|
4
|
+
|
5
|
+
validates_associated :item, :basket, :on => :update
|
6
|
+
validates_presence_of :item, :basket, :due_date, :on => :update
|
7
|
+
validates_uniqueness_of :item_id, :scope => :basket_id
|
8
|
+
validate :available_for_checkout?, :on => :create
|
9
|
+
|
10
|
+
before_validation :set_due_date, :on => :create
|
11
|
+
#normalize_attributes :item_identifier
|
12
|
+
|
13
|
+
attr_accessor :item_identifier, :ignore_restriction
|
14
|
+
|
15
|
+
def available_for_checkout?
|
16
|
+
if self.item.blank?
|
17
|
+
# errors[:base] << I18n.t('activerecord.errors.messages.checked_item.item_not_found')
|
18
|
+
errors[:base] << 'checked_item.item_not_found'
|
19
|
+
return false
|
20
|
+
end
|
21
|
+
|
22
|
+
unless self.item.available_for_checkout?
|
23
|
+
# errors[:base] << I18n.t('activerecord.errors.messages.checked_item.not_available_for_checkout')
|
24
|
+
errors[:base] << 'checked_item.not_available_for_checkout'
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
|
28
|
+
if self.item_checkout_type.blank?
|
29
|
+
# errors[:base] << I18n.t('activerecord.errors.messages.checked_item.this_group_cannot_checkout')
|
30
|
+
errors[:base] << 'checked_item.this_group_cannot_checkout'
|
31
|
+
return false
|
32
|
+
end
|
33
|
+
# ここまでは絶対に貸出ができない場合
|
34
|
+
|
35
|
+
# if self.item.rent?
|
36
|
+
# errors[:base] << I18n.t('activerecord.errors.messages.checked_item.already_checked_out')
|
37
|
+
# errors[:base] << 'checked_item.already_checked_out'
|
38
|
+
# return #
|
39
|
+
# end
|
40
|
+
|
41
|
+
return true if self.ignore_restriction == "1"
|
42
|
+
|
43
|
+
if self.item.manifestation.new_serial? && SystemConfiguration.get("checkouts.cannot_for_new_serial")
|
44
|
+
errors[:base] << 'checked_item.new_serial'
|
45
|
+
return false
|
46
|
+
end
|
47
|
+
|
48
|
+
checkout_count = self.basket.user.checked_item_count
|
49
|
+
CheckoutType.all.each do |checkout_type|
|
50
|
+
if checkout_count[:"#{checkout_type.name}"] + self.basket.checked_items.count(:id) >= self.item_checkout_type.checkout_limit
|
51
|
+
#errors[:base] << t('activerecord.errors.messages.checked_item.excessed_checkout_limit')
|
52
|
+
errors[:base] << 'checked_item.excessed_checkout_limit'
|
53
|
+
break
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#errors[:base] << I18n.t('activerecord.errors.messages.checked_item.in_transcation') if self.in_transaction?
|
58
|
+
if self.in_transaction?
|
59
|
+
errors[:base] << 'checked_item.in_transcation'
|
60
|
+
return
|
61
|
+
end
|
62
|
+
if self.item.reserved?
|
63
|
+
if self.available_for_reserve_checkout?
|
64
|
+
return true
|
65
|
+
else
|
66
|
+
#errors[:base] << I18n.t('activerecord.errors.messages.checked_item.reserved_item_included')
|
67
|
+
errors[:base] << 'checked_item.reserved_item_included'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
#errors[:base] << I18n.t('activerecord.errors.messages.checked_item.not_available_for_checkout') if self.item.not_for_loan?
|
71
|
+
if self.item.not_for_loan?
|
72
|
+
errors[:base] << 'checked_item.not_for_loan'
|
73
|
+
end
|
74
|
+
|
75
|
+
return false unless errors[:base]
|
76
|
+
end
|
77
|
+
|
78
|
+
def item_checkout_type
|
79
|
+
if item
|
80
|
+
self.basket.user.user_group.user_group_has_checkout_types.available_for_item(item).first
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def set_due_date
|
85
|
+
return nil unless self.item_checkout_type
|
86
|
+
|
87
|
+
lending_rule = self.item.lending_rule(self.basket.user)
|
88
|
+
return nil if lending_rule.nil?
|
89
|
+
|
90
|
+
if lending_rule.fixed_due_date.blank?
|
91
|
+
#self.due_date = item_checkout_type.checkout_period.days.since Time.zone.today
|
92
|
+
self.due_date = lending_rule.loan_period.days.since Time.zone.now
|
93
|
+
else
|
94
|
+
#self.due_date = item_checkout_type.fixed_due_date
|
95
|
+
self.due_date = lending_rule.fixed_due_date
|
96
|
+
end
|
97
|
+
# 返却期限日が閉館日の場合
|
98
|
+
# TODO date_truncはPostgreSQL独自の機能なので他のDBも少しは考慮に入れる
|
99
|
+
events = Event.find(:all, :conditions => ["? BETWEEN date_trunc('day', start_at) AND date_trunc('day', end_at)", due_date.beginning_of_day])
|
100
|
+
checkin_before = false
|
101
|
+
events.each do |e|
|
102
|
+
checkin_before = true if e.event_category.move_checkin_date == 2
|
103
|
+
end
|
104
|
+
while item.shelf.library.closed?(due_date)
|
105
|
+
if item_checkout_type.set_due_date_before_closing_day
|
106
|
+
self.due_date = due_date.yesterday.end_of_day
|
107
|
+
elsif checkin_before
|
108
|
+
self.due_date = due_date.yesterday.end_of_day
|
109
|
+
else
|
110
|
+
self.due_date = due_date.tomorrow.end_of_day
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
return self.due_date
|
115
|
+
end
|
116
|
+
|
117
|
+
def in_transaction?
|
118
|
+
true if CheckedItem.where(:item_id => self.item_id, :basket_id => self.basket_id).first
|
119
|
+
end
|
120
|
+
|
121
|
+
def destroy_reservation(basket)
|
122
|
+
if self.item.reserved?
|
123
|
+
if self.item.manifestation.is_reserved_by(basket.user)
|
124
|
+
reserve = Reserve.where(:user_id => basket.user_id, :manifestation_id => self.item.manifestation.id).first
|
125
|
+
reserve.destroy
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def available_for_reserve_checkout?
|
131
|
+
reserve = Reserve.waiting.where(:manifestation_id => self.item.manifestation.id, :user_id => self.basket.user.id).first rescue nil
|
132
|
+
retained_reserves = self.item.manifestation.reserves.hold
|
133
|
+
if retained_reserves && retained_reserves.include?(reserve)
|
134
|
+
begin
|
135
|
+
return true if self.item.reserve.user_id == self.basket.user.id
|
136
|
+
exchange_reserve_item(self.item, reserve)
|
137
|
+
return true
|
138
|
+
rescue Exception => e
|
139
|
+
logger.error e
|
140
|
+
end
|
141
|
+
end
|
142
|
+
false
|
143
|
+
end
|
144
|
+
|
145
|
+
def exchange_reserve_item(checkin_item, checkin_reserve)
|
146
|
+
begin
|
147
|
+
Reserve.transaction do
|
148
|
+
reserve = Reserve.waiting.where(:item_id => checkin_item.id).first rescue nil
|
149
|
+
item = checkin_reserve.item
|
150
|
+
raise Exception if CheckedItem.where(:item_id => checkin_reserve.item_id, :basket_id => self.basket_id).first
|
151
|
+
checkin_reserve.item = checkin_item
|
152
|
+
unless reserve.blank?
|
153
|
+
reserve.item = item
|
154
|
+
reserve.save(:validate => false)
|
155
|
+
end
|
156
|
+
checkin_reserve.save
|
157
|
+
end
|
158
|
+
rescue Exception => e
|
159
|
+
logger.error e
|
160
|
+
raise e
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
# == Schema Information
|
167
|
+
#
|
168
|
+
# Table name: checked_items
|
169
|
+
#
|
170
|
+
# id :integer not null, primary key
|
171
|
+
# item_id :integer not null
|
172
|
+
# basket_id :integer not null
|
173
|
+
# due_date :datetime not null
|
174
|
+
# created_at :datetime
|
175
|
+
# updated_at :datetime
|
176
|
+
#
|
177
|
+
|
@@ -0,0 +1,307 @@
|
|
1
|
+
class Checkout < ActiveRecord::Base
|
2
|
+
default_scope :order => 'due_date ASC, id DESC'#:order => 'id DESC'
|
3
|
+
scope :not_returned, where(:checkin_id => nil)
|
4
|
+
scope :overdue, lambda {|date| {:conditions => ['checkin_id IS NULL AND due_date < ?', date]}}
|
5
|
+
scope :due_date_on, lambda {|date| where(:checkin_id => nil, :due_date => date.beginning_of_day .. date.end_of_day)}
|
6
|
+
scope :completed, lambda {|start_date, end_date| {:conditions => ['created_at >= ? AND created_at < ?', start_date, end_date]}}
|
7
|
+
scope :on, lambda {|date| {:conditions => ['created_at >= ? AND created_at < ?', date.beginning_of_day, date.tomorrow.beginning_of_day]}}
|
8
|
+
|
9
|
+
belongs_to :user #, :counter_cache => true #, :validate => true
|
10
|
+
delegate :username, :user_number, :to => :user, :prefix => true
|
11
|
+
belongs_to :item #, :counter_cache => true #, :validate => true
|
12
|
+
belongs_to :checkin #, :validate => true
|
13
|
+
belongs_to :librarian, :class_name => 'User' #, :validate => true
|
14
|
+
belongs_to :basket #, :validate => true
|
15
|
+
has_many :reminder_list
|
16
|
+
|
17
|
+
validates_associated :user, :item, :librarian, :checkin #, :basket
|
18
|
+
# TODO: 貸出履歴を保存しない場合は、ユーザ名を削除する
|
19
|
+
#validates_presence_of :user, :item, :basket
|
20
|
+
validates_presence_of :item_id, :basket_id, :due_date
|
21
|
+
validates_uniqueness_of :item_id, :scope => [:basket_id, :user_id]
|
22
|
+
validate :is_not_checked?, :on => :create
|
23
|
+
#validates_date :due_date
|
24
|
+
|
25
|
+
def self.per_page
|
26
|
+
10
|
27
|
+
end
|
28
|
+
|
29
|
+
def day_of_overdue
|
30
|
+
due_date_datetype = due_date.strftime("%Y-%m-%d")
|
31
|
+
overdue = (Date.today - due_date_datetype.to_date)
|
32
|
+
overdue = 0 if overdue < 0
|
33
|
+
return overdue
|
34
|
+
end
|
35
|
+
|
36
|
+
def is_not_checked?
|
37
|
+
checkout = Checkout.not_returned.find(self.item) rescue nil
|
38
|
+
unless checkout.nil?
|
39
|
+
errors[:base] << I18n.t('activerecord.errors.messages.checkin.already_checked_out')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def checkout_renewable?
|
44
|
+
return false if self.overdue?
|
45
|
+
if self.item
|
46
|
+
return false if self.over_checkout_renewal_limit?
|
47
|
+
return false if self.reserved?
|
48
|
+
end
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
def reserved?
|
53
|
+
return true if self.item.reserved?
|
54
|
+
end
|
55
|
+
|
56
|
+
def over_checkout_renewal_limit?
|
57
|
+
return true if self.item.checkout_status(self.user).checkout_renewal_limit <= self.checkout_renewal_count
|
58
|
+
end
|
59
|
+
|
60
|
+
def overdue?
|
61
|
+
# if Time.zone.now.tomorrow.beginning_of_day >= self.due_date
|
62
|
+
if Time.zone.now.beginning_of_day > self.due_date
|
63
|
+
return true
|
64
|
+
else
|
65
|
+
return false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def is_today_due_date?
|
70
|
+
if Time.zone.now.beginning_of_day == self.due_date.beginning_of_day
|
71
|
+
return true
|
72
|
+
else
|
73
|
+
return false
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def set_renew_due_date(user)
|
78
|
+
if self.item
|
79
|
+
if self.checkout_renewal_count <= self.item.checkout_status(user).checkout_renewal_limit
|
80
|
+
renew_due_date = self.due_date.advance(:days => self.item.checkout_status(user).checkout_period)
|
81
|
+
else
|
82
|
+
renew_due_date = self.due_date
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.manifestations_count(start_date, end_date, manifestation)
|
88
|
+
self.completed(start_date, end_date).where(:item_id => manifestation.items.collect(&:id)).count
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.send_due_date_notification
|
92
|
+
template = 'recall_item'
|
93
|
+
queues = []
|
94
|
+
User.find_each do |user|
|
95
|
+
# 未来の日時を指定する
|
96
|
+
checkouts = user.checkouts.due_date_on(user.user_group.number_of_day_to_notify_due_date.days.from_now.beginning_of_day)
|
97
|
+
unless checkouts.empty?
|
98
|
+
queues << user.send_message(template, :manifestations => checkouts.collect(&:item).collect(&:manifestation))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
queues.size
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.send_overdue_notification
|
105
|
+
template = 'recall_overdue_item'
|
106
|
+
queues = []
|
107
|
+
User.find_each do |user|
|
108
|
+
user.user_group.number_of_time_to_notify_overdue.times do |i|
|
109
|
+
checkouts = user.checkouts.due_date_on((user.user_group.number_of_day_to_notify_overdue * (i + 1)).days.ago.beginning_of_day)
|
110
|
+
unless checkouts.empty?
|
111
|
+
queues << user.send_message(template, :manifestations => checkouts.collect(&:item).collect(&:manifestation))
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
queues.size
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.apend_to_reminder_list
|
119
|
+
queues_size = 0
|
120
|
+
User.find_each do |user|
|
121
|
+
user.user_group.number_of_time_to_notify_overdue.times do |i|
|
122
|
+
checkouts = user.checkouts.due_date_on((user.user_group.number_of_day_to_notify_overdue * (i + 1)).days.ago.beginning_of_day)
|
123
|
+
unless checkouts.empty?
|
124
|
+
checkouts.each do |checkout|
|
125
|
+
#logger.info checkout
|
126
|
+
r = ReminderList.where(:checkout_id => checkout.id)
|
127
|
+
unless r.nil?
|
128
|
+
r = ReminderList.new
|
129
|
+
r.checkout_id = checkout.id
|
130
|
+
r.status = 0
|
131
|
+
r.save!
|
132
|
+
logger.info "create ReminderList checkout_id=#{checkout.id}"
|
133
|
+
queues_size += 1
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
queues_size
|
141
|
+
end
|
142
|
+
|
143
|
+
# output
|
144
|
+
def self.output_checkouts(checkouts, user, current_user)
|
145
|
+
report = ThinReports::Report.new :layout => File.join(Rails.root, 'report', 'checkouts.tlf')
|
146
|
+
|
147
|
+
report.layout.config.list(:list) do
|
148
|
+
use_stores :total => 0
|
149
|
+
events.on :footer_insert do |e|
|
150
|
+
e.section.item(:total).value(checkouts.size)
|
151
|
+
e.section.item(:message).value(SystemConfiguration.get("checkouts_print.message"))
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
library = Library.find(current_user.library_id) rescue nil
|
156
|
+
|
157
|
+
report.start_new_page do |page|
|
158
|
+
page.item(:library).value(LibraryGroup.system_name(@locale))
|
159
|
+
page.item(:user).value(user.user_number)
|
160
|
+
page.item(:lend_user).value(current_user.user_number)
|
161
|
+
page.item(:lend_library).value(library.display_name)
|
162
|
+
page.item(:lend_library_telephone_number_1).value(library.telephone_number_1)
|
163
|
+
page.item(:lend_library_telephone_number_2).value(library.telephone_number_2)
|
164
|
+
page.item(:date).value(Time.now.strftime('%Y/%m/%d'))
|
165
|
+
|
166
|
+
checkouts.each do |checkout|
|
167
|
+
page.list(:list).add_row do |row|
|
168
|
+
row.item(:book).value(checkout.item.manifestation.original_title)
|
169
|
+
row.item(:due_date).value(checkout.due_date)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
return report
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.output_checkoutlist_pdf(checkouts, view)
|
177
|
+
report = ThinReports::Report.new :layout => File.join(Rails.root, 'report', 'checkoutlist.tlf')
|
178
|
+
|
179
|
+
# set page_num
|
180
|
+
report.events.on :page_create do |e|
|
181
|
+
e.page.item(:page).value(e.page.no)
|
182
|
+
end
|
183
|
+
report.events.on :generate do |e|
|
184
|
+
e.pages.each do |page|
|
185
|
+
page.item(:total).value(e.report.page_count)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
report.start_new_page do |page|
|
190
|
+
page.item(:date).value(Time.now)
|
191
|
+
if view == 'overdue'
|
192
|
+
page.item(:page_title).value(I18n.t('checkout.listing_overdue_item'))
|
193
|
+
else
|
194
|
+
page.item(:page_title).value(I18n.t('page.listing', :model => I18n.t('activerecord.models.checkout')))
|
195
|
+
end
|
196
|
+
|
197
|
+
if checkouts.size == 0
|
198
|
+
page.list(:list).add_row do |row|
|
199
|
+
row.item(:not_found).show
|
200
|
+
row.item(:not_found).value(I18n.t('page.no_record_found'))
|
201
|
+
(1..7).each do |i|
|
202
|
+
row.item("line#{i}").hide
|
203
|
+
end
|
204
|
+
end
|
205
|
+
else
|
206
|
+
checkouts.each do |checkout|
|
207
|
+
page.list(:list).add_row do |row|
|
208
|
+
row.item(:not_found).hide
|
209
|
+
user = checkout.user.patron.full_name
|
210
|
+
if SystemConfiguration.get("checkout_print.old") == true and checkout.user.patron.date_of_birth
|
211
|
+
age = (Time.now.strftime("%Y%m%d").to_f - checkout.user.patron.date_of_birth.strftime("%Y%m%d").to_f) / 10000
|
212
|
+
age = age.to_i
|
213
|
+
user = user + '(' + age.to_s + I18n.t('activerecord.attributes.patron.old') +')'
|
214
|
+
end
|
215
|
+
row.item(:user).value(user)
|
216
|
+
row.item(:title).value(checkout.item.manifestation.original_title)
|
217
|
+
row.item(:item_identifier).value(checkout.item.item_identifier)
|
218
|
+
row.item(:library).value(checkout.item.shelf.library.display_name.localize)
|
219
|
+
row.item(:shelf).value(checkout.item.shelf.display_name.localize)
|
220
|
+
row.item(:due_date).value(checkout.due_date.strftime("%Y/%m/%d"))
|
221
|
+
renewal_count = checkout.checkout_renewal_count.to_s + '/' + checkout.item.checkout_status(checkout.user).checkout_renewal_limit.to_s
|
222
|
+
row.item(:renewal_count).value(renewal_count)
|
223
|
+
due_date_datetype = checkout.due_date.strftime("%Y-%m-%d")
|
224
|
+
overdue = Date.today - due_date_datetype.to_date
|
225
|
+
overdue = 0 if overdue < 0
|
226
|
+
row.item(:overdue).value(overdue)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
return report
|
232
|
+
end
|
233
|
+
|
234
|
+
def self.output_checkoutlist_csv(checkouts, view)
|
235
|
+
data = String.new
|
236
|
+
data << "\xEF\xBB\xBF".force_encoding("UTF-8") + "\n"
|
237
|
+
columns = [
|
238
|
+
[:user,'activerecord.models.user'],
|
239
|
+
[:title, 'activerecord.attributes.manifestation.original_title'],
|
240
|
+
[:item_identifier,'activerecord.attributes.item.item_identifier'],
|
241
|
+
[:library, 'activerecord.models.library'],
|
242
|
+
[:shelf, 'activerecord.models.shelf'],
|
243
|
+
[:due_date, 'activerecord.attributes.checkout.due_date'],
|
244
|
+
[:renewal_count, 'activerecord.attributes.checkout.renewal_count'],
|
245
|
+
[:overdue, 'checkout.number_of_day_overdue'],
|
246
|
+
]
|
247
|
+
|
248
|
+
# title column
|
249
|
+
row = columns.map {|column| I18n.t(column[1])}
|
250
|
+
data << '"'+row.join("\"\t\"")+"\"\n"
|
251
|
+
|
252
|
+
# set
|
253
|
+
checkouts.each do |checkout|
|
254
|
+
row = []
|
255
|
+
columns.each do |column|
|
256
|
+
case column[0]
|
257
|
+
when :user
|
258
|
+
user = checkout.user.patron.full_name
|
259
|
+
if SystemConfiguration.get("reserve_print.old") == true and checkout.user.patron.date_of_birth
|
260
|
+
age = (Time.now.strftime("%Y%m%d").to_f - checkout.user.patron.date_of_birth.strftime("%Y%m%d").to_f) / 10000
|
261
|
+
age = age.to_i
|
262
|
+
user = user + '(' + age.to_s + I18n.t('activerecord.attributes.patron.old') +')'
|
263
|
+
end
|
264
|
+
row << user
|
265
|
+
when :title
|
266
|
+
row << checkout.item.manifestation.original_title
|
267
|
+
when :item_identifier
|
268
|
+
row << checkout.item.item_identifier
|
269
|
+
when :library
|
270
|
+
row << checkout.item.shelf.library.display_name.localize
|
271
|
+
when :shelf
|
272
|
+
row << checkout.item.shelf.display_name.localize
|
273
|
+
when :due_date
|
274
|
+
row << checkout.due_date.strftime("%Y/%m/%d")
|
275
|
+
when :renewal_count
|
276
|
+
renewal_count = checkout.checkout_renewal_count.to_s + '/' + checkout.item.checkout_status(checkout.user).checkout_renewal_limit.to_s
|
277
|
+
row << renewal_count
|
278
|
+
when :overdue
|
279
|
+
due_date_datetype = checkout.due_date.strftime("%Y-%m-%d")
|
280
|
+
overdue = Date.today - due_date_datetype.to_date
|
281
|
+
overdue = 0 if overdue < 0
|
282
|
+
row << overdue
|
283
|
+
end
|
284
|
+
end
|
285
|
+
data << '"'+row.join("\"\t\"")+"\"\n"
|
286
|
+
end
|
287
|
+
return data
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
# == Schema Information
|
292
|
+
#
|
293
|
+
# Table name: checkouts
|
294
|
+
#
|
295
|
+
# id :integer not null, primary key
|
296
|
+
# user_id :integer
|
297
|
+
# item_id :integer not null
|
298
|
+
# checkin_id :integer
|
299
|
+
# librarian_id :integer
|
300
|
+
# basket_id :integer
|
301
|
+
# due_date :datetime
|
302
|
+
# checkout_renewal_count :integer default(0), not null
|
303
|
+
# lock_version :integer default(0), not null
|
304
|
+
# created_at :datetime
|
305
|
+
# updated_at :datetime
|
306
|
+
#
|
307
|
+
|