comable-backend 0.7.0.beta2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a9a4aab8272e2f6d7559b2b904eff5dae392ac9b
4
- data.tar.gz: 6a467557d5063f57772c037adddabc6099bfce7a
3
+ metadata.gz: 468193b091875f22c8f2f66c4c7a39f4303514ea
4
+ data.tar.gz: 32459c209919309b128b318c4e3292aa84fb13d1
5
5
  SHA512:
6
- metadata.gz: 74082e26be423fa71b1d3196d9daf07251b106665314a77bde732c3a77812bb63a27853149375dd8ee14f763e620107788328e657de86291782a5223603a9c61
7
- data.tar.gz: cfa9c867269a22cb149cea5f1a5e69f67dd73fe40dc9b7e69985a0972bd5718a21ad8d17858a4e7a24dde9483096aa27e146ae4cd0e3faf6ef422c478db08cac
6
+ metadata.gz: 2fcf1ee77d9ef16c1a212ab958953cb7678ca29cead72042c9dd5864ce1a5ddad930f65676ef1c6dcba55a3acee473e428e907be633c24130e69d69d93b60dce
7
+ data.tar.gz: f54d0897d8ce819717a88661c35f189d384022df41f19f63de831ff626ec85ef433ec02d12c331a67251917b6d51fbf0065685b48851e4ead33723632347b07a
@@ -54,11 +54,12 @@ initialize_select2 = ->
54
54
  $select = $(this)
55
55
  options = { theme: 'bootstrap' }
56
56
  if $select.hasClass('ajax')
57
+ term_column = $select.data('term') || ['name_cont']
57
58
  options.ajax = {
58
59
  url: $select.data('source')
59
60
  dataType: 'json'
60
61
  cache: true
61
- data: (params) -> { q: { name_cont: params.term }, page: params.page }
62
+ data: (params) -> { q: { "#{term_column}" : params.term }, page: params.page }
62
63
  processResults: (data, page) -> { results: data }
63
64
  }
64
65
  $select.select2(options)
@@ -15,7 +15,11 @@ class Dispatcher
15
15
  action_name = path[1]
16
16
 
17
17
  switch page
18
- when 'orders:edit', 'pages:update'
18
+ when 'draft_orders:new', 'draft_orders:create', 'draft_orders:edit', 'draft_orders:update'
19
+ new OrderItemBuilder
20
+ new UserSelector
21
+ new DynamicOrder
22
+ when 'orders:new', 'orders:create', 'orders:edit', 'orders:update'
19
23
  new DynamicOrder
20
24
  when 'pages:new', 'pages:show', 'pages:edit', 'pages:update', 'pages:create'
21
25
  new Page
@@ -7,7 +7,7 @@ class @DynamicOrder
7
7
 
8
8
  listen_events: ->
9
9
  self = this
