shoppe 0.0.15 → 0.0.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (199) hide show
  1. data/README.rdoc +1 -0
  2. data/Rakefile +21 -1
  3. data/app/assets/javascripts/shoppe/application.coffee +5 -0
  4. data/app/assets/stylesheets/shoppe/application.scss +16 -3
  5. data/app/assets/stylesheets/shoppe/elements.scss +8 -0
  6. data/app/assets/stylesheets/shoppe/printable.scss +67 -0
  7. data/app/controllers/shoppe/application_controller.rb +1 -10
  8. data/app/controllers/shoppe/orders_controller.rb +4 -0
  9. data/app/controllers/shoppe/sessions_controller.rb +1 -0
  10. data/app/controllers/shoppe/settings_controller.rb +12 -0
  11. data/app/controllers/shoppe/users_controller.rb +2 -2
  12. data/app/controllers/shoppe/variants_controller.rb +1 -1
  13. data/app/helpers/shoppe/application_helper.rb +63 -8
  14. data/app/mailers/shoppe/order_mailer.rb +5 -7
  15. data/app/mailers/shoppe/user_mailer.rb +2 -2
  16. data/app/models/shoppe/country.rb +17 -1
  17. data/app/models/shoppe/delivery_service.rb +15 -0
  18. data/app/models/shoppe/delivery_service_price.rb +17 -0
  19. data/app/models/shoppe/order.rb +82 -9
  20. data/app/models/shoppe/order_item.rb +18 -0
  21. data/app/models/shoppe/product.rb +26 -1
  22. data/app/models/shoppe/product/product_attributes.rb +1 -1
  23. data/app/models/shoppe/product/variants.rb +3 -3
  24. data/app/models/shoppe/product_attribute.rb +15 -0
  25. data/app/models/shoppe/product_category.rb +12 -0
  26. data/app/models/shoppe/setting.rb +59 -0
  27. data/app/models/shoppe/stock_level_adjustment.rb +15 -0
  28. data/app/models/shoppe/tax_rate.rb +13 -1
  29. data/app/models/shoppe/user.rb +13 -0
  30. data/app/views/layouts/shoppe/application.html.haml +2 -1
  31. data/app/views/layouts/shoppe/printable.html.haml +11 -0
  32. data/app/views/shoppe/delivery_service_prices/index.html.haml +1 -1
  33. data/app/views/shoppe/order_mailer/accepted.text.erb +2 -2
  34. data/app/views/shoppe/order_mailer/received.text.erb +2 -2
  35. data/app/views/shoppe/order_mailer/rejected.text.erb +2 -2
  36. data/app/views/shoppe/order_mailer/shipped.text.erb +2 -2
  37. data/app/views/shoppe/orders/despatch_note.html.haml +45 -0
  38. data/app/views/shoppe/orders/index.html.haml +2 -2
  39. data/app/views/shoppe/orders/show.html.haml +21 -11
  40. data/app/views/shoppe/settings/edit.html.haml +19 -0
  41. data/app/views/shoppe/user_mailer/new_password.text.erb +1 -1
  42. data/app/views/shoppe/variants/form.html.haml +4 -0
  43. data/config/locales/en.yml +34 -0
  44. data/config/routes.rb +5 -0
  45. data/db/migrate/20130926094549_create_shoppe_initial_schema.rb +92 -33
  46. data/db/seeds.rb +1 -1
  47. data/lib/shoppe.rb +13 -35
  48. data/lib/shoppe/engine.rb +6 -6
  49. data/lib/shoppe/settings.rb +28 -0
  50. data/lib/shoppe/settings_loader.rb +16 -0
  51. data/lib/shoppe/setup_generator.rb +0 -4
  52. data/lib/shoppe/version.rb +1 -1
  53. data/test/{dummy → app}/README.rdoc +0 -0
  54. data/test/{dummy → app}/Rakefile +0 -0
  55. data/test/{dummy → app}/app/assets/javascripts/application.js +0 -0
  56. data/test/{dummy → app}/app/assets/stylesheets/application.css +0 -0
  57. data/test/{dummy → app}/app/controllers/application_controller.rb +0 -0
  58. data/test/{dummy → app}/app/helpers/application_helper.rb +0 -0
  59. data/test/{dummy → app}/app/views/layouts/application.html.erb +0 -0
  60. data/test/{dummy → app}/bin/bundle +0 -0
  61. data/test/{dummy → app}/bin/rails +0 -0
  62. data/test/{dummy → app}/bin/rake +0 -0
  63. data/test/{dummy → app}/config.ru +0 -0
  64. data/test/{dummy → app}/config/application.rb +0 -0
  65. data/test/{dummy → app}/config/boot.rb +0 -0
  66. data/test/app/config/database.example.yml +30 -0
  67. data/test/{dummy → app}/config/database.yml +9 -5
  68. data/test/{dummy → app}/config/environment.rb +0 -0
  69. data/test/{dummy → app}/config/environments/development.rb +0 -0
  70. data/test/{dummy → app}/config/environments/production.rb +0 -0
  71. data/test/{dummy → app}/config/environments/test.rb +0 -0
  72. data/test/{dummy → app}/config/initializers/backtrace_silencers.rb +0 -0
  73. data/test/{dummy → app}/config/initializers/filter_parameter_logging.rb +0 -0
  74. data/test/{dummy → app}/config/initializers/inflections.rb +0 -0
  75. data/test/{dummy → app}/config/initializers/mime_types.rb +0 -0
  76. data/test/{dummy → app}/config/initializers/secret_token.rb +0 -0
  77. data/test/app/config/initializers/session_store.rb +3 -0
  78. data/test/{dummy → app}/config/initializers/wrap_parameters.rb +0 -0
  79. data/test/{dummy → app}/config/locales/en.yml +0 -0
  80. data/test/{dummy → app}/config/routes.rb +0 -0
  81. data/{config/shoppe.example.yml → test/app/config/shoppe.yml} +0 -0
  82. data/test/{dummy → app}/db/development.sqlite3 +0 -0
  83. data/test/{dummy → app}/db/migrate/20131017165217_create_nifty_attachments_table.rb +0 -0
  84. data/test/{dummy → app}/db/migrate/20131017165222_create_nifty_key_value_store_table.rb +0 -0
  85. data/test/{dummy → app}/db/schema.rb +31 -16
  86. data/test/{dummy → app}/db/test.sqlite3 +0 -0
  87. data/test/app/log/development.log +8093 -0
  88. data/test/{dummy → app}/log/test.log +0 -0
  89. data/test/{dummy → app}/public/404.html +0 -0
  90. data/test/{dummy → app}/public/422.html +0 -0
  91. data/test/{dummy → app}/public/500.html +0 -0
  92. data/test/{dummy → app}/public/favicon.ico +0 -0
  93. data/test/app/tmp/cache/assets/development/sass/7c98994848dbb534749f971b176724aa382339bb/dialog.scssc +0 -0
  94. data/test/app/tmp/cache/assets/development/sass/edac894564dae62b78e653a08d1c41f10ade93f9/application.scssc +0 -0
  95. data/test/app/tmp/cache/assets/development/sass/edac894564dae62b78e653a08d1c41f10ade93f9/dialog.scssc +0 -0
  96. data/test/app/tmp/cache/assets/development/sass/edac894564dae62b78e653a08d1c41f10ade93f9/elements.scssc +0 -0
  97. data/test/app/tmp/cache/assets/development/sass/edac894564dae62b78e653a08d1c41f10ade93f9/reset.scssc +0 -0
  98. data/test/app/tmp/cache/assets/development/sass/edac894564dae62b78e653a08d1c41f10ade93f9/sub.scssc +0 -0
  99. data/test/app/tmp/cache/assets/development/sass/edac894564dae62b78e653a08d1c41f10ade93f9/variables.scssc +0 -0
  100. data/test/app/tmp/cache/assets/development/sprockets/06d540cec125e08e63a898c35e8235d6 +0 -0
  101. data/test/app/tmp/cache/assets/development/sprockets/0a6bca3e510625f255083bd154cc470b +0 -0
  102. data/test/app/tmp/cache/assets/development/sprockets/0d8942b2279b6bc7c68b3db3e2e4c342 +0 -0
  103. data/test/app/tmp/cache/assets/development/sprockets/122a65fdcbb923c3c1cd95549ef52f43 +0 -0
  104. data/test/app/tmp/cache/assets/development/sprockets/140840b7aefa4bf5beda2c32e20374a6 +0 -0
  105. data/test/app/tmp/cache/assets/development/sprockets/160ddfa6141944c4a03757fe91643137 +0 -0
  106. data/test/app/tmp/cache/assets/development/sprockets/1bb0d399b6b81fc3b47ff794b066873f +0 -0
  107. data/test/app/tmp/cache/assets/development/sprockets/1e1679158bd397a720be46fa3a5876a3 +0 -0
  108. data/test/app/tmp/cache/assets/development/sprockets/2a75ba35f8e751887ba89a914363fefd +0 -0
  109. data/test/app/tmp/cache/assets/development/sprockets/2cc6ef740b5691af5ee246c0dbc68f14 +0 -0
  110. data/test/app/tmp/cache/assets/development/sprockets/2f80004fb2e2ce07283a83ac15cf920a +0 -0
  111. data/test/app/tmp/cache/assets/development/sprockets/322295abdd8625fcce4da08f9565cc63 +0 -0
  112. data/test/app/tmp/cache/assets/development/sprockets/421b79f445cd87f3532a5c445877cbec +0 -0
  113. data/test/app/tmp/cache/assets/development/sprockets/4528fe4a109cad1ff031659cd9eeae17 +0 -0
  114. data/test/app/tmp/cache/assets/development/sprockets/45a9c7dfe9986570daa4c972277375ec +0 -0
  115. data/test/app/tmp/cache/assets/development/sprockets/48b2cd7153bbc442eaa84c3e24e963e0 +0 -0
  116. data/test/app/tmp/cache/assets/development/sprockets/4c3fef5a3e293ed6b6df3d869f54e1d1 +0 -0
  117. data/test/app/tmp/cache/assets/development/sprockets/4c8cb5cfd87990ebddbaa5b5fd594be5 +0 -0
  118. data/test/app/tmp/cache/assets/development/sprockets/4cefa37a52d669d3ca7e6aa1e1aaf435 +0 -0
  119. data/test/app/tmp/cache/assets/development/sprockets/4ea4f5c13aaeda9a7d39684ab72fa710 +0 -0
  120. data/test/app/tmp/cache/assets/development/sprockets/4ecd1cb66cb36718daadcfba0aa42c1e +0 -0
  121. data/test/app/tmp/cache/assets/development/sprockets/4ed3cbd180c275b98627eaeea4c9c838 +0 -0
  122. data/test/app/tmp/cache/assets/development/sprockets/519aa2b3c3ab8fd8f065c56507111878 +0 -0
  123. data/test/app/tmp/cache/assets/development/sprockets/51d409a48872319ac6a731aa880e6368 +0 -0
  124. data/test/app/tmp/cache/assets/development/sprockets/55bae604bcb5ccf7d9e0ed0fd61953b6 +0 -0
  125. data/test/app/tmp/cache/assets/development/sprockets/5805d2c402f412642d86ec03a7ec4a3d +0 -0
  126. data/test/app/tmp/cache/assets/development/sprockets/5cd772b44cdeae4d3b37b62193e946eb +0 -0
  127. data/test/app/tmp/cache/assets/development/sprockets/5f32b259cbcc52156d2fe21c185d9390 +0 -0
  128. data/test/app/tmp/cache/assets/development/sprockets/656ea3403f27a33b86d5bf9e8a0c0e46 +0 -0
  129. data/test/app/tmp/cache/assets/development/sprockets/679705affe2ad274da1ad48cb5137c21 +0 -0
  130. data/test/app/tmp/cache/assets/development/sprockets/69a687de4cbb95365bf8aa2037d63726 +0 -0
  131. data/test/app/tmp/cache/assets/development/sprockets/69d5224a79e874431294e8adf04e7d65 +0 -0
  132. data/test/app/tmp/cache/assets/development/sprockets/6bc5a76ff13bc4daebb7e164a4b64196 +0 -0
  133. data/test/app/tmp/cache/assets/development/sprockets/6c1a5456c2e5d87285dd1910762fe01e +0 -0
  134. data/test/app/tmp/cache/assets/development/sprockets/6d52ff2c9298014f2d648eb9e04a61a6 +0 -0
  135. data/test/app/tmp/cache/assets/development/sprockets/7938636d16e11b754d4dd046b89863c4 +0 -0
  136. data/test/app/tmp/cache/assets/development/sprockets/7ce7981501e05438faa017eb2e197379 +0 -0
  137. data/test/app/tmp/cache/assets/development/sprockets/7e232a7b4ac10fe1350e2b9b05ab0b02 +0 -0
  138. data/test/app/tmp/cache/assets/development/sprockets/81d7800826e89041f377af8570b8324f +0 -0
  139. data/test/app/tmp/cache/assets/development/sprockets/81f524fed55fe63e95c1aeccb5d83571 +0 -0
  140. data/test/app/tmp/cache/assets/development/sprockets/85984636ee801f63af86b35d7697d4c5 +0 -0
  141. data/test/app/tmp/cache/assets/development/sprockets/88de2cf8ce5990c5fa59f7c9f4599a65 +0 -0
  142. data/test/app/tmp/cache/assets/development/sprockets/8932a78ffe18ad2e3bb7ceb90ac4b933 +0 -0
  143. data/test/app/tmp/cache/assets/development/sprockets/8d6fd863923e78438318b02bf83be1c4 +0 -0
  144. data/test/app/tmp/cache/assets/development/sprockets/8f43db1e57a90ffbae3be00a895d5a09 +0 -0
  145. data/test/app/tmp/cache/assets/development/sprockets/91e11940ab63a407af03d21720ac2951 +0 -0
  146. data/test/app/tmp/cache/assets/development/sprockets/938abfdc262a8ab42e768545640bfb2a +0 -0
  147. data/test/app/tmp/cache/assets/development/sprockets/9e760b9565b110e433b7e42f827cb5f8 +0 -0
  148. data/test/app/tmp/cache/assets/development/sprockets/9e8fbfd56e8ef705ba94bb03b5b3696e +0 -0
  149. data/test/app/tmp/cache/assets/development/sprockets/9ebbf73fb48cdf8bc07a8bfdd6d14328 +0 -0
  150. data/test/app/tmp/cache/assets/development/sprockets/9f240d481b0818a6da0b1a1aaaac2b54 +0 -0
  151. data/test/app/tmp/cache/assets/development/sprockets/a2b956b30a80f996b5aeb1b2f226775c +0 -0
  152. data/test/app/tmp/cache/assets/development/sprockets/a5b5ed9849e8019160b73aa554132b37 +0 -0
  153. data/test/app/tmp/cache/assets/development/sprockets/a692ba7ed6cff183bb840c2622233c87 +0 -0
  154. data/test/app/tmp/cache/assets/development/sprockets/a951f4ceb83ae691f002b4f6183bc1ed +0 -0
  155. data/test/app/tmp/cache/assets/development/sprockets/accc4dc17ef18d0b510917a005340da5 +0 -0
  156. data/test/app/tmp/cache/assets/development/sprockets/b2db166e9974feb35358e7fcce87cb39 +0 -0
  157. data/test/app/tmp/cache/assets/development/sprockets/b519a4f6c5b5a0d9236bdca14e0eb00d +0 -0
  158. data/test/app/tmp/cache/assets/development/sprockets/b5cbeb3def40b118469fff2d80c1b596 +0 -0
  159. data/test/app/tmp/cache/assets/development/sprockets/b6f65271a0e77b349529ce9148dd2782 +0 -0
  160. data/test/app/tmp/cache/assets/development/sprockets/b9ad7ea18b7e55c3626a15d1dae142ed +0 -0
  161. data/test/app/tmp/cache/assets/development/sprockets/bc384ea2fdcc667aa4282209caba921f +0 -0
  162. data/test/app/tmp/cache/assets/development/sprockets/bcf06bf434bb3d3a5769036d6e24b301 +0 -0
  163. data/test/app/tmp/cache/assets/development/sprockets/bd83357635155d3457747e92e47da0ed +0 -0
  164. data/test/app/tmp/cache/assets/development/sprockets/c39634555e4eba3595350eeea648ddf4 +0 -0
  165. data/test/app/tmp/cache/assets/development/sprockets/c3ef336ca8f7e64969d8bfdcf837ad10 +0 -0
  166. data/test/app/tmp/cache/assets/development/sprockets/c55037904a95162828e5d0b087677878 +0 -0
  167. data/test/app/tmp/cache/assets/development/sprockets/c733f1a2fe9d05a3a634ff64a394f64b +0 -0
  168. data/test/app/tmp/cache/assets/development/sprockets/c83a337688a52890ba93372fea6ec932 +0 -0
  169. data/test/app/tmp/cache/assets/development/sprockets/ca92d0dbc43c066af9b31f2bc26d038d +0 -0
  170. data/test/app/tmp/cache/assets/development/sprockets/cae2fc80bfbc81ec7b6c11a72be18c98 +0 -0
  171. data/test/app/tmp/cache/assets/development/sprockets/cd665363677ffcef0dde972284e8d942 +0 -0
  172. data/test/app/tmp/cache/assets/development/sprockets/d5154a1eda9cfbfe54e091d6ead1ac5f +0 -0
  173. data/test/app/tmp/cache/assets/development/sprockets/daa7fa7a610bc5951cc3c4403f290eb6 +0 -0
  174. data/test/app/tmp/cache/assets/development/sprockets/dabc0e94bc1e37007351ac756dd2dd6a +0 -0
  175. data/test/app/tmp/cache/assets/development/sprockets/edf3c55a27678996371bffe56298925b +0 -0
  176. data/test/app/tmp/cache/assets/development/sprockets/f0f04c3b2b0091fa3ca4a1edacc23a1c +0 -0
  177. data/test/app/tmp/cache/assets/development/sprockets/f8610737fbfdcb85db95ae7c6a70514e +0 -0
  178. data/test/app/tmp/restart.txt +0 -0
  179. data/test/shoppe_test.rb +0 -5
  180. data/test/test_helper.rb +1 -1
  181. metadata +298 -98
  182. data/app/helpers/shoppe/shoppe_helper.rb +0 -30
  183. data/db/migrate/20131012123829_create_shoppe_product_attributes.rb +0 -11
  184. data/db/migrate/20131012163301_add_public_boolean_to_product_attributes.rb +0 -5
  185. data/db/migrate/20131013123937_add_cost_prices_to_various_objects.rb +0 -8
  186. data/db/migrate/20131013131658_add_stock_control_boolean_to_products.rb +0 -5
  187. data/db/migrate/20131017144430_create_shoppe_stock_level_adjustments.rb +0 -18
  188. data/db/migrate/20131017180920_create_shoppe_countries.rb +0 -16
  189. data/db/migrate/20131017183211_create_shoppe_tax_rates.rb +0 -26
  190. data/db/migrate/20131020204719_add_countries_to_tax_rates_and_delivery_prices.rb +0 -6
  191. data/db/migrate/20131021135208_add_notes_to_orders.rb +0 -5
  192. data/db/migrate/20131022090919_refactor_order_items_to_allow_any_product.rb +0 -6
  193. data/db/migrate/20131022092904_rename_product_title_to_name.rb +0 -5
  194. data/db/migrate/20131022093538_stock_level_adjustments_should_be_polymorphic.rb +0 -6
  195. data/db/migrate/20131022135331_add_parent_id_to_products.rb +0 -5
  196. data/db/migrate/20131022145653_cost_price_should_be_default_to_zero.rb +0 -9
  197. data/test/dummy/config/initializers/session_store.rb +0 -3
  198. data/test/dummy/config/shoppe.yml +0 -7
  199. data/test/dummy/log/development.log +0 -1162
