rightnow_oms 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/README.rdoc +83 -0
  2. data/Rakefile +29 -0
  3. data/app/assets/javascripts/rightnow_oms/app/app.js.coffee +8 -0
  4. data/app/assets/javascripts/rightnow_oms/app/controllers/cart.js.coffee +28 -0
  5. data/app/assets/javascripts/rightnow_oms/app/models/cart.js.coffee +53 -0
  6. data/app/assets/javascripts/rightnow_oms/app/models/cart_item.js.coffee +60 -0
  7. data/app/assets/javascripts/rightnow_oms/app/templates/cart_items/show.hjs +9 -0
  8. data/app/assets/javascripts/rightnow_oms/app/templates/cart_items/show_in_detail.hjs +15 -0
  9. data/app/assets/javascripts/rightnow_oms/app/templates/carts/show.hjs +14 -0
  10. data/app/assets/javascripts/rightnow_oms/app/templates/carts/show_in_detail.hjs +21 -0
  11. data/app/assets/javascripts/rightnow_oms/app/views/cart_items/show.js.coffee +7 -0
  12. data/app/assets/javascripts/rightnow_oms/app/views/cart_items/show_in_detail.js.coffee +15 -0
  13. data/app/assets/javascripts/rightnow_oms/app/views/carts/show.js.coffee +4 -0
  14. data/app/assets/javascripts/rightnow_oms/app/views/carts/show_in_detail.js.coffee +5 -0
  15. data/app/assets/javascripts/rightnow_oms/application.js +8 -0
  16. data/app/assets/javascripts/rightnow_oms/lib/ember/data/adapters/my_rest_adapter.js.coffee +183 -0
  17. data/app/assets/javascripts/rightnow_oms/lib/ember/data/extensions.js +19 -0
  18. data/app/assets/javascripts/rightnow_oms/lib/utils.js.coffee +2 -0
  19. data/app/assets/javascripts/rightnow_oms/vendor/ember-data.js +1772 -0
  20. data/app/assets/javascripts/rightnow_oms/vendor/ember-data.min.js +8 -0
  21. data/app/assets/javascripts/rightnow_oms/vendor/ember.js +15833 -0
  22. data/app/assets/javascripts/rightnow_oms/vendor/ember.min.js +13 -0
  23. data/app/assets/stylesheets/rightnow_oms/application.css +7 -0
  24. data/app/assets/stylesheets/rightnow_oms/cart_items.css +12 -0
  25. data/app/assets/stylesheets/rightnow_oms/carts.css.scss +21 -0
  26. data/app/controllers/rightnow_oms/application_controller.rb +17 -0
  27. data/app/controllers/rightnow_oms/cart_items_controller.rb +59 -0
  28. data/app/controllers/rightnow_oms/carts_controller.rb +18 -0
  29. data/app/helpers/rightnow_oms/application_helper.rb +4 -0
  30. data/app/helpers/rightnow_oms/cart_items_helper.rb +4 -0
  31. data/app/helpers/rightnow_oms/carts_helper.rb +4 -0
  32. data/app/models/rightnow_oms/cart.rb +42 -0
  33. data/app/models/rightnow_oms/cart_item.rb +34 -0
  34. data/app/views/rightnow_oms/carts/show.html.haml +8 -0
  35. data/config/routes.rb +4 -0
  36. data/db/migrate/20120202104431_create_rightnow_oms_carts.rb +14 -0
  37. data/db/migrate/20120203045059_create_rightnow_oms_cart_items.rb +18 -0
  38. data/db/migrate/20120207085551_add_group_to_rightnow_oms_cart_items.rb +5 -0
  39. data/db/migrate/20120207095146_add_parent_id_to_rightnow_oms_cart_items.rb +5 -0
  40. data/lib/rightnow_oms.rb +6 -0
  41. data/lib/rightnow_oms/engine.rb +5 -0
  42. data/lib/rightnow_oms/version.rb +3 -0
  43. data/lib/tasks/rightnow_oms_tasks.rake +4 -0
  44. metadata +171 -0
