nimbleshop_core 0.0.1.rc1

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 (359) hide show
  1. data/README.md +13 -0
  2. data/Rakefile +15 -0
  3. data/app/assets/images/engines/nimbleshop_authorizedotnet/american_express.png +0 -0
  4. data/app/assets/images/engines/nimbleshop_authorizedotnet/authorize_net_big.png +0 -0
  5. data/app/assets/images/engines/nimbleshop_authorizedotnet/authorizedotnet_big.png +0 -0
  6. data/app/assets/images/engines/nimbleshop_authorizedotnet/discover.png +0 -0
  7. data/app/assets/images/engines/nimbleshop_authorizedotnet/mastercard.png +0 -0
  8. data/app/assets/images/engines/nimbleshop_authorizedotnet/visa.png +0 -0
  9. data/app/assets/images/engines/nimbleshop_cod/cod_small.png +0 -0
  10. data/app/assets/images/engines/nimbleshop_paypalwp/paypal_big.png +0 -0
  11. data/app/assets/images/engines/nimbleshop_paypalwp/paypal_small.png +0 -0
  12. data/app/assets/images/engines/nimbleshop_splitable/splitable.png +0 -0
  13. data/app/assets/images/engines/nimbleshop_splitable/splitable_big.png +0 -0
  14. data/app/assets/images/engines/nimbleshop_splitable/splitable_small.png +0 -0
  15. data/app/assets/javascripts/admin/products/edit.js.coffee +19 -0
  16. data/app/assets/javascripts/admin/shipping_methods/edit.js.coffee +6 -0
  17. data/app/assets/javascripts/admin.js +25 -0
  18. data/app/assets/javascripts/fadeout_success.js.coffee +2 -0
  19. data/app/assets/javascripts/payment_method.js.coffee +19 -0
  20. data/app/assets/javascripts/product-group-condition.js.coffee +33 -0
  21. data/app/assets/javascripts/remove_deletion_of_product_pictures.js.coffee +5 -0
  22. data/app/assets/javascripts/shipit.js.coffee +10 -0
  23. data/app/assets/javascripts/twitter_bootstrap.js.coffee +4 -0
  24. data/app/assets/stylesheets/admin.css +9 -0
  25. data/app/assets/stylesheets/admin_bootstrap_and_overrides.css.less +38 -0
  26. data/app/assets/stylesheets/admin_custom.css +104 -0
  27. data/app/assets/twitter/bootstrap/glyphicons-halflings-white.png +0 -0
  28. data/app/assets/twitter/bootstrap/glyphicons-halflings.png +0 -0
  29. data/app/controllers/admin/custom_fields_controller.rb +56 -0
  30. data/app/controllers/admin/link_groups_controller.rb +76 -0
  31. data/app/controllers/admin/main_controller.rb +9 -0
  32. data/app/controllers/admin/navigations_controller.rb +49 -0
  33. data/app/controllers/admin/orders_controller.rb +47 -0
  34. data/app/controllers/admin/payment_methods_controller.rb +26 -0
  35. data/app/controllers/admin/product_groups_controller.rb +70 -0
  36. data/app/controllers/admin/products_controller.rb +71 -0
  37. data/app/controllers/admin/shipments_controller.rb +19 -0
  38. data/app/controllers/admin/shipping_methods_controller.rb +93 -0
  39. data/app/controllers/admin/shipping_zones_controller.rb +62 -0
  40. data/app/controllers/admin/shops_controller.rb +33 -0
  41. data/app/controllers/admin_controller.rb +38 -0
  42. data/app/helpers/admin_helper.rb +83 -0
  43. data/app/helpers/nimbleshop_helper.rb +43 -0
  44. data/app/helpers/payment_method_helper.rb +52 -0
  45. data/app/mailers/admin_mailer.rb +22 -0
  46. data/app/mailers/mailer.rb +31 -0
  47. data/app/models/address.rb +69 -0
  48. data/app/models/country_shipping_zone.rb +36 -0
  49. data/app/models/creditcard.rb +95 -0
  50. data/app/models/custom_field.rb +8 -0
  51. data/app/models/custom_field_answer/field.rb +101 -0
  52. data/app/models/custom_field_answer.rb +17 -0
  53. data/app/models/line_item.rb +48 -0
  54. data/app/models/link.rb +3 -0
  55. data/app/models/link_group.rb +8 -0
  56. data/app/models/navigation.rb +7 -0
  57. data/app/models/order.rb +158 -0
  58. data/app/models/payment_method.rb +20 -0
  59. data/app/models/payment_transaction.rb +11 -0
  60. data/app/models/picture.rb +30 -0
  61. data/app/models/product.rb +76 -0
  62. data/app/models/product_group.rb +65 -0
  63. data/app/models/product_group_condition.rb +8 -0
  64. data/app/models/regional_shipping_zone.rb +25 -0
  65. data/app/models/shipment.rb +19 -0
  66. data/app/models/shipment_carrier.rb +3 -0
  67. data/app/models/shipping_cost_calculator.rb +9 -0
  68. data/app/models/shipping_method.rb +103 -0
  69. data/app/models/shipping_zone.rb +9 -0
  70. data/app/models/shop.rb +26 -0
  71. data/app/models/tax_calculator.rb +18 -0
  72. data/app/observers/order_observer.rb +53 -0
  73. data/app/uploaders/picture_uploader.rb +65 -0
  74. data/app/views/admin/custom_fields/_form.html.erb +45 -0
  75. data/app/views/admin/custom_fields/edit.html.erb +7 -0
  76. data/app/views/admin/custom_fields/index.html.erb +31 -0
  77. data/app/views/admin/custom_fields/new.html.erb +7 -0
  78. data/app/views/admin/link_groups/_form.html.erb +31 -0
  79. data/app/views/admin/link_groups/_link_group.html.erb +50 -0
  80. data/app/views/admin/link_groups/_link_group_title.html.erb +5 -0
  81. data/app/views/admin/link_groups/edit.html.erb +8 -0
  82. data/app/views/admin/link_groups/index.html.erb +29 -0
  83. data/app/views/admin/link_groups/new.html.erb +9 -0
  84. data/app/views/admin/mailer/new_order_notification.text.erb +31 -0
  85. data/app/views/admin/main/index.html.erb +5 -0
  86. data/app/views/admin/navigations/new.html.erb +29 -0
  87. data/app/views/admin/orders/_line_item.html.erb +11 -0
  88. data/app/views/admin/orders/_line_items.html.erb +39 -0
  89. data/app/views/admin/orders/_payment_info.html.erb +20 -0
  90. data/app/views/admin/orders/_shipping_info.html.erb +40 -0
  91. data/app/views/admin/orders/index.html.erb +33 -0
  92. data/app/views/admin/orders/show.html.erb +40 -0
  93. data/app/views/admin/payment_methods/index.html.erb +6 -0
  94. data/app/views/admin/product_groups/_condition.html.mustache +20 -0
  95. data/app/views/admin/product_groups/_form.html.erb +72 -0
  96. data/app/views/admin/product_groups/edit.html.erb +7 -0
  97. data/app/views/admin/product_groups/index.html.erb +30 -0
  98. data/app/views/admin/product_groups/new.html.erb +7 -0
  99. data/app/views/admin/product_groups/show.html.erb +9 -0
  100. data/app/views/admin/products/_custom_field_answer.html.erb +9 -0
  101. data/app/views/admin/products/_form.html.erb +69 -0
  102. data/app/views/admin/products/_handle_pictures.html.erb +32 -0
  103. data/app/views/admin/products/_pictures.html.erb +33 -0
  104. data/app/views/admin/products/edit.html.erb +26 -0
  105. data/app/views/admin/products/index.html.erb +34 -0
  106. data/app/views/admin/products/new.html.erb +9 -0
  107. data/app/views/admin/shipping_methods/_form.html.erb +58 -0
  108. data/app/views/admin/shipping_methods/_shipping_method.html.erb +31 -0
  109. data/app/views/admin/shipping_methods/edit.html.erb +18 -0
  110. data/app/views/admin/shipping_methods/new.html.erb +7 -0
  111. data/app/views/admin/shipping_zones/_form.html.erb +31 -0
  112. data/app/views/admin/shipping_zones/_shipping_method.html.erb +13 -0
  113. data/app/views/admin/shipping_zones/_shipping_zone.html.erb +47 -0
  114. data/app/views/admin/shipping_zones/edit.html.erb +8 -0
  115. data/app/views/admin/shipping_zones/index.html.erb +16 -0
  116. data/app/views/admin/shipping_zones/new.html.erb +8 -0
  117. data/app/views/admin/shops/edit.html.erb +119 -0
  118. data/app/views/layouts/_admin_footer.html.erb +23 -0
  119. data/app/views/layouts/_admin_sidebar.html.erb +0 -0
  120. data/app/views/layouts/_container.html.erb +33 -0
  121. data/app/views/layouts/_top_nav_bar.html.erb +30 -0
  122. data/app/views/layouts/admin.html.erb +35 -0
  123. data/app/views/layouts/payment_method.html.erb +12 -0
  124. data/app/views/mailer/order_notification_to_buyer.text.erb +31 -0
  125. data/app/views/mailer/shipment_notification_to_buyer.text.erb +34 -0
  126. data/config/initializers/001_settings_application.rb +10 -0
  127. data/config/initializers/002_load_core_extensions.rb +8 -0
  128. data/config/initializers/field_with_error.rb +2 -0
  129. data/config/initializers/strip_and_nullify.rb +13 -0
  130. data/config/initializers/time_formats.rb +1 -0
  131. data/config/locales/en.yml +61 -0
  132. data/config/routes.rb +56 -0
  133. data/db/development.sqlite3 +0 -0
  134. data/db/migrate/20111022144421_create_product_groups.rb +12 -0
  135. data/db/migrate/20111022144426_create_products.rb +16 -0
  136. data/db/migrate/20111022144653_create_orders.rb +21 -0
  137. data/db/migrate/20111022144725_create_line_items.rb +15 -0
  138. data/db/migrate/20111022234951_create_shops.rb +20 -0
  139. data/db/migrate/20111026193227_create_link_groups.rb +12 -0
  140. data/db/migrate/20111026193435_create_navigations.rb +10 -0
  141. data/db/migrate/20111031135810_create_links.rb +10 -0
  142. data/db/migrate/20111106193938_create_custom_fields.rb +10 -0
  143. data/db/migrate/20111106195112_create_custom_field_answers.rb +14 -0
  144. data/db/migrate/20111106201548_create_product_group_conditions.rb +12 -0
  145. data/db/migrate/20111107035350_create_creditcard_transactions.rb +15 -0
  146. data/db/migrate/20111109190754_create_addresses.rb +24 -0
  147. data/db/migrate/20111125173344_create_pictures.rb +16 -0
  148. data/db/migrate/20111201024408_create_shipping_methods.rb +16 -0
  149. data/db/migrate/20111202143154_create_shipping_zones.rb +17 -0
  150. data/db/migrate/20111203034020_create_payment_methods.rb +14 -0
  151. data/db/migrate/20111221190000_create_preferences.rb +14 -0
  152. data/db/migrate/20120105234047_create_shipments.rb +11 -0
  153. data/db/migrate/20120105234553_create_shipment_carriers.rb +11 -0
  154. data/db/migrate/20120606165355_create_delayed_jobs.rb +22 -0
  155. data/db/production.sqlite3 +0 -0
  156. data/db/schema.rb +265 -0
  157. data/db/seeds.rb +1 -0
  158. data/db/test.sqlite3 +0 -0
  159. data/lib/assets/javascripts/loading_state_for_buttons.js.coffee +3 -0
  160. data/lib/assets/javascripts/show_help_on_hover.js.coffee +2 -0
  161. data/lib/assets/javascripts/utils/autoresize.js.coffee +3 -0
  162. data/lib/assets/javascripts/utils/focus.js.coffee +3 -0
  163. data/lib/assets/javascripts/utils/formatNumber.js.coffee +25 -0
  164. data/lib/assets/javascripts/utils/formatPrice.js.coffee +24 -0
  165. data/lib/generators/nimbleshop/app/app_generator.rb +84 -0
  166. data/lib/generators/nimbleshop/app/templates/config/application.yml +61 -0
  167. data/lib/generators/nimbleshop/app/templates/config/initializers/airbrake.rb +3 -0
  168. data/lib/generators/nimbleshop/app/templates/config/initializers/cache_images.rb +4 -0
  169. data/lib/generators/nimbleshop/app/templates/config/initializers/carrierwave.rb +36 -0
  170. data/lib/generators/nimbleshop/app/templates/config/initializers/delayed_job.rb +15 -0
  171. data/lib/generators/nimbleshop/app/templates/config/initializers/setup_email.rb +24 -0
  172. data/lib/nimbleshop/core_ext/activerecord_base.rb +18 -0
  173. data/lib/nimbleshop/core_ext/filelessio.rb +4 -0
  174. data/lib/nimbleshop/core_ext/force_ssl.rb +26 -0
  175. data/lib/nimbleshop/core_ext/mustache_templater_handler.rb +10 -0
  176. data/lib/nimbleshop/engine.rb +23 -0
  177. data/lib/nimbleshop/permalink/builder.rb +46 -0
  178. data/lib/nimbleshop/processor/base.rb +51 -0
  179. data/lib/nimbleshop/processor.rb +3 -0
  180. data/lib/nimbleshop/product_group_search/base_field.rb +19 -0
  181. data/lib/nimbleshop/product_group_search/core_field_strategy.rb +31 -0
  182. data/lib/nimbleshop/product_group_search/custom_field_strategy.rb +39 -0
  183. data/lib/nimbleshop/product_group_search/date_field.rb +16 -0
  184. data/lib/nimbleshop/product_group_search/extension.rb +46 -0
  185. data/lib/nimbleshop/product_group_search/number_field.rb +17 -0
  186. data/lib/nimbleshop/product_group_search/text_field.rb +33 -0
  187. data/lib/nimbleshop/product_group_search.rb +74 -0
  188. data/lib/nimbleshop/sampledata/data.rb +246 -0
  189. data/lib/nimbleshop/sampledata/pictures/product1/pic1.jpg +0 -0
  190. data/lib/nimbleshop/sampledata/pictures/product2/pic1.jpg +0 -0
  191. data/lib/nimbleshop/sampledata/pictures/product2/pic2.jpg +0 -0
  192. data/lib/nimbleshop/sampledata/pictures/product3/pic1.jpg +0 -0
  193. data/lib/nimbleshop/sampledata/pictures/product3/pic2.jpg +0 -0
  194. data/lib/nimbleshop/sampledata/pictures/product3/pic3.jpg +0 -0
  195. data/lib/nimbleshop/sampledata/pictures/product3/pic4.jpg +0 -0
  196. data/lib/nimbleshop/sampledata/pictures/product3/pic5.jpg +0 -0
  197. data/lib/nimbleshop/sampledata/pictures/product4/pic1.jpg +0 -0
  198. data/lib/nimbleshop/sampledata/pictures/product4/pic2.jpg +0 -0
  199. data/lib/nimbleshop/sampledata/pictures/product5/pic1.jpg +0 -0
  200. data/lib/nimbleshop/sampledata/pictures/product5/pic2.jpg +0 -0
  201. data/lib/nimbleshop/sampledata/pictures/product6/pic1.jpg +0 -0
  202. data/lib/nimbleshop/sampledata/pictures/product6/pic10.jpg +0 -0
  203. data/lib/nimbleshop/sampledata/pictures/product6/pic11.jpg +0 -0
  204. data/lib/nimbleshop/sampledata/pictures/product6/pic12.jpg +0 -0
  205. data/lib/nimbleshop/sampledata/pictures/product6/pic13.jpg +0 -0
  206. data/lib/nimbleshop/sampledata/pictures/product6/pic14.jpg +0 -0
  207. data/lib/nimbleshop/sampledata/pictures/product6/pic15.jpg +0 -0
  208. data/lib/nimbleshop/sampledata/pictures/product6/pic16.jpg +0 -0
  209. data/lib/nimbleshop/sampledata/pictures/product6/pic17.jpg +0 -0
  210. data/lib/nimbleshop/sampledata/pictures/product6/pic2.jpg +0 -0
  211. data/lib/nimbleshop/sampledata/pictures/product6/pic3.jpg +0 -0
  212. data/lib/nimbleshop/sampledata/pictures/product6/pic4.jpg +0 -0
  213. data/lib/nimbleshop/sampledata/pictures/product6/pic5.jpg +0 -0
  214. data/lib/nimbleshop/sampledata/pictures/product6/pic6.jpg +0 -0
  215. data/lib/nimbleshop/sampledata/pictures/product6/pic7.jpg +0 -0
  216. data/lib/nimbleshop/sampledata/pictures/product6/pic8.jpg +0 -0
  217. data/lib/nimbleshop/sampledata/pictures/product6/pic9.jpg +0 -0
  218. data/lib/nimbleshop/sampledata/pictures/product7/pic1.jpg +0 -0
  219. data/lib/nimbleshop/sampledata/pictures/product7/pic2.jpg +0 -0
  220. data/lib/nimbleshop/sampledata/pictures/product7/pic3.jpg +0 -0
  221. data/lib/nimbleshop/sampledata/pictures/product8/pic1.jpg +0 -0
  222. data/lib/nimbleshop/sampledata/pictures/product8/pic2.jpg +0 -0
  223. data/lib/nimbleshop/sampledata/pictures/product8/pic3.jpg +0 -0
  224. data/lib/nimbleshop/sampledata/pictures/product8/pic4.jpg +0 -0
  225. data/lib/nimbleshop/sampledata/pictures/product8/pic5.jpg +0 -0
  226. data/lib/nimbleshop/sampledata/pictures/product8/pic6.jpg +0 -0
  227. data/lib/nimbleshop/sampledata/pictures/product8/pic7.jpg +0 -0
  228. data/lib/nimbleshop/sampledata/pictures/product8/pic8.jpg +0 -0
  229. data/lib/nimbleshop/sampledata/pictures/product9/pic1.jpg +0 -0
  230. data/lib/nimbleshop/sampledata/pictures/product9/pic2.jpg +0 -0
  231. data/lib/nimbleshop/util.rb +60 -0
  232. data/lib/nimbleshop/version.rb +18 -0
  233. data/lib/nimbleshop_core.rb +23 -0
  234. data/lib/tasks/localhost2public.rake +8 -0
  235. data/lib/tasks/setup.rake +26 -0
  236. data/test/factories/address_factory.rb +31 -0
  237. data/test/factories/creditcard_factory.rb +30 -0
  238. data/test/factories/custom_field_answer_factory.rb +6 -0
  239. data/test/factories/custom_field_factory.rb +21 -0
  240. data/test/factories/line_item_factory.rb +7 -0
  241. data/test/factories/link_factory.rb +6 -0
  242. data/test/factories/link_group_factory.rb +5 -0
  243. data/test/factories/navigation_factory.rb +6 -0
  244. data/test/factories/order_factory.rb +49 -0
  245. data/test/factories/payment_method_factory.rb +6 -0
  246. data/test/factories/payment_transaction_factory.rb +42 -0
  247. data/test/factories/picture_factory.rb +11 -0
  248. data/test/factories/product_group_condition_factory.rb +40 -0
  249. data/test/factories/product_group_factory.rb +5 -0
  250. data/test/factories/products_factory.rb +11 -0
  251. data/test/factories/shipment_carrier_factory.rb +6 -0
  252. data/test/factories/shipment_factory.rb +6 -0
  253. data/test/factories/shipping_method_factory.rb +15 -0
  254. data/test/factories/shipping_zone_factory.rb +5 -0
  255. data/test/factories/shop_factory.rb +8 -0
  256. data/test/fixtures/files/avatar.png +0 -0
  257. data/test/fixtures/link_groups.yml +13 -0
  258. data/test/fixtures/payment_methods.yml +39 -0
  259. data/test/fixtures/shops.yml +15 -0
  260. data/test/helpers/admin_helper_test.rb +37 -0
  261. data/test/helpers/nimbleshop_helper_test.rb +17 -0
  262. data/test/integration/admin/link_groups_acceptance_test.rb +39 -0
  263. data/test/integration/admin/orders_acceptance_test.rb +63 -0
  264. data/test/integration/admin/payment_methods_acceptance_test.rb +13 -0
  265. data/test/integration/admin/product_groups_acceptance_test.rb +89 -0
  266. data/test/integration/admin/products_acceptance_test.rb +105 -0
  267. data/test/integration/admin/shipping_methods_acceptance_test.rb +63 -0
  268. data/test/integration/admin/shipping_zones_acceptance_test.rb +16 -0
  269. data/test/integration/admin/shops_acceptance_test.rb +44 -0
  270. data/test/integration/checkout/cart_acceptance_test.rb +113 -0
  271. data/test/integration/checkout/payment_confirmation_acceptance_test.rb +24 -0
  272. data/test/integration/checkout/paypal_acceptance_test.rb +34 -0
  273. data/test/integration/checkout/shipping_address_acceptance_test.rb +91 -0
  274. data/test/integration/checkout/shipping_method_acceptance_test.rb +51 -0
  275. data/test/integration/homepage_acceptance_test.rb +24 -0
  276. data/test/integration/products_acceptance_test.rb +12 -0
  277. data/test/integration/static_pages_acceptance_test.rb +13 -0
  278. data/test/mailers/mailer_test.rb +25 -0
  279. data/test/rails_app/Gemfile +27 -0
  280. data/test/rails_app/Gemfile.lock +218 -0
  281. data/test/rails_app/Rakefile +10 -0
  282. data/test/rails_app/app/controllers/application_controller.rb +6 -0
  283. data/test/rails_app/app/helpers/application_helper.rb +3 -0
  284. data/test/rails_app/app/views/layouts/application.html.erb +10 -0
  285. data/test/rails_app/config/application.rb +25 -0
  286. data/test/rails_app/config/application.yml +61 -0
  287. data/test/rails_app/config/boot.rb +5 -0
  288. data/test/rails_app/config/database.yml +18 -0
  289. data/test/rails_app/config/environment.rb +5 -0
  290. data/test/rails_app/config/environments/development.rb +18 -0
  291. data/test/rails_app/config/environments/production.rb +33 -0
  292. data/test/rails_app/config/environments/test.rb +33 -0
  293. data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  294. data/test/rails_app/config/initializers/inflections.rb +2 -0
  295. data/test/rails_app/config/initializers/secret_token.rb +2 -0
  296. data/test/rails_app/config/routes.rb +10 -0
  297. data/test/rails_app/config.ru +4 -0
  298. data/test/rails_app/db/development.sqlite3 +0 -0
  299. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +74 -0
  300. data/test/rails_app/db/schema.rb +52 -0
  301. data/test/rails_app/log/development.log +94 -0
  302. data/test/rails_app/log/test.log +0 -0
  303. data/test/rails_app/public/404.html +26 -0
  304. data/test/rails_app/public/422.html +26 -0
  305. data/test/rails_app/public/500.html +26 -0
  306. data/test/rails_app/public/favicon.ico +0 -0
  307. data/test/rails_app/script/rails +10 -0
  308. data/test/support/address_test_helper.rb +24 -0
  309. data/test/support/checkout_test_helper.rb +40 -0
  310. data/test/support/dbify_sql_helper.rb +12 -0
  311. data/test/support/images/cookware.jpg +0 -0
  312. data/test/support/must_be_like.rb +24 -0
  313. data/test/support/shipping_method_test_helper.rb +5 -0
  314. data/test/support/wait_for_ajax.rb +4 -0
  315. data/test/test_helper.rb +65 -0
  316. data/test/unit/address_test.rb +33 -0
  317. data/test/unit/country_shipping_zone_test.rb +17 -0
  318. data/test/unit/creditcard_test.rb +33 -0
  319. data/test/unit/custom_field_answer/field_test.rb +93 -0
  320. data/test/unit/order_test.rb +70 -0
  321. data/test/unit/payment_method/authorizedotnet_test.rb +21 -0
  322. data/test/unit/payment_method/paypalwp_test.rb +17 -0
  323. data/test/unit/payment_method/splitable_test.rb +18 -0
  324. data/test/unit/picture_test.rb +24 -0
  325. data/test/unit/processor/authorize_net_test.rb +236 -0
  326. data/test/unit/processor/paypal_test.rb +40 -0
  327. data/test/unit/processor/splitable_test.rb +123 -0
  328. data/test/unit/product_group_condition_test.rb +188 -0
  329. data/test/unit/product_group_test.rb +109 -0
  330. data/test/unit/product_test.rb +60 -0
  331. data/test/unit/shipping_cost_calculator_test.rb +19 -0
  332. data/test/unit/shipping_method_test.rb +197 -0
  333. data/test/unit/shop_test.rb +11 -0
  334. data/test/unit/tax_calculator_test.rb +13 -0
  335. data/test/vcr_cassettes/authorize_net/authorize-failure.yml +38 -0
  336. data/test/vcr_cassettes/authorize_net/authorize-success.yml +38 -0
  337. data/test/vcr_cassettes/authorize_net/capture-failure.yml +38 -0
  338. data/test/vcr_cassettes/authorize_net/capture-success.yml +38 -0
  339. data/test/vcr_cassettes/authorize_net/purchase-failure.yml +38 -0
  340. data/test/vcr_cassettes/authorize_net/purchase-success.yml +38 -0
  341. data/test/vcr_cassettes/authorize_net/refund-failure.yml +38 -0
  342. data/test/vcr_cassettes/authorize_net/refund-success.yml +38 -0
  343. data/test/vcr_cassettes/authorize_net/void-authorize.yml +38 -0
  344. data/test/vcr_cassettes/authorize_net/void-failure.yml +38 -0
  345. data/test/vcr_cassettes/authorize_net/void-success.yml +38 -0
  346. data/test/vcr_cassettes/splitable/split-create-failure.yml +48 -0
  347. data/test/vcr_cassettes/splitable/split-create-success.yml +50 -0
  348. data/test/vcr_cassettes/splitable/split-draft-create-failure.yml +50 -0
  349. data/test/vcr_cassettes/splitable/split-draft-create-success.yml +50 -0
  350. data/vendor/assets/javascripts/accounting.js +406 -0
  351. data/vendor/assets/javascripts/autoresize.js +275 -0
  352. data/vendor/assets/javascripts/jquery-1.7.1.js +9267 -0
  353. data/vendor/assets/javascripts/jquery-form.js +980 -0
  354. data/vendor/assets/javascripts/jquery-json.js +193 -0
  355. data/vendor/assets/javascripts/jquery-ui-1.8.16.js +11768 -0
  356. data/vendor/assets/javascripts/jquery-ujs.js +374 -0
  357. data/vendor/assets/javascripts/mustache.js +436 -0
  358. data/vendor/assets/javascripts/nested_form.js +51 -0
  359. metadata +740 -0
