Product error handling
This commit is contained in:
@@ -86,7 +86,7 @@ group :development do
|
|||||||
#gem 'pry-remote'
|
#gem 'pry-remote'
|
||||||
gem 'quiet_assets'
|
gem 'quiet_assets'
|
||||||
gem 'letter_opener'
|
gem 'letter_opener'
|
||||||
gem 'thin'
|
# gem 'thin'
|
||||||
gem 'faye'
|
gem 'faye'
|
||||||
gem 'capistrano', '~> 3.0', require: false
|
gem 'capistrano', '~> 3.0', require: false
|
||||||
gem 'capistrano-rvm', '~> 0.1', require: false
|
gem 'capistrano-rvm', '~> 0.1', require: false
|
||||||
|
|||||||
@@ -155,7 +155,6 @@ GEM
|
|||||||
mime-types (~> 1.15)
|
mime-types (~> 1.15)
|
||||||
multi_json (~> 1.0)
|
multi_json (~> 1.0)
|
||||||
rest-client (~> 1.6.1)
|
rest-client (~> 1.6.1)
|
||||||
daemons (1.1.9)
|
|
||||||
debug_inspector (0.0.2)
|
debug_inspector (0.0.2)
|
||||||
diff-lcs (1.2.5)
|
diff-lcs (1.2.5)
|
||||||
docile (1.1.5)
|
docile (1.1.5)
|
||||||
@@ -408,10 +407,6 @@ GEM
|
|||||||
net-scp (>= 1.1.2)
|
net-scp (>= 1.1.2)
|
||||||
net-ssh (>= 2.8.0)
|
net-ssh (>= 2.8.0)
|
||||||
temple (0.6.10)
|
temple (0.6.10)
|
||||||
thin (1.6.3)
|
|
||||||
daemons (~> 1.0, >= 1.0.9)
|
|
||||||
eventmachine (~> 1.0)
|
|
||||||
rack (~> 1.0)
|
|
||||||
thor (0.19.1)
|
thor (0.19.1)
|
||||||
thread_safe (0.3.4)
|
thread_safe (0.3.4)
|
||||||
tilt (1.4.1)
|
tilt (1.4.1)
|
||||||
@@ -487,7 +482,6 @@ DEPENDENCIES
|
|||||||
slim-rails
|
slim-rails
|
||||||
spring
|
spring
|
||||||
spring-commands-rspec
|
spring-commands-rspec
|
||||||
thin
|
|
||||||
turnip
|
turnip
|
||||||
uglifier (>= 1.0.3)
|
uglifier (>= 1.0.3)
|
||||||
web-console (~> 2.0.0.beta3)
|
web-console (~> 2.0.0.beta3)
|
||||||
|
|||||||
@@ -1,9 +1,24 @@
|
|||||||
App.MenuProductComponent = Ember.Component.extend
|
App.MenuProductComponent = Ember.Component.extend
|
||||||
editMode: false
|
editMode: false
|
||||||
|
code_filter: ''
|
||||||
|
showProduct: (-> !@get('code_filter') or (@get('product.code') || "").match(@get('code_filter'))).property('code_filter')
|
||||||
|
code_filter_display: (->
|
||||||
|
return new Ember.Handlebars.SafeString(' ') unless code = @get('product.code')
|
||||||
|
return code unless filter = @get('code_filter')
|
||||||
|
index = code.indexOf(filter)
|
||||||
|
if index >= 0
|
||||||
|
pre_code = code.substring(0,index)
|
||||||
|
highlight = code.substring(index,index + filter.length)
|
||||||
|
post_code = code.substring(index + filter.length)
|
||||||
|
new Ember.Handlebars.SafeString("#{pre_code}<span class='highlight'>#{highlight}</span>#{post_code}")
|
||||||
|
else
|
||||||
|
code
|
||||||
|
).property('code_filter')
|
||||||
actions:
|
actions:
|
||||||
makeEditable: -> @set('editMode', true)
|
makeEditable: -> @set('editMode', true)
|
||||||
save: ->
|
save: ->
|
||||||
@get('product').save() if @get('product.isDirty')
|
if @get('product.isDirty')
|
||||||
|
@get('product').save().then((-> true), (-> true))
|
||||||
@set 'editMode', false
|
@set 'editMode', false
|
||||||
destroyProduct: (product)->
|
destroyProduct: (product)->
|
||||||
if product.get('isNew')
|
if product.get('isNew')
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
App.MenuController = Ember.ObjectController.extend
|
App.MenuController = Ember.ObjectController.extend
|
||||||
needs: ['application']
|
needs: ['application']
|
||||||
|
product_code_filter: ''
|
||||||
product_categories: (-> @store.all('product_category')).property()
|
product_categories: (-> @store.all('product_category')).property()
|
||||||
sorted_product_categories: (-> @get('product_categories').sortBy('position')).property('product_categories.@each', 'product_categories.@each.position')
|
sorted_product_categories: (-> @get('product_categories').sortBy('position')).property('product_categories.@each', 'product_categories.@each.position')
|
||||||
|
product_code_filter_placeholder: t('product.code_filter.placeholder')
|
||||||
actions:
|
actions:
|
||||||
editProductCategory: (product_category)->
|
editProductCategory: (product_category)->
|
||||||
@modal 'product_category_edit',
|
@modal 'product_category_edit',
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
Ember.Handlebars.helper 'errors', (errors, params..., options)->
|
||||||
|
return "" unless errors and errors.length
|
||||||
|
result = ""
|
||||||
|
model_name = options.hash.includeAttribute
|
||||||
|
for error in errors
|
||||||
|
if model_name
|
||||||
|
attribute = ttry("attributes.#{model_name}.#{error.attribute}")
|
||||||
|
message = "#{attribute} #{error.message}"
|
||||||
|
else
|
||||||
|
message = error.message
|
||||||
|
result += "<div class='error'>#{message}</div>"
|
||||||
|
new Ember.Handlebars.SafeString(result)
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
App.ApplicationSerializer = DS.ActiveModelSerializer
|
App.ApplicationSerializer = DS.ActiveModelSerializer
|
||||||
|
|
||||||
App.ApplicationStore = DS.Store.extend
|
App.ApplicationStore = DS.Store.extend
|
||||||
adapter: DS.RESTAdapter.extend
|
adapter: DS.ActiveModelAdapter.extend
|
||||||
namespace: 'supplier'
|
namespace: 'supplier'
|
||||||
# user underscored paths
|
## user underscored paths
|
||||||
pathForType: (type)->
|
#pathForType: (type)->
|
||||||
Ember.String.pluralize(Ember.String.decamelize(type))
|
#Ember.String.pluralize(Ember.String.decamelize(type))
|
||||||
|
|||||||
@@ -1,13 +1,22 @@
|
|||||||
.row.menu-product-container
|
.row.menu-product-container
|
||||||
if editMode
|
if editMode
|
||||||
.small-3.columns= input value=product.name
|
.small-3.columns
|
||||||
.small-3.columns= edit-currency value=product.price validatePresence=true
|
= input value=product.name
|
||||||
|
= errors product.errors.name
|
||||||
|
.small-3.columns
|
||||||
|
= edit-currency value=product.price validatePresence=true
|
||||||
|
= errors product.errors.price
|
||||||
.small-3.columns= input value=product.code
|
.small-3.columns= input value=product.code
|
||||||
.small-3.columns
|
.small-3.columns
|
||||||
a.destroy-product-action{action "destroyProduct" product}: span
|
a.destroy-product-action{action "destroyProduct" product}: span
|
||||||
a.save-product-action{action "save"}: span
|
a.save-product-action{action "save"}: span
|
||||||
else
|
else
|
||||||
.small-3.columns: span= product.name
|
if showProduct
|
||||||
.small-3.columns= currency product.price
|
.small-3.columns
|
||||||
.small-3.columns: span= product.code_or_empty
|
span= product.name
|
||||||
|
= errors product.errors.name includeAttribute="product"
|
||||||
|
.small-3.columns
|
||||||
|
= currency product.price
|
||||||
|
= errors product.errors.price includeAttribute="product"
|
||||||
|
.small-3.columns: span= code_filter_display
|
||||||
.small-3.columns: span.fa.fa-edit{action "makeEditable"}
|
.small-3.columns: span.fa.fa-edit{action "makeEditable"}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
.products-menu-filters-container
|
||||||
|
= input value=product_code_filter type="search" placeholder=product_code_filter_placeholder
|
||||||
h2 Menu
|
h2 Menu
|
||||||
each product_category in sorted_product_categories
|
each product_category in sorted_product_categories
|
||||||
.row.product_category-container: .small-12.columns
|
.row.product_category-container: .small-12.columns
|
||||||
@@ -8,7 +10,7 @@ each product_category in sorted_product_categories
|
|||||||
a.edit-product-category-button{action "editProductCategory" product_category} href="#"
|
a.edit-product-category-button{action "editProductCategory" product_category} href="#"
|
||||||
a.add-product-product-category-button{action "addProduct" product_category} href="#": span
|
a.add-product-product-category-button{action "addProduct" product_category} href="#": span
|
||||||
each product in product_category.sorted_products
|
each product in product_category.sorted_products
|
||||||
= menu-product product=product
|
= menu-product product=product code_filter=product_code_filter
|
||||||
.row
|
.row
|
||||||
.small-12.columns
|
.small-12.columns
|
||||||
a.button{action "newProductCategory"} href="#" = t 'product_category.new_button'
|
a.button{action "newProductCategory"} href="#" = t 'product_category.new_button'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
.form-label.half=t 'attributes.product_category.name'
|
.form-label.half=t 'attributes.product_category.name'
|
||||||
.form-field.half= input valueBinding="model.name"
|
.form-field.half= input valueBinding="model.name"
|
||||||
.row
|
.row
|
||||||
.small-6.columns
|
.small-12.medium-6.columns
|
||||||
unless model.supplier.week_starts_on_monday
|
unless model.supplier.week_starts_on_monday
|
||||||
.form-row
|
.form-row
|
||||||
.form-label.half= t 'date.day_name.sunday'
|
.form-label.half= t 'date.day_name.sunday'
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
.form-row
|
.form-row
|
||||||
.form-label.half= t 'date.day_name.sunday'
|
.form-label.half= t 'date.day_name.sunday'
|
||||||
.form-field.half= view "boolean-switch" valueBinding=model.active_on_sunday
|
.form-field.half= view "boolean-switch" valueBinding=model.active_on_sunday
|
||||||
.small-6.columns
|
.small-12.medium-6.columns
|
||||||
.row
|
.row
|
||||||
.small-12.columns.text-center= view 'boolean-button' value=model.full_day reverse=true text_path="product_category.modal.active_between.top"
|
.small-12.columns.text-center= view 'boolean-button' value=model.full_day reverse=true text_path="product_category.modal.active_between.top"
|
||||||
unless model.full_day
|
unless model.full_day
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ each product_category in product_categories
|
|||||||
a{action "moveBelow" product_category} href="#"
|
a{action "moveBelow" product_category} href="#"
|
||||||
span.title= product_category.name
|
span.title= product_category.name
|
||||||
span.availability= product_category.availability_text
|
span.availability= product_category.availability_text
|
||||||
hr
|
if model.products
|
||||||
h4=t 'product_category.modal.move.products.title'
|
hr
|
||||||
hr
|
h4=t 'product_category.modal.move.products.title'
|
||||||
ul.sortable
|
hr
|
||||||
|
ul.sortable
|
||||||
each product in model.sorted_products
|
each product in model.sorted_products
|
||||||
li.sortable-item-container data-sortable-id=product.id
|
li.sortable-item-container data-sortable-id=product.id
|
||||||
span.handle
|
span.handle
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
//= require_self
|
//= require_self
|
||||||
|
|
||||||
var Qstorage = localStorage;
|
var Qstorage = localStorage;
|
||||||
|
|
||||||
$.extend($translations.en, <%= I18n.t('supplier', locale: :en).to_json %>);
|
$.extend($translations.en, <%= I18n.t('supplier', locale: :en).to_json %>);
|
||||||
$.extend($translations.nl, <%= I18n.t('supplier', locale: :nl).to_json %>);
|
$.extend($translations.nl, <%= I18n.t('supplier', locale: :nl).to_json %>);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
jQuery ->
|
#jQuery ->
|
||||||
$('#product-category-list').sortable
|
#$('#product-category-list').sortable
|
||||||
axis: 'y'
|
#axis: 'y'
|
||||||
handle: '.handle'
|
#handle: '.handle'
|
||||||
update: ->
|
#update: ->
|
||||||
$.post($(this).data('update-url'), $(this).sortable('serialize'))
|
#$.post($(this).data('update-url'), $(this).sortable('serialize'))
|
||||||
|
|||||||
@@ -32,9 +32,10 @@
|
|||||||
#translatable = undefined
|
#translatable = undefined
|
||||||
#isafety = undefined
|
#isafety = undefined
|
||||||
#replacable = undefined
|
#replacable = undefined
|
||||||
|
locale = Qstorage.getItem('locale') || 'en'
|
||||||
parts = path.split(".")
|
parts = path.split(".")
|
||||||
#accessor = "$translations.#{$locale}[\"#{parts.join("\"][\"")}\"]"
|
#accessor = "$translations.#{$locale}[\"#{parts.join("\"][\"")}\"]"
|
||||||
result = $translations[$locale]
|
result = $translations[locale]
|
||||||
try
|
try
|
||||||
result = result[part] for part in parts
|
result = result[part] for part in parts
|
||||||
catch err
|
catch err
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
.modal
|
.modal
|
||||||
margin: 10px auto
|
margin: 10px auto
|
||||||
width: 600px
|
width: 600px
|
||||||
|
max-width: 100%
|
||||||
background-color: #fff
|
background-color: #fff
|
||||||
padding: 1em
|
padding: 1em
|
||||||
max-height: calc(100% - 20px)
|
max-height: calc(100% - 20px)
|
||||||
overflow-y: scroll
|
overflow-y: scroll
|
||||||
|
z-index: 6524
|
||||||
.modal-close
|
.modal-close
|
||||||
+button($bg: #ddd)
|
+button($bg: #ddd)
|
||||||
.modal-confirm
|
.modal-confirm
|
||||||
@@ -29,6 +31,7 @@
|
|||||||
top: 0
|
top: 0
|
||||||
left: 0
|
left: 0
|
||||||
background-color: rgba(0, 0, 0, 0.5)
|
background-color: rgba(0, 0, 0, 0.5)
|
||||||
|
z-index: 6522
|
||||||
|
|
||||||
.flush--top
|
.flush--top
|
||||||
margin-top: 0
|
margin-top: 0
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
//DEPRICATED
|
//DEPRICATED
|
||||||
.row.product_category-container
|
.row.product_category-container
|
||||||
margin-bottom: 15px
|
margin-bottom: 15px
|
||||||
|
|
||||||
|
.products-menu-filters-container
|
||||||
|
float: right
|
||||||
|
width: 200px
|
||||||
|
|
||||||
.product_category-header
|
.product_category-header
|
||||||
border-top: 1px solid #ccc
|
border-top: 1px solid #ccc
|
||||||
border-bottom: 1px solid #ccc
|
border-bottom: 1px solid #ccc
|
||||||
@@ -40,6 +45,9 @@
|
|||||||
color: rgb(39, 6, 121)
|
color: rgb(39, 6, 121)
|
||||||
|
|
||||||
.menu-product-container
|
.menu-product-container
|
||||||
|
.highlight
|
||||||
|
text-decoration: underline
|
||||||
|
font-weight: bold
|
||||||
.destroy-product-action
|
.destroy-product-action
|
||||||
color: $alert-color
|
color: $alert-color
|
||||||
margin-right: 12px
|
margin-right: 12px
|
||||||
@@ -47,6 +55,10 @@
|
|||||||
@extend .fa
|
@extend .fa
|
||||||
@extend .fa-lg
|
@extend .fa-lg
|
||||||
@extend .fa-trash
|
@extend .fa-trash
|
||||||
|
.error
|
||||||
|
color: $alert-color
|
||||||
|
input
|
||||||
|
margin-bottom: 0
|
||||||
.save-product-action
|
.save-product-action
|
||||||
color: $success-color
|
color: $success-color
|
||||||
span
|
span
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ module Suppliers
|
|||||||
format.json { render json: @product, status: :created }
|
format.json { render json: @product, status: :created }
|
||||||
else
|
else
|
||||||
format.html { render action: "new" }
|
format.html { render action: "new" }
|
||||||
format.json { render json: @product.errors, status: :unprocessable_entity }
|
format.json { render json: {errors: @product.errors}, status: :unprocessable_entity }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -68,7 +68,7 @@ module Suppliers
|
|||||||
format.json { render json: @product }
|
format.json { render json: @product }
|
||||||
else
|
else
|
||||||
format.html { render action: "edit" }
|
format.html { render action: "edit" }
|
||||||
format.json { render json: @product.errors, status: :unprocessable_entity }
|
format.json { render json: {errors: @product.errors}, status: :unprocessable_entity }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
module ProductDecorator
|
module ProductDecorator
|
||||||
|
|
||||||
def category_links(options = {})
|
def category_links(options = {})
|
||||||
|
product_categories = [product_category].compact # changed from habtm to belongs_to
|
||||||
if namespace = options[:namespace]
|
if namespace = options[:namespace]
|
||||||
product_categories.map{|pc| link_to pc.name, [namespace, pc]}.join(', ').html_safe
|
product_categories.map{|pc| link_to pc.name, [namespace, pc]}.join(', ').html_safe
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class Product
|
|||||||
|
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
validates :supplier_id, presence: true
|
validates :supplier_id, presence: true
|
||||||
validates :price, presence: true, numericality: true
|
validates :price, numericality: {greater_than: 0}
|
||||||
view :by_supplier_id_and_id, key: [:supplier_id, :_id]
|
view :by_supplier_id_and_id, key: [:supplier_id, :_id]
|
||||||
|
|
||||||
#after_save :persist_product_category_ids
|
#after_save :persist_product_category_ids
|
||||||
|
|||||||
@@ -163,6 +163,8 @@ en:
|
|||||||
product:
|
product:
|
||||||
new: 'New ${model.product|downcase}'
|
new: 'New ${model.product|downcase}'
|
||||||
destroy_confirmation: Are you sure you want to delete ${models.product|downcase} %{name}
|
destroy_confirmation: Are you sure you want to delete ${models.product|downcase} %{name}
|
||||||
|
code_filter:
|
||||||
|
placeholder: Filter ${models.product|downcase} ${attributes.product.code|downcase}
|
||||||
preview:
|
preview:
|
||||||
header: 'Select moment to preview products'
|
header: 'Select moment to preview products'
|
||||||
description: 'Products visible to customers at chosen moment:'
|
description: 'Products visible to customers at chosen moment:'
|
||||||
|
|||||||
@@ -166,6 +166,8 @@ nl:
|
|||||||
product:
|
product:
|
||||||
new: 'Nieuw ${model.product|downcase}'
|
new: 'Nieuw ${model.product|downcase}'
|
||||||
destroy_confirmation: Weet je zeker dat je ${models.product|downcase} %{name} wilt verwijderen
|
destroy_confirmation: Weet je zeker dat je ${models.product|downcase} %{name} wilt verwijderen
|
||||||
|
code_filter:
|
||||||
|
placeholder: Filter ${models.product|downcase} ${attributes.product.code|downcase}
|
||||||
preview:
|
preview:
|
||||||
header: 'Selecteer tijdstip voor voorbeeld'
|
header: 'Selecteer tijdstip voor voorbeeld'
|
||||||
description: 'Producten op gekozen tijdstip:'
|
description: 'Producten op gekozen tijdstip:'
|
||||||
|
|||||||
Reference in New Issue
Block a user