diff --git a/.gitignore b/.gitignore
index 6a502e99..22ab23d9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,8 @@
# Ignore all logfiles and tempfiles.
/log/*.log
/tmp
+
+# Ignore upload files
+.DS_Store
+/public/uploads/product/photo/
+/config/config.yml
diff --git a/Gemfile b/Gemfile
index fba3b4e0..c2f72436 100644
--- a/Gemfile
+++ b/Gemfile
@@ -3,8 +3,19 @@ source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.1.0'
-# Use sqlite3 as the database for Active Record
-gem 'sqlite3'
+
+group :development do
+ # Use sqlite3 as the database for Active Record
+ gem 'sqlite3'
+ #Mailer
+ gem "letter_opener" #本機看信
+ gem 'roadie' #可在信裡面引入CSS
+end
+
+group :production do
+ gem 'pg'
+ gem 'rails_12factor'
+end
# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.3'
# Use Uglifier as compressor for JavaScript assets
@@ -38,3 +49,28 @@ gem 'spring', group: :development
# Use debugger
# gem 'debugger', group: [:development, :test]
+gem 'minitest', '~>5.3.4'
+
+gem "simple_form", "~> 3.1.0rc1"
+
+#使用者帳號管理
+gem 'devise'
+
+gem 'bootstrap-sass'
+
+#圖片上傳
+gem 'carrierwave'
+
+gem "mini_magick"
+
+#FSM
+gem 'aasm'
+
+#credit card
+gem 'stripe'
+# hide keys
+gem "settingslogic"
+gem "will_paginate"
+gem "ransack"
+
+
diff --git a/Gemfile.lock b/Gemfile.lock
index 53538d9b..bfb39425 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,6 +1,7 @@
GEM
remote: https://rubygems.org/
specs:
+ aasm (3.2.1)
actionmailer (4.1.0)
actionpack (= 4.1.0)
actionview (= 4.1.0)
@@ -27,8 +28,17 @@ GEM
minitest (~> 5.1)
thread_safe (~> 0.1)
tzinfo (~> 1.1)
+ addressable (2.3.6)
arel (5.0.1.20140414130214)
+ bcrypt (3.1.7)
+ bootstrap-sass (3.1.1.1)
+ sass (~> 3.2)
builder (3.2.2)
+ carrierwave (0.10.0)
+ activemodel (>= 3.2.0)
+ activesupport (>= 3.2.0)
+ json (>= 1.7)
+ mime-types (>= 1.16)
coffee-rails (4.0.1)
coffee-script (>= 2.2.0)
railties (>= 4.0.0, < 5.0)
@@ -36,6 +46,14 @@ GEM
coffee-script-source
execjs
coffee-script-source (1.7.0)
+ css_parser (1.3.5)
+ addressable
+ devise (3.2.4)
+ bcrypt (~> 3.0)
+ orm_adapter (~> 0.1)
+ railties (>= 3.2.6, < 5)
+ thread_safe (~> 0.1)
+ warden (~> 1.2.3)
erubis (2.7.0)
execjs (2.2.0)
hike (1.2.3)
@@ -47,12 +65,25 @@ GEM
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.8.1)
+ launchy (2.4.2)
+ addressable (~> 2.3)
+ letter_opener (1.2.0)
+ launchy (~> 2.2)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
mime-types (1.25.1)
- minitest (5.3.4)
+ mini_magick (3.7.0)
+ subexec (~> 0.2.1)
+ mini_portile (0.6.0)
+ minitest (5.3.5)
multi_json (1.10.1)
+ nokogiri (1.6.2.1)
+ mini_portile (= 0.6.0)
+ orm_adapter (0.5.0)
+ pg (0.17.1)
+ polyamorous (1.0.0)
+ activerecord (>= 3.0)
polyglot (0.3.5)
rack (1.5.2)
rack-test (0.6.2)
@@ -67,14 +98,32 @@ GEM
bundler (>= 1.3.0, < 2.0)
railties (= 4.1.0)
sprockets-rails (~> 2.0)
+ rails_12factor (0.0.2)
+ rails_serve_static_assets
+ rails_stdout_logging
+ rails_serve_static_assets (0.0.2)
+ rails_stdout_logging (0.0.3)
railties (4.1.0)
actionpack (= 4.1.0)
activesupport (= 4.1.0)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (10.3.2)
+ ransack (1.2.3)
+ actionpack (>= 3.0)
+ activerecord (>= 3.0)
+ activesupport (>= 3.0)
+ i18n
+ polyamorous (~> 1.0.0)
rdoc (4.1.1)
json (~> 1.4)
+ rest-client (1.6.7)
+ mime-types (>= 1.16)
+ roadie (2.4.3)
+ actionmailer (> 3.0.0, < 5.0.0)
+ css_parser (~> 1.3.4)
+ nokogiri (> 1.5.0)
+ sprockets
sass (3.2.19)
sass-rails (4.0.3)
railties (>= 4.0.0, < 5.0)
@@ -84,6 +133,10 @@ GEM
sdoc (0.4.0)
json (~> 1.8)
rdoc (~> 4.0, < 5.0)
+ settingslogic (2.0.9)
+ simple_form (3.1.0.rc1)
+ actionpack (~> 4.0)
+ activemodel (~> 4.0)
spring (1.1.3)
sprockets (2.11.0)
hike (~> 1.2)
@@ -95,6 +148,11 @@ GEM
activesupport (>= 3.0)
sprockets (~> 2.8)
sqlite3 (1.3.9)
+ stripe (1.14.0)
+ json (~> 1.8.1)
+ mime-types (~> 1.25)
+ rest-client (~> 1.4)
+ subexec (0.2.3)
thor (0.19.1)
thread_safe (0.3.4)
tilt (1.4.1)
@@ -108,18 +166,36 @@ GEM
uglifier (2.5.0)
execjs (>= 0.3.0)
json (>= 1.8.0)
+ warden (1.2.3)
+ rack (>= 1.0)
+ will_paginate (3.0.6)
PLATFORMS
ruby
DEPENDENCIES
+ aasm
+ bootstrap-sass
+ carrierwave
coffee-rails (~> 4.0.0)
+ devise
jbuilder (~> 2.0)
jquery-rails
+ letter_opener
+ mini_magick
+ minitest (~> 5.3.4)
+ pg
rails (= 4.1.0)
+ rails_12factor
+ ransack
+ roadie
sass-rails (~> 4.0.3)
sdoc (~> 0.4.0)
+ settingslogic
+ simple_form (~> 3.1.0rc1)
spring
sqlite3
+ stripe
turbolinks
uglifier (>= 1.3.0)
+ will_paginate
diff --git a/UserStory.todo b/UserStory.todo
new file mode 100644
index 00000000..2bf1d418
--- /dev/null
+++ b/UserStory.todo
@@ -0,0 +1,38 @@
+ ✔ 身為商家的管理者我要能夠在後台上架我的東西,並設定能夠販賣 @done (14-06-10 15:29)
+ ✔ 管理者必須要有一個後台 @done (14-06-10 15:29)
+ ✔ 後台必須要可以新增產品 @done (14-06-10 15:29)
+ ✔ 產品內容必須要有標題 文字 數量 圖片 @done (14-06-16 16:10)
+ ✔ 身為商家的管理者,我要能夠在後台設定權限,權限分為管理者以及消費者 @done (14-06-10 15:55)
+ ✔ 身為管理者,才可以進入後台 @done (14-06-10 15:55)
+ ✔ 身為管理者,必須要登入且是admin @done (14-06-10 15:55)
+ ✔ 管理這的身份必須要被分為 admin / user @done (14-06-10 15:55)
+ ☐ 作為一個消費者,我要在前台能夠找到商品並結賬
+ ✔ 身為消費者,我要在前台能夠找到商品並加到購物車 @done (14-06-18 15:52)
+ +購物車設計
+ ✔ 身為消費者,我要將商品加到購物車後,NAV_bar要可以顯示購物車中的商品數量 @done (14-06-18 17:10)
+ ✔ 身為消費者,我要可以在購物車頁清空購物車的商品 @done (14-06-19 11:26)
+ ✔ 身為消費者,我要可以從購物車內刪掉某些物品 @done (14-06-19 10:13)
+ ✔ 身為消費者,我可以在購物車中選擇我要買某些物品的數量 @done (14-06-20 15:07)
+ ✔ 身為消費者,我可以看到我購物車的總價 (小計 x 數量) @done (14-06-20 16:28)
+ ✔ 身為消費者,我在購物時數量為0的貨物不能買 @done (14-06-20 16:28)
+ +購物車訂單
+ ✔ 身為消費者,我要在前台能夠將多樣商品加到購物車,並生成一張訂單 @done (14-06-19 17:41)
+ ☐ 美化訂單
+ +訂單可以用信用卡結賬
+ ✔ 身為消費者,當系統生成一張訂單後,我可以填寫寄送資訊,並且用信用卡結賬 @done (14-06-20 22:56)
+ ✔ 身為消費者,當我用信用卡結賬後,我的信箱要能收到一張訂單確認信 @done (14-06-24 16:49)
+ ☐ 身為消費者,當我付款成功後,我的信箱要能收到一張確認信
+ ☐ 身為消費者,當我收到確認信上,要有可以檢視訂單的連結
+ ☐ 安裝SettingsLogic,把stripe的key放進SettingLogic的yml裏面
+ ☐ 把mailgun的key放進SettingLogic的yml裏面
+ +搜尋功能
+ ✔ 身為消費者,我可以搜尋產品的資料(ransack) @done (14-06-30 13:56)
+ +消費者訂單管理(account)
+ ✔ 身為消費者,可看到過去所有訂單(orders) @done (14-06-21 21:40)
+ ✔ 身為消費者,在結賬完後,會自動跳到訂單的管理界面 @done (14-06-21 22:19)
+☐ Admin 管理訂單
+ ✔ 身為管理者,可以在後台看到所有訂單 @done (14-06-21 22:47)
+ ✔ 訂單狀態分為未結賬 已結賬 出貨中 已出貨 辦理退貨 @done (14-06-21 22:47)
+ ✔ 身為管理者,可以在後台對單張訂單做狀態改變 @done (14-06-23 14:57)
+ ☐ 身為管理者,當我在將商品設為已出貨時,消費者應該收到一張已出貨的通知信
+ ☐ 身為商家,當消費者確定購物結賬後,該商品的庫存必須按照數量減少
diff --git a/app/assets/javascripts/account/orders.js.coffee b/app/assets/javascripts/account/orders.js.coffee
new file mode 100644
index 00000000..24f83d18
--- /dev/null
+++ b/app/assets/javascripts/account/orders.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/admin.js.coffee b/app/assets/javascripts/admin.js.coffee
new file mode 100644
index 00000000..24f83d18
--- /dev/null
+++ b/app/assets/javascripts/admin.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/admin/orders.js.coffee b/app/assets/javascripts/admin/orders.js.coffee
new file mode 100644
index 00000000..24f83d18
--- /dev/null
+++ b/app/assets/javascripts/admin/orders.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/admin/products.js.coffee b/app/assets/javascripts/admin/products.js.coffee
new file mode 100644
index 00000000..24f83d18
--- /dev/null
+++ b/app/assets/javascripts/admin/products.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index d6925fa4..eacbcbc4 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -13,4 +13,4 @@
//= require jquery
//= require jquery_ujs
//= require turbolinks
-//= require_tree .
+//= require orders
diff --git a/app/assets/javascripts/card_charges.js.coffee b/app/assets/javascripts/card_charges.js.coffee
new file mode 100644
index 00000000..24f83d18
--- /dev/null
+++ b/app/assets/javascripts/card_charges.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/carts.js.coffee b/app/assets/javascripts/carts.js.coffee
new file mode 100644
index 00000000..24f83d18
--- /dev/null
+++ b/app/assets/javascripts/carts.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/orders.js.coffee b/app/assets/javascripts/orders.js.coffee
new file mode 100644
index 00000000..536608ce
--- /dev/null
+++ b/app/assets/javascripts/orders.js.coffee
@@ -0,0 +1,35 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
+
+jQuery ($) ->
+ $("#payment-form").submit (event) ->
+ $form = $(this)
+
+ # Disable the submit button to prevent repeated clicks
+ $form.find("button").prop "disabled", true
+ Stripe.createToken $form, stripeResponseHandler
+
+ # Prevent the form from submitting with the default action
+ false
+
+ return
+
+stripeResponseHandler = (status, response) ->
+ $form = $("#payment-form")
+ if response.error
+
+ # Show the errors on the form
+ $form.find(".payment-errors").text response.error.message
+ $form.find("button").prop "disabled", false
+ else
+
+ # token contains id, last4, and card type
+ token = response.id
+
+ # Insert the token into the form so it gets submitted to the server
+ $form.append $("").val(token)
+
+ # and submit
+ $form.get(0).submit()
+ return
diff --git a/app/assets/javascripts/pages.js.coffee b/app/assets/javascripts/pages.js.coffee
new file mode 100644
index 00000000..24f83d18
--- /dev/null
+++ b/app/assets/javascripts/pages.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/javascripts/products.js.coffee b/app/assets/javascripts/products.js.coffee
new file mode 100644
index 00000000..24f83d18
--- /dev/null
+++ b/app/assets/javascripts/products.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
diff --git a/app/assets/stylesheets/account/orders.css.scss b/app/assets/stylesheets/account/orders.css.scss
new file mode 100644
index 00000000..53b61bac
--- /dev/null
+++ b/app/assets/stylesheets/account/orders.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the account/orders controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/admin.css.scss b/app/assets/stylesheets/admin.css.scss
new file mode 100644
index 00000000..6b557352
--- /dev/null
+++ b/app/assets/stylesheets/admin.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the admin controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/admin/orders.css.scss b/app/assets/stylesheets/admin/orders.css.scss
new file mode 100644
index 00000000..449abf68
--- /dev/null
+++ b/app/assets/stylesheets/admin/orders.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the admin/orders controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/admin/products.css.scss b/app/assets/stylesheets/admin/products.css.scss
new file mode 100644
index 00000000..da8969d1
--- /dev/null
+++ b/app/assets/stylesheets/admin/products.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the admin::products controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css
index a443db34..8070ddb4 100644
--- a/app/assets/stylesheets/application.css
+++ b/app/assets/stylesheets/application.css
@@ -12,4 +12,17 @@
*
*= require_tree .
*= require_self
+ *= require bootstrap
+ *= require products
*/
+
+.group:before, .group:after {
+ content: "";
+ display: table;
+}
+.group:after {
+ clear: both;
+}
+.group {
+ zoom: 1; /* IE6&7 */
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/card_charges.css.scss b/app/assets/stylesheets/card_charges.css.scss
new file mode 100644
index 00000000..24adb84c
--- /dev/null
+++ b/app/assets/stylesheets/card_charges.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the card_charges controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/cart_items.css.scss b/app/assets/stylesheets/cart_items.css.scss
new file mode 100644
index 00000000..065f8dbf
--- /dev/null
+++ b/app/assets/stylesheets/cart_items.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the cart_iterms controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/carts.css.scss b/app/assets/stylesheets/carts.css.scss
new file mode 100644
index 00000000..62647c9d
--- /dev/null
+++ b/app/assets/stylesheets/carts.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the carts controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/orders.css.scss b/app/assets/stylesheets/orders.css.scss
new file mode 100644
index 00000000..3b0428a9
--- /dev/null
+++ b/app/assets/stylesheets/orders.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the orders controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/pages.css.scss b/app/assets/stylesheets/pages.css.scss
new file mode 100644
index 00000000..0d6878aa
--- /dev/null
+++ b/app/assets/stylesheets/pages.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the pages controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/products.css.scss b/app/assets/stylesheets/products.css.scss
new file mode 100644
index 00000000..f05059f7
--- /dev/null
+++ b/app/assets/stylesheets/products.css.scss
@@ -0,0 +1,12 @@
+// Place all the styles related to the products controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
+
+.product-price{
+ padding-top: 20px;
+ padding-bottom: 20px;
+
+ font-size: 30px;
+ font-weight: bold;
+ color: #ff007c;
+}
diff --git a/app/controllers/account/orders_controller.rb b/app/controllers/account/orders_controller.rb
new file mode 100644
index 00000000..40e320a8
--- /dev/null
+++ b/app/controllers/account/orders_controller.rb
@@ -0,0 +1,7 @@
+class Account::OrdersController < ApplicationController
+ before_action :authenticate_user!
+
+ def index
+ @orders = current_user.orders.recent
+ end
+end
diff --git a/app/controllers/admin/orders_controller.rb b/app/controllers/admin/orders_controller.rb
new file mode 100644
index 00000000..a94dec30
--- /dev/null
+++ b/app/controllers/admin/orders_controller.rb
@@ -0,0 +1,42 @@
+class Admin::OrdersController < AdminController
+
+ before_filter :find_order, :except => [:index]
+
+ def index
+ @orders = Order.recent
+ end
+
+
+ def show
+
+ @order_info = @order.info
+ @order_items = @order.items
+ end
+
+ def ship
+ @order.ship!
+ redirect_to :back
+ end
+
+ def shipped
+ @order.deliver!
+ redirect_to :back
+ end
+
+ def cancel
+ @order.cancell_order!
+ redirect_to :back
+ end
+
+ def return
+ @order.return_good!
+ redirect_to :back
+ end
+
+ protected
+
+
+ def find_order
+ @order = Order.find_by_token(params[:id])
+ end
+end
diff --git a/app/controllers/admin/products_controller.rb b/app/controllers/admin/products_controller.rb
new file mode 100644
index 00000000..6941db1a
--- /dev/null
+++ b/app/controllers/admin/products_controller.rb
@@ -0,0 +1,53 @@
+class Admin::ProductsController < AdminController
+
+ def new
+ @product = Product.new
+ @photo = @product.photos.new
+ end
+
+ def create
+ @product = Product.new(product_params)
+
+ if @product.save
+ redirect_to admin_products_path
+ else
+ render :new
+ end
+ end
+
+ def show
+ @product = Product.find(params[:id])
+ end
+
+ def index
+ @products = Product.all
+ end
+
+ def edit
+ @product = Product.find(params[:id])
+ end
+
+ def update
+ @product = Product.find(params[:id])
+
+ if @product.save(product_params)
+ redirect_to admin_products_path(@product)
+ else
+ render :edit
+ end
+ end
+
+ def destroy
+ @product = Product.find(params[:id])
+
+ @product.destroy
+
+ redirect_to admin_products_path
+ end
+
+ private
+
+ def product_params
+ params.require(:product).permit(:title, :description, :quantity, :price, :photos_attributes =>[:image])
+ end
+end
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb
new file mode 100644
index 00000000..3bce92b3
--- /dev/null
+++ b/app/controllers/admin_controller.rb
@@ -0,0 +1,6 @@
+class AdminController < ApplicationController
+ layout "admin"
+
+ before_action :authenticate_user!
+ before_action :admin_required
+end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index d83690e1..f9ef5337 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -2,4 +2,26 @@ class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
+
+ def admin_required
+ current_user.admin?
+ end
+
+ helper_method :current_cart
+
+ def current_cart
+ @current_cart ||= find_cart
+ end
+
+ def find_cart
+
+ cart = Cart.find_by(id: session[:cart_id])
+
+ unless cart.present?
+ cart = Cart.create
+ end
+
+ session[:cart_id] = cart.id
+ cart
+ end
end
diff --git a/app/controllers/card_charges_controller.rb b/app/controllers/card_charges_controller.rb
new file mode 100644
index 00000000..a57f91d9
--- /dev/null
+++ b/app/controllers/card_charges_controller.rb
@@ -0,0 +1,28 @@
+class CardChargesController < ApplicationController
+
+ before_action :authenticate_user!
+
+ def create
+
+ @order = current_user.orders.find_by_token(params[:order_id])
+ @amount = @order.total * 100 # in cents
+
+ charge = StripeCharge.create(
+ :amount => @amount,
+ :card => params[:stripeToken],
+ :description => @order.token ,
+ )
+
+ if charge.successful?
+ @order.set_payment_with!("credit_card")
+ @order.make_payment!
+ redirect_to order_path(@order.token), :notice => "成功完成付款"
+ else
+ flash[:error] = charge.error_message
+ render "orders/pay_with_credit_card"
+ end
+
+ end
+
+
+end
diff --git a/app/controllers/cart_items_controller.rb b/app/controllers/cart_items_controller.rb
new file mode 100644
index 00000000..28b810af
--- /dev/null
+++ b/app/controllers/cart_items_controller.rb
@@ -0,0 +1,29 @@
+class CartItemsController < ApplicationController
+
+ before_action :authenticate_user!
+
+ def update
+ @cart = current_cart
+ @item = @cart.cart_items.find(params[:id])
+
+ @item.update(item_params)
+
+ redirect_to carts_path
+ end
+
+ def destroy
+ @cart = current_cart
+ @item = @cart.cart_items.find(params[:id])
+
+ @item.destroy
+
+ flash[:warning] = "已清空物品"
+ redirect_to :back
+ end
+
+ private
+
+ def item_params
+ params.require(:cart_item).permit(:quantity)
+ end
+end
diff --git a/app/controllers/carts_controller.rb b/app/controllers/carts_controller.rb
new file mode 100644
index 00000000..710915ac
--- /dev/null
+++ b/app/controllers/carts_controller.rb
@@ -0,0 +1,26 @@
+class CartsController < ApplicationController
+ before_action :authenticate_user!, :only => [:checkout]
+
+ def index
+ end
+
+ def destroy
+ @cart = current_cart
+ @cart.destroy
+
+ session[:card_id] = nil
+
+ flash[:notice] = "你已成功清空購物車"
+ redirect_to products_path
+ end
+
+ def checkout
+ @order = current_user.orders.build
+ @info = @order.build_info
+ end
+
+ def show
+
+ end
+
+end
diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb
new file mode 100644
index 00000000..66a1e250
--- /dev/null
+++ b/app/controllers/orders_controller.rb
@@ -0,0 +1,45 @@
+class OrdersController < ApplicationController
+
+ before_action :authenticate_user!
+
+ def show
+ @order = current_user.orders.find_by_token(params[:id])
+ @order_info = @order.info
+ @order_items = @order.items
+ end
+
+ def create
+ @order = current_user.orders.build(order_params)
+
+ if @order.save
+ #@order.build_item_cache_from_cart(current_cart)
+ #@order.calculate_total!(current_cart)
+
+ #OrderMailer.notify_order_placed(@order).deliver
+ OrderPlacingService.new(current_cart, @order).place_order!
+
+ redirect_to order_path(@order.token)
+ else
+ render "carts/checkout"
+ end
+ end
+
+ def pay_with_credit_card
+ @order = current_user.orders.find_by_token(params[:id])
+ #@order.set_payment_with!("credit_card")
+
+ current_cart.clear!
+
+ #@order.pay! #TODO: implemnt pay method later
+ #@order.make_payment! #TODO: should move to stripe callbacks
+
+ #redirect_to account_orders_path, :notice => "成功完成付款"
+ end
+
+ private
+
+ def order_params
+ params.require(:order).permit(:info_attributes =>
+ [:billing_name, :billing_address,:shipping_name, :shipping_address] )
+ end
+end
diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb
new file mode 100644
index 00000000..90fff55b
--- /dev/null
+++ b/app/controllers/pages_controller.rb
@@ -0,0 +1,5 @@
+class PagesController < ApplicationController
+
+ def index
+ end
+end
diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb
new file mode 100644
index 00000000..8ad5076c
--- /dev/null
+++ b/app/controllers/products_controller.rb
@@ -0,0 +1,69 @@
+class ProductsController < ApplicationController
+
+ before_filter :validate_search_key, :only => [:search]
+
+ def index
+ @products = Product.order("id DESC")
+ end
+
+
+ def show
+ @product = Product.find(params[:id])
+ end
+
+ def add_to_cart
+
+ @product = Product.find(params[:id])
+
+ if !current_cart.items.include?(@product)
+ if @product.quantity > 0
+ current_cart.add_product_to_cart(@product,1)
+ flash[:notice] = "你已成功將 #{@product.title} 加入購物車"
+ else
+ flash[:warning] = "此物品已經銷售完畢了,無法加入購物車"
+ end
+
+ else
+ flash[:warning] = "你的購物車內已有此物品"
+ end
+
+ redirect_to :back
+
+ end
+
+ def delete_from_cart
+
+ @product = Product.find(params[:id])
+
+ if current_cart.items.include?(@product)
+ current_cart.delete_item_from_cart(@product)
+ flash[:notice] = "你已成功將 #{@product.title} 從購物車中移除"
+ else
+ flash[:warning] = "你的購物車內已無此物品"
+ end
+
+ redirect_to :back
+
+ end
+
+ def search
+ if @query_string.present?
+ search_result = Product.ransack(@search_criteria).result(:distinct => true)
+ @products = search_result.paginate(:page => params[:page], :per_page => 20 )
+ end
+ end
+
+ protected
+
+ def validate_search_key
+ @query_string = params[:q].gsub(/\\|\'|\/|\?/, "") if params[:q].present?
+ @search_criteria = search_criteria(@query_string)
+ end
+
+
+ def search_criteria(query_string)
+ { :title_cont => query_string }
+ end
+
+
+end
diff --git a/app/helpers/account/orders_helper.rb b/app/helpers/account/orders_helper.rb
new file mode 100644
index 00000000..6f690c4e
--- /dev/null
+++ b/app/helpers/account/orders_helper.rb
@@ -0,0 +1,2 @@
+module Account::OrdersHelper
+end
diff --git a/app/helpers/admin/orders_helper.rb b/app/helpers/admin/orders_helper.rb
new file mode 100644
index 00000000..e5168e1b
--- /dev/null
+++ b/app/helpers/admin/orders_helper.rb
@@ -0,0 +1,8 @@
+module Admin::OrdersHelper
+
+ def render_order_options_for_admin(order)
+
+ render :partial => "admin/orders/state_option", :locals => { :order => order}
+
+ end
+end
diff --git a/app/helpers/admin/products_helper.rb b/app/helpers/admin/products_helper.rb
new file mode 100644
index 00000000..dc0dfcf4
--- /dev/null
+++ b/app/helpers/admin/products_helper.rb
@@ -0,0 +1,3 @@
+module Admin::ProductsHelper
+
+end
diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb
new file mode 100644
index 00000000..d5c6d355
--- /dev/null
+++ b/app/helpers/admin_helper.rb
@@ -0,0 +1,2 @@
+module AdminHelper
+end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index de6be794..b4aed09f 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -1,2 +1,19 @@
module ApplicationHelper
+ def notice_message
+ alert_types = { :notice => :success, :alert => :danger }
+
+ close_button_options = { :class => "close", "data-dismiss" => "alert", "aria-hidden" => true }
+ close_button = content_tag(:button, "×", close_button_options)
+
+ alerts = flash.map do |type, message|
+ alert_content = close_button + message
+
+ alert_type = alert_types[type.to_sym] || type
+ alert_class = "alert alert-#{alert_type} alert-dismissable"
+
+ content_tag(:div, alert_content, :class => alert_class)
+ end
+
+ alerts.join("\n").html_safe
+ end
end
diff --git a/app/helpers/card_charges_helper.rb b/app/helpers/card_charges_helper.rb
new file mode 100644
index 00000000..5c18c543
--- /dev/null
+++ b/app/helpers/card_charges_helper.rb
@@ -0,0 +1,2 @@
+module CardChargesHelper
+end
diff --git a/app/helpers/cart_items_helper.rb b/app/helpers/cart_items_helper.rb
new file mode 100644
index 00000000..f30f6834
--- /dev/null
+++ b/app/helpers/cart_items_helper.rb
@@ -0,0 +1,2 @@
+module CartItemsHelper
+end
diff --git a/app/helpers/carts_helper.rb b/app/helpers/carts_helper.rb
new file mode 100644
index 00000000..a3429fd7
--- /dev/null
+++ b/app/helpers/carts_helper.rb
@@ -0,0 +1,10 @@
+module CartsHelper
+
+ def cart_items_count(cart)
+ cart.cart_items.count
+ end
+
+ def render_cart_total_price(current_cart)
+ current_cart.total_price
+ end
+end
diff --git a/app/helpers/orders_helper.rb b/app/helpers/orders_helper.rb
new file mode 100644
index 00000000..812e9ef0
--- /dev/null
+++ b/app/helpers/orders_helper.rb
@@ -0,0 +1,21 @@
+module OrdersHelper
+ def render_order_link(order)
+ link_to(order.token, order_path(order.token))
+ end
+
+ def render_admin_order_link(order)
+ link_to(order.token, admin_order_path(order.token))
+ end
+
+ def render_order_created_time(order)
+ order.created_at.to_s(:short)
+ end
+
+ def render_order_user_name(user)
+ user.email
+ end
+
+ def render_order_state(order)
+ t("orders.order_state.#{order.aasm_state}")
+ end
+end
diff --git a/app/helpers/pages_helper.rb b/app/helpers/pages_helper.rb
new file mode 100644
index 00000000..2c057fd0
--- /dev/null
+++ b/app/helpers/pages_helper.rb
@@ -0,0 +1,2 @@
+module PagesHelper
+end
diff --git a/app/helpers/products_helper.rb b/app/helpers/products_helper.rb
new file mode 100644
index 00000000..40954d36
--- /dev/null
+++ b/app/helpers/products_helper.rb
@@ -0,0 +1,37 @@
+module ProductsHelper
+ def render_product_photo(photo, size = "thumb")
+
+ if photo.present?
+ image_url = photo.image.send(size).url
+ else
+
+ case size
+ when :medium
+ volume = "300x300"
+ else
+ volume = "200x200"
+ end
+
+ image_url = "http://placehold.it/#{volume}&text=No Pic"
+ end
+
+ image_tag(image_url, :class => "thumbnail")
+
+ end
+
+ def render_product_name(product)
+ product.title
+ end
+
+ def render_product_desc(product)
+ simple_format(product.description)
+ end
+
+ def render_product_quantity(product)
+ product.quantity
+ end
+
+ def render_product_price(product)
+ product.price
+ end
+end
diff --git a/app/mailers/order_mailer.rb b/app/mailers/order_mailer.rb
new file mode 100644
index 00000000..8f456fff
--- /dev/null
+++ b/app/mailers/order_mailer.rb
@@ -0,0 +1,15 @@
+class OrderMailer < ActionMailer::Base
+ default from: "staff@artstore.com"
+
+ def notify_order_placed(order)
+
+ @order = order
+ @user = order.user
+ @order_items = @order.items
+ @order_info = @order.info
+
+
+ mail(:to => @user.email , :subject => " [ArtStore] 感謝您完成本次的下單,以下是您這次購物明細 #{order.token}")
+ end
+
+end
diff --git a/app/models/cart.rb b/app/models/cart.rb
new file mode 100644
index 00000000..8782f540
--- /dev/null
+++ b/app/models/cart.rb
@@ -0,0 +1,24 @@
+class Cart < ActiveRecord::Base
+ has_many :cart_items, :dependent => :destroy
+ has_many :items, :through => :cart_items, :source => :product
+
+
+ def add_product_to_cart(product , amount)
+ cart_item = cart_items.build
+ cart_item.product = product
+ cart_item.quantity = amount
+ cart_item.save
+ end
+
+ def delete_item_from_cart(product)
+ items.delete(product)
+ end
+
+ def clear!
+ cart_items.delete_all
+ end
+
+ def total_price
+ cart_items.inject(0) { |sum, item| sum + (item.product.price * item.quantity)}
+ end
+end
diff --git a/app/models/cart_item.rb b/app/models/cart_item.rb
new file mode 100644
index 00000000..ddf0322b
--- /dev/null
+++ b/app/models/cart_item.rb
@@ -0,0 +1,4 @@
+class CartItem < ActiveRecord::Base
+ belongs_to :cart
+ belongs_to :product
+end
diff --git a/app/models/concerns.rb b/app/models/concerns.rb
new file mode 100644
index 00000000..bbcea32b
--- /dev/null
+++ b/app/models/concerns.rb
@@ -0,0 +1,5 @@
+module Concerns
+ def self.table_name_prefix
+ 'concerns_'
+ end
+end
diff --git a/app/models/concerns/tokenable.rb b/app/models/concerns/tokenable.rb
new file mode 100644
index 00000000..f30d3753
--- /dev/null
+++ b/app/models/concerns/tokenable.rb
@@ -0,0 +1,13 @@
+module Tokenable
+
+ extend ActiveSupport::Concern
+
+ included do
+ before_create :generate_token
+ end
+
+ def generate_token
+ self.token = SecureRandom.uuid
+ end
+
+end
diff --git a/app/models/order.rb b/app/models/order.rb
new file mode 100644
index 00000000..b4bea92f
--- /dev/null
+++ b/app/models/order.rb
@@ -0,0 +1,73 @@
+class Order < ActiveRecord::Base
+
+ belongs_to :user
+ has_many :items, :class_name => "OrderItem", :dependent => :destroy
+ has_one :info, :class_name => "OrderInfo", :dependent => :destroy
+
+ accepts_nested_attributes_for :info
+
+ scope :recent, -> { order("id DESC")}
+
+ include Tokenable
+
+ def build_item_cache_from_cart(cart)
+ cart.items.each do |cart_item|
+ item = items.build
+ item.product_name = cart_item.title
+ item.quantity = cart.cart_items.find_by(:product_id => cart_item.id).quantity
+ item.price = cart_item.price
+ item.save
+ end
+ end
+
+ def calculate_total!(current_cart)
+ self.total = current_cart.total_price
+ self.save
+ end
+
+ #before_create :generate_token
+
+ #def generate_token
+ #self.token = SecureRandom.uuid
+ #end
+
+ def set_payment_with!(method)
+ self.update_column(:payment_method, method)
+ end
+
+ def pay!
+ self.update_column(:paid, true)
+ end
+
+ include AASM
+
+ aasm do
+ state :order_placed, :initial => true
+ state :paid, :after_commit => :pay!
+ event :make_payment do
+ transitions :from => :order_placed, :to => :paid
+ end
+
+ state :shipping
+ event :ship do
+ transitions :from => :paid, :to => :shipping
+ end
+
+ state :shipped
+ event :deliver do
+ transitions :from => :shipping, :to => :shipped
+ end
+
+ state :order_cancelled
+ event :cancell_order do
+ transitions :from => [:order_placed, :paid ], :to => :order_cancelled
+ end
+
+ state :good_returned
+ event :return_good do
+ transitions :from => [:shipped ], :to => :good_returned
+ end
+
+ end
+
+end
diff --git a/app/models/order_info.rb b/app/models/order_info.rb
new file mode 100644
index 00000000..59143ae2
--- /dev/null
+++ b/app/models/order_info.rb
@@ -0,0 +1,10 @@
+class OrderInfo < ActiveRecord::Base
+ belongs_to :order
+
+
+ validates :billing_name , :presence => true
+ validates :billing_address , :presence => true
+ validates :shipping_name , :presence => true
+ validates :shipping_address , :presence => true
+
+end
diff --git a/app/models/order_item.rb b/app/models/order_item.rb
new file mode 100644
index 00000000..7d3194a5
--- /dev/null
+++ b/app/models/order_item.rb
@@ -0,0 +1,2 @@
+class OrderItem < ActiveRecord::Base
+end
diff --git a/app/models/photo.rb b/app/models/photo.rb
new file mode 100644
index 00000000..a3e078be
--- /dev/null
+++ b/app/models/photo.rb
@@ -0,0 +1,5 @@
+class Photo < ActiveRecord::Base
+ belongs_to :product
+
+ mount_uploader :image, PhotoUploader
+end
diff --git a/app/models/product.rb b/app/models/product.rb
new file mode 100644
index 00000000..626ecca6
--- /dev/null
+++ b/app/models/product.rb
@@ -0,0 +1,14 @@
+class Product < ActiveRecord::Base
+
+ has_many :photos
+ accepts_nested_attributes_for :photos
+
+ validates :title , :presence => true
+ validates :quantity , :presence => true
+
+
+ def default_photo
+ photos.first
+ end
+
+end
diff --git a/app/models/setting.rb b/app/models/setting.rb
new file mode 100644
index 00000000..ab37808e
--- /dev/null
+++ b/app/models/setting.rb
@@ -0,0 +1,4 @@
+class Setting < Settingslogic
+ source "#{Rails.root}/config/config.yml"
+ namespace Rails.env
+end
\ No newline at end of file
diff --git a/app/models/user.rb b/app/models/user.rb
new file mode 100644
index 00000000..a7265a15
--- /dev/null
+++ b/app/models/user.rb
@@ -0,0 +1,12 @@
+class User < ActiveRecord::Base
+ # Include default devise modules. Others available are:
+ # :confirmable, :lockable, :timeoutable and :omniauthable
+ devise :database_authenticatable, :registerable,
+ :recoverable, :rememberable, :trackable, :validatable
+
+ has_many :orders
+
+ def admin?
+ is_admin
+ end
+end
diff --git a/app/services/order_placing_service.rb b/app/services/order_placing_service.rb
new file mode 100644
index 00000000..c7f4b7c8
--- /dev/null
+++ b/app/services/order_placing_service.rb
@@ -0,0 +1,12 @@
+class OrderPlacingService
+ def initialize(cart,order)
+ @order = order
+ @cart = cart
+ end
+
+ def place_order!
+ @order.build_item_cache_from_cart(@cart)
+ @order.calculate_total!(@cart)
+ OrderMailer.notify_order_placed(@order).deliver
+ end
+end
\ No newline at end of file
diff --git a/app/services/stripe_charge.rb b/app/services/stripe_charge.rb
new file mode 100644
index 00000000..372c4cd9
--- /dev/null
+++ b/app/services/stripe_charge.rb
@@ -0,0 +1,32 @@
+class StripeCharge
+
+ attr_reader :error_message, :response
+
+ def initialize(options={})
+ @response = options[:response]
+ @error_message = options[:error_message]
+ end
+
+ def self.create(options={})
+
+ #Stripe.api_key = Setting.stripe.secret_key
+ Stripe.api_key = 'sk_test_pCZIG0qP8mLQCBXabYuUEUcB'
+
+ begin
+ response = Stripe::Charge.create(
+ amount: options[:amount],
+ currency: "usd",
+ card: options[:card],
+ description: options[:description]
+ )
+ new(:response => response)
+ rescue Stripe::CardError => e
+ new(:error_message => e.message)
+ end
+ end
+
+ def successful?
+ @response.present?
+ end
+
+end
\ No newline at end of file
diff --git a/app/uploaders/photo_uploader.rb b/app/uploaders/photo_uploader.rb
new file mode 100644
index 00000000..cf6a990b
--- /dev/null
+++ b/app/uploaders/photo_uploader.rb
@@ -0,0 +1,62 @@
+# encoding: utf-8
+
+class PhotoUploader < CarrierWave::Uploader::Base
+
+ # Include RMagick or MiniMagick support:
+ # include CarrierWave::RMagick
+ include CarrierWave::MiniMagick
+
+ # Choose what kind of storage to use for this uploader:
+ storage :file
+ # storage :fog
+
+ # Override the directory where uploaded files will be stored.
+ # This is a sensible default for uploaders that are meant to be mounted:
+ def store_dir
+ "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
+ end
+
+ process :resize_to_fit => [800, 800]
+
+ version :thumb do
+ process :resize_to_fill => [200,200]
+ end
+
+
+ version :medium do
+ process :resize_to_fill => [400,400]
+ end
+
+ # Provide a default URL as a default if there hasn't been a file uploaded:
+ # def default_url
+ # # For Rails 3.1+ asset pipeline compatibility:
+ # # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
+ #
+ # "/images/fallback/" + [version_name, "default.png"].compact.join('_')
+ # end
+
+ # Process files as they are uploaded:
+ # process :scale => [200, 300]
+ #
+ # def scale(width, height)
+ # # do something
+ # end
+
+ # Create different versions of your uploaded files:
+ # version :thumb do
+ # process :resize_to_fit => [50, 50]
+ # end
+
+ # Add a white list of extensions which are allowed to be uploaded.
+ # For images you might use something like this:
+ # def extension_white_list
+ # %w(jpg jpeg gif png)
+ # end
+
+ # Override the filename of the uploaded files:
+ # Avoid using model.id or version_name here, see uploader/store.rb for details.
+ # def filename
+ # "something.jpg" if original_filename
+ # end
+
+end
diff --git a/app/views/account/orders/index.html.erb b/app/views/account/orders/index.html.erb
new file mode 100644
index 00000000..dc2bcfb1
--- /dev/null
+++ b/app/views/account/orders/index.html.erb
@@ -0,0 +1,20 @@
+
訂單列表
+
+
+
+
+
#
+
生成時間
+
+
+
+
+ <% @orders.each do |order| %>
+
+
<%= render_order_link(order) %>
+
<%= render_order_created_time(order) %>
+
+ <% end %>
+
+
+
\ No newline at end of file
diff --git a/app/views/admin/orders/_state_option.html.erb b/app/views/admin/orders/_state_option.html.erb
new file mode 100644
index 00000000..609ff585
--- /dev/null
+++ b/app/views/admin/orders/_state_option.html.erb
@@ -0,0 +1,21 @@
+
\ No newline at end of file
diff --git a/app/views/admin/orders/index.html.erb b/app/views/admin/orders/index.html.erb
new file mode 100644
index 00000000..20f45f85
--- /dev/null
+++ b/app/views/admin/orders/index.html.erb
@@ -0,0 +1,24 @@
+
訂單列表
+
+
+
+
+
+
#
+
生成時間
+
訂購者
+
訂單狀態
+
+
+
+ <% @orders.each do |order| %>
+
+
<%= render_admin_order_link(order) %>
+
<%= render_order_created_time(order) %>
+
<%= render_order_user_name(order.user) %>
+
<%= render_order_state(order) %>
+
+ <% end %>
+
+
+
\ No newline at end of file
diff --git a/app/views/admin/orders/show.html.erb b/app/views/admin/orders/show.html.erb
new file mode 100644
index 00000000..83d5da9b
--- /dev/null
+++ b/app/views/admin/orders/show.html.erb
@@ -0,0 +1,89 @@
+
\ No newline at end of file
diff --git a/app/views/admin/products/edit.html.erb b/app/views/admin/products/edit.html.erb
new file mode 100644
index 00000000..e3b94e48
--- /dev/null
+++ b/app/views/admin/products/edit.html.erb
@@ -0,0 +1,44 @@
+
+
+
+
+
+<% end %>
\ No newline at end of file
diff --git a/app/views/admin/products/index.html.erb b/app/views/admin/products/index.html.erb
new file mode 100644
index 00000000..bdfe3029
--- /dev/null
+++ b/app/views/admin/products/index.html.erb
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+<% end %>
\ No newline at end of file
diff --git a/app/views/admin/products/show.html.erb b/app/views/admin/products/show.html.erb
new file mode 100644
index 00000000..284e2d19
--- /dev/null
+++ b/app/views/admin/products/show.html.erb
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/app/views/carts/index.html.erb b/app/views/carts/index.html.erb
new file mode 100644
index 00000000..ac08fa1a
--- /dev/null
+++ b/app/views/carts/index.html.erb
@@ -0,0 +1,54 @@
+
+
+
+
購物車
+
+
+
+
+
商品資訊
+
+
單價
+
購買數量
+
+
+
+
+ <% current_cart.cart_items.each do |item| %>
+
\ No newline at end of file
diff --git a/app/views/orders/pay_with_credit_card.html.erb b/app/views/orders/pay_with_credit_card.html.erb
new file mode 100644
index 00000000..d24c5f63
--- /dev/null
+++ b/app/views/orders/pay_with_credit_card.html.erb
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+<%= form_tag order_card_charges_path(@order.token), :id => "payment-form", :class => "form form-horizontal" do %>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<% end %>
\ No newline at end of file
diff --git a/app/views/orders/show.html.erb b/app/views/orders/show.html.erb
new file mode 100644
index 00000000..7ef0f4bd
--- /dev/null
+++ b/app/views/orders/show.html.erb
@@ -0,0 +1,85 @@
+
\ No newline at end of file
diff --git a/app/views/pages/index.html.erb b/app/views/pages/index.html.erb
new file mode 100644
index 00000000..c3e72117
--- /dev/null
+++ b/app/views/pages/index.html.erb
@@ -0,0 +1 @@
+
Hello !
diff --git a/app/views/partial/_nav.html.erb b/app/views/partial/_nav.html.erb
new file mode 100644
index 00000000..20457eaf
--- /dev/null
+++ b/app/views/partial/_nav.html.erb
@@ -0,0 +1,34 @@
+
\ No newline at end of file
diff --git a/app/views/products/_product_item.html.erb b/app/views/products/_product_item.html.erb
new file mode 100644
index 00000000..dc79be86
--- /dev/null
+++ b/app/views/products/_product_item.html.erb
@@ -0,0 +1,13 @@
+
+
+
+ <%= link_to product_path(product) do %>
+ <%= render_product_photo(product.default_photo) %>
+ <% end %>
+
+
+
+ <%= render_product_name(product) %>
+
+
+
\ No newline at end of file
diff --git a/app/views/products/index.html.erb b/app/views/products/index.html.erb
new file mode 100644
index 00000000..ce091dc0
--- /dev/null
+++ b/app/views/products/index.html.erb
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/app/views/products/search.html.erb b/app/views/products/search.html.erb
new file mode 100644
index 00000000..24df3d08
--- /dev/null
+++ b/app/views/products/search.html.erb
@@ -0,0 +1,9 @@
+
\ No newline at end of file
diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb
new file mode 100644
index 00000000..93e8df13
--- /dev/null
+++ b/app/views/products/show.html.erb
@@ -0,0 +1,29 @@
+