@@ -1,3 +1,20 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: shoppe_delivery_service_prices
4
+ #
5
+ # id :integer not null, primary key
6
+ # delivery_service_id :integer
7
+ # code :string(255)
8
+ # price :decimal(8, 2)
9
+ # cost_price :decimal(8, 2)
10
+ # tax_rate_id :integer
11
+ # min_weight :decimal(8, 2)
12
+ # max_weight :decimal(8, 2)
13
+ # created_at :datetime
14
+ # updated_at :datetime
15
+ # country_ids :text
16
+ #
17
+
1
18
  module Shoppe
2
19
  class DeliveryServicePrice < ActiveRecord::Base
3
20
 
@@ -1,3 +1,50 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: shoppe_orders
4
+ #
5
+ # id :integer not null, primary key
6
+ # token :string(255)
7
+ # first_name :string(255)
8
+ # last_name :string(255)
9
+ # company :string(255)
10
+ # billing_address1 :string(255)
11
+ # billing_address2 :string(255)
12
+ # billing_address3 :string(255)
13
+ # billing_address4 :string(255)
14
+ # billing_postcode :string(255)
15
+ # billing_country_id :integer
16
+ # email_address :string(255)
17
+ # phone_number :string(255)
18
+ # status :string(255)
19
+ # received_at :datetime
20
+ # accepted_at :datetime
21
+ # shipped_at :datetime
22
+ # created_at :datetime
23
+ # updated_at :datetime
24
+ # delivery_service_id :integer
25
+ # delivery_price :decimal(8, 2)
26
+ # delivery_cost_price :decimal(8, 2)
27
+ # delivery_tax_rate :decimal(8, 2)
28
+ # delivery_tax_amount :decimal(8, 2)
29
+ # paid_at :datetime
30
+ # accepted_by :integer
31
+ # shipped_by :integer
32
+ # consignment_number :string(255)
33
+ # rejected_at :datetime
34
+ # rejected_by :integer
35
+ # ip_address :string(255)
36
+ # payment_reference :string(255)
37
+ # payment_method :string(255)
38
+ # notes :text
39
+ # separate_delivery_address :boolean default(FALSE)
40
+ # delivery_address1 :string(255)
41
+ # delivery_address2 :string(255)
42
+ # delivery_address3 :string(255)
43
+ # delivery_address4 :string(255)
44
+ # deilvery_postcode :string(255)
45
+ # delivery_country_id :integer
46
+ #
47
+
1
48
  module Shoppe
