stall 0.1.1 → 0.1.2

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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +45 -0
  3. data/app/assets/javascripts/stall.coffee +2 -0
  4. data/app/assets/javascripts/stall/cart-form.coffee +23 -0
  5. data/app/controllers/stall/application_controller.rb +10 -2
  6. data/app/controllers/stall/carts_controller.rb +31 -10
  7. data/app/controllers/stall/checkout/steps_controller.rb +36 -4
  8. data/app/controllers/stall/checkouts_controller.rb +12 -3
  9. data/app/controllers/stall/line_items_controller.rb +3 -3
  10. data/app/controllers/stall/payments_controller.rb +5 -3
  11. data/app/helpers/stall/add_to_cart_helper.rb +1 -1
  12. data/app/helpers/stall/checkout_helper.rb +22 -2
  13. data/app/helpers/stall/payments_helper.rb +8 -0
  14. data/app/mailers/stall/admin_mailer.rb +11 -0
  15. data/app/mailers/stall/base_mailer.rb +17 -0
  16. data/app/mailers/stall/customer_mailer.rb +13 -0
  17. data/app/models/address.rb +3 -0
  18. data/app/models/address_ownership.rb +3 -0
  19. data/app/models/adjustment.rb +3 -0
  20. data/app/models/cart.rb +3 -0
  21. data/app/models/customer.rb +3 -0
  22. data/app/models/line_item.rb +3 -0
  23. data/app/models/payment.rb +3 -0
  24. data/app/models/payment_method.rb +3 -0
  25. data/app/models/product_list.rb +3 -0
  26. data/app/models/shipment.rb +3 -0
  27. data/app/models/shipping_method.rb +3 -0
  28. data/app/models/stall/models.rb +4 -0
  29. data/app/models/stall/models/address.rb +45 -0
  30. data/app/models/stall/models/address_ownership.rb +26 -0
  31. data/app/models/stall/models/adjustment.rb +49 -0
  32. data/app/models/stall/models/cart.rb +37 -0
  33. data/app/models/stall/models/customer.rb +18 -0
  34. data/app/models/stall/models/line_item.rb +57 -0
  35. data/app/models/stall/models/payment.rb +33 -0
  36. data/app/models/stall/models/payment_method.rb +18 -0
  37. data/app/models/stall/models/product_list.rb +147 -0
  38. data/app/models/stall/models/shipment.rb +29 -0
  39. data/app/models/stall/models/shipping_method.rb +16 -0
  40. data/app/services/stall/add_to_cart_service.rb +11 -1
  41. data/app/services/stall/cart_update_service.rb +26 -0
  42. data/app/services/stall/payment_notification_service.rb +23 -9
  43. data/app/services/stall/shipping_fee_calculator_service.rb +13 -2
  44. data/app/views/checkout/steps/_informations.html.haml +3 -3
  45. data/app/views/checkout/steps/_payment.html.haml +25 -4
  46. data/app/views/checkout/steps/_payment_method.html.haml +1 -3
  47. data/app/views/checkout/steps/_payment_return.html.haml +6 -0
  48. data/app/views/checkout/steps/_shipping_method.html.haml +1 -1
  49. data/app/views/stall/admin_mailer/order_paid_email.html.haml +4 -0
  50. data/app/views/stall/carts/show.html.haml +36 -8
  51. data/app/views/stall/customer_mailer/order_paid_email.html.haml +8 -0
  52. data/app/views/stall/line_items/_added.html.haml +1 -1
  53. data/app/views/stall/shared/mailers/_address.html.haml +18 -0
  54. data/app/views/stall/shared/mailers/_cart.html.haml +114 -0
  55. data/config/locales/stall.fr.yml +90 -8
  56. data/db/migrate/20160304134849_change_all_json_columns_to_jsonb.rb +18 -0
  57. data/db/migrate/20160307142924_add_state_to_stall_addresses.rb +5 -0
  58. data/db/migrate/20160308142713_create_adjustments.rb +16 -0
  59. data/db/migrate/20160309165136_add_identifier_to_stall_product_lists.rb +5 -0
  60. data/db/migrate/20160316114649_add_data_to_stall_shipments.rb +5 -0
  61. data/db/migrate/20160317141632_add_state_to_stall_shipments.rb +5 -0
  62. data/db/migrate/20160629102943_add_active_to_stall_shipping_methods.rb +11 -0
  63. data/db/migrate/20160629104617_add_active_to_stall_payment_methods.rb +11 -0
  64. data/db/migrate/20160705110151_add_locale_to_stall_customers.rb +5 -0
  65. data/lib/generators/stall/checkout/step/templates/step.html.haml.erb +1 -1
  66. data/lib/generators/stall/checkout/step/templates/step.rb.erb +10 -2
  67. data/lib/generators/stall/checkout/wizard/templates/wizard.rb.erb +1 -1
  68. data/lib/generators/stall/install/templates/initializer.rb +85 -1
  69. data/lib/generators/stall/model/model_generator.rb +27 -0
  70. data/lib/generators/stall/service/service_generator.rb +39 -0
  71. data/lib/generators/stall/service/templates/service.rb.erb +16 -0
  72. data/lib/generators/stall/shipping/calculator/calculator_generator.rb +17 -0
  73. data/lib/generators/stall/shipping/calculator/templates/calculator.rb.erb +29 -0
  74. data/lib/stall.rb +4 -0
  75. data/lib/stall/addressable.rb +28 -2
  76. data/lib/stall/cart_helper.rb +84 -0
  77. data/lib/stall/carts_cleaner.rb +46 -0
  78. data/lib/stall/checkout.rb +2 -0
  79. data/lib/stall/checkout/informations_checkout_step.rb +3 -5
  80. data/lib/stall/checkout/payment_checkout_step.rb +3 -0
  81. data/lib/stall/checkout/payment_return_checkout_step.rb +11 -0
  82. data/lib/stall/checkout/shipping_method_checkout_step.rb +2 -1
  83. data/lib/stall/checkout/step.rb +47 -11
  84. data/lib/stall/checkout/step_form.rb +71 -0
  85. data/lib/stall/checkout/wizard.rb +15 -5
  86. data/lib/stall/config.rb +51 -0
  87. data/lib/stall/engine.rb +24 -2
  88. data/lib/stall/payable.rb +26 -0
  89. data/lib/stall/payments.rb +7 -3
  90. data/lib/stall/payments/config.rb +37 -0
  91. data/lib/stall/payments/fake_gateway_payment_notification.rb +34 -0
  92. data/lib/stall/payments/gateway.rb +19 -12
  93. data/lib/stall/payments/urls_config.rb +40 -0
  94. data/lib/stall/priceable.rb +7 -0
  95. data/lib/stall/rails/currency_helper.rb +1 -1
  96. data/lib/stall/routes.rb +17 -4
  97. data/lib/stall/sellable.rb +1 -2
  98. data/lib/stall/shipping.rb +3 -1
  99. data/lib/stall/shipping/calculator.rb +36 -3
  100. data/lib/stall/shipping/config.rb +17 -3
  101. data/lib/stall/shipping/country_weight_table_calculator.rb +1 -1
  102. data/lib/stall/shipping/free_shipping_calculator.rb +1 -1
  103. data/lib/stall/utils.rb +2 -2
  104. data/lib/stall/utils/config_dsl.rb +5 -1
  105. data/lib/stall/version.rb +1 -1
  106. data/lib/tasks/stall_tasks.rake +11 -0
  107. metadata +73 -15
  108. data/app/assets/javascripts/stall/application.js +0 -13
  109. data/app/assets/javascripts/stall/carts.js +0 -2
  110. data/app/helpers/stall/cart_helper.rb +0 -28
  111. data/app/models/stall/address.rb +0 -5
  112. data/app/models/stall/address_ownership.rb +0 -8
  113. data/app/models/stall/cart.rb +0 -31
  114. data/app/models/stall/customer.rb +0 -8
  115. data/app/models/stall/line_item.rb +0 -49
  116. data/app/models/stall/payment.rb +0 -14
  117. data/app/models/stall/payment_method.rb +0 -7
  118. data/app/models/stall/product_list.rb +0 -68
  119. data/app/models/stall/shipment.rb +0 -15
  120. data/app/models/stall/shipping_method.rb +0 -5