@@ -0,0 +1,8 @@
1
+ class ProductGroupCondition < ActiveRecord::Base
2
+
3
+ include ProductGroupSearch
4
+
5
+ belongs_to :product_group
6
+ validates_presence_of :name, :operator, :value
7
+
8
+ end
@@ -0,0 +1,25 @@
1
+ class RegionalShippingZone < ShippingZone
2
+
3
+ validates :state_code, presence: true, uniqueness: { scope: :country_shipping_zone_id }
4
+
5
+ validate :code_validity, if: lambda { |r| r.state_code && r.country }
6
+
7
+ before_save :set_name
8
+
9
+ delegate :country, to: :country_shipping_zone, allow_nil: true
10
+
11
+ private
12
+
13
+ def code_validity
14
+ country = country_shipping_zone.country
15
+ unless country.subregions.coded(state_code)
16
+ errors.add(:state_code, "#{state_code} is an invalid regional code for country #{country.name}")
17
+ end
18
+ end
19
+
20
+ def set_name
21
+ country = country_shipping_zone.country
22
+ self.name = country.subregions.coded(state_code).name
23
+ end
24
+
25
+ end
@@ -0,0 +1,19 @@
1
+ class Shipment < ActiveRecord::Base
2
+
3
+ attr_accessor :notify_customer
4
+
5
+ belongs_to :shipment_carrier
6
+ belongs_to :order
7
+
8
+ delegate :name, to: :shipment_carrier
9
+
10
+ def tracking_url
11
+ case shipment_carrier.permalink
12
+ when 'fedex'
13
+ "http://www.fedex.com/Tracking?tracknumbers=#{tracking_number}"
14
+ else
15
+ "https://www.google.com/search?q=#{tracking_number}"
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,3 @@
1
+ class ShipmentCarrier < ActiveRecord::Base
2
+ include Permalink::Builder
3
+ end
@@ -0,0 +1,9 @@
1
+ class ShippingCostCalculator
2
+ def initialize(order)
3
+ @order = order
4
+ end
5
+
6
+ def shipping_cost
7
+ @order.shipping_method.try(:shipping_cost) || 0.0
8
+ end
9
+ end
@@ -0,0 +1,103 @@
1
+ class ShippingMethod < ActiveRecord::Base
2
+
3
+ alias_attribute :shipping_cost, :shipping_price
4
+ alias_attribute :higher_price_limit, :maximum_order_amount
5
+
6
+ belongs_to :shipping_zone
7
+
8
+ validates_presence_of :minimum_order_amount, :base_price, if: :country_level?
9
+ validates_presence_of :name
10
+
11
+ validates_numericality_of :minimum_order_amount,
12
+ less_than: :higher_price_limit,
13
+ if: lambda { |r| r.country_level? && r.higher_price_limit && (r.higher_price_limit > 0 ) },
14
+ message: '^ Maximum order amount must be greater than 0',
15
+ allow_nil: true
16
+
17
+ validates_numericality_of :maximum_order_amount,
18
+ greater_than: 0,
19
+ if: lambda { |r| r.country_level? },
20
+ allow_nil: true
21
+
22
+
23
+ scope :active, where(active: true)
24
+
25
+ scope :atleast, lambda { |r| where('shipping_methods.minimum_order_amount <= ?', r) }
26
+
27
+ scope :atmost, lambda { |r| where('shipping_methods.maximum_order_amount is null or shipping_methods.maximum_order_amount >= ?', r) }
28
+
29
+ scope :in_price_range, lambda { |r| atleast(r).atmost(r) }
30
+
31
+ scope :in_country, lambda { |country_code| joins(:shipping_zone).where(shipping_zones: { country_code: country_code }) }
32
+
33
+ def self.in_state(state_code, country_code)
34
+ where({
35
+ shipping_zones: { state_code: state_code },
36
+ country_shipping_zones_shipping_zones: { country_code: country_code }
37
+ }).joins(shipping_zone: :country_shipping_zone)
38
+ end
39
+
40
+ before_create :create_regional_shipping_methods, if: :country_level?
41
+
42
+ before_save :update_regions_status, if: :country_level?
43
+
44
+ belongs_to :parent, class_name: 'ShippingMethod', foreign_key: 'parent_id'
45
+ has_many :regions, class_name: 'ShippingMethod', foreign_key: 'parent_id', dependent: :destroy
46
+
47
+ # returns shipping methods available for the given address and for the given amount
48
+ def self.available_for(amount, address)
49
+ a = address.state_code ? in_state(address.state_code, address.country_code) : in_country(address.country_code)
50
+ a.active.in_price_range(amount)
51
+ end
52
+
53
+ def self.available_for_countries(amount)
54
+ active.in_price_range(amount).includes(:shipping_zone).map { |t| t.shipping_zone.country_code }.uniq
55
+ end
56
+
57
+ def shipping_price
58
+ country_level? ? base_price : (parent.base_price + offset)
59
+ end
60
+
61
+ def country_level?
62
+ shipping_zone.is_a?(CountryShippingZone)
63
+ end
64
+
65
+ def update_offset(value)
66
+ value ||= 0
67
+ value = value.to_f
68
+
69
+ unless country_level?
70
+ self.offset += value
71
+ save
72
+ end
73
+ end
74
+
75
+ def enable!
76
+ update_attributes(active: true)
77
+ end
78
+
79
+ def disable!
80
+ update_attributes(active: false)
81
+ end
82
+
83
+ private
84
+
85
+ def create_regional_shipping_methods
86
+ shipping_zone.regional_shipping_zones.each do |t|
87
+ options = { shipping_zone: t,
88
+ name: name,
89
+ minimum_order_amount: minimum_order_amount,
90
+ maximum_order_amount: maximum_order_amount }
91
+
92
+ options.merge!(active: false) unless active
93
+ regions.build(options)
94
+ end
95
+ end
96
+
97
+ def update_regions_status
98
+ if persisted? && active_changed? && active == false
99
+ regions.each { |region| region.update_attributes!(active: false) }
100
+ end
101
+ end
102
+
103
+ end
@@ -0,0 +1,9 @@
1
+ class ShippingZone < ActiveRecord::Base
2
+
3
+ include Permalink::Builder
4
+
5
+ has_many :shipping_methods, dependent: :destroy, conditions: { active: true }
6
+
7
+ belongs_to :country_shipping_zone
8
+
9
+ end
@@ -0,0 +1,26 @@
1
+ class Shop < ActiveRecord::Base
2
+
3
+ before_validation :sanitize_twitter_handle, if: :twitter_handle
4
+
5
+ validates :from_email, email: true, allow_blank: false
6
+
7
+ validates_format_of :facebook_url, with: URI::regexp, allow_blank: true
8
+
9
+ validates_presence_of :name, :theme, :time_zone, :default_creditcard_action
10
+ validates_inclusion_of :default_creditcard_action, in: %W( authorize purchase )
11
+ validates_numericality_of :tax_percentage, greater_than_or_equal_to: 0, less_than: 100
12
+
13
+ class << self
14
+ alias_method :current, :first
15
+ end
16
+
17
+ def twitter_url
18
+ twitter_handle.blank? ? nil : "http://twitter.com/#{twitter_handle}"
19
+ end
20
+
21
+ private
22
+
23
+ def sanitize_twitter_handle
24
+ twitter_handle.gsub!(/^@/, '')
25
+ end
26
+ end
@@ -0,0 +1,18 @@
1
+ class TaxCalculator
2
+ def initialize(order)
3
+ @order = order
4
+ end
5
+
6
+ # Returns tax amount in float
7
+ def tax
8
+ amount = BigDecimal(@order.line_items_total.to_s)
9
+
10
+ (amount * BigDecimal(tax_percentage.to_s) * BigDecimal.new("0.01")).round(2).to_f
11
+ end
12
+
13
+ private
14
+
15
+ def tax_percentage
16
+ Shop.first.tax_percentage
17
+ end
18
+ end
@@ -0,0 +1,53 @@
1
+ class OrderObserver < ActiveRecord::Observer
2
+
3
+ # All the methods listed below get transition object as the second
4
+ # parameter. It is an instance of +StateMachine::Transition+.
5
+ #
6
+ # p transition.to => 'pending'
7
+ # p transition.from => 'abandoned'
8
+ # p transition.event => :pending
9
+ # p transition => #<StateMachine::Transition attribute=:payment_status event=:pending from="abandoned" from_name=:abandoned to="pending" to_name=:pending>
10
+ #
11
+
12
+ #
13
+ # Ideally what to do after state transition should be pushed to
14
+ # individual payment method. In this way we will not have the if
15
+ # condition that we are seeing in after_pending .
16
+ #
17
+
18
+ def after_purchase(order, transition)
19
+ Mailer.delay.order_notification_to_buyer(order.number)
20
+ AdminMailer.delay.new_order_notification(order.number)
21
+
22
+ order.mark_as_purchased!
23
+ order.shipping_pending
24
+ ActiveSupport::Notifications.instrument("order.purchased", { order_number: order.number } )
25
+ end
26
+
27
+ def after_authorize(order, transition)
28
+ Mailer.delay.order_notification_to_buyer(order.number)
29
+ AdminMailer.delay.new_order_notification(order.number)
30
+
31
+ order.mark_as_purchased!
32
+ order.shipping_pending
33
+ end
34
+
35
+ def after_kapture(order, transition)
36
+ end
37
+
38
+ def after_pending(order, transition)
39
+ if order.payment_method.is_a? NimbleshopCod::Cod
40
+ Mailer.delay.order_notification_to_buyer(order.number)
41
+ AdminMailer.delay.new_order_notification(order.number)
42
+ end
43
+
44
+ order.shipping_pending
45
+ end
46
+
47
+ def after_void(order, transition)
48
+ end
49
+
50
+ def after_refund(order, transition)
51
+ end
52
+
53
+ end
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+
3
+ class PictureUploader < CarrierWave::Uploader::Base
4
+
5
+ # include CarrierWave::RMagick
6
+ # include CarrierWave::ImageScience
7
+ include CarrierWave::MiniMagick
8
+
9
+ # Override the directory where uploaded files will be stored. This is a sensible default for uploaders that are meant to be mounted .
10
+ def store_dir
11
+ "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
12
+ end
13
+
14
+ # Add a white list of extensions which are allowed to be uploaded. For images you might use something like this:
15
+ def extension_white_list
16
+ %w(jpg jpeg gif png)
17
+ end
18
+
19
+ #manipulation_type = :resize_to_limit
20
+ #manipulation_type = :resize_to_fit
21
+ manipulation_type = :resize_to_fill
22
+
23
+ sizes = { tiny: [16, 16],
24
+ tiny_plus: [32, 32],
25
+ small: [50, 50],
26
+ small_plus: [100, 100],
27
+ medium: [160, 160],
28
+ medium_plus: [240, 240],
29
+ large: [480, 480],
30
+ large_plus: [600, 600]
31
+ }
32
+
33
+ version :tiny do
34
+ process manipulation_type => sizes.fetch(:tiny)
35
+ end
36
+
37
+ version :tiny_plus do
38
+ process manipulation_type => sizes.fetch(:tiny_plus)
39
+ end
40
+
41
+ version :small do
42
+ process manipulation_type => sizes.fetch(:small)
43
+ end
44
+
45
+ version :small_plus do
46
+ process manipulation_type => sizes.fetch(:small_plus)
47
+ end
48
+
49
+ version :medium do
50
+ process manipulation_type => sizes.fetch(:medium)
51
+ end
52
+
53
+ version :medium_plus do
54
+ process manipulation_type => sizes.fetch(:medium_plus)
55
+ end
56
+
57
+ version :large do
58
+ process manipulation_type => sizes.fetch(:large)
59
+ end
60
+
61
+ version :large_plus do
62
+ process manipulation_type => sizes.fetch(:large_plus)
63
+ end
64
+
65
+ end
@@ -0,0 +1,45 @@
1
+ <div class='well'>
2
+ <%= form_for([:admin, @custom_field], html: {class: 'form-horizontal'}) do |f| %>
3
+
4
+ <% if @custom_field.errors.any? %>
5
+ <div class="alert alert-error">
6
+ <p> <%= t(:error_bang) %></p>
7
+ <ul>
8
+ <% @custom_field.errors.full_messages.each do |message| %>
9
+ <li><%= message %></li>
10
+ <% end %>
11
+ </ul>
12
+ </div>
13
+ <% end %>
14
+
15
+ <fieldset>
16
+ <div class="control-group">
17
+ <%= f.label :name, class: 'control-label' %>
18
+ <div class="controls">
19
+ <%= f.text_field :name, class: 'input-xlarge focus' %>
20
+ </div>
21
+ </div>
22
+
23
+ <div class="control-group">
24
+ <%= f.label :field_type, class: 'control-label' %>
25
+ <div class="controls">
26
+ <% if @custom_field.new_record? %>
27
+ <%= f.text_field :field_type, class: 'input-xlarge' %>
28
+ <p class="help-block">
29
+ Valid values are text, number or date .
30
+ </p>
31
+ <% else %>
32
+ <%= f.text_field :field_type, class: 'input-xlarge disabled', disabled: 'disabled' %>
33
+ <% end %>
34
+ </div>
35
+ </div>
36
+ </fieldset>
37
+
38
+ <div class="form-actions">
39
+ <%= f.submit 'Submit', class: 'btn btn-primary', 'data-loading-text' => 'processing ...' %>
40
+ &nbsp;
41
+ <%= link_to 'Cancel', admin_custom_fields_path, class: 'btn' %>
42
+ </div>
43
+
44
+ <% end %>
45
+ <div>
@@ -0,0 +1,7 @@
1
+ <% page_title "editing custom field #{@custom_field.name}" %>
2
+
3
+ <div>
4
+ <h1><%= t(:edit_custom_field) %></h1>
5
+ </div>
6
+
7
+ <%= render 'form' %>
@@ -0,0 +1,31 @@
1
+ <% page_title 'custom fields' %>
2
+
3
+ <div>
4
+ <h1 class='ns-page-title'><%= t(:custom_fields) %></h1>
5
+
6
+ <%= link_to(new_admin_custom_field_path, class: 'btn btn-success new-action') do %>
7
+ <i class="icon-plus"></i> <%= t(:add_new_custom_field) %>
8
+ <% end %>
9
+ <div class='clear'></div>
10
+ </div>
11
+
12
+ <br />
13
+
14
+ <table class="table table-striped">
15
+ <tbody>
16
+ <% @custom_fields.each do |custom_field| %>
17
+ <tr>
18
+ <td><%= custom_field.name %></td>
19
+ <td><%= custom_field.field_type %></td>
20
+ <td>
21
+ <%= link_to t(:edit), edit_admin_custom_field_path(custom_field), title: 'Edit' %>
22
+ |
23
+ <%= link_to [:admin, custom_field], confirm: t(:delete_confirmation_for_custom_field), method: 'delete', class: 'delete', title: 'Delete' do %>
24
+ <%= delete_icon %>
25
+ <% end %>
26
+ </td>
27
+ </td>
28
+ </tr>
29
+ <% end %>
30
+ </tbody>
31
+ </table>
@@ -0,0 +1,7 @@
1
+ <% page_title "new custom field" %>
2
+
3
+ <div>
4
+ <h1><%= t(:add_new_custom_field) %></h1>
5
+ </div>
6
+
7
+ <%= render 'form' %>
@@ -0,0 +1,31 @@
1
+ <div class='well'>
2
+ <%= form_for [:admin, @link_group], html: {class: 'form-horizontal' } do |f| %>
3
+
4
+ <% if @link_group.errors.any? %>
5
+ <div class="alert alert-error">
6
+ <p> <%= t(:error_bang) %> </p>
7
+ <ul>
8
+ <% @link_group.errors.full_messages.each do |message| %>
9
+ <li><%= message %></li>
10
+ <% end %>
11
+ </ul>
12
+ </div>
13
+ <% end %>
14
+
15
+ <fieldset>
16
+ <div class="control-group">
17
+ <%= f.label :name, 'Name', class: 'control-label' %>
18
+ <div class="controls">
19
+ <%= f.text_field :name, class: 'span6 focus' %>
20
+ </div>
21
+ </div>
22
+ </fieldset>
23
+
24
+ <div class="form-actions">
25
+ <%= f.submit 'Submit', class: 'btn btn-primary', 'data-loading-text' => 'processing ...' %>
26
+ &nbsp;
27
+ <%= link_to t(:cancel), admin_link_groups_path, class: 'btn' %>
28
+ </div>
29
+
30
+ <% end %>
31
+ </div>
@@ -0,0 +1,50 @@
1
+ <div class='well'>
2
+ <table class="table table-striped">
3
+ <thead>
4
+ <tr>
5
+ <th colspan='3'>
6
+ <div>
7
+
8
+ <div class='link_group_name'>
9
+ <h3><%= link_group.name %></h3>
10
+ </div>
11
+
12
+ <div class='link_group_edit'>
13
+ <%= link_to t(:edit), edit_admin_link_group_path(link_group) %>
14
+ |
15
+ <%= link_to [:admin, link_group], class: 'delete', data: { confirm: t(:delete_confirmation_for_link_group) }, method: 'delete', title: 'Delete' do %>
16
+ <i class='icon-remove icon-white'></i>
17
+ <% end %>
18
+ </div>
19
+
20
+ <div style='float:right'>
21
+ <%= link_to new_admin_link_group_navigation_path(link_group), class: 'btn btn-success' do %>
22
+ <i class='icon-plus'></i> Add new link
23
+ <% end %>
24
+ </div>
25
+
26
+ <div style='clear:both;'></div>
27
+ </div>
28
+ </th>
29
+ </tr>
30
+ <tr>
31
+ <th>Link name </th>
32
+ <th>&nbsp;</th>
33
+ <th>&nbsp;</th>
34
+ </tr>
35
+ </thead>
36
+ <tbody>
37
+ <% link_group.navigations.each do |nav| %>
38
+ <tr>
39
+ <td> <%= nav.product_group.name %> </td>
40
+ <td>&nbsp; </td>
41
+ <td>
42
+ <%= link_to [:admin, link_group, nav], data: { confirm: t(:delete_confirmation_for_link) }, class: 'delete', title: 'Delete', method: 'delete' do %>
43
+ <i class='icon-remove icon-white'></i>
44
+ <% end %>
45
+ </td>
46
+ </tr>
47
+ <% end %>
48
+ </tbody>
49
+ </table>
50
+ </div>
@@ -0,0 +1,5 @@
1
+ <h2><%= link_group.name %></h2>
2
+ <%= button_to "destroy", [:admin, link_group], :method => :delete %>
3
+ <%= link_to '#', :id => link_group.permalink, :class => 'edit-link-group' do %>
4
+ <button class="btn"><%= t(:edit) %></button>
5
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <% page_title "edit link group #{@link_group.name}" %>
2
+
3
+ <div class='page-header'>
4
+ <h1 style='float:left;'><%= t(:edit_link_group) %></h1>
5
+ <div style='clear:both;'></div>
6
+ </div>
7
+
8
+ <%= render 'form' %>
@@ -0,0 +1,29 @@
1
+ <% page_title 'link groups' %>
2
+
3
+ <%= link_to 'What is it?', '' %>
4
+
5
+ <div>
6
+ <h1 class='ns-page-title'><%= t(:link_groups) %></h1>
7
+ <%= link_to new_admin_link_group_path, class: 'btn btn-success new-action', id: 'add_new_link_group' do %>
8
+ <i class="icon-plus"></i> <%= t(:add_new_link_group) %>
9
+ <% end %>
10
+ <div class='clear'></div>
11
+ </div>
12
+
13
+ <% if @link_group && @link_group.errors.any? %>
14
+ <div class="alert-message block-message error">
15
+ <p> <%= t(:error_bang) %> </p>
16
+ <ul>
17
+ <% @link_group.errors.full_messages.each do |message| %>
18
+ <li><%= message %></li>
19
+ <% end %>
20
+ </ul>
21
+ </div>
22
+ <% end %>
23
+
24
+ <br />
25
+ <br />
26
+
27
+ <% @link_groups.each do |link_group| %>
28
+ <%= render 'link_group', link_group: link_group %>
29
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% page_title 'new link group' %>
2
+
3
+ <div>
4
+ <h1><%= t(:add_new_link_group) %></h1>
5
+ </div>
6
+
7
+ <br />
8
+
9
+ <%= render 'form' %>
@@ -0,0 +1,31 @@
1
+ Order #<%= @order.number %> was placed by <%= @order.final_billing_address.name %> .
2
+
3
+ Payment date: <%= @payment_date %>
4
+
5
+ Shipping address:
6
+ <% @order.shipping_address.full_address_array.each do |line| %>
7
+ <%= line %>
8
+ <% end %>
9
+
10
+ <% unless @order.shipping_address.use_for_billing %>
11
+ Billing address :
12
+ <% @order.billing_address.full_address_array.each do |line| %>
13
+ <%= line %>
14
+ <% end %>
15
+ <% end %>
16
+
17
+ Items purchased:
18
+
19
+ <% @order.line_items.each do |line_item| %>
20
+ <% product = line_item.product %>
21
+ Name: <%= truncate(sanitize(product.name), length: 90) %>
22
+ Item price: <%= number_to_currency(product.price) %>
23
+ Item quantity: <%= line_item.quantity %>
24
+ Item total price: <%= number_to_currency(line_item.price) %>
25
+ <% end %>
26
+
27
+ Shipping method: <%= @order.shipping_method.name %>
28
+ Shipping cost: <%= number_to_currency(@order.shipping_method.shipping_cost) %>
29
+
30
+ Total amount: <%= number_to_currency(@order.total_amount) %>
31
+
@@ -0,0 +1,5 @@
1
+ <% page_title 'admin dashboard' %>
2
+
3
+ <div class="hero-unit">
4
+ <h1><%= t(:welcome_admin) %></h1>
5
+ </div>
@@ -0,0 +1,29 @@
1
+ <% page_title 'add a new link' %>
2
+
3
+ <div>
4
+ <h1 class='ns-page-title'>Add a new link to link group <%= @link_group.name %></h1>
5
+ <div class='clear'></div>
6
+ </div>
7
+
8
+ <br />
9
+
10
+ <div class='well'>
11
+ <%= form_for([:admin, @link_group, @navigation], html: {class: 'form-horizontal'}) do |f| %>
12
+
13
+ <fieldset>
14
+ <div class="control-group">
15
+ <%= f.label :product_group_id, 'Product Group', class: 'control-label' %>
16
+ <div class="controls">
17
+ <%= f.collection_select :product_group_id, ProductGroup.all, :id, :name %>
18
+ </div>
19
+ </div>
20
+ </fieldset>
21
+
22
+ <div class="form-actions">
23
+ <%= f.submit('Add', class: 'btn btn-primary') %>
24
+ &nbsp;
25
+ <%= link_to 'Cancel', admin_link_groups_path, class: 'btn' %>
26
+ </div>
27
+
28
+ <% end %>
29
+ <div>
@@ -0,0 +1,11 @@
1
+ <tr>
2
+ <td class="pic">
3
+ <%= image_tag(line_item.picture_small, alt: line_item.product_name) %>
4
+ </td>
5
+ <td>
6
+ <strong><%= line_item.product_name %></strong>
7
+ </td>
8
+ <td><%= number_to_currency(line_item.product_price) %></td>
9
+ <td> <%=line_item.quantity%> </td>
10
+ <td><%= number_to_currency(line_item.price) %></td>
11
+ </tr>