tienda 1.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 (193) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +35 -0
  4. data/app/assets/images/tienda/chosen-sprite.png +0 -0
  5. data/app/assets/images/tienda/chosen-sprite@2x.png +0 -0
  6. data/app/assets/images/tienda/document.svg +1 -0
  7. data/app/assets/images/tienda/icons/bag.svg +1 -0
  8. data/app/assets/images/tienda/icons/balance.svg +1 -0
  9. data/app/assets/images/tienda/icons/box.svg +1 -0
  10. data/app/assets/images/tienda/icons/building.svg +1 -0
  11. data/app/assets/images/tienda/icons/chart.svg +1 -0
  12. data/app/assets/images/tienda/icons/chat.svg +1 -0
  13. data/app/assets/images/tienda/icons/checkbox.svg +1 -0
  14. data/app/assets/images/tienda/icons/checkbox2.svg +1 -0
  15. data/app/assets/images/tienda/icons/cloud.svg +1 -0
  16. data/app/assets/images/tienda/icons/cone.svg +1 -0
  17. data/app/assets/images/tienda/icons/credit_card.svg +1 -0
  18. data/app/assets/images/tienda/icons/currency.svg +1 -0
  19. data/app/assets/images/tienda/icons/edit.svg +14 -0
  20. data/app/assets/images/tienda/icons/flowchart.svg +1 -0
  21. data/app/assets/images/tienda/icons/gift.svg +1 -0
  22. data/app/assets/images/tienda/icons/globe.svg +1 -0
  23. data/app/assets/images/tienda/icons/id.svg +1 -0
  24. data/app/assets/images/tienda/icons/id2.svg +1 -0
  25. data/app/assets/images/tienda/icons/locked.svg +1 -0
  26. data/app/assets/images/tienda/icons/report.svg +1 -0
  27. data/app/assets/images/tienda/icons/search.svg +1 -0
  28. data/app/assets/images/tienda/icons/support.svg +1 -0
  29. data/app/assets/images/tienda/icons/tags.svg +1 -0
  30. data/app/assets/images/tienda/icons/toolbox.svg +1 -0
  31. data/app/assets/images/tienda/icons/unlocked.svg +1 -0
  32. data/app/assets/images/tienda/icons/wallet.svg +1 -0
  33. data/app/assets/images/tienda/logo.svg +47 -0
  34. data/app/assets/images/tienda/move.svg +1 -0
  35. data/app/assets/images/tienda/shoppe.svg +25 -0
  36. data/app/assets/images/tienda/square.svg +9 -0
  37. data/app/assets/images/tienda/statuses/accepted.svg +14 -0
  38. data/app/assets/images/tienda/statuses/paid.svg +16 -0
  39. data/app/assets/images/tienda/statuses/received.svg +15 -0
  40. data/app/assets/images/tienda/statuses/rejected.svg +14 -0
  41. data/app/assets/images/tienda/statuses/shipped.svg +14 -0
  42. data/app/assets/images/tienda/table-tear-off.png +0 -0
  43. data/app/assets/javascripts/tienda/application.coffee +119 -0
  44. data/app/assets/javascripts/tienda/chosen.jquery.js +1166 -0
  45. data/app/assets/javascripts/tienda/jquery_ui.js +6 -0
  46. data/app/assets/javascripts/tienda/mousetrap.js +9 -0
  47. data/app/assets/javascripts/tienda/order_form.coffee +47 -0
  48. data/app/assets/stylesheets/tienda/application.scss +585 -0
  49. data/app/assets/stylesheets/tienda/chosen.scss +424 -0
  50. data/app/assets/stylesheets/tienda/dialog.scss +25 -0
  51. data/app/assets/stylesheets/tienda/elements.scss +79 -0
  52. data/app/assets/stylesheets/tienda/printable.scss +67 -0
  53. data/app/assets/stylesheets/tienda/reset.scss +93 -0
  54. data/app/assets/stylesheets/tienda/sub.scss +106 -0
  55. data/app/assets/stylesheets/tienda/variables.scss +1 -0
  56. data/app/controllers/tienda/application_controller.rb +46 -0
  57. data/app/controllers/tienda/attachments_controller.rb +14 -0
  58. data/app/controllers/tienda/countries_controller.rb +47 -0
  59. data/app/controllers/tienda/dashboard_controller.rb +9 -0
  60. data/app/controllers/tienda/delivery_service_prices_controller.rb +45 -0
  61. data/app/controllers/tienda/delivery_services_controller.rb +47 -0
  62. data/app/controllers/tienda/orders_controller.rb +90 -0
  63. data/app/controllers/tienda/payments_controller.rb +33 -0
  64. data/app/controllers/tienda/product_categories_controller.rb +47 -0
  65. data/app/controllers/tienda/products_controller.rb +58 -0
  66. data/app/controllers/tienda/sessions_controller.rb +34 -0
  67. data/app/controllers/tienda/settings_controller.rb +16 -0
  68. data/app/controllers/tienda/stock_level_adjustments_controller.rb +40 -0
  69. data/app/controllers/tienda/tax_rates_controller.rb +49 -0
  70. data/app/controllers/tienda/users_controller.rb +53 -0
  71. data/app/controllers/tienda/variants_controller.rb +50 -0
  72. data/app/helpers/tienda/application_helper.rb +60 -0
  73. data/app/mailers/tienda/order_mailer.rb +25 -0
  74. data/app/mailers/tienda/user_mailer.rb +10 -0
  75. data/app/models/tienda/country.rb +27 -0
  76. data/app/models/tienda/delivery_service.rb +33 -0
  77. data/app/models/tienda/delivery_service_price.rb +31 -0
  78. data/app/models/tienda/order/actions.rb +98 -0
  79. data/app/models/tienda/order/billing.rb +105 -0
  80. data/app/models/tienda/order/delivery.rb +229 -0
  81. data/app/models/tienda/order/states.rb +69 -0
  82. data/app/models/tienda/order.rb +93 -0
  83. data/app/models/tienda/order_item.rb +239 -0
  84. data/app/models/tienda/payment.rb +80 -0
  85. data/app/models/tienda/product/product_attributes.rb +20 -0
  86. data/app/models/tienda/product/variants.rb +51 -0
  87. data/app/models/tienda/product.rb +169 -0
  88. data/app/models/tienda/product_attribute.rb +66 -0
  89. data/app/models/tienda/product_category.rb +23 -0
  90. data/app/models/tienda/setting.rb +68 -0
  91. data/app/models/tienda/stock_level_adjustment.rb +19 -0
  92. data/app/models/tienda/tax_rate.rb +46 -0
  93. data/app/models/tienda/user.rb +49 -0
  94. data/app/validators/permalink_validator.rb +7 -0
  95. data/app/views/layouts/tienda/application.html.haml +34 -0
  96. data/app/views/layouts/tienda/printable.html.haml +11 -0
  97. data/app/views/layouts/tienda/sub.html.haml +10 -0
  98. data/app/views/tienda/countries/_form.html.haml +35 -0
  99. data/app/views/tienda/countries/edit.html.haml +6 -0
  100. data/app/views/tienda/countries/index.html.haml +25 -0
  101. data/app/views/tienda/countries/new.html.haml +7 -0
  102. data/app/views/tienda/delivery_service_prices/_form.html.haml +44 -0
  103. data/app/views/tienda/delivery_service_prices/edit.html.haml +6 -0
  104. data/app/views/tienda/delivery_service_prices/index.html.haml +23 -0
  105. data/app/views/tienda/delivery_service_prices/new.html.haml +6 -0
  106. data/app/views/tienda/delivery_services/_form.html.haml +38 -0
  107. data/app/views/tienda/delivery_services/edit.html.haml +9 -0
  108. data/app/views/tienda/delivery_services/index.html.haml +27 -0
  109. data/app/views/tienda/delivery_services/new.html.haml +6 -0
  110. data/app/views/tienda/order_mailer/accepted.text.erb +12 -0
  111. data/app/views/tienda/order_mailer/received.text.erb +12 -0
  112. data/app/views/tienda/order_mailer/rejected.text.erb +10 -0
  113. data/app/views/tienda/order_mailer/shipped.text.erb +16 -0
  114. data/app/views/tienda/orders/_form.html.haml +55 -0
  115. data/app/views/tienda/orders/_order_details.html.haml +57 -0
  116. data/app/views/tienda/orders/_order_items.html.haml +38 -0
  117. data/app/views/tienda/orders/_order_items_form.html.haml +61 -0
  118. data/app/views/tienda/orders/_payments_form.html.haml +15 -0
  119. data/app/views/tienda/orders/_payments_table.html.haml +37 -0
  120. data/app/views/tienda/orders/_search_form.html.haml +24 -0
  121. data/app/views/tienda/orders/_status_bar.html.haml +35 -0
  122. data/app/views/tienda/orders/despatch_note.html.haml +45 -0
  123. data/app/views/tienda/orders/edit.html.haml +21 -0
  124. data/app/views/tienda/orders/index.html.haml +39 -0
  125. data/app/views/tienda/orders/new.html.haml +14 -0
  126. data/app/views/tienda/orders/show.html.haml +25 -0
  127. data/app/views/tienda/payments/refund.html.haml +13 -0
  128. data/app/views/tienda/product_categories/_form.html.haml +26 -0
  129. data/app/views/tienda/product_categories/edit.html.haml +6 -0
  130. data/app/views/tienda/product_categories/index.html.haml +19 -0
  131. data/app/views/tienda/product_categories/new.html.haml +6 -0
  132. data/app/views/tienda/products/_form.html.haml +118 -0
  133. data/app/views/tienda/products/_table.html.haml +42 -0
  134. data/app/views/tienda/products/edit.html.haml +8 -0
  135. data/app/views/tienda/products/import.html.haml +63 -0
  136. data/app/views/tienda/products/index.html.haml +9 -0
  137. data/app/views/tienda/products/new.html.haml +7 -0
  138. data/app/views/tienda/sessions/new.html.haml +12 -0
  139. data/app/views/tienda/sessions/reset.html.haml +12 -0
  140. data/app/views/tienda/settings/edit.html.haml +19 -0
  141. data/app/views/tienda/shared/error.html.haml +6 -0
  142. data/app/views/tienda/stock_level_adjustments/index.html.haml +40 -0
  143. data/app/views/tienda/tax_rates/form.html.haml +28 -0
  144. data/app/views/tienda/tax_rates/index.html.haml +17 -0
  145. data/app/views/tienda/user_mailer/new_password.text.erb +9 -0
  146. data/app/views/tienda/users/_form.html.haml +27 -0
  147. data/app/views/tienda/users/edit.html.haml +5 -0
  148. data/app/views/tienda/users/index.html.haml +17 -0
  149. data/app/views/tienda/users/new.html.haml +7 -0
  150. data/app/views/tienda/variants/form.html.haml +66 -0
  151. data/app/views/tienda/variants/index.html.haml +33 -0
  152. data/config/locales/en.yml +650 -0
  153. data/config/locales/pl.yml +650 -0
  154. data/config/locales/pt-BR.yml +643 -0
  155. data/config/routes.rb +42 -0
  156. data/db/countries.txt +252 -0
  157. data/db/migrate/20150124094549_create_tienda_initial_schema.rb +184 -0
  158. data/db/seeds.rb +128 -0
  159. data/db/seeds_data/poe400.jpg +0 -0
  160. data/db/seeds_data/snom-870-blk.jpg +0 -0
  161. data/db/seeds_data/snom-870-grey.jpg +0 -0
  162. data/db/seeds_data/snom-mm2.jpg +0 -0
  163. data/db/seeds_data/spa303.jpg +0 -0
  164. data/db/seeds_data/t18p.jpg +0 -0
  165. data/db/seeds_data/t20p.jpg +0 -0
  166. data/db/seeds_data/t22p.jpg +0 -0
  167. data/db/seeds_data/t26p.jpg +0 -0
  168. data/db/seeds_data/t41pn.jpg +0 -0
  169. data/db/seeds_data/t46gn.jpg +0 -0
  170. data/db/seeds_data/w52p.jpg +0 -0
  171. data/db/seeds_data/yhs32.jpg +0 -0
  172. data/lib/tasks/tienda.rake +29 -0
  173. data/lib/tienda/associated_countries.rb +20 -0
  174. data/lib/tienda/country_importer.rb +14 -0
  175. data/lib/tienda/default_navigation.rb +20 -0
  176. data/lib/tienda/engine.rb +48 -0
  177. data/lib/tienda/error.rb +21 -0
  178. data/lib/tienda/errors/inappropriate_delivery_service.rb +6 -0
  179. data/lib/tienda/errors/insufficient_stock_to_fulfil.rb +15 -0
  180. data/lib/tienda/errors/invalid_configuration.rb +6 -0
  181. data/lib/tienda/errors/not_enough_stock.rb +15 -0
  182. data/lib/tienda/errors/payment_declined.rb +6 -0
  183. data/lib/tienda/errors/refund_failed.rb +6 -0
  184. data/lib/tienda/errors/unorderable_item.rb +6 -0
  185. data/lib/tienda/navigation_manager.rb +81 -0
  186. data/lib/tienda/orderable_item.rb +39 -0
  187. data/lib/tienda/settings.rb +26 -0
  188. data/lib/tienda/settings_loader.rb +16 -0
  189. data/lib/tienda/setup_generator.rb +10 -0
  190. data/lib/tienda/version.rb +3 -0
  191. data/lib/tienda/view_helpers.rb +16 -0
  192. data/lib/tienda.rb +59 -0
  193. metadata +604 -0