@@ -11,11 +11,16 @@ fr:
11
11
  success: "Votre panier a bien été mis à jour."
12
12
  error: "Votre panier n'a pu être mis à jour, merci de vérifier les champs."
13
13
  recap:
14
+ order_ref: "Commande n°%{ref}"
15
+ ordered_at: "Passée le %{at}"
16
+ subtotal: "Sous-total"
17
+ total_shipment_price: "Livraison"
14
18
  total_eot_price: "Prix total HT"
15
19
  total_vat: "Total TVA"
16
20
  total_price: "Prix total"
17
21
  update: "Mettre à jour le panier"
18
22
  validate: "Passer la commande"
23
+ paid_at: "Payée le %{at}"
19
24
 
20
25
  line_items:
21
26
  form:
@@ -29,6 +34,8 @@ fr:
29
34
  description: "Merci de vérifier que vous avez bien rempli la quantité avant d'ajouter le produit au panier."
30
35
 
31
36
  checkout:
37
+ shared:
38
+ not_checkoutable: "Aucun produit dans le panier, impossible de passer la commande."
32
39
  informations:
33
40
  title: "Vos informations"
34
41
  validate: "Valider mes adresses"
@@ -41,23 +48,72 @@ fr:
41
48
  validate: "Valider mon mode de paiement"
