bbmb 2.0.0

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.
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