2
49
  class Order < ActiveRecord::Base
3
50
 
@@ -17,7 +64,8 @@ module Shoppe
17
64
 
18
65
  # Relationships
19
66
  belongs_to :delivery_service, :class_name => 'Shoppe::DeliveryService'
20
- belongs_to :country, :class_name => 'Shoppe::Country'
67
+ belongs_to :billing_country, :class_name => 'Shoppe::Country', :foreign_key => 'billing_country_id'
68
+ belongs_to :delivery_country, :class_name => 'Shoppe::Country', :foreign_key => 'delivery_country_id'
21
69
  belongs_to :accepter, :class_name => 'Shoppe::User', :foreign_key => 'accepted_by'
22
70
  belongs_to :rejecter, :class_name => 'Shoppe::User', :foreign_key => 'rejected_by'
23
71
  belongs_to :shipper, :class_name => 'Shoppe::User', :foreign_key => 'shipped_by'
@@ -30,14 +78,23 @@ module Shoppe
30
78
  with_options :if => Proc.new { |o| !o.building? } do |order|
31
79
  order.validates :first_name, :presence => true
32
80
  order.validates :last_name, :presence => true
33
- order.validates :address1, :presence => true
34
- order.validates :address3, :presence => true
35
- order.validates :address4, :presence => true
36
- order.validates :postcode, :presence => true
37
- order.validates :country, :presence => true
81
+ order.validates :billing_address1, :presence => true
82
+ order.validates :billing_address3, :presence => true
83
+ order.validates :billing_address4, :presence => true
84
+ order.validates :billing_postcode, :presence => true
85
+ order.validates :billing_country, :presence => true
38
86
  order.validates :email_address, :format => {:with => /\A\b[A-Z0-9\.\_\%\-\+]+@(?:[A-Z0-9\-]+\.)+[A-Z]{2,6}\b\z/i}