42
49
  payment:
43
50
  title: "Paiement"
51
+ error: |
52
+ Votre paiement n'a pas pu être pris en compte, vous pouvez réessayer
53
+ de payer avec le bouton : "Payer ma commande"
54
+ payment_return:
55
+ title: "Paiement effectué"
56
+ help: |
57
+ Votre paiement a bien été pris en compte et votre commande a été
58
+ validée. Celle-ci sera traitée dans les plus bref délais.
59
+ <br><br>
60
+ Un e-mail de confirmation vous a été envoyé.
61
+ <br><br>
62
+ Merci pour votre confiance !
63
+
64
+ back_to_shop: "Retour à la boutique"
44
65
 
45
66
  payments:
46
67
  gateway:
47
68
  pay: "Payer ma commande"
48
69
 
70
+ addresses:
71
+ civilities:
72
+ m: M.
73
+ mme: Mme.
74
+
75
+ mailers:
76
+ customer:
77
+ order_paid_email:
78
+ subject: "Le paiement de votre commande n°%{ref} a bien été effectué !"
79
+ intro: "Votre commande sera traitée dans les meilleurs délais."
80
+ admin:
81
+ order_paid_email:
82
+ subject: "Une nouvelle commande a été passée sur le site - %{ref}"
83
+
49
84
  activerecord:
85
+ enums:
86
+ shipment:
87
+ state:
88
+ pending: "En attente"
89
+ shipped: "Expédié"
90
+ payment:
91
+ state:
92
+ pending: "En attente"
93
+ shipped: "Payé"
94
+ models:
95
+ line_item: "Produit"
96
+ customer: "Client"
97
+ address: "Adresse"
98
+ cart: "Panier"
99
+ shipment: "Livraison"
100
+ payment: "Paiement"
50
101
  attributes:
51
- stall/line_item:
52
- name: "Produit"
53
- unit_price: "Prix unitaire"
54
- unit_eot_price: "Prix unitaire HT"
55
- price: "Prix"
56
- eot_price: "Prix HT"
102
+ line_item:
103
+ sellable: "Produit source"
104
+ name: "Nom du produit"
57
105
  quantity: "Quantité"
58
- stall/customer:
106
+ unit_eot_price: "Prix unitaire HT"
107
+ unit_price: "Prix unitaire TTC"
108
+ eot_price: "Prix total HT"
109
+ price: "Prix total TTC"
110
+ vat_rate: "Taux de TVA"
111
+ weight: "Poids"
112
+ customer:
59
113
  email: "Adresse e-mail"
60
- stall/address:
114
+ shipping_address: "Adresse de livraison"
115
+ billing_address: "Adresse de facturation"
116
+ address:
61
117
  civility: "Civilité"
62
118
  first_name: "Prénom"
63
119
  last_name: "Nom"
@@ -67,3 +123,29 @@ fr:
67
123
  city: "Ville"
68
124
  country: "Pays"
69
125
  phone: "Téléphone"