@@ -0,0 +1,20 @@
1
+ require 'tienda/navigation_manager'
2
+
3
+ # This file defines all the default navigation managers used in Tienda. Of course,
4
+ # modules can make changes to these by removing them or adding their own. This
5
+ # file is loaded on application initialization so if you make changes, you'll need
6
+ # to restart the webserver.
7
+
8
+ #
9
+ # This is the default navigation manager for the admin interface.
10
+ #
11
+ Tienda::NavigationManager.build(:admin_primary) do
12
+ add_item :orders
13
+ add_item :products
14
+ add_item :product_categories
15
+ add_item :delivery_services
16
+ add_item :tax_rates
17
+ add_item :users
18
+ add_item :countries
19
+ add_item :settings
20
+ end
@@ -0,0 +1,48 @@
1
+ module Tienda
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Tienda
4
+
5
+ if Tienda.respond_to?(:root)
6
+ config.autoload_paths << File.join(Tienda.root, 'lib')
7
+ config.assets.precompile += ['tienda/sub.css', 'tienda/printable.css']
8
+ end
9
+
10
+ # We don't want any automatic generators in the engine.
11
+ config.generators do |g|
12
+ g.orm :active_record
13
+ g.test_framework false
14
+ g.stylesheets false
15
+ g.javascripts false
16
+ g.helper false
17
+ end
18
+
19
+ initializer 'tienda.initialize' do |app|
20
+ # Add the default settings
21
+ Tienda.add_settings_group :system_settings, [:store_name, :email_address, :currency_unit, :tax_name, :demo_mode]
22
+
23
+ # Add middleware
24
+ app.config.middleware.use Tienda::SettingsLoader
25
+
26
+ # Load our migrations into the application's db/migrate path
27
+ unless app.root.to_s.match root.to_s
28
+ config.paths["db/migrate"].expanded.each do |expanded_path|
29
+ app.config.paths["db/migrate"] << expanded_path
30
+ end
31
+ end
32
+
33
+ # Load view helpers for the base application
34
+ ActiveSupport.on_load(:action_view) do
35
+ require 'tienda/view_helpers'
36
+ ActionView::Base.send :include, Tienda::ViewHelpers
37
+ end
38
+
39
+ # Load default navigation
40
+ require 'tienda/default_navigation'
41
+ end
42
+
43
+ generators do
44
+ require 'tienda/setup_generator'
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,21 @@
1
+ module Tienda
2
+ class Error < StandardError
3
+
4
+ def initialize(options = {})
5
+ if options.is_a?(String)
6
+ @options = {:message => options}
7
+ else
8
+ @options = options
9
+ end
10
+ end
11
+
12
+ def message
13
+ @options[:message]
14
+ end
15
+
16
+ def options
17
+ @options
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,6 @@
1
+ module Tienda
2
+ module Errors
3
+ class InappropriateDeliveryService < Error
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,15 @@
1
+ module Tienda
2
+ module Errors
3
+ class InsufficientStockToFulfil < Error
4
+
5
+ def order
6
+ @options[:order]
7
+ end
8
+
9
+ def out_of_stock_items
10
+ @options[:out_of_stock_items]
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ module Tienda
2
+ module Errors
3
+ class InvalidConfiguration < Error
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,15 @@
1
+ module Tienda
2
+ module Errors
3
+ class NotEnoughStock < Error
4
+
5
+ def available_stock
6
+ @options[:ordered_item].stock
7
+ end
8
+
9
+ def requested_stock
10
+ @options[:requested_stock]
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ module Tienda
2
+ module Errors
3
+ class PaymentDeclined < Tienda::Error
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Tienda
2
+ module Errors
3
+ class RefundFailed < Error
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Tienda
2
+ module Errors
3
+ class UnorderableItem < Error
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,81 @@
1
+ module Tienda
2
+ class NavigationManager
3
+
4
+ def self.managers
5
+ @managers ||= []
6
+ end
7
+
8
+ def self.create(identifier)
9
+ managers << self.new(identifier.to_s)
10
+ end
11
+
12
+ def self.build(identifier, &block)
13
+ manager = self.new(identifier.to_s)
14
+ manager.instance_eval(&block) if block_given?
15
+ managers << manager
16
+ end
17
+
18
+ def self.find(identifier)
19
+ managers.select { |m| m.identifier == identifier.to_s }.first
20
+ end
21
+
22
+ def self.render(identifier)
23
+ find(identifier).try(:to_html)
24
+ end
25
+
26
+ attr_reader :identifier
27
+
28
+ def initialize(identifier)
29
+ @identifier = identifier
30
+ end
31
+
32
+ def items
33
+ @items ||= []
34
+ end
35
+
36
+ def add_item(identifier, options = {}, &block)
37
+ item = NavigationItem.new
38
+ item.manager = self
39
+ item.identifier = identifier.to_s
40
+ item.url = options[:url] if options[:url]
41
+ item.link_options = options[:link_options] if options[:link_options]
42
+ item.active_if = block if block_given?
43
+ items << item
44
+ end
45
+
46
+ def remove_item(identifier)
47
+ items.remote_if { |i| i.identifier.to_s == identifier.to_s }
48
+ end
49
+
50
+ class NavigationItem
51
+ attr_accessor :manager
52
+ attr_accessor :identifier
53
+ attr_accessor :url
54
+ attr_accessor :link_options
55
+ attr_accessor :active_if
56
+
57
+ def description
58
+ I18n.translate("tienda.navigation.#{manager.identifier}.#{identifier}")
59
+ end
60
+
61
+ def url(request = nil)
62
+ (@url.is_a?(Proc) && request && request.instance_eval(&@url) ) ||
63
+ @url ||
64
+ Tienda::Engine.routes.url_helpers.send("#{identifier}_path")
65
+ end
66
+
67
+ def active?(request)
68
+ if active_if.is_a?(Proc)
69
+ request.instance_eval(&active_if) == true
70
+ elsif active_nav_var = request.instance_variable_get('@active_nav')
71
+ active_nav_var.to_s == identifier
72
+ end
73
+ end
74
+
75
+ def link_options
76
+ @link_options ||= {}
77
+ end
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,39 @@
1
+ module Tienda
2
+ # All items which can be ordered should include this module and ensure that all methods
3
+ # have been overridden. It's a lazy-mans protocol.
4
+ module OrderableItem
5
+
6
+ # stock_level_adjustments must be an association
7
+
8
+ def full_name
9
+ end
10
+
11
+ def orderable?
12
+ end
13
+
14
+ def sku
15
+ end
16
+
17
+ def price
18
+ end
19
+
20
+ def cost_price
21
+ end
22
+
23
+ def tax_rate
24
+ end
25
+
26
+ def stock_control?
27
+ end
28
+
29
+ def in_stock?
30
+ end
31
+
32
+ def stock
33
+ end
34
+
35
+ def weight
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ module Tienda
2
+ class Settings
3
+
4
+ def initialize(hash)
5
+ @hash = hash
6
+ end
7
+
8
+ def outbound_email_address
9
+ "#{store_name} <#{email_address}>"
10
+ end
11
+
12
+ def method_missing(key, _ = nil)
13
+ key = key.to_s.gsub(/\?\z/, '')
14
+ if value = @hash[key.to_s]
15
+ value
16
+ elsif I18n.translate("tienda.settings.defaults").keys.include?(key.to_sym)
17
+ I18n.translate("tienda.settings.defaults")[key.to_sym]
18
+ end
19
+ end
20
+
21
+ def [](value)
22
+ @hash[value]
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,16 @@
1
+ module Tienda
2
+ class SettingsLoader
3
+
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ Tienda.reset_settings
10
+ @app.call(env)
11
+ ensure
12
+ Tienda.reset_settings
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ require 'rails/generators'
2
+ module Tienda
3
+ class SetupGenerator < Rails::Generators::Base
4
+
5
+ def create_route
6
+ route 'mount Tienda::Engine => "/tienda"'
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module Tienda
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,16 @@
1
+ module Tienda
2
+ module ViewHelpers
3
+
4
+ # Returns currency values with the currency unit as specified by the Tienda settings
5
+ def number_to_currency(number, options = {})
6
+ options[:unit] ||= Tienda.settings.currency_unit
7
+ super
8
+ end
9
+
10
+ # Returns a number of kilograms with the appropriate suffix
11
+ def number_to_weight(kg)
12
+ "#{kg}#{t('tienda.helpers.number_to_weight.kg', :default => 'kg')}"
13
+ end
14
+
15
+ end
16
+ end
data/lib/tienda.rb ADDED
@@ -0,0 +1,59 @@
1
+ require "coffee-rails"
2
+ require "sass-rails"
3
+ require "jquery-rails"
4
+ require 'haml'
5
+ require 'bcrypt'
6
+ require 'dynamic_form'
7
+ require 'kaminari'
8
+ require 'ransack'
9
+
10
+ require 'nifty/utils'
11
+ require 'nifty/key_value_store'
12
+ require 'nifty/attachments'
13
+ require 'nifty/dialog'
14
+
15
+ module Tienda
16
+ class << self
17
+
18
+ # The path to the root of the Tienda applicatinio
19
+ #
20
+ # @return [String]
21
+ def root
22
+ File.expand_path('../../', __FILE__)
23
+ end
24
+
25
+ # Tienda settings as configured in the database
26
+ #
27
+ # @return [Tienda::Settings]
28
+ def settings
29
+ Thread.current[:tienda_settings] ||= Tienda::Settings.new(Tienda::Setting.to_hash)
30
+ end
31
+
32
+ # Clears the settings from the thread cache so they will be taken
33
+ # from the database on next access
34
+ #
35
+ # @return [NilClass]
36
+ def reset_settings
37
+ Thread.current[:tienda_settings] = nil
38
+ end
39
+
40
+ # Defines a new set of settings which should be configrable from the settings page
41
+ # in the Tienda UI.
42
+ def add_settings_group(group, fields = [])
43
+ settings_groups[group] ||= []
44
+ settings_groups[group] = settings_groups[group] | fields
45
+ end
46
+
47
+ # All settings groups which are available for configuration on the settings page.
48
+ #
49
+ # @return [Hash]
50
+ def settings_groups
51
+ @settings_groups ||= {}
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+ # Start your engines.
59
+ require "tienda/engine"