enju_standalone_interface 0.0.1
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.
- 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
|
+
|