126
+ state: "État"
127
+ product_list:
128
+ reference: "Référence"
129
+ customer: "Client"
130
+ created_at: "Date"
131
+ line_items: "Produits"
132
+ cart:
133
+ state: "Étape du panier"
134
+ total_price: "Montant total"
135
+ payment: "Paiement"
136
+ shipment: "Livraison"
137
+ shipping_address: "Adresse de livraison"
138
+ billing_address: "Adresse de facturation"
139
+ shipment:
140
+ price: "Prix"
141
+ eot_price: "Prix HT"
142
+ vat_rate: "Taux de TVA"
143
+ sent_at: "Expédié le"
144
+ shipping_method: "Mode de livraison"
145
+ tracking_code: "Code de suivi"
146
+ state: "État"
147
+ payment:
148
+ payment_method: "Mode de paiement"
149
+ paid_at: "Payé le"
150
+ transaction_id: "Numéro de transaction"
151
+ state: "État"
@@ -0,0 +1,18 @@
1
+ # This allows to avoid SELECT DISTINCT errors where JSON field type would throw
2
+ # a PG::UndefinedFunction error
3
+ #
4
+ # See : https://github.com/activerecord-hackery/ransack/issues/453
5
+ #
6
+ class ChangeAllJsonColumnsToJsonb < ActiveRecord::Migration
7
+ def up
8
+ change_column :stall_line_items, :data, 'jsonb USING CAST(data AS jsonb)'
9
+ change_column :stall_payments, :data, 'jsonb USING CAST(data AS jsonb)'
10
+ change_column :stall_product_lists, :data, 'jsonb USING CAST(data AS jsonb)'
11
+ end
12
+
13
+ def down
14
+ change_column :stall_line_items, :data, 'json USING CAST(data AS json)'
15
+ change_column :stall_payments, :data, 'json USING CAST(data AS json)'
16
+ change_column :stall_product_lists, :data, 'json USING CAST(data AS json)'
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ class AddStateToStallAddresses < ActiveRecord::Migration
2
+ def change
3
+ add_column :stall_addresses, :state, :string
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ class CreateAdjustments < ActiveRecord::Migration
2
+ def change
3
+ create_table :stall_adjustments do |t|
4
+ t.string :name, null: false
5
+ t.monetize :eot_price, null: false, currency: { present: false }
6
+ t.monetize :price, null: false, currency: { present: false }
7
+ t.decimal :vat_rate, null: false
8
+ t.string :type
9
+ t.references :cart, index: true
10
+
11
+ t.timestamps null: false
12
+ end
13
+
14
+ add_foreign_key :stall_adjustments, :stall_product_lists, column: :cart_id
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ class AddIdentifierToStallProductLists < ActiveRecord::Migration
2
+ def change
3
+ add_column :stall_product_lists, :identifier, :string, null: false, default: 'default'
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddDataToStallShipments < ActiveRecord::Migration
2
+ def change
3
+ add_column :stall_shipments, :data, :jsonb
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddStateToStallShipments < ActiveRecord::Migration
2
+ def change
3
+ add_column :stall_shipments, :state, :integer, default: 0
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ class AddActiveToStallShippingMethods < ActiveRecord::Migration
2
+ def up
3
+ add_column :stall_shipping_methods, :active, :boolean, default: true
4
+
5
+ ShippingMethod.update_all(active: true)
6
+ end
7
+
8
+ def down
9
+ remove_column :stall_shipping_methods, :active
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ class AddActiveToStallPaymentMethods < ActiveRecord::Migration
2
+ def up
3
+ add_column :stall_payment_methods, :active, :boolean, default: true
4
+
5
+ PaymentMethod.update_all(active: true)
6
+ end
7
+
8
+ def down
9
+ remove_column :stall_payment_methods, :active
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ class AddLocaleToStallCustomers < ActiveRecord::Migration
2
+ def change
3
+ add_column :stall_customers, :locale, :string, default: I18n.default_locale
4
+ end
5
+ end
@@ -1,6 +1,6 @@
1
1
  %h1= t('stall.checkout.<%= base_file_name %>.title')
2
2
 
3
- = simple_form_for cart, as: :cart, url: step_path(cart) do |form|
3
+ = simple_form_for cart, as: :cart, url: step_path do |form|
4
4
 
5
5
  %button.btn.btn-primary{ type: 'submit' }
6
6
  = t('stall.checkout.<%= base_file_name %>.validate')