10
- $('input').on('change', ->
10
+ $(document).on('change', 'input', ->
11
11
  attribute_name = $(this).attr('data-name')
12
12
  return unless jQuery.inArray(attribute_name, self.refresh_trigger_attributes)
13
13
  self.refresh_order_item_prices_for(this)
@@ -18,7 +18,7 @@ class @DynamicOrder
18
18
 
19
19
  $price = $group.find('[data-name="price"]')
20
20
  $quantity = $group.find('[data-name="quantity"]')
21
- $subtotal_price = $group.find('[data-name="subtotal_price"]')
21
+ $subtotal_price = $group.find('[data-name="subtotal-price"]')
22
22
 
23
23
  price = Number($price.val())
24
24
  quantity = Number($quantity.val())
@@ -28,14 +28,14 @@ class @DynamicOrder
28
28
 
29
29
  refresh_order_prices: ->
30
30
  item_total_price = 0
31
- $('[data-name="subtotal_price"]').each( ->
31
+ $('[data-name="subtotal-price"]').each( ->
32
32
  item_total_price += Number($(this).val())
33
33
  )
34
34
 
35
- $item_total_price = $('[data-name="item_total_price"]')
36
- $payment_fee = $('[data-name="payment_fee"]')
37
- $shipment_fee = $('[data-name="shipment_fee"]')
38
- $total_price = $('[data-name="total_price"]')
35
+ $item_total_price = $('[data-name="item-total-price"]')
36
+ $payment_fee = $('[data-name="payment-fee"]')
37
+ $shipment_fee = $('[data-name="shipment-fee"]')
38
+ $total_price = $('[data-name="total-price"]')
39
39
 
40
40
  payment_fee = Number($payment_fee.val())
41
41
  shipment_fee = Number($shipment_fee.val())
@@ -0,0 +1,42 @@
1
+ class @OrderItemBuilder
2
+ NEW_ORDER_ITEM_SELECTOR = '.js-new-order-item'
3
+ LINK_TO_REMOVE_ORDER_ITEM_SELECTOR = '.js-remove-order-item'
4
+
5
+ constructor: ->
6
+ @setSelectors()
7
+ @$variantSelector.on('select2:select', (event) => @buildOrderItem(event.params.data))
8
+ $(document).on('click', LINK_TO_REMOVE_ORDER_ITEM_SELECTOR, (event) => @removeOrderItem(event.target))
9
+
10
+ setSelectors: ->
11
+ @$variantSelector = $('#js-variant-selector')
12
+ @$linkToAddOrderItem = $('#js-add-order-item')
13
+ @$orderItemsTable = $('#js-order-items-table').find('tbody')
14
+
15
+ buildOrderItem: (variant) ->
16
+ $orderItem = @newOrderItem()
17
+ @fillOrderItem($orderItem, variant)
18
+ @$orderItemsTable.append($orderItem)
19
+ @refreshPricesFor($orderItem)
20
+
21
+ # TODO: Commonize this method
22
+ newOrderItem: ->
23
+ newId = new Date().getTime()
24
+ @$linkToAddOrderItem.click()
25
+ $orderItem = $(NEW_ORDER_ITEM_SELECTOR).filter('.hidden').last()
26
+ $orderItem.removeClass('hidden')
27
+ $orderItem.html($orderItem.html().replace(/new_order_item/g, newId))
28
+ $orderItem
29
+
30
+ fillOrderItem: ($orderItem, variant) ->
31
+ $orderItem.find('[data-name="variant-id"]').val(variant.id)
32
+ $orderItem.find('[data-name="name"]').val(variant.text)
33
+ $orderItem.find('[data-name="sku"]').val(variant.sku)
34
+ $orderItem.find('[data-name="price"]').val(variant.price)
35
+ $orderItem.find('[data-name="subtotal-price"]').val(variant.price)
36
+ $orderItem.find('[data-name="image-url"]').attr('src', variant.image_url)
37
+
38
+ removeOrderItem: (element) ->
39
+ $(element).closest(NEW_ORDER_ITEM_SELECTOR).remove()
40
+
41
+ refreshPricesFor: ($orderItem) ->
42
+ $orderItem.find('[data-name="price"]').trigger('change')
@@ -0,0 +1,15 @@
1
+ class @UserSelector
2
+ constructor: ->
3
+ @setSelectors()
4
+ @$userSelector.on('select2:select', (event) => @fillUser(event.params.data))
5
+
6
+ setSelectors: ->
7
+ @$userSelector = $('#js-user-selector')
8
+ @$user = $('#js-user-fields')
9
+
10
+ fillUser: (user) ->
11
+ @$user.find('[data-name="email"]').val(user.email)
12
+ @$user.find('[data-name="bill-family-name"]').val(user.bill_address.family_name)
13
+ @$user.find('[data-name="bill-first-name"]').val(user.bill_address.first_name)
14
+ @$user.find('[data-name="bill-zip-code"]').val(user.bill_address.zip_code)
15
+ @$user.find('[data-name="bill-state-name"]').val(user.bill_address.state_name)
@@ -0,0 +1,88 @@
1
+ require_dependency 'comable/admin/application_controller'
2
+
3
+ module Comable
4
+ module Admin
5
+ class DraftOrdersController < Comable::Admin::ApplicationController
6
+ include Comable::PermittedAttributes
7
+
8
+ load_and_authorize_resource :order, parent: false, class: Comable::DraftOrder.name
9
+
10
+ def index
11
+ @q = Comable::Order.draft.ransack(params[:q])
12
+ @orders = @q.result.page(params[:page]).per(15).recent.accessible_by(current_ability)
13
+ end
14
+
15
+ def show
16
+ render :edit
17
+ end
18
+
19
+ def new
20
+ build_associations
21
+ end
22
+
23
+ def create
24
+ if save_order_as_draft
25
+ @order.update!(draft: false) if @order.completed?
26
+ redirect_to admin_order_path, notice: Comable.t('successful')
27
+ else
28
+ build_associations
29
+ flash.now[:alert] = Comable.t('failure')
30
+ render :new
31
+ end
32
+ end
33
+
34
+ def edit
35
+ end
36
+
37
+ def update
38
+ @order.attributes = order_params
39
+
40
+ if save_order_as_draft
41
+ @order.update!(draft: false) if @order.completed?
42
+ redirect_to admin_order_path, notice: Comable.t('successful')
43
+ else
44
+ flash.now[:alert] = Comable.t('failure')
45
+ render :edit
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def admin_order_path
52
+ if @order.draft?
53
+ comable.admin_draft_order_path(@order)
54
+ else
55
+ comable.admin_order_path(@order)
56
+ end
57
+ end
58
+
59
+ def save_order_as_draft
60
+ @order.next_draft_state
61
+ rescue ActiveRecord::RecordInvalid
62
+ false
63
+ end
64
+
65
+ # rubocop:disable Metrics/MethodLength
66
+ def order_params
67
+ params.require(:order).permit(
68
+ :id,
69
+ :user_id,
70
+ :email,
71
+ :same_as_bill_address,
72
+ bill_address_attributes: permitted_address_attributes,
73
+ ship_address_attributes: permitted_address_attributes,
74
+ order_items_attributes: [:id, :name, :sku, :price, :quantity, :variant_id],
75
+ payment_attributes: [:id, :_destroy, :payment_method_id],
76
+ shipments_attributes: [:id, :_destroy, :shipment_method_id]
77
+ )
78
+ end
79
+ # rubocop:enable Metrics/MethodLength
80
+
81
+ def build_associations
82
+ @order.build_bill_address unless @order.bill_address
83
+ @order.build_ship_address unless @order.ship_address
84
+ @order.build_payment unless @order.payment
85
+ end
86
+ end
87
+ end
88
+ end
@@ -18,6 +18,10 @@ module Comable
18
18
  def show
19
19
  end
20
20
 
21
+ def new
22
+ redirect_to comable.new_admin_draft_order_path
23
+ end
24
+
21
25
  def edit
22
26
  end
23
27
 
@@ -87,7 +91,7 @@ module Comable
87
91
  :total_price,
88
92
  bill_address_attributes: permitted_address_attributes,
89
93
  ship_address_attributes: permitted_address_attributes,
90
- order_items_attributes: [:id, :name, :code, :price, :quantity]
94
+ order_items_attributes: [:id, :name, :price, :quantity]
91
95
  )
92
96
  end
93
97
 
@@ -10,6 +10,11 @@ module Comable
10
10
  def index
11
11
  @q = Comable::User.ransack(params[:q])
12
12
  @users = @q.result.page(params[:page]).accessible_by(current_ability).by_newest
13
+
14
+ respond_to do |format|
15
+ format.html
16
+ format.json { render json: @users }
17
+ end
13
18
  end
14
19
 
15
20
  def show
@@ -3,12 +3,20 @@ require_dependency 'comable/admin/application_controller'
3
3
  module Comable
4
4
  module Admin
5
5
  class VariantsController < Comable::Admin::ApplicationController
6
- load_and_authorize_resource :product, class: Comable::Product.name
7
- load_and_authorize_resource :variant, class: Comable::Variant.name, through: :product
6
+ # for /admin/variants
7
+ load_and_authorize_resource :variant, class: Comable::Variant.name, only: :index
8
+
9
+ # for /admin/products/:product_id/variants/:id
10
+ load_and_authorize_resource :product, class: Comable::Product.name, except: :index
11
+ load_and_authorize_resource :variant, class: Comable::Variant.name, except: :index, through: :product
8
12
 
9
13
  def index
10
14
  @q = @variants.ransack(params[:q])
11
15
  @variants = @q.result.includes(:product).page(params[:page]).accessible_by(current_ability).by_newest
16
+
17
+ respond_to do |format|
18
+ format.json { render json: @variants }
19
+ end
12
20
  end
13
21
 
14
22
  def show
@@ -13,7 +13,7 @@ AwesomeAdminLayout.define(only: Comable::Admin::ApplicationController) do |contr
13
13
  end
14
14
 
15
15
  item Comable.t('admin.nav.order') do
16
- link comable.admin_orders_path
16
+ nest :orders
17
17
  icon 'shopping-cart'
18
18
  end
19
19
 
@@ -43,6 +43,18 @@ AwesomeAdminLayout.define(only: Comable::Admin::ApplicationController) do |contr
43
43
  end
44
44
  end
45
45
 
46
+ navigation :orders do
47
+ brand Comable.t('admin.nav.order')
48
+
49
+ item Comable.t('admin.nav.order') do
50
+ link comable.admin_orders_path
51
+ end
52
+
53
+ item Comable.t('admin.nav.draft_order') do
54
+ link comable.admin_draft_orders_path
55
+ end
56
+ end
57
+
46
58
  navigation :products do
47
59
  brand Comable.t('admin.nav.product')
48
60
 
@@ -0,0 +1,179 @@
1
+ = error_messages_for @order
2
+
3
+ = form_for [comable, :admin, :draft, @order] do |f|
4
+ .hidden
5
+ = f.submit
6
+
7
+ .col-md-6
8
+ .row
9
+ fieldset
10
+ .col-md-3
11
+ legend
12
+ = f.object.class.human_attribute_name(:order_items)
13
+ .help-block
14
+
15
+ .col-md-9
16
+ - if @order.new_record?
17
+ .form-group
18
+ = select_tag :variant, nil, id: 'js-variant-selector', class: 'select2 ajax', data: { source: comable.admin_variants_path, term: :product_name_cont }
19
+ = link_to_add_fields nil, f, :order_items, id: 'js-add-order-item', class: 'hidden'
20
+
21
+ table.table#js-order-items-table
22
+ thead
23
+ tr
24
+ th colspan="2"
25
+ = f.object.order_items.klass.human_attribute_name(:product)
26
+ th
27
+ = f.object.order_items.klass.human_attribute_name(:price)
28
+ th
29
+ = f.object.order_items.klass.human_attribute_name(:quantity)
30
+ th
31
+ = f.object.order_items.klass.human_attribute_name(:subtotal_price)
32
+ tbody
33
+ = f.fields_for :order_items do |ff|
34
+ = render 'comable/admin/shared/order_items_fields', f: ff
35
+ tfoot
36
+ tr
37
+ th.text-right colspan="4"
38
+ = f.object.class.human_attribute_name(:item_total_price)
39
+ td
40
+ = f.text_field :item_total_price, disabled: true, data: { name: 'item-total-price' }
41
+
42
+ .form-group
43
+ = f.fields_for :payment do |ff|
44
+ .panel.panel-default
45
+ .panel-heading
46
+ = f.object.class.human_attribute_name(:payment_method)
47
+
48
+ ul.list-group
49
+ = ff.collection_radio_buttons :payment_method_id, Comable::PaymentMethod.all, :id, :name do |b|
50
+ li.list-group-item
51
+ .radio
52
+ = b.label do
53
+ = b.radio_button
54
+ strong
55
+ = b.text
56
+ p
57
+ = "#{b.object.class.human_attribute_name(:fee)}: "
58
+ = number_to_currency b.object.fee
59
+
60
+ - if @order.shipment?
61
+ .form-group
62
+ = f.fields_for :shipments do |ff|
63
+ .panel.panel-default
64
+ .panel-heading
65
+ | #{f.object.class.human_attribute_name(:shipment_method)} ##{ff.index.next}
66
+
67
+ ul.list-group
68
+ = ff.collection_radio_buttons :shipment_method_id, Comable::ShipmentMethod.all, :id, :name do |b|
69
+ li.list-group-item
70
+ .radio
71
+ = b.label do
72
+ = b.radio_button
73
+ strong
74
+ = b.text
75
+ p
76
+ = "#{b.object.class.human_attribute_name(:fee)}: "
77
+ = number_to_currency b.object.fee
78
+
79
+ .col-md-6#js-user-fields
80
+ .row
81
+ fieldset
82
+ .col-md-3
83
+ legend
84
+ = Comable.t('admin.user')
85
+ .help-block
86
+
87
+ .col-md-9
88
+ - if @order.new_record?
89
+ .form-group
90
+ = f.collection_select :user_id, [@order.user].compact, :id, :text, {}, id: 'js-user-selector', class: 'select2 ajax', data: { source: comable.admin_users_path, term: :email_or_bill_address_full_name_cont }
91
+
92
+ .form-group
93
+ = f.label :email
94
+ = f.email_field :email, data: { name: 'email' }
95
+
96
+ - if f.object.bill_address
97
+ hr
98
+
99
+ fieldset
100
+ .col-md-3
101
+ legend
102
+ = f.object.class.human_attribute_name(:bill_address)
103
+ .help-block
104
+
105
+ .col-md-9
106
+ = f.fields_for :bill_address do |ff|
107
+ .form-group
108
+ = ff.label :full_name
109
+ .row
110
+ .col-sm-6
111
+ = ff.text_field :family_name, placeholder: ff.object.class.human_attribute_name(:family_name), data: { name: 'bill-family-name' }
112
+ .col-sm-6
113
+ = ff.text_field :first_name, placeholder: ff.object.class.human_attribute_name(:first_name), data: { name: 'bill-first-name' }
114
+
115
+ .form-group
116
+ = ff.label :zip_code
117
+ = ff.text_field :zip_code, max_length: 8, data: { name: 'bill-zip-code' }
118
+
119
+ .form-group
120
+ = ff.label :state_name
121
+ = ff.text_field :state_name, data: { name: 'bill-state-name' }
122
+
123
+ .form-group
124
+ = ff.label :city
125
+ = ff.text_field :city, data: { name: 'bill-city' }
126
+
127
+ .form-group
128
+ = ff.label :detail
129
+ = ff.text_field :detail, data: { name: 'bill-detail' }
130
+
131
+ .form-group
132
+ = ff.label :phone_number
133
+ = ff.text_field :phone_number, max_length: 18, data: { name: 'bill-phone-number' }
134
+
135
+ - if f.object.ship_address
136
+ hr
137
+
138
+ fieldset
139
+ .col-md-3
140
+ legend
141
+ = f.object.class.human_attribute_name(:ship_address)
142
+ .help-block
143
+
144
+ .col-md-9
145
+ .form-group
146
+ .checkbox
147
+ label
148
+ = f.check_box :same_as_bill_address, data: { name: 'same-as-bill-address' }
149
+ = f.object.class.human_attribute_name(:same_as_bill_address)
150
+
151
+ #js-ship-address-fields
152
+ = f.fields_for :ship_address do |ff|
153
+ .form-group
154
+ = ff.label :full_name
155
+ .row
156
+ .col-sm-6
157
+ = ff.text_field :family_name, placeholder: ff.object.class.human_attribute_name(:family_name), data: { name: 'ship-family-name' }
158
+ .col-sm-6
159
+ = ff.text_field :first_name, placeholder: ff.object.class.human_attribute_name(:first_name), data: { name: 'ship-first-name' }
160
+
161
+ .form-group
162
+ = ff.label :zip_code
163
+ = ff.text_field :zip_code, max_length: 8, data: { name: 'ship-zip-code' }
164
+
165
+ .form-group
166
+ = ff.label :state_name
167
+ = ff.text_field :state_name, data: { name: 'ship-state-name' }
168
+
169
+ .form-group
170
+ = ff.label :city
171
+ = ff.text_field :city, data: { name: 'ship-city' }
172
+
173
+ .form-group
174
+ = ff.label :detail
175
+ = ff.text_field :detail, data: { name: 'ship-detail' }
176
+
177
+ .form-group
178
+ = ff.label :phone_number
179
+ = ff.text_field :phone_number, max_length: 18, data: { name: 'ship-phone-number' }
@@ -0,0 +1,18 @@
1
+ .comable-page
2
+ .comable-main-fixed-top
3
+ .comable-page-heading
4
+ ul.pull-right.list-inline
5
+ li
6
+ = link_to_save
7
+
8
+ h1.page-header
9
+ ol.breadcrumb
10
+ li>
11
+ = link_to Comable.t('admin.nav.draft_order'), comable.admin_draft_orders_path
12
+ li>
13
+ = link_to @order.code, comable.admin_draft_order_path(@order)
14
+ li.active
15
+ = Comable.t('admin.actions.edit')
16
+
17
+ .comable-page-body
18
+ = render 'form'
@@ -0,0 +1,92 @@
1
+ .comable-page
2
+ .comable-page-heading
3
+ ul.pull-right.list-inline
4
+ li
5
+ .btn-group role="group"
6
+ = link_to_previous_page @orders, '<', class: 'btn btn-default' do
7
+ .btn.btn-default disabled="disabled"
8
+ | <
9
+ = link_to_next_page @orders, '>', class: 'btn btn-default' do
10
+ .btn.btn-default disabled="disabled"
11
+ | >
12
+ li
13
+ = link_to Comable.t('admin.actions.new'), comable.new_admin_draft_order_path, class: 'btn btn-default'
14
+ li.dropdown
15
+ = link_to '#', class: 'btn btn-default', 'data-toggle' => 'dropdown' do
16
+ = Comable.t('admin.more')
17
+ i.fa.fa-angle-down<
18
+
19
+ h1.page-header
20
+ = Comable.t('admin.nav.draft_order')
21
+ small<
22
+ | #{@orders.total_count} #{Comable.t('admin.results')}
23
+
24
+ .comable-page-body
25
+ .comable-search
26
+ = search_form_for @q, url: comable.admin_draft_orders_path do |f|
27
+ .input-group
28
+ span.input-group-btn
29
+ button.btn.btn-default.dropdown-toggle type="button" data-toggle="dropdown"
30
+ i.fa.fa-search
31
+ span.caret<
32
+ ul.dropdown-menu role="menu"
33
+ li
34
+ = link_to Comable.t('admin.advanced_search'), 'javascript:void(0)', 'data-toggle' => 'collapse', 'data-target' => '#comable-advanced-search'
35
+ li
36
+ = link_to Comable.t('admin.clear_search_conditions'), comable.admin_draft_orders_path
37
+ = f.text_field :code_cont, class: 'form-control'
38
+ span.input-group-btn
39
+ = f.submit Comable.t('admin.search'), class: 'btn btn-default'
40
+ .hidden
41
+ = f.label :user_id
42
+ = f.text_field :user_id_eq
43
+
44
+ = render 'comable/admin/shared/advanced_search', f: f
45
+
46
+ section
47
+ - if @orders.empty?
48
+ = Comable.t('admin.not_found')
49
+ - else
50
+ table.table.table-striped
51
+ thead
52
+ th
53
+ = sort_link [:comable, @q], :code
54
+ th
55
+ = sort_link [:comable, @q], :state
56
+ th
57
+ = @orders.klass.human_attribute_name(:payment_state)
58
+ th
59
+ = @orders.klass.human_attribute_name(:shipment_state)
60
+ th
61
+ = @orders.klass.human_attribute_name(:bill_full_name)
62
+ th
63
+ = @orders.klass.human_attribute_name(:order_items)
64
+ th
65
+ = sort_link [:comable, @q], :total_price
66
+ th
67
+ = sort_link [:comable, @q], :created_at
68
+ tbody
69
+ - @orders.each do |order|
70
+ tr
71
+ td
72
+ = link_to order.code, comable.admin_draft_order_path(order)
73
+ td
74
+ = order.human_state_name
75
+ td
76
+ = order.payment_human_state_name
77
+ td
78
+ = order.shipment_human_state_name
79
+ td
80
+ = order.bill_full_name
81
+ td
82
+ ul.list-unstyled
83
+ - order.order_items.each do |order_item|
84
+ li
85
+ | #{order_item.name_with_sku} x #{order_item.quantity}
86
+ td
87
+ = number_to_currency order.total_price
88
+ td
89
+ = l order.created_at
90
+
91
+ .text-center
92
+ = paginate @orders, theme: :comable_backend
@@ -0,0 +1,16 @@
1
+ .comable-page
2
+ .comable-main-fixed-top
3
+ .comable-page-heading
4
+ ul.pull-right.list-inline
5
+ li
6
+ = link_to_save
7
+
8
+ h1.page-header
9
+ ol.breadcrumb
10
+ li>
11
+ = link_to Comable.t('admin.nav.draft_order'), comable.admin_draft_orders_path
12
+ li.active
13
+ = Comable.t('admin.actions.new')
14
+
15
+ .comable-page-body
16
+ = render 'form'
@@ -0,0 +1,157 @@
1
+ = error_messages_for @order
2
+
3
+ = form_for [comable, :admin, @order] do |f|
4
+ .hidden
5
+ = f.submit
6
+
7
+ .col-md-6
8
+ .row
9
+ fieldset
10
+ .col-md-3
11
+ legend
12
+ = f.object.class.human_attribute_name(:order_items)
13
+ .help-block
14
+
15
+ .col-md-9
16
+ - if @order.new_record?
17
+ .form-group
18
+ = select_tag :variant, nil, id: 'js-variant-selector', class: 'select2 ajax', data: { source: comable.admin_variants_path, term: :product_name_cont }
19
+ = link_to_add_fields nil, f, :order_items, id: 'js-add-order-item', class: 'hidden'
20
+
21
+ table.table#js-order-items-table
22
+ thead
23
+ tr
24
+ th colspan="2"
25
+ = f.object.order_items.klass.human_attribute_name(:product)
26
+ th
27
+ = f.object.order_items.klass.human_attribute_name(:price)
28
+ th
29
+ = f.object.order_items.klass.human_attribute_name(:quantity)
30
+ th
31
+ = f.object.order_items.klass.human_attribute_name(:subtotal_price)
32
+ tbody
33
+ = f.fields_for :order_items do |ff|
34
+ = render 'comable/admin/shared/order_items_fields', f: ff
35
+ tfoot
36
+ tr
37
+ th.text-right colspan="4"
38
+ = f.object.class.human_attribute_name(:item_total_price)
39
+ td
40
+ = f.text_field :item_total_price, disabled: true, data: { name: 'item-total-price' }
41
+ tr
42
+ th.text-right colspan="4"
43
+ = f.object.class.human_attribute_name(:payment_fee)
44
+ td
45
+ = f.text_field :payment_fee, data: { name: 'payment-fee' }
46
+ tr
47
+ th.text-right colspan="4"
48
+ = f.object.class.human_attribute_name(:shipment_fee)
49
+ td
50
+ = f.text_field :shipment_fee, data: { name: 'shipment-fee' }
51
+ tr
52
+ th.text-right colspan="4"
53
+ = f.object.class.human_attribute_name(:total_price)
54
+ td
55
+ = f.text_field :total_price, disabled: true, data: { name: 'total-price' }
56
+
57
+ .col-md-6#js-user-fields
58
+ .row
59
+ fieldset
60
+ .col-md-3
61
+ legend
62
+ = Comable.t('admin.user')
63
+ .help-block
64
+
65
+ .col-md-9
66
+ - if @order.new_record?
67
+ .form-group
68
+ = f.collection_select :user_id, [@order.user].compact, :id, :text, {}, id: 'js-user-selector', class: 'select2 ajax', data: { source: comable.admin_users_path, term: :email_or_bill_address_full_name_cont }
69
+
70
+ .form-group
71
+ = f.label :email
72
+ = f.email_field :email, data: { name: 'email' }
73
+
74
+ - if f.object.bill_address
75
+ hr
76
+
77
+ fieldset
78
+ .col-md-3
79
+ legend
80
+ = f.object.class.human_attribute_name(:bill_address)
81
+ .help-block
82
+
83
+ .col-md-9
84
+ = f.fields_for :bill_address do |ff|
85
+ .form-group
86
+ = ff.label :full_name
87
+ .row
88
+ .col-sm-6
89
+ = ff.text_field :family_name, placeholder: ff.object.class.human_attribute_name(:family_name), data: { name: 'bill-family-name' }
90
+ .col-sm-6
91
+ = ff.text_field :first_name, placeholder: ff.object.class.human_attribute_name(:first_name), data: { name: 'bill-first-name' }
92
+
93
+ .form-group
94
+ = ff.label :zip_code
95
+ = ff.text_field :zip_code, max_length: 8, data: { name: 'bill-zip-code' }
96
+
97
+ .form-group
98
+ = ff.label :state_name
99
+ = ff.text_field :state_name, data: { name: 'bill-state-name' }
100
+
101
+ .form-group
102
+ = ff.label :city
103
+ = ff.text_field :city, data: { name: 'bill-city' }
104
+
105
+ .form-group
106
+ = ff.label :detail
107
+ = ff.text_field :detail, data: { name: 'bill-detail' }
108
+
109
+ .form-group
110
+ = ff.label :phone_number
111
+ = ff.text_field :phone_number, max_length: 18, data: { name: 'bill-phone-number' }
112
+
113
+ - if f.object.ship_address
114
+ hr
115
+
116
+ fieldset
117
+ .col-md-3
118
+ legend
119
+ = f.object.class.human_attribute_name(:ship_address)
120
+ .help-block
121
+
122
+ .col-md-9
123
+ .form-group
124
+ .checkbox
125
+ label
126
+ = f.check_box :same_as_bill_address, data: { name: 'same-as-bill-address' }
127
+ = f.object.class.human_attribute_name(:same_as_bill_address)
128
+
129
+ #js-ship-address-fields
130
+ = f.fields_for :ship_address do |ff|
131
+ .form-group
132
+ = ff.label :full_name
133
+ .row
134
+ .col-sm-6
135
+ = ff.text_field :family_name, placeholder: ff.object.class.human_attribute_name(:family_name), data: { name: 'ship-family-name' }
136
+ .col-sm-6
137
+ = ff.text_field :first_name, placeholder: ff.object.class.human_attribute_name(:first_name), data: { name: 'ship-first-name' }
138
+
139
+ .form-group
140
+ = ff.label :zip_code
141
+ = ff.text_field :zip_code, max_length: 8, data: { name: 'ship-zip-code' }
142
+
143
+ .form-group
144
+ = ff.label :state_name
145
+ = ff.text_field :state_name, data: { name: 'ship-state-name' }
146
+
147
+ .form-group
148
+ = ff.label :city
149
+ = ff.text_field :city, data: { name: 'ship-city' }
150
+
151
+ .form-group
152
+ = ff.label :detail
153
+ = ff.text_field :detail, data: { name: 'ship-detail' }
154
+
155
+ .form-group
156
+ = ff.label :phone_number
157
+ = ff.text_field :phone_number, max_length: 18, data: { name: 'ship-phone-number' }
@@ -15,156 +15,4 @@
15
15
  = Comable.t('admin.actions.edit')
16
16
 
17
17
  .comable-page-body
18
- section
19
- = error_messages_for @order
20
-
21
- = form_for @order, url: comable.admin_order_path(@order) do |f|
22
- .hidden
23
- = f.submit
24
-
25
- fieldset
26
- .col-md-3
27
- legend
28
- = Comable.t('admin.general')
29
- .help-block
30
-
31
- .col-md-9
32
- .form-group
33
- = f.label :email
34
- = f.email_field :email
35
-
36
- - if f.object.bill_address
37
- hr
38
-
39
- fieldset
40
- .col-md-3
41
- legend
42
- = f.object.class.human_attribute_name(:bill_address)
43
- .help-block
44
-
45
- .col-md-9
46
- = f.fields_for :bill_address do |ff|
47
- .form-group
48
- = ff.label :full_name
49
- .row
50
- .col-sm-6
51
- = ff.text_field :family_name, placeholder: ff.object.class.human_attribute_name(:family_name)
52
- .col-sm-6
53
- = ff.text_field :first_name, placeholder: ff.object.class.human_attribute_name(:first_name)
54
-
55
- .form-group
56
- = ff.label :zip_code
57
- = ff.text_field :zip_code, max_length: 8
58
-
59
- .form-group
60
- = ff.label :state_name
61
- = ff.text_field :state_name
62
-
63
- .form-group
64
- = ff.label :city
65
- = ff.text_field :city
66
-
67
- .form-group
68
- = ff.label :detail
69
- = ff.text_field :detail
70
-
71
- .form-group
72
- = ff.label :phone_number
73
- = ff.text_field :phone_number, max_length: 18
74
-
75
- - if f.object.ship_address
76
- hr
77
-
78
- fieldset
79
- .col-md-3
80
- legend
81
- = f.object.class.human_attribute_name(:ship_address)
82
- .help-block
83
-
84
- .col-md-9
85
- = f.fields_for :ship_address do |ff|
86
- .form-group
87
- = ff.label :full_name
88
- .row
89
- .col-sm-6
90
- = ff.text_field :family_name, placeholder: ff.object.class.human_attribute_name(:family_name)
91
- .col-sm-6
92
- = ff.text_field :first_name, placeholder: ff.object.class.human_attribute_name(:first_name)
93
-
94
- .form-group
95
- = ff.label :zip_code
96
- = ff.text_field :zip_code, max_length: 8
97
-
98
- .form-group
99
- = ff.label :state_name
100
- = ff.text_field :state_name
101
-
102
- .form-group
103
- = ff.label :city
104
- = ff.text_field :city
105
-
106
- .form-group
107
- = ff.label :detail
108
- = ff.text_field :detail
109
-
110
- .form-group
111
- = ff.label :phone_number
112
- = ff.text_field :phone_number, max_length: 18
113
-
114
- - if f.object.order_items
115
- hr
116
-
117
- fieldset
118
- .col-md-3
119
- legend
120
- = f.object.class.human_attribute_name(:order_items)
121
- .help-block
122
-
123
- .col-md-9
124
- table.table
125
- thead
126
- tr
127
- th colspan="2"
128
- = f.object.order_items.klass.human_attribute_name(:product)
129
- th
130
- = f.object.order_items.klass.human_attribute_name(:price)
131
- th
132
- = f.object.order_items.klass.human_attribute_name(:quantity)
133
- th
134
- = f.object.order_items.klass.human_attribute_name(:subtotal_price)
135
- tbody
136
- = f.fields_for :order_items do |ff|
137
- tr.comable-order-items
138
- td width="180"
139
- = image_tag ff.object.image_url, width: '100%'
140
- td
141
- p
142
- = ff.text_field :name, placeholder: ff.object.class.human_attribute_name(:name), data: { name: 'name' }
143
- p.text-muted
144
- = ff.text_field :sku, placeholder: ff.object.class.human_attribute_name(:sku), data: { name: 'sku' }
145
- td
146
- = ff.text_field :price, placeholder: ff.object.class.human_attribute_name(:price), data: { name: 'price' }
147
- td
148
- = ff.text_field :quantity, placeholder: ff.object.class.human_attribute_name(:quantity), data: { name: 'quantity' }
149
- td
150
- = ff.text_field :subtotal_price, disabled: true, data: { name: 'subtotal_price' }
151
- tr
152
- th.text-right colspan="4"
153
- = f.object.class.human_attribute_name(:item_total_price)
154
- td
155
- = f.text_field :item_total_price, disabled: true, data: { name: 'item_total_price' }
156
- tr
157
- th.text-right colspan="4"
158
- = f.object.class.human_attribute_name(:payment_fee)
159
- td
160
- = f.text_field :payment_fee, data: { name: 'payment_fee' }
161
- tr
162
- th.text-right colspan="4"
163
- = f.object.class.human_attribute_name(:shipment_fee)
164
- td
165
- = f.text_field :shipment_fee, data: { name: 'shipment_fee' }
166
- tr
167
- th.text-right colspan="4"
168
- = f.object.class.human_attribute_name(:total_price)
169
- td
170
- = f.text_field :total_price, disabled: true, data: { name: 'total_price' }
18
+ = render 'form'
@@ -9,6 +9,8 @@
9
9
  = link_to_next_page @orders, '>', class: 'btn btn-default' do
10
10
  .btn.btn-default disabled="disabled"
11
11
  | >
12
+ li
13
+ = link_to Comable.t('admin.actions.new'), comable.new_admin_order_path, class: 'btn btn-default'
12
14
  li.dropdown
13
15
  = link_to '#', class: 'btn btn-default', 'data-toggle' => 'dropdown' do
14
16
  = Comable.t('admin.more')
@@ -0,0 +1,16 @@
1
+ .comable-page
2
+ .comable-main-fixed-top
3
+ .comable-page-heading
4
+ ul.pull-right.list-inline
5
+ li
6
+ = link_to_save
7
+
8
+ h1.page-header
9
+ ol.breadcrumb
10
+ li>
11
+ = link_to Comable.t('admin.nav.order'), comable.admin_orders_path
12
+ li.active
13
+ = Comable.t('admin.actions.new')
14
+
15
+ .comable-page-body
16
+ = render 'form'
@@ -6,11 +6,11 @@
6
6
  = link_to comable.ship_admin_order_path(@order), class: 'btn btn-primary', method: :post, disabled: !@order.can_ship? do
7
7
  i.fa.fa-truck>
8
8
  = Comable.t('admin.ship')
9
- - if @order.completed?
9
+ - if @order.can_cancel?
10
10
  li
11
11
  = link_to comable.cancel_admin_order_path(@order), class: 'btn btn-default', method: :post do
12
12
  = @order.class.human_state_event_name(:cancel)
13
- - if @order.canceled?
13
+ - if @order.can_resume?
14
14
  li
15
15
  = button_to comable.resume_admin_order_path(@order), class: 'btn btn-default', method: :post do
16
16
  = @order.class.human_state_event_name(:resume)
@@ -10,8 +10,7 @@
10
10
  .btn.btn-default disabled="disabled"
11
11
  | >
12
12
  li
13
- = link_to comable.root_path do
14
- = link_to Comable.t('admin.actions.new'), comable.new_admin_product_path, class: 'btn btn-default'
13
+ = link_to Comable.t('admin.actions.new'), comable.new_admin_product_path, class: 'btn btn-default'
15
14
  li.dropdown
16
15
  = link_to '#', class: 'btn btn-default', 'data-toggle' => 'dropdown' do
17
16
  = Comable.t('admin.more')
@@ -0,0 +1,20 @@
1
+ - dynamic_field = f.index.is_a? String
2
+ - css_class = ['js-new-order-item', 'hidden'].join(' ') if dynamic_field
3
+
4
+ tr.comable-order-items class="#{css_class}"
5
+ td width="180"
6
+ = image_tag f.object.image_url, width: '100%', data: { name: 'image-url' }
7
+ td
8
+ p
9
+ = f.text_field :name, placeholder: f.object.class.human_attribute_name(:name), data: { name: 'name' }
10
+ p.text-muted
11
+ = f.text_field :sku, placeholder: f.object.class.human_attribute_name(:sku), data: { name: 'sku' }
12
+ td
13
+ = f.text_field :price, placeholder: f.object.class.human_attribute_name(:price), data: { name: 'price' }
14
+ td
15
+ = f.text_field :quantity, placeholder: f.object.class.human_attribute_name(:quantity), data: { name: 'quantity' }
16
+ td
17
+ = f.text_field :subtotal_price, disabled: true, data: { name: 'subtotal-price' }
18
+ br
19
+ = f.text_field :variant_id, data: { name: 'variant-id' }, class: 'hidden'
20
+ = link_to Comable.t('admin.actions.destroy'), 'javascript:void(0)', class: 'js-remove-order-item'
data/config/routes.rb CHANGED
@@ -5,7 +5,7 @@ Comable::Core::Engine.routes.draw do
5
5
  resource :dashboard, only: :show
6
6
 
7
7
  resources :products do
8
- resources :variants
8
+ resources :variants, except: :index
9
9
 
10
10
  resources :stocks
11
11
 
@@ -22,7 +22,9 @@ Comable::Core::Engine.routes.draw do
22
22
  end
23
23
  end
24
24
 
25
- resources :orders do
25
+ resources :variants, only: :index
26
+
27
+ resources :orders, except: :create do
26
28
  collection do
27
29
  get :export
28
30
  end
@@ -38,6 +40,8 @@ Comable::Core::Engine.routes.draw do
38
40
  end
39
41
  end
40
42
 
43
+ resources :draft_orders
44
+
41
45
  resources :categories
42
46
  resources :stock_locations
43
47
  resources :pages
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: comable-backend
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0.beta2
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - YOSHIDA Hiroki
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-31 00:00:00.000000000 Z
11
+ date: 2015-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: comable-core
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.7.0.beta2
19
+ version: 0.7.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.7.0.beta2
26
+ version: 0.7.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rails
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -487,13 +487,15 @@ files:
487
487
  - app/assets/javascripts/comable/admin/categories.coffee
488
488
  - app/assets/javascripts/comable/admin/dashboard.coffee
489
489
  - app/assets/javascripts/comable/admin/dispatcher.coffee
490
+ - app/assets/javascripts/comable/admin/dynamic_order.coffee
490
491
  - app/assets/javascripts/comable/admin/navigations.coffee
491
- - app/assets/javascripts/comable/admin/orders.coffee
492
+ - app/assets/javascripts/comable/admin/order_item_builder.coffee
492
493
  - app/assets/javascripts/comable/admin/pages.coffee
493
494
  - app/assets/javascripts/comable/admin/products.coffee
494
495
  - app/assets/javascripts/comable/admin/search.coffee
495
496
  - app/assets/javascripts/comable/admin/stocks.coffee
496
497
  - app/assets/javascripts/comable/admin/themes.coffee
498
+ - app/assets/javascripts/comable/admin/user_selector.coffee
497
499
  - app/assets/javascripts/comable/admin/variants.coffee
498
500
  - app/assets/stylesheets/comable/admin/_common.scss
499
501
  - app/assets/stylesheets/comable/admin/_dashboard.scss
@@ -517,6 +519,7 @@ files:
517
519
  - app/controllers/comable/admin/application_controller.rb
518
520
  - app/controllers/comable/admin/categories_controller.rb
519
521
  - app/controllers/comable/admin/dashboard_controller.rb
522
+ - app/controllers/comable/admin/draft_orders_controller.rb
520
523
  - app/controllers/comable/admin/navigations_controller.rb
521
524
  - app/controllers/comable/admin/orders_controller.rb
522
525
  - app/controllers/comable/admin/pages_controller.rb
@@ -543,17 +546,23 @@ files:
543
546
  - app/views/comable/admin/categories/index.slim
544
547
  - app/views/comable/admin/dashboard/_widget.slim
545
548
  - app/views/comable/admin/dashboard/show.slim
549
+ - app/views/comable/admin/draft_orders/_form.slim
550
+ - app/views/comable/admin/draft_orders/edit.slim
551
+ - app/views/comable/admin/draft_orders/index.slim
552
+ - app/views/comable/admin/draft_orders/new.slim
546
553
  - app/views/comable/admin/navigations/_form.slim
547
554
  - app/views/comable/admin/navigations/_navigation_item_fields.slim
548
555
  - app/views/comable/admin/navigations/edit.slim
549
556
  - app/views/comable/admin/navigations/index.slim
550
557
  - app/views/comable/admin/navigations/new.slim
551
558
  - app/views/comable/admin/navigations/search_linkable_ids.coffee
559
+ - app/views/comable/admin/orders/_form.slim
552
560
  - app/views/comable/admin/orders/_google_map.slim
553
561
  - app/views/comable/admin/orders/_payment_state.slim
554
562
  - app/views/comable/admin/orders/_shipment_state.slim
555
563
  - app/views/comable/admin/orders/edit.slim
556
564
  - app/views/comable/admin/orders/index.slim
565
+ - app/views/comable/admin/orders/new.slim
557
566
  - app/views/comable/admin/orders/show.slim
558
567
  - app/views/comable/admin/pages/_form.slim
559
568
  - app/views/comable/admin/pages/edit.slim
@@ -577,6 +586,7 @@ files:
577
586
  - app/views/comable/admin/shared/_notifier.slim
578
587
  - app/views/comable/admin/shared/_option_type_fields.slim
579
588
  - app/views/comable/admin/shared/_option_types_fields.slim
589
+ - app/views/comable/admin/shared/_order_items_fields.slim
580
590
  - app/views/comable/admin/shared/_stocks_fields.slim
581
591
  - app/views/comable/admin/shared/_value_fields.slim
582
592
  - app/views/comable/admin/shared/_variant_form.slim
@@ -612,7 +622,6 @@ files:
612
622
  - app/views/comable/admin/users/show.slim
613
623
  - app/views/comable/admin/variants/_form.slim
614
624
  - app/views/comable/admin/variants/edit.slim
615
- - app/views/comable/admin/variants/index.slim
616
625
  - app/views/comable/admin/variants/new.slim
617
626
  - app/views/kaminari/comable_backend/_first_page.html.slim
618
627
  - app/views/kaminari/comable_backend/_gap.html.slim
@@ -641,9 +650,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
641
650
  version: '0'
642
651
  required_rubygems_version: !ruby/object:Gem::Requirement
643
652
  requirements:
644
- - - ">"
653
+ - - ">="
645
654
  - !ruby/object:Gem::Version
646
- version: 1.3.1
655
+ version: '0'
647
656
  requirements: []
648
657
  rubyforge_project:
649
658
  rubygems_version: 2.4.5
@@ -1,97 +0,0 @@
1
- .comable-page
2
- .comable-page-heading
3
- ul.pull-right.list-inline
4
- li
5
- .btn-group role="group"
6
- = link_to_previous_page @products, '<', class: 'btn btn-default' do
7
- .btn.btn-default disabled="disabled"
8
- | <
9
- = link_to_next_page @products, '>', class: 'btn btn-default' do
10
- .btn.btn-default disabled="disabled"
11
- | >
12
- li
13
- = link_to comable.root_path do
14
- = link_to Comable.t('admin.actions.new'), comable.new_admin_product_path, class: 'btn btn-default'
15
- li.dropdown
16
- = link_to '#', class: 'btn btn-default', 'data-toggle' => 'dropdown' do
17
- = Comable.t('admin.more')
18
- i.fa.fa-angle-down<
19
- ul.dropdown-menu.dropdown-menu-right
20
- li
21
- = link_to Comable.t('admin.export_to_csv'), comable.export_admin_products_path(format: :csv, q: params[:q])
22
- li
23
- = link_to Comable.t('admin.export_to_excel'), comable.export_admin_products_path(format: :xlsx, q: params[:q])
24
- li.divider
25
- li
26
- a.btn-file
27
- span>
28
- = Comable.t('admin.import')
29
- = form_tag comable.import_admin_products_path, multipart: true do
30
- = file_field_tag :file
31
-
32
- h1.page-header
33
- = Comable.t('admin.nav.product')
34
- small<
35
- | #{@products.total_count} #{Comable.t('admin.results')}
36
-
37
- .comable-page-body
38
- .comable-search
39
- = search_form_for @q, url: comable.admin_products_path do |f|
40
- .input-group
41
- span.input-group-btn
42
- button.btn.btn-default.dropdown-toggle type="button" data-toggle="dropdown"
43
- i.fa.fa-search
44
- span.caret<
45
- ul.dropdown-menu role="menu"
46
- li
47
- = link_to Comable.t('admin.advanced_search'), 'javascript:void(0)', 'data-toggle' => 'collapse', 'data-target' => '#comable-advanced-search'
48
- li
49
- = link_to Comable.t('admin.clear_search_conditions'), comable.admin_products_path
50
- = f.text_field :name_or_variants_sku_cont_any_splitted, class: 'form-control'
51
- span.input-group-btn
52
- = f.submit Comable.t('admin.search'), class: 'btn btn-default'
53
-
54
- = render 'comable/admin/shared/advanced_search', f: f
55
-
56
- section
57
- - if @products.empty?
58
- = Comable.t('admin.not_found')
59
- - else
60
- table.table.table-striped
61
- thead
62
- th
63
- th
64
- = sort_link [:comable, @q], :code
65
- th
66
- = sort_link [:comable, @q], :name
67
- th
68
- = sort_link [:comable, @q], :price
69
- th
70
- = Comable.t('admin.stocks')
71
- tbody
72
- - @products.each do |product|
73
- - quantity = product.stocks.to_a.sum(&:quantity)
74
- tr
75
- td.comable-image
76
- = link_to comable.admin_product_path(product), class: 'thumbnail' do
77
- = image_tag product.image_url, width: '100%'
78
- td
79
- = link_to product.code, comable.admin_product_path(product)
80
- - unless product.published?
81
- span.fa.fa-eye-slash.text-muted<
82
- td
83
- = product.name
84
- td
85
- = number_to_currency product.price
86
- td
87
- ul.list-unstyled
88
- - product.stocks.each do |stock|
89
- li
90
- strong class="#{(quantity <= 0) ? 'text-danger' : (quantity <= 10) ? 'text-warning' : 'text-success'}"
91
- = number_with_delimiter stock.quantity
92
- - if stock.sku?
93
- span<
94
- | (#{stock.sku_name})
95
-
96
- .text-center
97
- = paginate @products, theme: :comable_backend