39
87
  order.validates :phone_number, :format => {:with => /\A[\d\ \-x\(\)]{7,}\z/}
40
88
  end
89
+ with_options :if => :separate_delivery_address? do |order|
90
+ order.validates :delivery_name, :presence => true
91
+ order.validates :delivery_address1, :presence => true
92
+ order.validates :delivery_address3, :presence => true
93
+ order.validates :delivery_address4, :presence => true
94
+ order.validates :delivery_postcode, :presence => true
95
+ order.validates :delivery_country, :presence => true
96
+ end
97
+
41
98
  validate do
42
99
  unless available_delivery_services.include?(self.delivery_service)
43
100
  errors.add :delivery_service_id, "is not suitable for this order"
@@ -54,6 +111,12 @@ module Shoppe
54
111
  self.status = 'building' if self.status.blank?
55
112
  self.token = SecureRandom.uuid if self.token.blank?
56
113
  end
114
+
115
+ [:delivery_name, :delivery_address1, :delivery_address2, :delivery_address3, :delivery_address4, :delivery_postcode, :delivery_country].each do |f|
116
+ define_method(f) do
117
+ separate_delivery_address? ? super() : send(f.to_s.gsub('delivery_', 'billing_'))
118
+ end
119
+ end
57
120
 
58
121
  # Is this order still being built by the user?