data/README.rdoc ADDED
@@ -0,0 +1,83 @@
1
+ = RightnowOms
2
+
3
+ == Description
4
+
5
+ A common gem for managing your carts and orders. RightnowOms is a rails mountable engine. It gets a lot of benifits from Ember.JS[http://emberjs.com]
6
+
7
+ == Requirements
8
+
9
+ Add the following gems to your Gemfile:
10
+
11
+ * jquery-rails
12
+ * ember-rails
13
+ * haml-rails
14
+ * coffee-rails
15
+ * sass-rails
16
+ * acts_as_api
17
+
18
+ == Installation
19
+
20
+ Make sure that all requirements are met and add RightnowOms to your Gemfile.
21
+
22
+ gem 'rightnow_oms'
23
+
24
+ Mount RightnowOms to your application.
25
+
26
+ # config/routes.rb
27
+ mount RightnowOms::Engine => "rightnow_oms"
28
+
29
+ Create the migrations with:
30
+
31
+ rake rightnow_oms:install:migrations
32
+ rake db:migrate
33
+
34
+ Run +bundle install+ and require ember and ember-data in your +app/assets/javascripts/application.js+:
35
+
36
+ = require rightnow_oms/vendor/ember
37
+ = require rightnow_oms/vendor/ember-data
38
+
39
+ Add the following line to your +app/assets/javascripts/application.js+:
40
+
41
+ = require rightnow_oms/application
42
+
43
+ Add the stylesheets to your +app/assets/stylesheets/application.css+:
44
+
45
+ = require rightnow_oms/application
46
+
47
+ Create a layout for your detailed cart view:
48
+
49
+ # app/views/layouts/rightnow_oms/application.html.haml
50
+ !!!
51
+ %html
52
+ %head
53
+ %title Dummy
54
+ = stylesheet_link_tag "application"
55
+ = javascript_include_tag "application"
56
+ = csrf_meta_tags
57
+
58
+ %body
59
+ = yield
60
+
61
+ Add a place holder for your cart in your views:
62
+
63
+ <div id="cart-wrapper">
64
+ <script type="text/x-handlebars">
65
+ {{ view RightnowOms.ShowCartView }}
66
+ </script>
67
+ </div>
68
+
69
+ == Development
70
+
71
+ RightnowOms is developed with Ruby 1.9.3-p0 and Rails 3.1.3
72
+
73
+ bundle install
74
+ bundle exec rake app:db:migrate
75
+ bundle exec rake app:db:seed
76
+
77
+ # Run the tests
78
+ rspec
79
+
80
+ # Start the dummy application
81
+ rails s
82
+
83
+ Copyright 2011-2012 Beijing Menglifang Network Technology and Science Co.,Ltd. All rights reserved.
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'RightnowOms'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ rdoc.rdoc_files.include('app/**/*.rb')
22
+ end
23
+
24
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
25
+ load 'rails/tasks/engine.rake'
26
+
27
+
28
+ Bundler::GemHelper.install_tasks
29
+
@@ -0,0 +1,8 @@
1
+ window.RightnowOms = Ember.Application.create
2
+ rootElement: '#cart-wrapper'
3
+
4
+ window.RightnowOms.store = DS.Store.create
5
+ adapter:
6
+ DS.MyRESTAdapter.create
7
+ bulkCommit: false
8
+ namespace: 'rightnow_oms'
@@ -0,0 +1,28 @@
1
+ RightnowOms.cartController = Ember.Object.create
2
+ store: RightnowOms.store
3
+
4
+ load: (cart) ->
5
+ RightnowOms.store.load(RightnowOms.Cart, cart.id, cart)
6
+ @set('content', RightnowOms.store.find(RightnowOms.Cart, cart.id))
7
+
8
+ reload: ->
9
+ @set('content', RightnowOms.store.find(RightnowOms.Cart, @get('content').get('id')))
10
+
11
+ # item: a hash
12
+ addCartItem: (item) ->
13
+ cartItem = @get('content').addCartItem(item)
14
+ @store.commit()
15
+
16
+ cartItem
17
+
18
+ increaseCartItem: (id) ->
19
+ @get('content').increaseCartItem(id)
20
+ @store.commit()
21
+
22
+ decreaseCartItem: (id) ->
23
+ @get('content').decreaseCartItem(id)
24
+ @store.commit()
25
+
26
+ removeCartItem: (id) ->
27
+ @get('content').removeCartItem(id)
28
+ @store.commit()
@@ -0,0 +1,53 @@
1
+ RightnowOms.Cart = DS.Model.extend
2
+ cartItems: (->
3
+ RightnowOms.CartItem.all()
4
+ ).property()
5
+
6
+ cartableCount: (->
7
+ count = 0
8
+ @get('cartItems').forEach (item) ->
9
+ count += item.get('quantity')
10
+
11
+ count
12
+ ).property("cartItems.@each.quantity")
13
+
14
+ total: (->
15
+ total = 0
16
+ @get('cartItems').forEach (item) ->
17
+ total += parseFloat(item.get('price')) * item.get('quantity')
18
+
19
+ round(total, 2)
20
+ ).property("cartableCount")
21
+
22
+ addCartItem: (item) ->
23
+ cartItem = RightnowOms.CartItem.findByName(item.name)
24
+
25
+ if cartItem?
26
+ cartItem.increase() unless cartItem.get('parent')?
27
+ else
28
+ cartItem = RightnowOms.store.createRecord(RightnowOms.CartItem, item)
29
+
30
+ cartItem
31
+
32
+ removeCartItem: (id) ->
33
+ cartItem = RightnowOms.CartItem.findById(id)
34
+
35
+ cartItem.deleteRecord() if cartItem?
36
+
37
+ cartItem
38
+
39
+ increaseCartItem: (id) ->
40
+ cartItem = RightnowOms.CartItem.findById(id)
41
+
42
+ cartItem.increase()
43
+ cartItem
44
+
45
+ decreaseCartItem: (id) ->
46
+ cartItem = RightnowOms.CartItem.findById(id)
47
+
48
+ cartItem.decrease()
49
+ #removeCartItem(id) if cartItem.get('quantity') <= 0
50
+ cartItem
51
+
52
+ RightnowOms.Cart.reopenClass
53
+ isSingleton: true
@@ -0,0 +1,60 @@
1
+ RightnowOms.CartItem = DS.Model.extend
2
+ cartable_id: DS.attr('integer')
3
+ cartable_type: DS.attr('string')
4
+ name: DS.attr('string')
5
+ price: DS.attr('string')
6
+ quantity: DS.attr('integer')
7
+ group: DS.attr('string')
8
+ parent_id: DS.attr('integer')
9
+
10
+ subtotal: (->
11
+ round(round(@get('price'), 2) * @get('quantity'), 2)
12
+ ).property('price', 'quantity')
13
+
14
+ children: (->
15
+ RightnowOms.CartItem.all().filterProperty('parent_id', @get('id'))
16
+ ).property()
17
+
18
+ parent: (->
19
+ if @get('parent_id')?
20
+ RightnowOms.CartItem.all().filterProperty('id', @get('parent_id'))
21
+ ).property()
22
+
23
+ hasChildren: (->
24
+ @get('children.length') > 0
25
+ ).property()
26
+
27
+ hasParent: (->
28
+ @get('parent_id')?
29
+ ).property('parent_id')
30
+
31
+ increase: ->
32
+ @get('children').forEach((child) ->
33
+ child.increase()
34
+ )
35
+
36
+ @set('quantity', @get('quantity') + 1)
37
+
38
+ decrease: ->
39
+ @get('children').forEach((child) ->
40
+ child.decrease()
41
+ )
42
+
43
+ @set('quantity', @get('quantity') - 1)
44
+
45
+ deleteRecord: ->
46
+ @get('children').forEach((child) ->
47
+ child.deleteRecord()
48
+ )
49
+
50
+ @_super()
51
+
52
+ RightnowOms.CartItem.reopenClass
53
+ all: ->
54
+ RightnowOms.store.findAll(RightnowOms.CartItem)
55
+
56
+ findByName: (name) ->
57
+ @all().filterProperty('name', name).get('firstObject')
58
+
59
+ findById: (id) ->
60
+ @all().filterProperty('id', id).get('firstObject')
@@ -0,0 +1,9 @@
1
+ {{#with cartItem }}
2
+ <td>{{ name }}</td>
3
+ <td class='price'>{{ price }}x{{ quantity }}</td>
4
+ <td>
5
+ {{#unless hasParent }}
6
+ <a href="#" {{ action "deleteRecord" }}>删除</a>
7
+ {{/unless}}
8
+ </td>
9
+ {{/with}}
@@ -0,0 +1,15 @@
1
+ {{#with cartItem}}
2
+ <td>{{ name }}</td>
3
+ <td class="price">¥{{ price }}</td>
4
+ <td class="quantity">
5
+ {{#if hasParent }}
6
+ {{ quantity }}
7
+ {{else}}
8
+ <a href="#" {{ action "decrease" }}>-</a>
9
+ <span> {{ quantity }} </span>
10
+ <a href="#" {{ action "increase" }}>+</a>
11
+ {{/if}}
12
+ </td>
13
+ <td class="subtotal">¥{{ subtotal }}</td>
14
+ <td><a href="#" {{ action "deleteRecord" }}>删除</a></td>
15
+ {{/with}}
@@ -0,0 +1,14 @@
1
+ <div class="cart-bar">
2
+ <span>购物车 {{ cart.cartableCount }} 件</span>
3
+ <span><a href='/rightnow_oms/cart'>去结算 >></a></span>
4
+ </div>
5
+
6
+ <div class="cart-items">
7
+ <table>
8
+ {{#each cart.cartItems}}
9
+ {{ view RightnowOms.ShowCartItemView cartItemBinding="this" }}
10
+ {{/each}}
11
+ <tr><td colspan="3">总计:¥{{ cart.total }}</td></tr>
12
+ </table>
13
+ </div>
14
+
@@ -0,0 +1,21 @@
1
+ <h2>我的购物车</h2>
2
+ <table>
3
+ <tr>
4
+ <td>商品名称</td>
5
+ <td>商品价格</td>
6
+ <td>商品数量</td>
7
+ <td>商品总价</td>
8
+ <td>删除商品</td>
9
+ </tr>
10
+ </tr>
11
+ {{#each cart.cartItems}}
12
+ {{ view RightnowOms.ShowCartItemInDetailView cartItemBinding="this" }}
13
+ {{/each}}
14
+ <tr>
15
+ <td colspan="4">总价:<span class="total-price">¥{{ cart.total }}</span></td>
16
+ <td></td>
17
+ </tr>
18
+ </table>
19
+
20
+ <a href="/"><< 继续购物</a>
21
+ <a href="#">去结算 >></a>
@@ -0,0 +1,7 @@
1
+ RightnowOms.ShowCartItemView = Ember.View.extend
2
+ tagName: 'tr'
3
+ templateName: 'rightnow_oms/app/templates/cart_items/show'
4
+
5
+ deleteRecord: ->
6
+ item = this.get('cartItem')
7
+ RightnowOms.cartController.removeCartItem(item.get('id'))
@@ -0,0 +1,15 @@
1
+ RightnowOms.ShowCartItemInDetailView = Ember.View.extend
2
+ tagName: 'tr'
3
+ templateName: 'rightnow_oms/app/templates/cart_items/show_in_detail'
4
+
5
+ deleteRecord: ->
6
+ item = @get('cartItem')
7
+ RightnowOms.cartController.removeCartItem(item.get('id'))
8
+
9
+ increase: ->
10
+ item = @get('cartItem')
11
+ RightnowOms.cartController.increaseCartItem(item.get('id'))
12
+
13
+ decrease: ->
14
+ item = @get('cartItem')
15
+ RightnowOms.cartController.decreaseCartItem(item.get('id'))
@@ -0,0 +1,4 @@
1
+ RightnowOms.ShowCartView = Ember.View.extend
2
+ templateName: 'rightnow_oms/app/templates/carts/show'
3
+
4
+ cartBinding: 'RightnowOms.cartController.content'
@@ -0,0 +1,5 @@
1
+ RightnowOms.ShowCartInDetailView = Ember.View.extend
2
+ classNames: ["detailed-cart"]
3
+ templateName: 'rightnow_oms/app/templates/carts/show_in_detail'
4
+
5
+ cartBinding: 'RightnowOms.cartController.content'
@@ -0,0 +1,8 @@
1
+ //= require_tree ./lib
2
+ //
3
+ //= require ./app/app
4
+ //= require ./app/models/cart_item
5
+ //= require ./app/models/cart
6
+ //= require_tree ./app/controllers
7
+ //= require_tree ./app/views
8
+ //= require_tree ./app/templates
@@ -0,0 +1,183 @@
1
+ get = Ember.get
2
+ set = Ember.set
3
+ getPath = Ember.getPath
4
+
5
+ DS.MyRESTAdapter = DS.RESTAdapter.extend
6
+ createRecord: (store, type, model) ->
7
+ root = @rootForType(type)
8
+ url = @buildUrl(type)
9
+ data = {}
10
+
11
+ data[root] = get(model, 'data')
12
+
13
+ @ajax(url, "POST", {
14
+ data: data,
15
+ success: (json) ->
16
+ store.didCreateRecord(model, json[root])
17
+ })
18
+
19
+ createRecords: (store, type, models) ->
20
+ if (get(@, 'bulkCommit') == false)
21
+ return @_super(store, type, models)
22
+
23
+ root = @rootForType(type)
24
+ plural = @pluralize(root)
25
+
26
+ data = {}
27
+ data[plural] = models.map((model) ->
28
+ get(model, 'data')
29
+
30
+ )
31
+ @ajax(@buildUrl(type), "POST", {
32
+ data: data,
33
+ success: (json) ->
34
+ store.didCreateRecords(type, models, json[plural])
35
+ })
36
+
37
+ updateRecord: (store, type, model) ->
38
+ root = @rootForType(type)
39
+
40
+ data = {}
41
+ data[root] = get(model, 'data')
42
+
43
+ @ajax(@buildUrl(type, @getPrimaryKeyValue(type, model)), "PUT", {
44
+ data: data,
45
+ success: (json) ->
46
+ store.didUpdateRecord(model)
47
+ })
48
+
49
+ updateRecords: (store, type, models) ->
50
+ if (get(@, 'bulkCommit') == false)
51
+ return @_super(store, type, models)
52
+
53
+ root = @rootForType(type)
54
+ plural = @pluralize(root)
55
+
56
+ data = {}
57
+ data[plural] = models.map((model) ->
58
+ get(model, 'data')
59
+ )
60
+
61
+ @ajax(@buildUrl(type), "POST", {
62
+ data: data,
63
+ success: (json) ->
64
+ store.didUpdateRecords(models, json[plural])
65
+ })
66
+
67
+ deleteRecord: (store, type, model) ->
68
+ root = @rootForType(type)
69
+ url = @buildUrl(type, @getPrimaryKeyValue(type, model))
70
+
71
+ @ajax(url, "DELETE", {
72
+ success: (json) ->
73
+ store.didDeleteRecord(model)
74
+ })
75
+
76
+ deleteRecords: (store, type, models) ->
77
+ if (get(@, 'bulkCommit') == false)
78
+ return @_super(store, type, models)
79
+
80
+ root = @rootType(type)
81
+ plural = @pluralize(root)
82
+ primaryKey = getPath(type, 'proto.primaryKey')
83
+
84
+ data = {}
85
+ data[plural] = models.map((model) ->
86
+ get(model, primaryKey)
87
+ )
88
+
89
+ @ajax(@buildUrl(type) + "/delete", "POST", {
90
+ data: data
91
+ success: (json) ->
92
+ store.didDeleteRecords(models)
93
+ })
94
+
95
+ find: (store, type, id) ->
96
+ url = ''
97
+ root = @rootForType(type)
98
+
99
+ if @isSingleton(type)
100
+ url = @buildUrl(type)
101
+ else
102
+ url = @buildUrl(type, id)
103
+
104
+ @ajax(url, "GET", {
105
+ success: (json) ->
106
+ store.load(type, json[root])
107
+ })
108
+
109
+ findMany: (store, type, ids) ->
110
+ root = @rootForType(type)
111
+ plural = @pluralize(root)
112
+
113
+ @ajax(@buildUrl(type), "GET", {
114
+ data: { ids: ids },
115
+ success: (json) ->
116
+ store.loadMany(type, ids, json[plural])
117
+ })
118
+ url = "/" + plural
119
+
120
+ findAll: (store, type) ->
121
+ root = @rootForType(type)
122
+ plural = @pluralize(root)
123
+
124
+ @ajax(@buildUrl(type), "GET", {
125
+ success: (json) ->
126
+ store.loadMany(type, json[plural])
127
+ })
128
+
129
+ findQuery: (store, type, query, modelArray) ->
130
+ root = @rootForType(type)
131
+ plural = @pluralize(root)
132
+
133
+ @ajax(@buildUrl(type), "GET", {
134
+ data: query,
135
+ success: (json) ->
136
+ modelArray.load(json[plural])
137
+ })
138
+
139
+ # HELPERS
140
+
141
+ plurals: {}
142
+
143
+ # define a plurals hash in your subclass to define
144
+ # special-case pluralization
145
+ pluralize: (name) ->
146
+ @plurals[name] || name + "s"
147
+
148
+ rootForType: (type) ->
149
+ if type.url
150
+ return type.url
151
+
152
+ # use the last part of the name as the URL
153
+ parts = type.toString().split(".")
154
+ name = parts[parts.length - 1]
155
+ name.replace(/([A-Z])/g, '_$1').toLowerCase().slice(1)
156
+
157
+ getPrimaryKeyValue: (type, model)->
158
+ primaryKey = getPath(type, 'proto.primaryKey')
159
+ get(model, primaryKey)
160
+
161
+ buildUrl: (type, suffix) ->
162
+ url = [""]
163
+ root = @rootForType(type)
164
+
165
+ url.push(@namespace) if @namespace?
166
+ if @isSingleton(type)
167
+ url.push(root)
168
+ else
169
+ url.push(@pluralize(root))
170
+ url.push(suffix) if suffix?
171
+
172
+ url.join('/')
173
+
174
+ isSingleton: (type) ->
175
+ if type.isSingleton then type.isSingleton else false
176
+
177
+ ajax: (url, type, hash) ->
178
+ hash.url = url
179
+ hash.type = type
180
+ hash.dataType = "json"
181
+
182
+ jQuery.ajax(hash)
183
+