bbmb 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/History.txt +5 -0
  2. data/LICENSE.txt +339 -0
  3. data/Manifest.txt +91 -0
  4. data/README.txt +25 -0
  5. data/Rakefile +28 -0
  6. data/bin/admin +71 -0
  7. data/bin/bbmbd +61 -0
  8. data/lib/bbmb.rb +9 -0
  9. data/lib/bbmb/config.rb +106 -0
  10. data/lib/bbmb/html/state/change_password.rb +50 -0
  11. data/lib/bbmb/html/state/current_order.rb +81 -0
  12. data/lib/bbmb/html/state/customer.rb +109 -0
  13. data/lib/bbmb/html/state/customers.rb +52 -0
  14. data/lib/bbmb/html/state/favorites.rb +19 -0
  15. data/lib/bbmb/html/state/favorites_result.rb +21 -0
  16. data/lib/bbmb/html/state/global.rb +62 -0
  17. data/lib/bbmb/html/state/history.rb +95 -0
  18. data/lib/bbmb/html/state/info.rb +23 -0
  19. data/lib/bbmb/html/state/json.rb +16 -0
  20. data/lib/bbmb/html/state/login.rb +76 -0
  21. data/lib/bbmb/html/state/order.rb +21 -0
  22. data/lib/bbmb/html/state/orders.rb +19 -0
  23. data/lib/bbmb/html/state/result.rb +64 -0
  24. data/lib/bbmb/html/state/show_pass.rb +16 -0
  25. data/lib/bbmb/html/state/viral/admin.rb +41 -0
  26. data/lib/bbmb/html/state/viral/customer.rb +143 -0
  27. data/lib/bbmb/html/util/known_user.rb +51 -0
  28. data/lib/bbmb/html/util/multilingual.rb +18 -0
  29. data/lib/bbmb/html/util/session.rb +52 -0
  30. data/lib/bbmb/html/util/validator.rb +55 -0
  31. data/lib/bbmb/html/view/backorder.rb +24 -0
  32. data/lib/bbmb/html/view/change_password.rb +42 -0
  33. data/lib/bbmb/html/view/copyleft.rb +41 -0
  34. data/lib/bbmb/html/view/current_order.rb +482 -0
  35. data/lib/bbmb/html/view/customer.rb +152 -0
  36. data/lib/bbmb/html/view/customers.rb +145 -0
  37. data/lib/bbmb/html/view/favorites.rb +162 -0
  38. data/lib/bbmb/html/view/favorites_result.rb +26 -0
  39. data/lib/bbmb/html/view/foot.rb +21 -0
  40. data/lib/bbmb/html/view/head.rb +32 -0
  41. data/lib/bbmb/html/view/history.rb +60 -0
  42. data/lib/bbmb/html/view/info.rb +33 -0
  43. data/lib/bbmb/html/view/json.rb +20 -0
  44. data/lib/bbmb/html/view/list_prices.rb +51 -0
  45. data/lib/bbmb/html/view/login.rb +46 -0
  46. data/lib/bbmb/html/view/multilingual.rb +17 -0
  47. data/lib/bbmb/html/view/navigation.rb +30 -0
  48. data/lib/bbmb/html/view/order.rb +123 -0
  49. data/lib/bbmb/html/view/orders.rb +50 -0
  50. data/lib/bbmb/html/view/result.rb +107 -0
  51. data/lib/bbmb/html/view/search.rb +28 -0
  52. data/lib/bbmb/html/view/show_pass.rb +60 -0
  53. data/lib/bbmb/html/view/template.rb +61 -0
  54. data/lib/bbmb/model/customer.rb +96 -0
  55. data/lib/bbmb/model/order.rb +255 -0
  56. data/lib/bbmb/model/product.rb +99 -0
  57. data/lib/bbmb/model/promotion.rb +52 -0
  58. data/lib/bbmb/model/quota.rb +27 -0
  59. data/lib/bbmb/model/subject.rb +46 -0
  60. data/lib/bbmb/persistence/none.rb +6 -0
  61. data/lib/bbmb/persistence/odba.rb +42 -0
  62. data/lib/bbmb/persistence/odba/model/customer.rb +47 -0
  63. data/lib/bbmb/persistence/odba/model/order.rb +50 -0
  64. data/lib/bbmb/persistence/odba/model/product.rb +26 -0
  65. data/lib/bbmb/persistence/odba/model/quota.rb +12 -0
  66. data/lib/bbmb/util/invoicer.rb +126 -0
  67. data/lib/bbmb/util/mail.rb +140 -0
  68. data/lib/bbmb/util/multilingual.rb +57 -0
  69. data/lib/bbmb/util/numbers.rb +67 -0
  70. data/lib/bbmb/util/password_generator.rb +44 -0
  71. data/lib/bbmb/util/polling_manager.rb +135 -0
  72. data/lib/bbmb/util/server.rb +159 -0
  73. data/lib/bbmb/util/target_dir.rb +36 -0
  74. data/lib/bbmb/util/transfer_dat.rb +34 -0
  75. data/lib/bbmb/util/updater.rb +27 -0
  76. data/test/data/ydim.yml +2 -0
  77. data/test/model/test_customer.rb +75 -0
  78. data/test/model/test_order.rb +426 -0
  79. data/test/model/test_product.rb +238 -0
  80. data/test/model/test_promotion.rb +40 -0
  81. data/test/stub/persistence.rb +57 -0
  82. data/test/suite.rb +12 -0
  83. data/test/test_bbmb.rb +18 -0
  84. data/test/util/test_invoicer.rb +189 -0
  85. data/test/util/test_mail.rb +359 -0
  86. data/test/util/test_money.rb +71 -0
  87. data/test/util/test_password_generator.rb +27 -0
  88. data/test/util/test_polling_manager.rb +312 -0
  89. data/test/util/test_server.rb +189 -0
  90. data/test/util/test_target_dir.rb +82 -0
  91. data/test/util/test_transfer_dat.rb +45 -0
  92. metadata +190 -0
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+ # Html::State::Customers -- bbmb.ch -- 18.09.2006 -- hwyss@ywesee.com
3
+
4
+ require 'bbmb/html/state/global'
5
+ require 'bbmb/html/view/customers'
6
+ require 'bbmb/model/customer'
7
+ require 'ostruct'
8
+
9
+ module BBMB
10
+ module Html
11
+ module State
12
+ class Customers < Global
13
+ DIRECT_EVENT = :customers
14
+ VIEW = View::Customers
15
+ FILTER = [ :customer_id, :organisation, :plz, :city, :email ]
16
+ def init
17
+ start = Time.now
18
+ @model = BBMB.persistence.all(Model::Customer)
19
+ @sortby = [:organisation]
20
+ BBMB.logger.debug('State') {
21
+ sprintf("Customers#init: loaded %i customers in %1.5fs",
22
+ @model.size, Time.now - start)
23
+ }
24
+ @filter = Proc.new { |model|
25
+ if(filter = @session.event_bound_user_input(:filter))
26
+ pattern = Regexp.new(filter.gsub("*", ".*"), 'i')
27
+ model = model.select { |customer|
28
+ FILTER.any? { |key| pattern.match(customer.send(key).to_s) }
29
+ }
30
+ end
31
+ get_sortby!
32
+ model.sort! { |a, b| compare_entries(a, b) }
33
+ @sort_reverse && model.reverse!
34
+ page(model)
35
+ }
36
+ end
37
+ def page(model)
38
+ page = OpenStruct.new
39
+ index = @session.user_input(:index).to_i
40
+ step = @session.user.pagestep || BBMB.config.pagestep
41
+ page.index = index
42
+ page.first = index + 1
43
+ page.step = step
44
+ page.total = model.size
45
+ page.customers = model[index, step]
46
+ page.last = index + page.customers.size
47
+ page
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ # Html::State::Favorites -- bbmb.ch -- 28.09.2006 -- hwyss@ywesee.com
3
+
4
+ require 'bbmb/html/state/global'
5
+ require 'bbmb/html/view/favorites'
6
+
7
+ module BBMB
8
+ module Html
9
+ module State
10
+ class Favorites < Global
11
+ DIRECT_EVENT = :favorites
12
+ VIEW = View::Favorites
13
+ def init
14
+ @model = _customer.favorites
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ # Html::State::Result -- bbmb.ch -- 21.09.2006 -- hwyss@ywesee.com
3
+
4
+ require 'bbmb/html/state/result'
5
+ require 'bbmb/html/view/favorites_result'
6
+
7
+ module BBMB
8
+ module Html
9
+ module State
10
+ class FavoritesResult < Result
11
+ VIEW = View::FavoritesResult
12
+ def direct_event
13
+ [:search_favorites, {:query => @query}]
14
+ end
15
+ def _order
16
+ _customer.favorites
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+ # Html::State::Global -- bbmb.ch -- 18.09.2006 -- hwyss@ywesee.com
3
+
4
+ require 'sbsm/state'
5
+ require 'bbmb/html/state/login'
6
+ require 'encoding/character/utf-8'
7
+
8
+ module BBMB
9
+ module Html
10
+ module State
11
+ class Global < SBSM::State
12
+ class << self
13
+ def mandatory(*keys)
14
+ define_method(:_mandatory) { keys }
15
+ define_method(:mandatory) { _mandatory }
16
+ define_method(:mandatory?) { |key| mandatory.include?(key) }
17
+ end
18
+ end
19
+ def logout
20
+ @session.logout
21
+ State::Login.new(@session, nil)
22
+ end
23
+ def direct_arguments
24
+ if(keys = direct_argument_keys)
25
+ keys.inject({}) { |memo, key|
26
+ memo.store(key, @session.user_input(key))
27
+ memo
28
+ }
29
+ end
30
+ end
31
+ def direct_argument_keys
32
+ end
33
+ def direct_request?(event)
34
+ requested_event(event) == direct_event
35
+ end
36
+ def requested_event(event)
37
+ if(args = direct_arguments)
38
+ [ event, args ]
39
+ else
40
+ event
41
+ end
42
+ end
43
+ def trigger(event)
44
+ if(direct_request?(event))
45
+ self
46
+ else
47
+ super
48
+ end
49
+ end
50
+ def user_input(*args)
51
+ data = super
52
+ data.each { |key, val|
53
+ if(val.is_a?(String))
54
+ data.store(key, val.empty? ? nil : u(val))
55
+ end
56
+ }
57
+ data
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env ruby
2
+ # Html::State::History -- bbmb.ch -- 03.10.2006 -- hwyss@ywesee.com
3
+
4
+ require 'bbmb/html/state/global'
5
+ require 'bbmb/html/view/history'
6
+
7
+ module BBMB
8
+ module Html
9
+ module State
10
+ class History < Global
11
+ VIEW = View::History
12
+ class PositionFacade
13
+ attr_reader :quantity, :total
14
+ def initialize
15
+ @positions = []
16
+ @quantity = 0
17
+ @prices = []
18
+ @total = 0
19
+ end
20
+ def add(position)
21
+ @positions.push(position)
22
+ @quantity += position.quantity
23
+ @prices.push(position.price)
24
+ @total = position.total + @total
25
+ end
26
+ def order_count
27
+ @positions.size
28
+ end
29
+ def price_extremes
30
+ [@prices.min, @prices.max]
31
+ end
32
+ def respond_to?(key)
33
+ super || @positions.last.respond_to?(key)
34
+ end
35
+ def method_missing(key, *args, &block)
36
+ @positions.last.send(key, *args, &block)
37
+ end
38
+ end
39
+ class HistoryFacade
40
+ include Enumerable
41
+ attr_accessor :sorted
42
+ def initialize
43
+ @map = {}
44
+ @positions = []
45
+ end
46
+ def add(order)
47
+ order.each { |position|
48
+ add_position(position)
49
+ }
50
+ end
51
+ def add_position(position)
52
+ key = position.article_number
53
+ pos = @map.fetch(key) {
54
+ pos = @map.store(key, PositionFacade.new)
55
+ @positions = @map.values
56
+ pos
57
+ }
58
+ pos.add(position)
59
+ end
60
+ def each(&block)
61
+ @positions.each(&block)
62
+ end
63
+ def empty?
64
+ @positions.empty?
65
+ end
66
+ def reverse!
67
+ @positions.reverse!
68
+ end
69
+ def sort!(*args, &block)
70
+ @positions.sort!(*args, &block)
71
+ end
72
+ def turnover
73
+ @positions.inject(0) { |inj, position|
74
+ position.total + inj
75
+ }
76
+ end
77
+ end
78
+ def init
79
+ @model = HistoryFacade.new
80
+ if(@customer = _customer)
81
+ @customer.orders.sort_by { |order| order.commit_time }.each { |order|
82
+ @model.add(order)
83
+ }
84
+ end
85
+ end
86
+ def direct_argument_keys
87
+ [:customer_id]
88
+ end
89
+ def direct_event
90
+ [:history, {:customer_id => @customer.customer_id}]
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ # Html::State::Info -- bbmb.ch -- 30.11.2006 -- hwyss@ywesee.com
3
+
4
+ require 'bbmb/html/state/global'
5
+ require 'bbmb/html/view/info'
6
+ require 'ostruct'
7
+
8
+ module BBMB
9
+ module Html
10
+ module State
11
+ class Info < Global
12
+ VIEW = Html::View::Info
13
+ def init
14
+ model = OpenStruct.new
15
+ model.event = @model[:event]
16
+ model.message = @model[:message]
17
+ @model = model
18
+ super
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # Html::State::Json -- bbmb.ch -- 26.09.2006 -- hwyss@ywesee.com
3
+
4
+ require 'bbmb/html/view/json'
5
+ require 'sbsm/state'
6
+
7
+ module BBMB
8
+ module Html
9
+ module State
10
+ class Json < SBSM::State
11
+ VIEW = View::Json
12
+ VOLATILE = true
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env ruby
2
+ # Html::State::Login -- bbmb.ch -- 15.09.2006 -- hwyss@ywesee.com
3
+
4
+ require 'bbmb/html/state/info'
5
+ require 'bbmb/html/state/viral/admin'
6
+ require 'bbmb/html/state/viral/customer'
7
+ require 'bbmb/html/view/login'
8
+ require 'bbmb/util/mail'
9
+ require 'sbsm/state'
10
+ require 'yus/session'
11
+
12
+ module BBMB
13
+ module Html
14
+ module State
15
+ class Login < SBSM::State
16
+ VIEW = View::Login
17
+ def login
18
+ reconsider_permissions(@session.login)
19
+ trigger(:home)
20
+ rescue Yus::UnknownEntityError
21
+ @errors.store(:email, create_error(:e_authentication_error, :email, nil))
22
+ self
23
+ rescue Yus::AuthenticationError
24
+ @errors.store(:pass, create_error(:e_authentication_error, :pass, nil))
25
+ self
26
+ end
27
+ def home
28
+ self
29
+ end
30
+ def request_access
31
+ lnf = @session.lookandfeel
32
+ if(lnf.enabled?(:request_access, false))
33
+ keys = [ :firstname, :lastname, :organisation, :address1, :plz, :city,
34
+ :phone_business, :email, :customer_id, ]
35
+ input = user_input(keys, keys)
36
+ if(error?)
37
+ @errors.clear
38
+ @errors.store(:all, create_error(:e_need_all_fields, :all, nil))
39
+ self
40
+ else
41
+ body = <<-EOS
42
+ Vorname: #{input[:firstname]}
43
+ Name: #{input[:lastname]}
44
+ Tierarztpraxis: #{input[:organisation]}
45
+ Strasse / Nr.: #{input[:address1]}
46
+ PLZ: #{input[:plz]}
47
+ Ort: #{input[:city]}
48
+ Tel. Praxis: #{input[:phone_business]}
49
+ E-Mail Adresse: #{input[:email]}
50
+ TVS/Virbac-Nr: #{input[:customer_id]}
51
+ EOS
52
+ BBMB::Util::Mail.send_request(input[:email], input[:organisation], body)
53
+ Info.new(@session, :message => :request_sent, :event => :logout)
54
+ end
55
+ end
56
+ end
57
+ private
58
+ def reconsider_permissions(user)
59
+ viral_modules(user) { |mod|
60
+ self.extend(mod)
61
+ }
62
+ end
63
+ def viral_modules(user)
64
+ [
65
+ ['.Admin', State::Viral::Admin],
66
+ ['.Customer', State::Viral::Customer],
67
+ ].each { |key, mod|
68
+ if(user.allowed?("login", BBMB.config.auth_domain + key))
69
+ yield mod
70
+ end
71
+ }
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ # Html::State::Order -- bbmb.ch -- 27.09.2006 -- hwyss@ywesee.com
3
+
4
+ require 'bbmb/html/state/global'
5
+ require 'bbmb/html/view/order'
6
+
7
+ module BBMB
8
+ module Html
9
+ module State
10
+ class Order < Global
11
+ VIEW = View::Order
12
+ def direct_argument_keys
13
+ [:order_id]
14
+ end
15
+ def direct_event
16
+ [:order, {:order_id => @model.order_id}]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ # Html::State::Orders -- bbmb.ch -- 27.09.2006 -- hwyss@ywesee.com
3
+
4
+ require 'bbmb/html/state/global'
5
+ require 'bbmb/html/view/orders'
6
+
7
+ module BBMB
8
+ module Html
9
+ module State
10
+ class Orders < Global
11
+ DIRECT_EVENT = :orders
12
+ VIEW = View::Orders
13
+ def init
14
+ @model = _customer.orders
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+ # Html::State::Result -- bbmb.ch -- 21.09.2006 -- hwyss@ywesee.com
3
+
4
+ require 'bbmb/html/state/global'
5
+ require 'bbmb/html/view/result'
6
+
7
+ module BBMB
8
+ module Html
9
+ module State
10
+ class Result < Global
11
+ class Result
12
+ include Enumerable
13
+ attr_reader :order, :products
14
+ def initialize(order, products)
15
+ @order, @products = order, products
16
+ end
17
+ def each(&block)
18
+ @products.each(&block)
19
+ end
20
+ def empty?
21
+ @products.empty?
22
+ end
23
+ def ordered_quantity(article_number)
24
+ @order.quantity(article_number)
25
+ end
26
+ def quota(article_id)
27
+ @order.quota(article_id)
28
+ end
29
+ def reverse!
30
+ @products.reverse!
31
+ end
32
+ def size
33
+ @products.size
34
+ end
35
+ def sort_by(&block)
36
+ @products = @products.sort_by(&block)
37
+ self
38
+ end
39
+ def sort!(*args, &block)
40
+ @products.sort!(*args, &block)
41
+ end
42
+ end
43
+ VIEW = View::Result
44
+ def init
45
+ @query = @session.persistent_user_input(:query)
46
+ products = Model::Product.search_by_description(@query)
47
+ unless(@session.lookandfeel.enabled? :free_products, false)
48
+ products = products.select { |product| product.price }
49
+ end
50
+ @model = Result.new _order, products
51
+ end
52
+ def direct_argument_keys
53
+ [:query]
54
+ end
55
+ def direct_event
56
+ [:search, {:query => @query}]
57
+ end
58
+ def _order
59
+ _customer.current_order
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end