59
122
  def building?
@@ -99,7 +162,17 @@ module Shoppe
99
162
 
100
163
  # The name of the customer
101
164
  def customer_name
102
- company.blank? ? "#{first_name} #{last_name}" : "#{company} (#{first_name} #{last_name})"
165
+ company.blank? ? full_name : "#{company} (#{full_name})"
166
+ end
167
+
168
+ # The name for billing purposes
169
+ def billing_name
170
+ company.blank? ? full_name : "#{full_name} (#{company})"
171
+ end
172
+
173
+ # The full anme of the customer
174
+ def full_name
175
+ "#{first_name} #{last_name}"
103
176
  end
104
177
 
105
178
  # Is this order empty? (i.e. doesn't have any items associated with it)
@@ -161,7 +234,7 @@ module Shoppe
161
234
  def delivery_service_prices
162
235
  @delivery_service_prices ||= begin
163
236
  prices = Shoppe::DeliveryServicePrice.joins(:delivery_service).where(:shoppe_delivery_services => {:active => true}).order("`default` desc, price asc").for_weight(total_weight)
164
- prices = prices.select { |p| p.countries.empty? || p.country?(self.country) }
237
+ prices = prices.select { |p| p.countries.empty? || p.country?(self.billing_country) }
165
238
  prices