@@ -1,13 +1,21 @@
1
1
  class <%= class_name %> < Stall::Checkout::Step
2
+ # Declare your step validations here
3
+ # Those validations will be run against the cart object
4
+ #
5
+ # validations do
6
+ # validates :foo, presence: true
7
+ # end
8
+
2
9
  # Prepare the `cart` before showing your view
3
10
  #
4
11
  # def prepare
5
12
  # end
6
13
 
7
- # Process `params` here, defaults to updating the cart with `cart_params`
8
- # (params[:cart])
14
+ # Process `params` here, defaults to assigning the cart with `cart_params`
15
+ # (params[:cart]) to the cart, running the step validations
9
16
  #
10
17
  # def process
18
+ # save
11
19
  # end
12
20
 
13
21
  # Handle the case where the step should be skipped by returning true from
@@ -1,3 +1,3 @@
1
1
  class <%= class_name %> < Stall::Checkout::Wizard
2
- steps :informations, :shipping_method, :payment_method, :payment
2
+ steps :informations, :shipping_method, :payment_method, :payment, :payment_return
3
3
  end
@@ -1,4 +1,30 @@
1
1
  Stall.configure do |config|
2
+ # Store name used by the system when a human readable identifier for your
3
+ # store is needed, e.g. for payment gateways
4
+ #
5
+ config.store_name = "My stall (Change me in config/initializers/stall.rb)"
6
+
7
+ # Configure the admin e-mail to which order notifications will be sent
8
+ #
9
+ # Either set the `STALL_ADMIN_EMAIL` env var or use the below config.
10
+ #
11
+ # You can also set that param as a proc / lambda that will get the cart
12
+ # as argument, allowing you to dynamically define which e-mail to send
13
+ # notifications *to*
14
+ #
15
+ # config.admin_email = ENV['STALL_ADMIN_EMAIL']
16
+
17
+ # Configure the e-mail address used to send e-mails to customers for
18
+ # order notifications
19
+ #
20
+ # Either set the `STALL_SENDER_EMAIL` env var or use the below config
21
+ #
22
+ # You can also set that param as a proc / lambda that will get the cart
23
+ # as argument, allowing you to dynamically define which e-mail to send
24
+ # notifications *from*
25
+ #
26
+ # config.sender_email = ENV['STALL_SENDER_EMAIL']
27
+
2
28
  # Global default VAT rate, can be overrided by products
3
29
  #
4
30
  # config.vat_rate = BigDecimal.new('20.0')
@@ -11,6 +37,19 @@ Stall.configure do |config|
11
37
  #
12
38
  # config.application_controller_ancestor = '::ApplicationController'
13
39
 
40
+ # Set a layout to use in the checkouts controllers
41
+ #
42
+ # The default is set to nil, which will make the controllers inherit from the
43
+ # layout of the controller set in `config.application_controller_ancestor`
44
+ #
45
+ # config.default_layout = nil
46
+
47
+ # Defines the parent mailer for the Stall customer and admin mailers
48
+ #
49
+ # If commented out, ActionMailer::Base will be used
50
+ #
51
+ config.mailers_parent_class = 'ApplicationMailer'
52
+
14
53
  # Default currency used in the app for money objects.
15
54
  #
16
55
  # Note : If you need multi currency support in your app, you'll have to ensure
@@ -19,6 +58,15 @@ Stall.configure do |config|
19
58
  #
20
59
  # param :default_currency, 'EUR'
21
60
 
61
+ # Default app domain use for building URLs in payment gateway forms and in
62
+ # e-mails.
63
+ #
64
+ # Add the `APP_DOMAIN` environment variable, or modify the parameter below.
65
+ #
66
+ # Ex : 'localhost:3000', 'www.example.com'
67
+ #
68
+ # config.default_app_domain = ENV['APP_DOMAIN']
69
+
22
70
  # Defined the default checkout wizard used for checking carts out in the
23
71
  # shop process.
24
72
  #
@@ -39,12 +87,30 @@ Stall.configure do |config|
39
87
 
40
88
  # Allows configuring which countries are available for free shipping offers
41
89
  #
42
- # Accepts an array of country codes or a proc with a Stall::Address argument
90
+ # Accepts an array of country codes or a proc with an Address argument
43
91
  #
