many changes
This commit is contained in:
@@ -33,6 +33,8 @@ gem 'couch_potato' , :git => 'git://github.com/bterkuile/couch_potato.git'
|
||||
gem 'simply_stored' , :git => 'git://github.com/bterkuile/simply_stored.git'
|
||||
gem 'devise', '2.0.4'
|
||||
gem 'devise_simply_stored'
|
||||
gem 'simple_form'
|
||||
gem 'draper'
|
||||
|
||||
gem 'rqrcode'
|
||||
gem 'mini_magick'
|
||||
@@ -48,12 +50,16 @@ group :development do
|
||||
gem 'pry'
|
||||
gem 'pry-remote'
|
||||
gem 'rspec-rails'
|
||||
gem 'rb-fsevent', :require => false if RUBY_PLATFORM =~ /darwin/i
|
||||
gem 'guard-rspec'
|
||||
gem 'thin'
|
||||
end
|
||||
|
||||
group :test do
|
||||
gem 'steak'
|
||||
gem 'pry'
|
||||
gem 'steak'
|
||||
gem 'rb-fsevent', :require => false if RUBY_PLATFORM =~ /darwin/i
|
||||
gem 'guard-rspec'
|
||||
gem 'factory_girl_rails'
|
||||
end
|
||||
|
||||
|
||||
+30
-5
@@ -9,7 +9,7 @@ GIT
|
||||
|
||||
GIT
|
||||
remote: git://github.com/bterkuile/simply_stored.git
|
||||
revision: 955a484c4046b3343f07fd0d783342d01bf26f66
|
||||
revision: 04f58b15bb308420f78c66d27ce4d4d3b58183ff
|
||||
specs:
|
||||
simply_stored (1.0.0)
|
||||
activesupport
|
||||
@@ -88,6 +88,9 @@ GEM
|
||||
devise_simply_stored (0.0.3)
|
||||
devise
|
||||
diff-lcs (1.1.3)
|
||||
draper (0.18.0)
|
||||
actionpack (~> 3.2)
|
||||
activesupport (~> 3.2)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.0.0)
|
||||
execjs (1.4.0)
|
||||
@@ -99,6 +102,14 @@ GEM
|
||||
railties (>= 3.0.0)
|
||||
ffi (1.2.0)
|
||||
fssm (0.2.9)
|
||||
guard (1.5.4)
|
||||
listen (>= 0.4.2)
|
||||
lumberjack (>= 1.0.2)
|
||||
pry (>= 0.9.10)
|
||||
thor (>= 0.14.6)
|
||||
guard-rspec (2.3.0)
|
||||
guard (>= 1.1)
|
||||
rspec (~> 2.11)
|
||||
haml (3.1.7)
|
||||
haml-rails (0.3.5)
|
||||
actionpack (>= 3.1, < 4.1)
|
||||
@@ -127,6 +138,8 @@ GEM
|
||||
libwebsocket (0.1.7.1)
|
||||
addressable
|
||||
websocket
|
||||
listen (0.6.0)
|
||||
lumberjack (1.0.2)
|
||||
mail (2.4.4)
|
||||
i18n (>= 0.4.0)
|
||||
mime-types (~> 1.16)
|
||||
@@ -135,7 +148,7 @@ GEM
|
||||
mime-types (1.19)
|
||||
mini_magick (3.4)
|
||||
subexec (~> 0.2.1)
|
||||
multi_json (1.3.7)
|
||||
multi_json (1.4.0)
|
||||
mustache (0.99.4)
|
||||
nokogiri (1.5.5)
|
||||
orm_adapter (0.0.7)
|
||||
@@ -172,12 +185,17 @@ GEM
|
||||
rdoc (~> 3.4)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
rake (10.0.2)
|
||||
rb-fsevent (0.9.2)
|
||||
rdoc (3.12)
|
||||
json (~> 1.4)
|
||||
rest-client (1.6.7)
|
||||
mime-types (>= 1.16)
|
||||
rqrcode (0.4.2)
|
||||
rspec-core (2.12.0)
|
||||
rspec (2.12.0)
|
||||
rspec-core (~> 2.12.0)
|
||||
rspec-expectations (~> 2.12.0)
|
||||
rspec-mocks (~> 2.12.0)
|
||||
rspec-core (2.12.1)
|
||||
rspec-expectations (2.12.0)
|
||||
diff-lcs (~> 1.1.3)
|
||||
rspec-mocks (2.12.0)
|
||||
@@ -199,6 +217,9 @@ GEM
|
||||
libwebsocket (~> 0.1.3)
|
||||
multi_json (~> 1.0)
|
||||
rubyzip
|
||||
simple_form (2.0.4)
|
||||
actionpack (~> 3.0)
|
||||
activemodel (~> 3.0)
|
||||
slim (1.3.4)
|
||||
temple (~> 0.5.5)
|
||||
tilt (~> 1.3.3)
|
||||
@@ -208,7 +229,7 @@ GEM
|
||||
railties (~> 3.0)
|
||||
slim (~> 1.0)
|
||||
slop (3.3.3)
|
||||
sprockets (2.2.1)
|
||||
sprockets (2.2.2)
|
||||
hike (~> 1.2)
|
||||
multi_json (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
@@ -229,7 +250,7 @@ GEM
|
||||
treetop (1.4.12)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
twitter-bootstrap-rails (2.1.6)
|
||||
twitter-bootstrap-rails (2.1.7)
|
||||
actionpack (>= 3.1)
|
||||
execjs
|
||||
railties (>= 3.1)
|
||||
@@ -252,7 +273,9 @@ DEPENDENCIES
|
||||
couch_potato!
|
||||
devise (= 2.0.4)
|
||||
devise_simply_stored
|
||||
draper
|
||||
factory_girl_rails
|
||||
guard-rspec
|
||||
haml-rails
|
||||
jquery-rails
|
||||
kaminari-bootstrap
|
||||
@@ -263,9 +286,11 @@ DEPENDENCIES
|
||||
pry-remote
|
||||
rack-cors
|
||||
rails (= 3.2.9)
|
||||
rb-fsevent
|
||||
rqrcode
|
||||
rspec-rails
|
||||
sass-rails (~> 3.2.3)
|
||||
simple_form
|
||||
simply_stored!
|
||||
slim-rails
|
||||
steak
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# A sample Guardfile
|
||||
# More info at https://github.com/guard/guard#readme
|
||||
|
||||
guard 'rspec' do
|
||||
watch(%r{^spec/.+_spec\.rb$})
|
||||
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
||||
watch('spec/spec_helper.rb') { "spec" }
|
||||
|
||||
# Rails example
|
||||
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
||||
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
||||
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
||||
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
||||
watch('config/routes.rb') { "spec/routing" }
|
||||
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
||||
|
||||
# Capybara features specs
|
||||
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
||||
|
||||
# Turnip features and steps
|
||||
watch(%r{^spec/acceptance/(.+)\.feature$})
|
||||
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
||||
end
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
//
|
||||
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
||||
// GO AFTER THE REQUIRES BELOW.
|
||||
//
|
||||
//= require jquery
|
||||
//= require jquery_ujs
|
||||
//= require jquery-ui
|
||||
//= require twitter/bootstrap
|
||||
//= require mustache
|
||||
//= require faye
|
||||
//= require supplier/base
|
||||
//= require_directory .
|
||||
//= require_self
|
||||
var path_mapping = {
|
||||
@@ -33,8 +33,5 @@ function redirect_to(mapping, variables){
|
||||
window.location = path_mapping[mapping] + '?' + vars.join('&')
|
||||
}
|
||||
function currency(num) {
|
||||
if (isNaN(num) || num === '' || num === null) {
|
||||
num = 0.0;
|
||||
}
|
||||
return '€ ' + parseFloat(num).toFixed(2);
|
||||
return Qwaiter.currency(num);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
jQuery ->
|
||||
$('#product-category-list').sortable
|
||||
axis: 'y'
|
||||
handle: '.handle'
|
||||
update: ->
|
||||
$.post($(this).data('update-url'), $(this).sortable('serialize'))
|
||||
@@ -283,29 +283,23 @@ class Quser
|
||||
@populate_products_table('/user/list_products_for_table.json?'+authentication_string+'&table_id='+table_id)
|
||||
populate_products_table: (src)->
|
||||
$.getJSON(data_host + src, (res) =>
|
||||
if res.has_occupied_info
|
||||
include_order_buttons = !res.is_occupied
|
||||
delete(res['has_occupied_info'])
|
||||
delete(res['is_occupied'])
|
||||
else
|
||||
include_order_buttons = true
|
||||
body = $('#products-table tbody')
|
||||
if res.table_number
|
||||
$('.table-number').text(res.table_number)
|
||||
delete(res['table_number'])
|
||||
if res.supplier_name
|
||||
$('.supplier-name').text(res.supplier_name)
|
||||
delete(res['supplier_name'])
|
||||
include_order_buttons = res.my_list
|
||||
|
||||
$('.table-number').text(res.table_number) if res.table_number
|
||||
$('.supplier-name').text(res.supplier_name) if res.supplier_name
|
||||
|
||||
window.products = {}
|
||||
body = $('#products-table tbody')
|
||||
body.find('tr').remove()
|
||||
script_id = if include_order_buttons then '#products-category-for-order-template' else '#products-category-template'
|
||||
for category, products of res
|
||||
#for category, products of res
|
||||
for category in res.categories
|
||||
body.append @mustache(script_id,
|
||||
category: category,
|
||||
products: products,
|
||||
category: category.name,
|
||||
products: category.products,
|
||||
include_order_buttons: include_order_buttons
|
||||
)
|
||||
for product in products
|
||||
for product in category.products
|
||||
window.products[product._id] = product
|
||||
)
|
||||
increment_products_counter: (product_id)->
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#product-category-list
|
||||
list-style: none
|
||||
li
|
||||
clear: both
|
||||
margin-bottom: 8px
|
||||
.name
|
||||
padding: 5px 5px
|
||||
@@ -26,3 +26,7 @@ body
|
||||
border: 1px solid black
|
||||
padding: 2px
|
||||
display: inline-block
|
||||
.handle
|
||||
cursor: move
|
||||
font-size: 0.8em
|
||||
color: #777
|
||||
|
||||
@@ -19,7 +19,7 @@ class DashboardController < ApplicationController
|
||||
|
||||
# Testing action
|
||||
def select_qrcode
|
||||
@tables = Table.all.sample(2)
|
||||
@tables = Table.all.sample(2) | List.active.map(&:table)
|
||||
render layout: 'phone'
|
||||
end
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ module Suppliers
|
||||
# GET /product_categories
|
||||
# GET /product_categories.json
|
||||
def index
|
||||
@product_categories = current_supplier.product_categories
|
||||
@product_categories = current_supplier.product_categories.sort_by(&:position)
|
||||
|
||||
respond_to do |format|
|
||||
format.html # index.html.erb
|
||||
@@ -83,5 +83,14 @@ module Suppliers
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
# POST /supplier/product_categories/sort
|
||||
# params ~= product_category: ['abc', 'def', 'another id', ...]
|
||||
def sort
|
||||
@product_categories = ProductCategory.find(params[:product_category])
|
||||
1.upto(@product_categories.size){|i| @product_categories[i-1].position = i}
|
||||
CouchPotato.database.couchrest_database.bulk_save(@product_categories)
|
||||
render nothing: true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ module Suppliers
|
||||
# GET /products
|
||||
# GET /products.json
|
||||
def index
|
||||
@products = current_supplier.products
|
||||
@products = ProductDecorator.decorate(current_supplier.products)
|
||||
|
||||
respond_to do |format|
|
||||
format.html # index.html.erb
|
||||
@@ -15,7 +15,7 @@ module Suppliers
|
||||
# GET /products/1
|
||||
# GET /products/1.json
|
||||
def show
|
||||
@product = Product.find(params[:id])
|
||||
@product = ProductDecorator.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
format.html # show.html.erb
|
||||
@@ -27,7 +27,6 @@ module Suppliers
|
||||
# GET /products/new.json
|
||||
def new
|
||||
@product = Product.new
|
||||
@product.product_category_id = params[:product_category_id].presence
|
||||
|
||||
respond_to do |format|
|
||||
format.html # new.html.erb
|
||||
|
||||
@@ -85,11 +85,17 @@ class UserController < ApplicationController
|
||||
handle_message_params
|
||||
end
|
||||
format.json do
|
||||
products = list.supplier.products
|
||||
products.include_relation(:product_categories)
|
||||
products.sort_by!{|p| p.product_category.try(:position) || 90000}
|
||||
h = products.inject({table_number: list.table_number, supplier_name: @supplier.name}){|h, p| n = p.product_category.try(:name) || 'other'; h[n] ||= []; h[n] << p; h}
|
||||
h = ProductCategory.for_user(current_user, table: list.table, list: list) # list is performance parameter
|
||||
render json: h
|
||||
#products = list.supplier.products
|
||||
#product_categories = list.supplier.product_categories
|
||||
#other = product_categories.find(&:other?) || (product_categories << ProductCategory.other).last # Container for non categorized products
|
||||
|
||||
#product_categories.sort_by!{|p| p.product_category.try(:position) || 90000}
|
||||
#h = {table_number: list.table_number, supplier_name: @supplier.name}
|
||||
#h[:categories] = product_categories.map{|pc| {pc.name => pc.product_ids.map{|p| p.as_json}}}
|
||||
#){|h, p| n = p.product_category.try(:name) || 'other'; h[n] ||= []; h[n] << p; h}
|
||||
#render json: h
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -100,15 +106,7 @@ class UserController < ApplicationController
|
||||
format.html do
|
||||
end
|
||||
format.json do
|
||||
products = @table.supplier.products
|
||||
products.include_relation(:product_categories)
|
||||
products.sort_by!{|p| p.product_category.try(:position) || 90000}
|
||||
h = products.inject({
|
||||
table_number: @table.number,
|
||||
supplier_name: @table.supplier.name,
|
||||
has_occupied_info: true,
|
||||
is_occupied: @table.occupied?
|
||||
}){|h, p| n = p.product_category.try(:name) || 'other'; h[n] ||= []; h[n] << p; h}
|
||||
h = ProductCategory.for_user(current_user, table: @table)
|
||||
render json: h
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
class ProductDecorator < Draper::Base
|
||||
decorates :product
|
||||
|
||||
def category_links(options = {})
|
||||
if namespace = options[:namespace]
|
||||
product_categories.map{|pc| h.link_to pc.name, [namespace, pc]}.join(', ').html_safe
|
||||
else
|
||||
product_categories.map{|pc| h.link_to pc.name, pc}.join(', ').html_safe
|
||||
end
|
||||
end
|
||||
|
||||
# Accessing Helpers
|
||||
# You can access any helper via a proxy
|
||||
#
|
||||
# Normal Usage: helpers.number_to_currency(2)
|
||||
# Abbreviated : h.number_to_currency(2)
|
||||
#
|
||||
# Or, optionally enable "lazy helpers" by including this module:
|
||||
# include Draper::LazyHelpers
|
||||
# Then use the helpers with no proxy:
|
||||
# number_to_currency(2)
|
||||
|
||||
# Defining an Interface
|
||||
# Control access to the wrapped subject's methods using one of the following:
|
||||
#
|
||||
# To allow only the listed methods (whitelist):
|
||||
# allows :method1, :method2
|
||||
#
|
||||
# To allow everything except the listed methods (blacklist):
|
||||
# denies :method1, :method2
|
||||
|
||||
# Presentation Methods
|
||||
# Define your own instance methods, even overriding accessors
|
||||
# generated by ActiveRecord:
|
||||
#
|
||||
# def created_at
|
||||
# h.content_tag :span, attributes["created_at"].strftime("%a %m/%d/%y"),
|
||||
# :class => 'timestamp'
|
||||
# end
|
||||
end
|
||||
+7
-1
@@ -8,6 +8,8 @@ class List
|
||||
property :closed_at, type: Time
|
||||
property :join_requests, type: Array, default: []
|
||||
property :price, type: Float
|
||||
property :is_payed, type: :boolean, default: false
|
||||
property :payed_at, type: Time
|
||||
|
||||
has_many :orders, dependent: :destroy
|
||||
belongs_to :table
|
||||
@@ -90,6 +92,11 @@ class List
|
||||
database.view(for_supplier_view({startkey: [supplier.id, range.last], endkey: [supplier.id, range.first], include_docs: true, reduce: false, descending: true}.merge(options)))
|
||||
end
|
||||
|
||||
def mark_as_payed
|
||||
self.is_payed = true
|
||||
self.payed_at = Time.now
|
||||
end
|
||||
|
||||
def close!
|
||||
orders.include_relation(:product_orders)
|
||||
set_price
|
||||
@@ -155,7 +162,6 @@ class List
|
||||
add_user(user)
|
||||
user.save
|
||||
self.is_dirty
|
||||
binding.pry
|
||||
if save
|
||||
broadcast_user user.id, 'join_request_approved'
|
||||
end
|
||||
|
||||
+17
-1
@@ -5,10 +5,26 @@ class Product
|
||||
property :code
|
||||
property :price, type: Float
|
||||
|
||||
belongs_to :product_category
|
||||
#belongs_to :product_category
|
||||
has_and_belongs_to_many :product_categories, storing_keys: false
|
||||
belongs_to :supplier # direct! category is an aid
|
||||
has_many :product_orders
|
||||
|
||||
validates :supplier_id, presence: true
|
||||
after_save :persist_product_category_ids
|
||||
|
||||
def product_category_ids=(ids)
|
||||
@product_category_ids = ids.select(&:present?)
|
||||
end
|
||||
|
||||
private
|
||||
def persist_product_category_ids
|
||||
return unless @product_category_ids.present?
|
||||
database.load(@product_category_ids).each do |product_category|
|
||||
product_category.product_ids ||= []
|
||||
product_category.product_ids |= [id]
|
||||
product_category.save
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -5,10 +5,41 @@ class ProductCategory
|
||||
property :position, type: Fixnum, default: 0
|
||||
|
||||
belongs_to :supplier
|
||||
has_many :products
|
||||
has_and_belongs_to_many :products, storing_keys: true
|
||||
|
||||
attr_protected :supplier_id
|
||||
|
||||
validates :position, numericality: true
|
||||
validates :supplier_id, presence: true
|
||||
|
||||
def self.for_user(user, options = {})
|
||||
table = options[:table]
|
||||
raise "ProductCategory.for_user requires a table" unless table.present?
|
||||
list = options[:list] || table.active_list
|
||||
|
||||
# Get supplier objects
|
||||
products = table.supplier.products
|
||||
product_categories = table.supplier.product_categories || []
|
||||
|
||||
# sort categories
|
||||
product_categories.sort_by!{|pc| (pc.position || 90000).to_i }
|
||||
|
||||
# Append other category if not defined by supplier
|
||||
other = product_categories.find(&:other?) || (product_categories << self.other).last # Container for non categorized products
|
||||
|
||||
# Initialize base return object
|
||||
h = {table_number: table.number, supplier_name: table.supplier.name, my_list: list.try(:user_ids).to_a.include?(user.id)}
|
||||
|
||||
(products - product_categories.map(&:products).flatten).each{ |p| other.add_product(p) }
|
||||
|
||||
h[:categories] = product_categories.map{|pc| {name: pc.name, products: pc.products.to_a.map{|p| p.as_json}}}.select{|pc| pc && pc[:products].present?}
|
||||
h
|
||||
end
|
||||
|
||||
def other?
|
||||
%w[other overig].include?(name.to_s.downcase)
|
||||
end
|
||||
def self.other(options = {})
|
||||
new(options.reverse_merge(name: I18n.t('user.product_category.other_name')))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -50,6 +50,7 @@ html lang="en"
|
||||
//li= link_to t('supplier.menu.active_orders', orders: Order.model_name.human_plural), supplier_active_orders_path
|
||||
//li= link_to t('supplier.menu.active_lists', lists: List.model_name.human_plural), supplier_active_lists_path
|
||||
li= link_to ProductCategory.model_name.human_plural, suppliers_product_categories_path
|
||||
li= link_to ProductCategory.model_name.human_plural, suppliers_product_categories_path
|
||||
li= link_to Product.model_name.human_plural, suppliers_products_path
|
||||
li= link_to Section.model_name.human_plural, suppliers_sections_path
|
||||
li= link_to Table.model_name.human_plural, suppliers_tables_path
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
= f.label :price, class: 'control-label'
|
||||
.controls
|
||||
= f.text_field :price, class: 'text_field'
|
||||
.control-group class=(@product.errors[:product_category_id].any? ? 'error' : nil)
|
||||
/.control-group class=(@product.errors[:product_category_id].any? ? 'error' : nil)
|
||||
= f.label :product_category_id, ProductCategory.model_name.human, class: 'control-label'
|
||||
.controls
|
||||
= f.collection_select :product_category_id, @product_categories, :id, :name, include_blank: ''
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
= form_for [:suppliers, @product_category], html: {class: 'form-horizontal' } do |f|
|
||||
= simple_form_for [:suppliers, @product_category], html: {class: 'form-horizontal'} do |f|
|
||||
= render 'error_messages', target: @product_category
|
||||
.control-group class=(@product_category.errors[:name].any? ? 'error' : nil)
|
||||
= f.label :name, class: 'control-label'
|
||||
= f.input :name
|
||||
.control-group
|
||||
= hidden_field_tag 'product_category[product_ids][]', ''
|
||||
= label_tag nil, Product.model_name.human_plural, class: 'control-label'
|
||||
.controls
|
||||
= f.text_field :name, class: 'text_field'
|
||||
.control-group class=(@product_category.errors[:position].any? ? 'error' : nil)
|
||||
= f.label :position, class: 'control-label'
|
||||
.controls
|
||||
= f.text_field :position, class: 'text_field'
|
||||
- for product in current_supplier.products
|
||||
= check_box_tag "product_category[product_ids][]", product.id, @product_category.product_ids.to_a.include?(product.id), id: "product-checker-#{product.id}"
|
||||
= label_tag "product-checker-#{product.id}", product.name
|
||||
br
|
||||
.form-actions
|
||||
= f.submit nil, class: 'btn btn-primary'
|
||||
= f.button :submit, class: 'btn-primary'
|
||||
'
|
||||
= link_to t("helpers.links.cancel"), suppliers_product_categories_path, class: 'btn'
|
||||
|
||||
@@ -2,25 +2,16 @@
|
||||
.page-header= title :index, model_class
|
||||
.well
|
||||
- if @product_categories.any?
|
||||
table.table
|
||||
thead
|
||||
tr
|
||||
th= model_class.human_attribute_name(:name)
|
||||
th= model_class.human_attribute_name(:position)
|
||||
th.timestamp= model_class.human_attribute_name(:created_at)
|
||||
th.actions=t 'helpers.actions'
|
||||
tbody
|
||||
- @product_categories.each do |product_category|
|
||||
tr
|
||||
td.link= link_to product_category.name, [:suppliers, product_category]
|
||||
td= product_category.position
|
||||
td.timestamp=l product_category.created_at, format: :short
|
||||
td.actions
|
||||
= link_to t('helpers.links.edit'), [:edit, :suppliers, product_category], class: 'btn btn-mini'
|
||||
'
|
||||
= link_to t("helpers.links.destroy"), [:suppliers, product_category], method: :delete, data: {confirm: are_you_sure? }, class: 'btn btn-mini btn-danger'
|
||||
ul#product-category-list data-update-url=sort_suppliers_product_categories_path
|
||||
- for product_category in @product_categories
|
||||
= content_tag_for :li, product_category do
|
||||
span.handle [drag]
|
||||
span.name= link_to product_category.name, [:suppliers, product_category]
|
||||
.pull-right.actions
|
||||
= link_to t('helpers.links.edit'), [:edit, :suppliers, product_category], class: 'btn btn-mini'
|
||||
'
|
||||
= link_to t("helpers.links.destroy"), [:suppliers, product_category], method: :delete, data: {confirm: are_you_sure? }, class: 'btn btn-mini btn-danger'
|
||||
- else
|
||||
= no_content_given model_class
|
||||
.form-actions
|
||||
= link_to t("helpers.links.new"), new_suppliers_product_category_path, class: 'btn btn-primary'
|
||||
|
||||
|
||||
@@ -14,5 +14,5 @@ dl.dl-horizontal.show-list
|
||||
'
|
||||
= link_to t("helpers.links.destroy"), [:suppliers, @product_category], method: :delete, data: {confirm: are_you_sure? }, class: 'btn btn-danger'
|
||||
- content_for :row do
|
||||
- @products = @product_category.products
|
||||
- @products = ProductDecorator.decorate(@product_category.products)
|
||||
= render template: 'suppliers/products/index'
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
= form_for [:suppliers, @product], html: {class: 'form-horizontal' } do |f|
|
||||
= simple_form_for [:suppliers, @product], html: {class: 'form-horizontal'} do |f|
|
||||
= render 'error_messages', target: @product
|
||||
.control-group class=(@product.errors[:name].any? ? 'error' : nil)
|
||||
= f.label :name, class: 'control-label'
|
||||
= f.input :name
|
||||
= f.input :code
|
||||
= f.input :price
|
||||
.control-group
|
||||
= hidden_field_tag 'product[product_category_ids][]', []
|
||||
= label_tag nil, ProductCategory.model_name.human_plural, class: 'control-label'
|
||||
.controls
|
||||
= f.text_field :name, class: 'text_field'
|
||||
.control-group class=(@product.errors[:code].any? ? 'error' : nil)
|
||||
= f.label :code, class: 'control-label'
|
||||
.controls
|
||||
= f.text_field :code, class: 'text_field'
|
||||
.control-group class=(@product.errors[:price].any? ? 'error' : nil)
|
||||
= f.label :price, class: 'control-label'
|
||||
.controls
|
||||
= f.text_field :price, class: ['text_field', :currency]
|
||||
.control-group class=(@product.errors[:product_category_id].any? ? 'error' : nil)
|
||||
= f.label :product_category_id, ProductCategory.model_name.human, class: 'control-label'
|
||||
.controls
|
||||
= f.collection_select :product_category_id, current_supplier.product_categories, :id, :name, include_blank: ''
|
||||
- for product_category in current_supplier.product_categories
|
||||
= check_box_tag "product[product_category_ids][]", product_category.id, @product.product_categories.to_a.include?(product_category), id: "product-category-checker-#{product_category.id}"
|
||||
= label_tag "product-category-checker-#{product_category.id}", product_category.name
|
||||
br
|
||||
|
||||
.form-actions
|
||||
= f.submit nil, class: 'btn btn-primary'
|
||||
= f.button :submit, class: 'btn-primary'
|
||||
'
|
||||
= link_to t("helpers.links.cancel"), suppliers_products_path, class: 'btn'
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
th= model_class.human_attribute_name(:name)
|
||||
th= model_class.human_attribute_name(:code)
|
||||
th.currency= model_class.human_attribute_name(:price)
|
||||
th= ProductCategory.model_name.human
|
||||
th= ProductCategory.model_name.human_plural
|
||||
th.timestamp= model_class.human_attribute_name(:created_at)
|
||||
th.actions=t 'helpers.actions'
|
||||
tbody
|
||||
@@ -17,7 +17,7 @@
|
||||
td.link= link_to product.name, [:suppliers, product]
|
||||
td= product.code
|
||||
td.currency=currency product.price
|
||||
td.link= link_to_if product.product_category.present?, product.product_category.try(:name), [:suppliers, product.product_category]
|
||||
td.link= product.category_links namespace: :suppliers
|
||||
td.timestamp=l product.created_at, format: :short
|
||||
td.actions
|
||||
= link_to t('helpers.links.edit'), [:edit, :suppliers, product], class: 'btn btn-mini'
|
||||
|
||||
@@ -8,9 +8,8 @@ dl.dl-horizontal.show-list
|
||||
dd= @product.code
|
||||
dt= model_class.human_attribute_name(:price)
|
||||
dd=currency @product.price
|
||||
- if @product.product_category.present?
|
||||
dt= ProductCategory.model_name.human
|
||||
dd= link_to @product.product_category.name, @product.product_category
|
||||
dt= ProductCategory.model_name.human_plural
|
||||
dd= @product.category_links(namespace: :suppliers)
|
||||
|
||||
.form-actions
|
||||
= link_to t("helpers.links.back"), suppliers_products_path, class: 'btn'
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
# Use this setup block to configure all options available in SimpleForm.
|
||||
SimpleForm.setup do |config|
|
||||
# Wrappers are used by the form builder to generate a
|
||||
# complete input. You can remove any component from the
|
||||
# wrapper, change the order or even add your own to the
|
||||
# stack. The options given below are used to wrap the
|
||||
# whole input.
|
||||
config.wrappers :default, :class => :input,
|
||||
:hint_class => :field_with_hint, :error_class => :field_with_errors do |b|
|
||||
## Extensions enabled by default
|
||||
# Any of these extensions can be disabled for a
|
||||
# given input by passing: `f.input EXTENSION_NAME => false`.
|
||||
# You can make any of these extensions optional by
|
||||
# renaming `b.use` to `b.optional`.
|
||||
|
||||
# Determines whether to use HTML5 (:email, :url, ...)
|
||||
# and required attributes
|
||||
b.use :html5
|
||||
|
||||
# Calculates placeholders automatically from I18n
|
||||
# You can also pass a string as f.input :placeholder => "Placeholder"
|
||||
b.use :placeholder
|
||||
|
||||
## Optional extensions
|
||||
# They are disabled unless you pass `f.input EXTENSION_NAME => :lookup`
|
||||
# to the input. If so, they will retrieve the values from the model
|
||||
# if any exists. If you want to enable the lookup for any of those
|
||||
# extensions by default, you can change `b.optional` to `b.use`.
|
||||
|
||||
# Calculates maxlength from length validations for string inputs
|
||||
b.optional :maxlength
|
||||
|
||||
# Calculates pattern from format validations for string inputs
|
||||
b.optional :pattern
|
||||
|
||||
# Calculates min and max from length validations for numeric inputs
|
||||
b.optional :min_max
|
||||
|
||||
# Calculates readonly automatically from readonly attributes
|
||||
b.optional :readonly
|
||||
|
||||
## Inputs
|
||||
b.use :label_input
|
||||
b.use :hint, :wrap_with => { :tag => :span, :class => :hint }
|
||||
b.use :error, :wrap_with => { :tag => :span, :class => :error }
|
||||
end
|
||||
|
||||
# The default wrapper to be used by the FormBuilder.
|
||||
config.default_wrapper = :default
|
||||
|
||||
# Define the way to render check boxes / radio buttons with labels.
|
||||
# Defaults to :nested for bootstrap config.
|
||||
# :inline => input + label
|
||||
# :nested => label > input
|
||||
config.boolean_style = :nested
|
||||
|
||||
# Default class for buttons
|
||||
config.button_class = 'btn'
|
||||
|
||||
# Method used to tidy up errors. Specify any Rails Array method.
|
||||
# :first lists the first message for each field.
|
||||
# Use :to_sentence to list all errors for each field.
|
||||
# config.error_method = :first
|
||||
|
||||
# Default tag used for error notification helper.
|
||||
config.error_notification_tag = :div
|
||||
|
||||
# CSS class to add for error notification helper.
|
||||
config.error_notification_class = 'alert alert-error'
|
||||
|
||||
# ID to add for error notification helper.
|
||||
# config.error_notification_id = nil
|
||||
|
||||
# Series of attempts to detect a default label method for collection.
|
||||
# config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
|
||||
|
||||
# Series of attempts to detect a default value method for collection.
|
||||
# config.collection_value_methods = [ :id, :to_s ]
|
||||
|
||||
# You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
|
||||
# config.collection_wrapper_tag = nil
|
||||
|
||||
# You can define the class to use on all collection wrappers. Defaulting to none.
|
||||
# config.collection_wrapper_class = nil
|
||||
|
||||
# You can wrap each item in a collection of radio/check boxes with a tag,
|
||||
# defaulting to :span. Please note that when using :boolean_style = :nested,
|
||||
# SimpleForm will force this option to be a label.
|
||||
# config.item_wrapper_tag = :span
|
||||
|
||||
# You can define a class to use in all item wrappers. Defaulting to none.
|
||||
# config.item_wrapper_class = nil
|
||||
|
||||
# How the label text should be generated altogether with the required text.
|
||||
# config.label_text = lambda { |label, required| "#{required} #{label}" }
|
||||
|
||||
# You can define the class to use on all labels. Default is nil.
|
||||
config.label_class = 'control-label'
|
||||
|
||||
# You can define the class to use on all forms. Default is simple_form.
|
||||
# config.form_class = :simple_form
|
||||
|
||||
# You can define which elements should obtain additional classes
|
||||
# config.generate_additional_classes_for = [:wrapper, :label, :input]
|
||||
|
||||
# Whether attributes are required by default (or not). Default is true.
|
||||
# config.required_by_default = true
|
||||
|
||||
# Tell browsers whether to use default HTML5 validations (novalidate option).
|
||||
# Default is enabled.
|
||||
config.browser_validations = false
|
||||
|
||||
# Collection of methods to detect if a file type was given.
|
||||
# config.file_methods = [ :mounted_as, :file?, :public_filename ]
|
||||
|
||||
# Custom mappings for input types. This should be a hash containing a regexp
|
||||
# to match as key, and the input type that will be used when the field name
|
||||
# matches the regexp as value.
|
||||
# config.input_mappings = { /count/ => :integer }
|
||||
|
||||
# Custom wrappers for input types. This should be a hash containing an input
|
||||
# type as key and the wrapper that will be used for all inputs with specified type.
|
||||
# config.wrapper_mappings = { :string => :prepend }
|
||||
|
||||
# Default priority for time_zone inputs.
|
||||
# config.time_zone_priority = nil
|
||||
|
||||
# Default priority for country inputs.
|
||||
# config.country_priority = nil
|
||||
|
||||
# Default size for text inputs.
|
||||
# config.default_input_size = 50
|
||||
|
||||
# When false, do not use translations for labels.
|
||||
# config.translate_labels = true
|
||||
|
||||
# Automatically discover new inputs in Rails' autoload path.
|
||||
# config.inputs_discovery = true
|
||||
|
||||
# Cache SimpleForm inputs discovery
|
||||
# config.cache_discovery = !Rails.env.development?
|
||||
end
|
||||
@@ -0,0 +1,45 @@
|
||||
# Use this setup block to configure all options available in SimpleForm.
|
||||
SimpleForm.setup do |config|
|
||||
config.wrappers :bootstrap, :tag => 'div', :class => 'control-group', :error_class => 'error' do |b|
|
||||
b.use :html5
|
||||
b.use :placeholder
|
||||
b.use :label
|
||||
b.wrapper :tag => 'div', :class => 'controls' do |ba|
|
||||
ba.use :input
|
||||
ba.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' }
|
||||
ba.use :hint, :wrap_with => { :tag => 'p', :class => 'help-block' }
|
||||
end
|
||||
end
|
||||
|
||||
config.wrappers :prepend, :tag => 'div', :class => "control-group", :error_class => 'error' do |b|
|
||||
b.use :html5
|
||||
b.use :placeholder
|
||||
b.use :label
|
||||
b.wrapper :tag => 'div', :class => 'controls' do |input|
|
||||
input.wrapper :tag => 'div', :class => 'input-prepend' do |prepend|
|
||||
prepend.use :input
|
||||
end
|
||||
input.use :hint, :wrap_with => { :tag => 'span', :class => 'help-block' }
|
||||
input.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' }
|
||||
end
|
||||
end
|
||||
|
||||
config.wrappers :append, :tag => 'div', :class => "control-group", :error_class => 'error' do |b|
|
||||
b.use :html5
|
||||
b.use :placeholder
|
||||
b.use :label
|
||||
b.wrapper :tag => 'div', :class => 'controls' do |input|
|
||||
input.wrapper :tag => 'div', :class => 'input-append' do |append|
|
||||
append.use :input
|
||||
end
|
||||
input.use :hint, :wrap_with => { :tag => 'span', :class => 'help-block' }
|
||||
input.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' }
|
||||
end
|
||||
end
|
||||
|
||||
# Wrappers for forms and inputs using the Twitter Bootstrap toolkit.
|
||||
# Check the Bootstrap docs (http://twitter.github.com/bootstrap)
|
||||
# to learn about the different styles for forms and inputs,
|
||||
# buttons and other elements.
|
||||
config.default_wrapper = :bootstrap
|
||||
end
|
||||
@@ -14,9 +14,21 @@ en:
|
||||
are_you_sure: 'Are you sure?'
|
||||
place_order: Place order
|
||||
show_active_list: Show %{list}
|
||||
edit: Edit
|
||||
show: Show
|
||||
new: New
|
||||
destroy: Delete
|
||||
back: Back
|
||||
cancel: Cancel
|
||||
forms:
|
||||
errors:
|
||||
title: There are problems found during saving (%{count})
|
||||
submit:
|
||||
create: 'Add %{model}'
|
||||
update: 'Update %{model}'
|
||||
submit: 'Save %{model}'
|
||||
list:
|
||||
no_records: There are no items present
|
||||
messages:
|
||||
cannot_order_on_non_active_list: You cannot place an order on a closed list
|
||||
order_is_placed: Your order has been received in good order
|
||||
@@ -130,6 +142,8 @@ en:
|
||||
show_active_list_products: Go to the menu
|
||||
basket:
|
||||
total: Total
|
||||
product_category:
|
||||
other_name: Overig
|
||||
section:
|
||||
first_section_title: Room
|
||||
manage_tables:
|
||||
|
||||
@@ -13,9 +13,21 @@ nl:
|
||||
are_you_sure: 'Weet je dit zeker?'
|
||||
place_order: Bestellen
|
||||
show_active_list: Toon %{list}
|
||||
edit: Bewerk
|
||||
show: Toon
|
||||
new: Nieuw
|
||||
destroy: Verwijder
|
||||
back: Terug
|
||||
cancel: Terug
|
||||
forms:
|
||||
errors:
|
||||
title: Er zijn een problemen opgetreden (%{count})
|
||||
submit:
|
||||
create: '%{model} toevoegen'
|
||||
update: '%{model} bewaren'
|
||||
submit: '%{model} opslaan'
|
||||
list:
|
||||
no_records: Er zijn geen items aanwezig
|
||||
messages:
|
||||
cannot_order_on_non_active_list: Je kan niet bestellen op een gesloten lijst
|
||||
order_is_placed: Je bestelling is in goede orde aangekomen
|
||||
@@ -143,6 +155,8 @@ nl:
|
||||
show_active_list_products: Ga naar het menu
|
||||
basket:
|
||||
total: Totaal
|
||||
product_category:
|
||||
other_name: Overig
|
||||
section:
|
||||
first_section_title: Ruimte
|
||||
manage_tables:
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
en:
|
||||
simple_form:
|
||||
"yes": 'Yes'
|
||||
"no": 'No'
|
||||
required:
|
||||
text: 'required'
|
||||
mark: '*'
|
||||
# You can uncomment the line below if you need to overwrite the whole required html.
|
||||
# When using html, text and mark won't be used.
|
||||
# html: '<abbr title="required">*</abbr>'
|
||||
error_notification:
|
||||
default_message: "Please review the problems below:"
|
||||
# Labels and hints examples
|
||||
# labels:
|
||||
# defaults:
|
||||
# password: 'Password'
|
||||
# user:
|
||||
# new:
|
||||
# email: 'E-mail to sign in.'
|
||||
# edit:
|
||||
# email: 'E-mail.'
|
||||
# hints:
|
||||
# defaults:
|
||||
# username: 'User name to sign in.'
|
||||
# password: 'No special characters, please.'
|
||||
|
||||
+5
-1
@@ -90,7 +90,11 @@ Qwaiter::Application.routes.draw do
|
||||
end
|
||||
resources :products
|
||||
resources :lists
|
||||
resources :product_categories
|
||||
resources :product_categories do
|
||||
collection do
|
||||
post :sort
|
||||
end
|
||||
end
|
||||
root to: 'sections#index'
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
= simple_form_for(@<%= singular_table_name %>) do |f|
|
||||
= f.error_notification
|
||||
|
||||
.form-inputs
|
||||
<%- attributes.each do |attribute| -%>
|
||||
= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %>
|
||||
<%- end -%>
|
||||
|
||||
.form-actions
|
||||
= f.button :submit
|
||||
@@ -9,8 +9,12 @@ feature 'Supplier main board spec.rb', %q{
|
||||
create_supplier 'supplier@qwaiter.com'
|
||||
create_user 'user@qwaiter.com'
|
||||
end
|
||||
def create_active_list(options = {})
|
||||
|
||||
end
|
||||
|
||||
scenario 'loaded orders should have a list_id present for handling actions' do
|
||||
create_active_list
|
||||
login_supplier_as 'supplier@qwaiter.com'
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe ProductDecorator do
|
||||
end
|
||||
@@ -1,5 +1,6 @@
|
||||
FactoryGirl.define do
|
||||
factory :list do
|
||||
association :table
|
||||
association :supplier
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
FactoryGirl.define do
|
||||
factory :user do
|
||||
email "test@example.com"
|
||||
password "secret"
|
||||
end
|
||||
end
|
||||
@@ -14,4 +14,17 @@ describe List do
|
||||
end
|
||||
end
|
||||
|
||||
describe :mark_as_payed do
|
||||
it "should set payed_at to a time" do
|
||||
@list.payed_at.should be_nil
|
||||
@list.mark_as_payed
|
||||
@list.payed_at.should be_kind_of Time
|
||||
end
|
||||
it "should set is_payed to true" do
|
||||
@list.is_payed.should be_false
|
||||
@list.mark_as_payed
|
||||
@list.is_payed.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Product do
|
||||
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user