166
239
  end
167
240
  end
@@ -343,7 +416,7 @@ module Shoppe
343
416
 
344
417
  # Specify which attributes can be searched
345
418
  def self.ransackable_attributes(auth_object = nil)
346
- ["id", "postcode", "address1", "address2", "address3", "address4", "first_name", "last_name", "company", "email_address", "phone_number", "consignment_number", "status", "received_at"] + _ransackers.keys
419
+ ["id", "billing_postcode", "billing_address1", "billing_address2", "billing_address3", "billing_address4", "first_name", "last_name", "company", "email_address", "phone_number", "consignment_number", "status", "received_at"] + _ransackers.keys
347
420
  end
348
421
 
349
422
  # Specify which associations can be searched
@@ -1,3 +1,21 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: shoppe_order_items
4
+ #
5
+ # id :integer not null, primary key
6
+ # order_id :integer
7
+ # ordered_item_id :integer
8
+ # ordered_item_type :string(255)
9
+ # quantity :integer default(1)
10
+ # unit_price :decimal(8, 2)
11
+ # unit_cost_price :decimal(8, 2)
12
+ # tax_amount :decimal(8, 2)
13
+ # tax_rate :decimal(8, 2)
14
+ # weight :decimal(8, 3) default(0.0)
15
+ # created_at :datetime
16
+ # updated_at :datetime
17
+ #
18
+
1
19
  module Shoppe