44
92
  # Defaults to nil, which means all countries are available
45
93
  #
46
94
  # config.shipping.free_shipping.available = nil
47
95
 
96
+ # Register custom shipping methods and calculators
97
+ #
98
+ # If no existing shipping method / calculator cover your needs, you can
99
+ # create one by subclassing Stall::Shipping::Calculator
100
+ #
101
+ # Read more at : https://github.com/rails-stall/stall/wiki/Shipping-methods
102
+ #
103
+ # config.shipping.register_calculator :my_calculator, 'MyCalculator'
104
+
105
+ # Register custom payment methods and gateways
106
+ #
107
+ # If no existing payment method / gateway cover your needs, you can
108
+ # create one by subclassing Stall::Payments::Gateway
109
+ #
110
+ # Read more at : https://github.com/rails-stall/stall/wiki/Payment-methods
111
+ #
112
+ # config.payment.register_gateway :my_gateway, 'MyGateway'
113
+
48
114
  # Allows hooking into checkout steps initialization in the steps controller
49
115
  # to inject dependencies to all or a specific step
50
116
  #
@@ -54,4 +120,22 @@ Stall.configure do |config|
54
120
  # # Only inject in the :some step :
55
121
  # step.inject(:ip, request.remote_ip) if SomeCheckoutStep === step
56
122
  # end
123
+
124
+ # Configure app services to override default Stall services and add
125
+ # functionalities to existing ones
126
+ #
127
+ # config.services = {
128
+ # payment_notification: 'PaymentNotificationService'
129
+ # }
130
+
131
+ # Delay before empty carts are cleaned with the `stall:carts:clean` task
132
+ #
133
+ # config.empty_carts_expires_after = 1.day
134
+
135
+ # Delay before aborted carts are cleaned with the `stall:carts:clean` task
136
+ #
137
+ # Aborted carts are controlled with a scope on the cart model. To change
138
+ # the `aborted` behavior, you can override the `.aborted` scope in your model.
139
+ #
140
+ # config.aborted_carts_expires_after = 14.days
57
141
  end
@@ -0,0 +1,27 @@
1
+ module Stall
2
+ class ModelGenerator < ::Rails::Generators::NamedBase
3
+ class ModelModelNotFound < StandardError; end
4
+
5
+ MODELS_DIR = File.expand_path('../../../../../app/models', __FILE__)
6
+ source_root MODELS_DIR
7
+
8
+ def copy_model_template
9
+ if File.exist?(source_path)
10
+ template source_path, "app/models/#{ file_path_with_ext }"
11
+ else
12
+ raise ModelModelNotFound,
13
+ "Could not find any stall model for #{ class_name }"
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def source_path
20
+ @source_path ||= File.join(MODELS_DIR, file_path_with_ext)
21
+ end
22
+
23
+ def file_path_with_ext
24
+ @file_path_with_ext ||= "#{ file_path }.rb"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,39 @@
1
+ module Stall
2
+ class ServiceGenerator < ::Rails::Generators::NamedBase
3
+ source_root File.expand_path('../templates', __FILE__)
4
+
5
+ def store_services_folder_existence
6
+ @services_folder_existed = File.exist?('app/services')
7
+ end
8
+
9
+ def copy_service_template
10
+ template 'service.rb.erb', "app/services/#{ service_file_path }.rb"
11
+ end
12
+
13
+ def post_template_message
14
+ puts "\n" +
15
+ "Service class generated. Please add the service to the " +
16
+ "`config.services` hash in your config/initializers/stall.rb file\n\n"
17
+
18
+ return if @services_folder_existed
19
+
20
+ puts " * Warning : app/services folder was just created, \n" +
21
+ " * please restart your server to let Rails know that it should\n" +
22
+ " * autoload this folder.\n\n"
23
+ end
24
+
25
+ private
26
+
27
+ def service_class_name
28
+ @service_class_name ||= service_file_path.camelize
29
+ end
30
+
31
+ def stall_service_class_name
32
+ @stall_service_class_name ||= ['Stall', service_class_name.demodulize].join('::')
33
+ end
34
+
35
+ def service_file_path
36
+ @service_file_path ||= [file_path.gsub(/service$/, ''), 'service'].join('_')
37
+ end
38
+ end
39
+ end