2
20
  class OrderItem < ActiveRecord::Base
3
21
 
@@ -1,3 +1,28 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: shoppe_products
4
+ #
5
+ # id :integer not null, primary key
6
+ # parent_id :integer
7
+ # product_category_id :integer
8
+ # name :string(255)
9
+ # sku :string(255)
10
+ # permalink :string(255)
11
+ # description :text
12
+ # short_description :text
13
+ # active :boolean default(TRUE)
14
+ # weight :decimal(8, 3) default(0.0)
15
+ # price :decimal(8, 2) default(0.0)
16
+ # cost_price :decimal(8, 2) default(0.0)
17
+ # tax_rate_id :integer
18
+ # created_at :datetime
19
+ # updated_at :datetime
20
+ # featured :boolean default(FALSE)
21
+ # in_the_box :text
22
+ # stock_control :boolean default(TRUE)
23
+ # default :boolean default(FALSE)
24
+ #
25
+
1
26
  module Shoppe
2
27
  class Product < ActiveRecord::Base
3
28
 
@@ -38,7 +63,7 @@ module Shoppe
38
63
  # Scopes
39
64
  scope :active, -> { where(:active => true) }
40
65
  scope :featured, -> {where(:featured => true)}
41
- scope :ordered, -> {order('name asc')}
66
+ scope :ordered, -> {order('`default` desc, name asc')}
42
67
 
43
68
  # Return the name of the product
44
69
  def full_name
@@ -1,5 +1,5 @@
1
1
  module Shoppe
2
- class Product
2
+ class Product < ActiveRecord::Base
3
3
 
4
4
  # Relationships
5
5
  has_many :product_attributes, -> { order(:position) }, :class_name => 'Shoppe::ProductAttribute'
@@ -1,8 +1,8 @@
1
1
  module Shoppe
2
- class Product
2
+ class Product < ActiveRecord::Base
3
3
 
4
4
  # Relationships
5
- has_many :variants, :class_name => 'Shoppe::Product', :foreign_key => 'parent_id', :dependent => :destroy
5
+ has_many :variants, -> { order("`default` desc, name asc")}, :class_name => 'Shoppe::Product', :foreign_key => 'parent_id', :dependent => :destroy
6
6
  belongs_to :parent, :class_name => 'Shoppe::Product', :foreign_key => 'parent_id'
7
7
 
8
8
  # Validations
@@ -19,7 +19,7 @@ module Shoppe
19
19
 
20
20
  def default_variant
21
21
  return nil if self.parent
22
- @default_variant ||= self.variants.first
22
+ @default_variant ||= self.variants.select { |v| v.default? }.first
23
23
  end
24
24
 
25
25
  end
@@ -1,3 +1,18 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: shoppe_product_attributes
4
+ #
5
+ # id :integer not null, primary key
6
+ # product_id :integer
7
+ # key :string(255)
8
+ # value :string(255)
9
+ # position :integer default(1)
10
+ # searchable :boolean default(TRUE)
11
+ # created_at :datetime
12
+ # updated_at :datetime
13
+ # public :boolean default(TRUE)
14
+ #
15
+
1
16
  module Shoppe
2
17
  class ProductAttribute < ActiveRecord::Base
3
18
 
@@ -1,3 +1,15 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: shoppe_product_categories
4
+ #
5
+ # id :integer not null, primary key
6
+ # name :string(255)
7
+ # permalink :string(255)
8
+ # description :text
9
+ # created_at :datetime
10
+ # updated_at :datetime
11
+ #
12
+
1
13
  module Shoppe
2
14
  class ProductCategory < ActiveRecord::Base
3
15
 
@@ -0,0 +1,59 @@
1
+ require 'ostruct'
2
+
3
+ module Shoppe
4
+ class Setting < ActiveRecord::Base
5
+
6
+ validates :key, :presence => true, :uniqueness => true
7
+ validates :value, :presence => true
8
+ validates :value_type, :presence => true
9
+
10
+ before_validation do
11
+ self.value_type = I18n.t("shoppe.settings.types")[self.key.to_sym].try(:capitalize) || self.value.class.to_s
12
+ self.value = encoded_value
13
+ end
14
+
15
+ # The encoded value for saving in the backend (as a string)
16
+ def encoded_value
17
+ case value_type
18
+ when 'Array', 'Hash' then value.to_json
19
+ when 'Boolean' then value.to_s == 'true' ? 'true' : 'false'
20
+ else value.to_s
21
+ end
22
+ end
23
+
24
+ # The decoded value for the setting attribute (in it's native type)
25
+ def decoded_value
26
+ case value_type
27
+ when 'Fixnum' then value.to_i
28
+ when 'Float' then value.to_f
29
+ when 'Array', 'Hash' then JSON.parse(value)
30
+ when 'Boolean' then value == 'true' ? true : false
31
+ else value.to_s
32
+ end
33
+ end
34
+
35
+ # A full hash of all settings available in the current scope
36
+ def self.to_hash
37
+ all.inject({}) do |h, setting|
38
+ h[setting.key.to_s] = setting.decoded_value
39
+ h
40
+ end
41
+ end
42
+
43
+ # Update settings from a given hash and persist them. Accepts a
44
+ # hash of keys (which should be strings).
45
+ def self.update_from_hash(hash)
46
+ existing_settings = self.all.to_a
47
+ hash.each do |key, value|
48
+ existing = existing_settings.select { |s| s.key.to_s == key.to_s }.first
49
+ if existing
50
+ value.blank? ? existing.destroy! : existing.update!(:value => value)
51
+ else
52
+ value.blank? ? nil : self.create!(:key => key, :value => value)
53
+ end
54
+ end
55
+ hash
56
+ end
57
+
58
+ end
59
+ end
@@ -1,3 +1,18 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: shoppe_stock_level_adjustments
4
+ #
5
+ # id :integer not null, primary key
6
+ # item_id :integer
7
+ # item_type :string(255)
8
+ # description :string(255)
9
+ # adjustment :integer default(0)
10
+ # parent_type :string(255)
11
+ # parent_id :integer
12
+ # created_at :datetime
13
+ # updated_at :datetime
14
+ #
15
+
1
16
  module Shoppe
2
17
  class StockLevelAdjustment < ActiveRecord::Base
3
18
 
@@ -1,3 +1,15 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: shoppe_tax_rates
4
+ #
5
+ # id :integer not null, primary key
6
+ # name :string(255)
7
+ # rate :decimal(8, 2)
8
+ # created_at :datetime
9
+ # updated_at :datetime
10
+ # country_ids :text
11
+ #
12
+
1
13
  module Shoppe
2
14
  class TaxRate < ActiveRecord::Base
3
15
 
@@ -23,7 +35,7 @@ module Shoppe
23
35
  end
24
36
 
25
37
  def rate_for(order)
26
- if countries.empty? || order.country.nil? || country?(order.country)
38
+ if countries.empty? || order.billing_country.nil? || country?(order.billing_country)
27
39
  self.rate
28
40
  else
29
41
  0.0
@@ -1,3 +1,16 @@
1
+ # == Schema Information
2
+ #
3
+ # Table name: shoppe_users
4
+ #
5
+ # id :integer not null, primary key
6
+ # first_name :string(255)
7
+ # last_name :string(255)
8
+ # email_address :string(255)
9
+ # password_digest :string(255)
10
+ # created_at :datetime
11
+ # updated_at :datetime
12
+ #
13
+
1
14
  module Shoppe
2
15
  class User < ActiveRecord::Base
3
16
 
@@ -21,6 +21,7 @@
21
21
  %li= link_to "Delivery Services", [:delivery_services], :class => @active_nav == :delivery_services ? 'active' : ''
22
22
  %li= link_to "Tax Rates", :tax_rates, :class => @active_nav == :tax_rates ? 'active' : ''
23
23
  %li= link_to "Users", [:users], :class => @active_nav == :users ? 'active' : ''
24
+ %li= link_to "Settings", :settings, :class => @active_nav == :settings ? 'active' : ''
24
25
  %li= link_to "Logout", [:logout], :method => :delete
25
26
 
26
27
  %header.main
@@ -32,5 +33,5 @@
32
33
  = yield
33
34
 
34
35
  %footer
35
- %p.store= link_to "Goto Storefront", '/'
36
+ %p.store= link_to "&larr; Goto #{Shoppe.settings.store_name}".html_safe, '/'
36
37
 
@@ -0,0 +1,11 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title= @page_title
5
+ = stylesheet_link_tag 'shoppe/printable', :media => :all
6
+ :javascript
7
+ window.print();
8
+ %body
9
+ #content
10
+ = yield
11
+
@@ -17,6 +17,6 @@
17
17
  - for price in @delivery_service_prices
18
18
  %tr
19
19
  %td= link_to number_to_currency(price.price), [:edit, @delivery_service, price]
20
- %td #{price.min_weight}kg &rarr; #{price.max_weight}kg
20
+ %td #{number_to_weight price.min_weight} &rarr; #{number_to_weight price.max_weight}
21
21
  %td= price.code
22
22
 
@@ -8,5 +8,5 @@ We will e-mail you again when we ship your order from our warehouse.
8
8
 
9
9
  Many thanks,
10
10
 
11
- <%=Shoppe.config[:store_name]%>
12
- <%=Shoppe.config[:email_address]%>
11
+ <%=Shoppe.settings.store_name%>
12
+ <%=Shoppe.settings.email_address%>