diff --git a/.gitignore b/.gitignore index 06073069..64bcc76e 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ /tmp .sass-cache/ *.swp +*~ db/xapian_db company_logo* public/assets diff --git a/Gemfile.lock b/Gemfile.lock index 0c32942e..d3788551 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -192,7 +192,7 @@ GEM tilt (~> 1.1, != 1.3.0) subexec (0.2.2) temple (0.4.0) - therubyracer (0.10.1) + therubyracer (0.10.2) libv8 (~> 3.3.10) thin (1.4.1) daemons (>= 1.0.9) @@ -203,11 +203,11 @@ GEM treetop (1.4.10) polyglot polyglot (>= 0.3.1) - twitter-bootstrap-rails (2.1.1) + twitter-bootstrap-rails (2.1.3) actionpack (>= 3.1) - less-rails (~> 2.2.2) + less-rails (~> 2.2.3) railties (>= 3.1) - therubyracer (= 0.10.1) + therubyracer (~> 0.10.2) tzinfo (0.3.33) uglifier (1.2.7) execjs (>= 0.3.0) diff --git a/Models.dia b/Models.dia index 42127149..c3269c3a 100644 Binary files a/Models.dia and b/Models.dia differ diff --git a/Models.dia~ b/Models.dia~ deleted file mode 100644 index 13ab58d5..00000000 Binary files a/Models.dia~ and /dev/null differ diff --git a/app/assets/images/icons/order-check.png b/app/assets/images/icons/order-check.png new file mode 100644 index 00000000..719338eb Binary files /dev/null and b/app/assets/images/icons/order-check.png differ diff --git a/app/assets/images/icons/order-check.svg b/app/assets/images/icons/order-check.svg new file mode 100644 index 00000000..6bd8ed99 --- /dev/null +++ b/app/assets/images/icons/order-check.svg @@ -0,0 +1,458 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/app/assets/images/icons/order-doublecheck.png b/app/assets/images/icons/order-doublecheck.png new file mode 100644 index 00000000..c69f078e Binary files /dev/null and b/app/assets/images/icons/order-doublecheck.png differ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 57338106..8819730e 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -13,4 +13,6 @@ //= require jquery //= require jquery_ujs //= require twitter/bootstrap -//= require_tree . +//= require_directory . +//= require_self + diff --git a/app/assets/javascripts/qrammer.js.coffee b/app/assets/javascripts/qrammer.js.coffee index 929e9bfe..609f891a 100644 --- a/app/assets/javascripts/qrammer.js.coffee +++ b/app/assets/javascripts/qrammer.js.coffee @@ -26,6 +26,101 @@ root.Qrammer = window.active_list[product._id].number += 1 Qrammer.build_product_list() build_product_list: -> + table = $('#active-order-table') + tbody = table.find('tbody') + tbody = $('').appendTo(table) unless tbody.length + tbody.find('tr').remove() + total = 0.0 + for product_id, info of window.active_list + total += info.product.price * info.number + row = $('').attr('id', 'active-order-row-'+product_id).appendTo(tbody) + row.append(''+info.product.name+'') + row.append(''+info.number+'') + row.append(''+Qrammer.currency(info.product.price * info.number)+'') + x_btn = $('').click(-> delete(window.active_list[product_id]) && Qrammer.build_product_list() ) + row.append($('').append(x_btn)) + $('#active-order-total').html(Qrammer.currency(total)) + table.show() + clear_active_list: -> + window.active_list = {} + $('#active-order-table').hide() + order_active_list: (post_uri)-> + h = {list_id: active_list_id} + for product_id, info of window.active_list + h['products['+product_id+']'] = info.number + $.post(post_uri, h, ((res) -> Qrammer.handle_response(res)), 'json') + handle_response: (res) -> + if(typeof(res) == 'string') + return unless res.length + if res[0] == '{' + res = JSON.parse(res) + else + eval(res) + return + alert(res['message']) if res['message'] && !res['ok'] + alert(res['message']) if res['message'] && res['ok'] + load_active_order_list: (supplier_id) -> + $.get('/suppliers/'+supplier_id+'/active_order_list.json', (res) -> + body = $('#active-orders-table tbody') + body.find('tr').remove() + foot = $('#active-orders-table tfoot') + if(!res.orders && !res.orders.length) + alert('No orders in list'); + return; + for order in res.orders + order_txts = [] + row = $('').appendTo(body) + process_btn = $('') + process_callback = ( (ord) -> + -> + my_btn = $(this) + $.post('/orders/'+ord.id+'/is_being_processed', {}, (res)-> my_btn.remove()) + )(order) + process_btn.click(process_callback) + + delivered_btn = $('') + delivered_callback = ( (ord, r) -> + -> + my_btn = $(this) + $.post('/orders/'+ord.id+'/is_delivered', {}, (res)-> r.slideUp('slow')) + )(order, row) + delivered_btn.click(delivered_callback) + for product in order.products + order_txts.push(product.name + ' (' + product['number'] + ')') + row.append($('').text(order_txts.join(', '))) + row.append($('').text(order.table_number)) + row.append($('').html(Qrammer.currency(order.total_amount))) + td_buttons = $('') + td_buttons.append(process_btn).append(' ') if order.state == 'placed' + td_buttons.append(delivered_btn) + row.append(td_buttons) + #foot.append(''+Qrammer.currency(res.total_amount)+''); + ) + load_active_lists: (supplier_id) -> + $.get('/suppliers/'+supplier_id+'/active_lists.json', (res) -> + body = $('#active-lists-table tbody') + body.find('tr').remove() + foot = $('#active-lists-table tfoot') + for list in res.lists + order_txts = [] + row = $('').appendTo(body) + close_btn = $('') + close_callback = ( (lst, r) -> + -> + my_btn = $(this) + $.post('/lists/'+lst._id+'/is_closed', {}, (res)-> r.slideUp('slow')) + )(list, row) + close_btn.click(close_callback) + + row.append($('').text(list._id)) + row.append($('').html(Qrammer.currency(list.total_amount))) + td_buttons = $('') + td_buttons.append(close_btn) + row.append(td_buttons) + #foot.append(''+Qrammer.currency(res.total_amount)+''); + ) + + build_product_list_as_modal: -> wrapper = $('') callback_wrapper = -> wrapper.modal('hide') @@ -50,4 +145,7 @@ root.Qrammer = .append($('Yes').click(callback_wrapper)) .appendTo(wrapper) wrapper.modal() - + +jQuery.ajaxSetup + 'beforeSend': (xhr) -> + xhr.setRequestHeader("Accept", "text/javascript") diff --git a/app/assets/stylesheets/structure.css.sass b/app/assets/stylesheets/structure.css.sass new file mode 100644 index 00000000..63b77bf9 --- /dev/null +++ b/app/assets/stylesheets/structure.css.sass @@ -0,0 +1,33 @@ +table + thead + th + &.currency + text-align: right + tbody + td + &.currency + text-align: right + &.numeric + text-align: right + &.actions + text-align: right + tfoot + td + &.currency + text-align: right +#active-list-table + tbody + tr + td + &:first-child + padding-left: 35px + background-position: 5px center + background-repeat: no-repeat + &.placed + td + &:first-child + background-image: image-url('icons/order-check.png') + &.delivered + td + &:first-child + background-image: image-url('icons/order-doublecheck.png') diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 258705b5..450d8692 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,10 +1,31 @@ class ApplicationController < ActionController::Base + protect_from_forgery private - def active_list - List.find(session[:list_id]) + def check_active_list_state + if session[:active_list_id] + unless active_list.active? + session[:active_list_id] = nil + redirect_to root_path, alert: t('messages.the_list_has_been_closed') + end + end + end + + def active_list + return nil unless session[:active_list_id] + @active_list ||= List.find(session[:active_list_id]) + end + + def js_alert(message) + {ok: false, message: message}.to_json + end + def js_notice(message) + {ok: true, message: message}.to_json + end + + helper_method :active_list end diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 6860fdc3..5d734330 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -1,5 +1,6 @@ class DashboardController < ApplicationController + before_filter :check_active_list_state, except: :home def home end @@ -17,8 +18,8 @@ class DashboardController < ApplicationController @list = List.new(table: @table) #@list.add_user(current_user) @list.save - session[:list_id] = @list.id - redirect_to root_path + session[:active_list_id] = @list.id + redirect_to action: :show_products end end @@ -27,4 +28,28 @@ class DashboardController < ApplicationController end + + def order_active_list + respond_to do |format| + format.html do + redirect_to(root_path, alert: t('messages.cannot_order_without_list_id')) and return if params[:list_id].blank? + @list = List.find(params[:list_id]) + redirect_to(root_path, alert: t('messages.cannot_order_on_non_active_list')) and return unless @list.active? + @list.place_order params[:products] + redirect_to root_path, notice: t('messages.order_is_placed') + end + format.js do + render js: js_alert(t('messages.cannot_order_without_list_id')) and return if params[:list_id].blank? + @list = List.find(params[:list_id]) + render js: js_alert(t('messages.cannot_order_on_non_active_list')) and return unless @list.active? + @list.place_order params[:products] + render js: js_notice( t('messages.order_is_placed') ) + end + end + end + + def view_active_list + redirect_to(root_path, alert: t('messages.there_is_no_list_active')) and return unless session[:active_list_id].present? + + end end diff --git a/app/controllers/lists_controller.rb b/app/controllers/lists_controller.rb index b2a888f5..47570537 100644 --- a/app/controllers/lists_controller.rb +++ b/app/controllers/lists_controller.rb @@ -82,6 +82,40 @@ class ListsController < ApplicationController end end + def current + @list = List.find(params[:id]) + @list.orders.include_relations(product_orders: :product) + respond_to do |format| + format.json do + h = @list.as_json + h[:orders] = [] + list_total = 0.0 + for order in @list.orders + ho = {products: []} + order_total = 0.0 + for product_order in order.product_orders + order_total += (product_order.amount * product_order.product.price).round(2) + ho[:products] << {name: product_order.product.name, id: product_order.product_id, number: product_order.amount, price: product_order.product.price} + end + ho[:total_amount] = order_total.round(2) + ho[:state] = order.state + list_total += ho[:total_amount] + h[:orders] << ho + end + h[:total_amount] = list_total.round(2) + render json: h + end + + end + + end + + # POST /orders/1/is_delivered + def is_closed + @list = List.find(params[:id]) + @list.close! + render nothing: true + end private def set_relation_options diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb new file mode 100644 index 00000000..2d8e8e3c --- /dev/null +++ b/app/controllers/orders_controller.rb @@ -0,0 +1,104 @@ +class OrdersController < ApplicationController + before_filter :set_relation_options, only: [:new, :edit, :create, :update] + # GET /orders + # GET /orders.json + def index + @orders = Order.all + + respond_to do |format| + format.html # index.html.erb + format.json { render json: @orders } + end + end + + # GET /orders/1 + # GET /orders/1.json + def show + @order = Order.find(params[:id]) + + respond_to do |format| + format.html # show.html.erb + format.json { render json: @order } + end + end + + # GET /orders/new + # GET /orders/new.json + def new + @order = Order.new + + respond_to do |format| + format.html # new.html.erb + format.json { render json: @order } + end + end + + # GET /orders/1/edit + def edit + @order = Order.find(params[:id]) + end + + # POST /orders + # POST /orders.json + def create + @order = Order.new(params[:order]) + + respond_to do |format| + if @order.save + format.html { redirect_to @order, notice: t('action.create.successfull', model: Order.model_name.human) } + format.json { render json: @order, status: :created, location: @order } + else + format.html { render action: "new" } + format.json { render json: @order.errors, status: :unprocessable_entity } + end + end + end + + # PUT /orders/1 + # PUT /orders/1.json + def update + @order = Order.find(params[:id]) + + respond_to do |format| + if @order.update_attributes(params[:order]) + format.html { redirect_to @order, notice: t('action.update.successfull', model: Order.model_name.human) } + format.json { head :no_content } + else + format.html { render action: "edit" } + format.json { render json: @order.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /orders/1 + # DELETE /orders/1.json + def destroy + @order = Order.find(params[:id]) + @order.destroy + + respond_to do |format| + format.html { redirect_to orders_url, notice: t('action.destroy.successfull', model: Order.model_name.human) } + format.json { head :no_content } + end + end + + # POST /orders/1/is_being_processed + def is_being_processed + @order = Order.find(params[:id]) + @order.is_being_processed! + render nothing: true + end + + # POST /orders/1/is_delivered + def is_delivered + @order = Order.find(params[:id]) + @order.is_delivered! + render nothing: true + end + + private + + def set_relation_options + @lists = List.all + end +end diff --git a/app/controllers/suppliers_controller.rb b/app/controllers/suppliers_controller.rb index 1a4b1241..943ff279 100644 --- a/app/controllers/suppliers_controller.rb +++ b/app/controllers/suppliers_controller.rb @@ -98,6 +98,58 @@ class SuppliersController < ApplicationController end end end + + # GET /suppliers/1/active_order_list + # GET /suppliers/1/active_order_list.json + def active_order_list + @supplier = Supplier.find(params[:id]) + respond_to do |format| + format.html + format.json do + h = @supplier.as_json + h[:orders] = [] + list_total = 0.0 + for order in @supplier.active_orders + ho = {products: []} + order_total = 0.0 + for product_order in order.product_orders + order_total += (product_order.amount * product_order.product.price).round(2) + ho[:products] << {name: product_order.product.name, id: product_order.product_id, number: product_order.amount, price: product_order.product.price} + end + ho[:total_amount] = order_total.round(2) + ho[:state] = order.state + ho[:table_number] = order.table_number + ho[:id] = order.id + list_total += ho[:total_amount] + h[:orders] << ho + end + h[:total_amount] = list_total.round(2) + render json: h + end + end + end + + # GET /suppliers/1/active_lists + # GET /suppliers/1/active_lists.json + def active_lists + @supplier = Supplier.find(params[:id]) + respond_to do |format| + format.html + format.json do + h = @supplier.as_json + h[:lists] = [] + grand_total = 0.0 + for list in @supplier.active_lists + hl = list.as_json + hl[:total_amount] = list.orders.inject(0.0){|sum, o| sum + o.product_orders.inject(0.0){|s, po| s + (po.amount * po.product.price).round(2)}}.round(2) + grand_total += hl[:total_amount] + h[:lists] << hl + end + h[:total_amount] = grand_total.round(2) + render json: h + end + end + end private def set_relation_options diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 9a1aef14..17235e98 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -19,7 +19,7 @@ module ApplicationHelper end def list_open? - session[:list_id].present? + session[:active_list_id].present? end def no_content_given(model) diff --git a/app/models/list.rb b/app/models/list.rb index 183f1d8f..a0077d5d 100644 --- a/app/models/list.rb +++ b/app/models/list.rb @@ -1,15 +1,18 @@ class List include SimplyStored::Couch - property :state + property :state, default: 'active' # active, #closed + property :need_help, type: :boolean, default: false + property :needs_payment, type: :boolean, default: false property :closed_at, type: Time - has_many :orders + has_many :orders, dependent: :destroy belongs_to :table has_and_belongs_to_many :users, storing_keys: true validates :table_id, presence: true def close! + #TODO: close orders self.state = 'closed' self.closed_at = Time.now save @@ -18,4 +21,18 @@ class List def supplier table.supplier end + + def active? + state == 'active' + end + + def place_order(products) + return unless products.any? + @order = Order.create list: self, supplier: supplier + return unless @order.id + products.each do |product_id, number| + number = number.to_i + ProductOrder.create order: @order, product_id: product_id, amount: number if number > 0 + end + end end diff --git a/app/models/order.rb b/app/models/order.rb index dcf5576c..14899e4a 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -1,9 +1,45 @@ class Order include SimplyStored::Couch + property :state, default: 'placed' # placed, active, delivered, cancelled + belongs_to :list belongs_to :user + belongs_to :supplier - has_many :product_orders - has_many :products, through: :product_orders + has_many :product_orders, dependent: :destroy + #has_many :products, through: :product_orders + validates :supplier_id, presence: true + + view :active_for_supplier_view, type: :custom, map_function: %[function(doc){ + if(doc.ruby_class == 'Order' && (doc.state == 'placed' || doc.state == 'active')){ + emit(doc.supplier_id, 1); + } + }], reduce_function: '_sum' + + def self.active_for_supplier(supplier_id) + database.view(active_for_supplier_view(key: supplier_id, reduce: false, include_docs: true)) + end + def table_number + list.table.number + end + alias table_nr table_number + + + def placed? + state == 'placed' + end + def active? + state == 'active' + end + + def is_being_processed! + self.state = 'active' + save + end + + def is_delivered! + self.state = 'delivered' + save + end end diff --git a/app/models/product_order.rb b/app/models/product_order.rb index d0286dfc..76a1b54c 100644 --- a/app/models/product_order.rb +++ b/app/models/product_order.rb @@ -1,6 +1,9 @@ class ProductOrder include SimplyStored::Couch - + + property :amount, type: Fixnum + belongs_to :product belongs_to :order + end diff --git a/app/models/supplier.rb b/app/models/supplier.rb index d869d251..b2b7096f 100644 --- a/app/models/supplier.rb +++ b/app/models/supplier.rb @@ -2,9 +2,31 @@ class Supplier include SimplyStored::Couch property :name - has_many :lists - has_many :orders, through: :lists - has_many :products - has_many :product_categories - has_many :tables + #has_many :orders, through: :lists + has_many :products, dependent: :destroy + has_many :product_categories, dependent: :destroy + has_many :tables, dependent: :destroy + #has_many :lists, through: :tables + has_many :orders + + def active_orders + return @active_orders if @active_orders + @active_orders = Order.active_for_supplier(id) + @active_orders.include_relation(list: :table, product_orders: :order) + @active_orders + end + + def active_lists + return @active_lists if @active_lists + @tables ||= active_tables + @tables.include_relation(:lists) + @active_lists = @tables.map(&:lists).flatten.select(&:active?) + @active_lists.include_relations(:table, orders: {product_orders: :product}) + end + + + def active_tables + tables + end + end diff --git a/app/views/dashboard/home.html.slim b/app/views/dashboard/home.html.slim index 7ca57290..ae7f30df 100644 --- a/app/views/dashboard/home.html.slim +++ b/app/views/dashboard/home.html.slim @@ -1,14 +1,14 @@ .page-header= title 'Home' ul.nav.nav-tabs.nav-stacked - if list_open? - li.active= link_to '€ 23,45'.html_safe, '#' li= link_to 'Place order', '/show_products?supplier_id=' + active_list.supplier.id - li= link_to 'Active list', '#' + li= link_to 'Active list', view_active_list_path li= link_to 'Request bill', '#' li= link_to 'I have a question', '#' - else li= link_to 'Place order', '/select_qrcode' li= link_to 'Subscribe to list', '#' + li= link_to 'Check out menu', '#' ul.nav.nav-tabs.nav-stacked li= link_to 'View history', '#' diff --git a/app/views/dashboard/show_products.html.slim b/app/views/dashboard/show_products.html.slim index c99ac7dc..33eaa156 100644 --- a/app/views/dashboard/show_products.html.slim +++ b/app/views/dashboard/show_products.html.slim @@ -1,6 +1,24 @@ button onClick='Qrammer.build_product_list()' class='btn btn-inverse'Lijst table#products-table.table.table-striped.table-hover tbody +- content_for :sidebar do + table#active-order-table.table.hide + thead + tr + th Product + th # + th.currency Total + th + tbody + tfoot + tr + td colspan=2 + button class="btn btn-primary" onClick="Qrammer.order_active_list('/order_active_list')" Bestellen + |  + button class="btn btn btn-warning" onClick="Qrammer.clear_active_list()" Clear + td.currency + strong#active-order-total + td - content_for :footer do javascript: jQuery(function(){ @@ -8,12 +26,12 @@ table#products-table.table.table-striped.table-hover window.products = res body = $('#products-table tbody') for(var category in window.products){ - body.append('

'+category+'

'); + body.append('

'+category+'

'); var category_ref = window.products[category]; for(var iproduct = 0; iproduct < window.products[category].length; iproduct++){ var product_index = iproduct; row = $(''); - button = $(''); + button = $(''); var callback = (function(ref){ return function(){ Qrammer.add_product(ref[product_index]) } })(category_ref) diff --git a/app/views/dashboard/view_active_list.html.slim b/app/views/dashboard/view_active_list.html.slim new file mode 100644 index 00000000..064bb10b --- /dev/null +++ b/app/views/dashboard/view_active_list.html.slim @@ -0,0 +1,37 @@ +.page-header + h1 List overview +table#active-list-table.table + thead + tr + th Order + th.currency Price + tbody + tfoot +- content_for :footer do + javascript: + jQuery(function(){ + $.get('#{current_list_path(session[:active_list_id], format: :json).html_safe}', function(res){ + var body = $('#active-list-table tbody'); + var foot = $('#active-list-table tfoot'); + if(!res.orders && !res.orders.length){ + alert('No orders in list'); + return; + } + for(var iorder = 0; iorder < res.orders.length; iorder++){ + var order_txts = []; + var order = res.orders[iorder]; + var row = $('').appendTo(body); + row.addClass(order.state); + //if(order.state == 'placed') row.addClass('info'); + //if(order.state == 'delivered') row.addClass('success'); + if(order.state == 'cancelled') row.addClass('error'); + for(var iproduct = 0; iproduct < order.products.length; iproduct++){ + var product = order.products[iproduct]; + order_txts.push(product.name + ' (' + product['number'] + ')') + } + row.append($('').text(order_txts.join(', '))); + row.append($('').html(Qrammer.currency(res.orders[iorder].total_amount))) + } + foot.append(''+Qrammer.currency(res.total_amount)+''); + }) + }) diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index 1f69807d..f96e61fb 100644 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ -16,6 +16,8 @@ html lang="en" link href="images/apple-touch-icon-72x72.png" rel="apple-touch-icon-precomposed" sizes="72x72" link href="images/apple-touch-icon.png" rel="apple-touch-icon-precomposed" link href="images/favicon.ico" rel="shortcut icon" + javascript: + var active_list_id = #{session[:active_list_id] ? "'#{session[:active_list_id]}'" : 'null'}; body .navbar.navbar-fixed-top @@ -56,6 +58,7 @@ html lang="en" li.nav-header Links li= link_to "Home", root_path li= link_to "Companytools", 'http://www.companytools.nl/' + = yield :sidebar footer p © Companytools 2012 diff --git a/app/views/orders/_form.html.slim b/app/views/orders/_form.html.slim new file mode 100644 index 00000000..30cacca6 --- /dev/null +++ b/app/views/orders/_form.html.slim @@ -0,0 +1,14 @@ += form_for @order, html: {class: 'form-horizontal' } do |f| + = render 'error_messages', target: @order + .control-group class=(@order.errors[:state].any? ? 'error' : nil) + = f.label :state, class: 'control-label' + .controls + = f.text_field :state, class: 'text_field' + .control-group class=(@order.errors[:supplier_id].any? ? 'error' : nil) + = f.label :supplier_id, Supplier.model_name.human, class: 'control-label' + .controls + = f.select :supplier_id, options_for_select(@suppliers.map{|a| [a.name, a.id]}), include_blank: nil + .form-actions + = f.submit nil, class: 'btn btn-primary' + ' + = link_to t("helpers.links.cancel"), orders_path, class: 'btn' diff --git a/app/views/orders/edit.html.slim b/app/views/orders/edit.html.slim new file mode 100644 index 00000000..b2fb432d --- /dev/null +++ b/app/views/orders/edit.html.slim @@ -0,0 +1,4 @@ +- model_class = Order +.page-header + = title :edit, model_class += render 'form' diff --git a/app/views/orders/index.html.slim b/app/views/orders/index.html.slim new file mode 100644 index 00000000..af117872 --- /dev/null +++ b/app/views/orders/index.html.slim @@ -0,0 +1,24 @@ +- model_class = Order +div.page-header= title :index, model_class +- if @orders.any? + table.table.table-striped + thead + tr + th= model_class.human_attribute_name(:state) + th= Supplier.model_name.human + th= model_class.human_attribute_name(:created_at) + th=t 'helpers.actions' + tbody + - @orders.each do |order| + tr + td= link_to order.state, order + td= link_to_if order.supplier.present?, order.supplier.try(:name), order.supplier + td=l order.created_at, format: :short + td + = link_to t('helpers.links.edit'), [:edit, order], class: 'btn btn-mini' + ' + = link_to t("helpers.links.destroy"), order, method: :delete, data: {confirm: are_you_sure? }, class: 'btn btn-mini btn-danger' +- else + = no_content_given model_class += link_to t("helpers.links.new"), new_order_path, class: 'btn btn-primary' + diff --git a/app/views/orders/new.html.slim b/app/views/orders/new.html.slim new file mode 100644 index 00000000..7963a2b0 --- /dev/null +++ b/app/views/orders/new.html.slim @@ -0,0 +1,4 @@ +- model_class = Order +.page-header + = title :new, model_class += render 'form' diff --git a/app/views/orders/show.html.slim b/app/views/orders/show.html.slim new file mode 100644 index 00000000..a268b3ad --- /dev/null +++ b/app/views/orders/show.html.slim @@ -0,0 +1,16 @@ +- model_class = Order +.page-header= title :show, @order + +dl.dl-horizontal.show-list + dt= model_class.human_attribute_name(:state) + dd= @order.state + - if @order.supplier.present? + dt= Supplier.model_name.human + dd= link_to @order.supplier.name, @order.supplier + +.form-actions + = link_to t("helpers.links.back"), orders_path, class: 'btn' + ' + = link_to t('helpers.links.edit'), [:edit, @order], class: 'btn' + ' + = link_to t("helpers.links.destroy"), @order, method: :delete, data: {confirm: are_you_sure? }, class: 'btn btn-danger' diff --git a/app/views/suppliers/active_lists.html.slim b/app/views/suppliers/active_lists.html.slim new file mode 100644 index 00000000..d3b6b082 --- /dev/null +++ b/app/views/suppliers/active_lists.html.slim @@ -0,0 +1,15 @@ +.page-header= title 'Active lists' +table#active-lists-table.table + thead + tr + th.number Table number + th.currency Price + th.actions + tbody +- content_for :footer do + javascript: + jQuery(function(){ + Qrammer.load_active_lists('#{@supplier.id}') + setInterval( "Qrammer.load_active_lists('#{@supplier.id}')", 7500); + }); + diff --git a/app/views/suppliers/active_order_list.html.slim b/app/views/suppliers/active_order_list.html.slim new file mode 100644 index 00000000..e9e37c6c --- /dev/null +++ b/app/views/suppliers/active_order_list.html.slim @@ -0,0 +1,16 @@ +.page-header= title 'Active orders' +table#active-orders-table.table + thead + tr + th Order + th.number Table number + th.currency Price + th.actions + tbody +- content_for :footer do + javascript: + jQuery(function(){ + Qrammer.load_active_order_list('#{@supplier.id}') + setInterval( "Qrammer.load_active_order_list('#{@supplier.id}')", 7500); + }); + diff --git a/app/views/users/_form.html.slim b/app/views/users/_form.html.slim index 2aa2049c..f1a17de6 100644 --- a/app/views/users/_form.html.slim +++ b/app/views/users/_form.html.slim @@ -1,41 +1,42 @@ = form_for @user, html: {class: 'form-horizontal' } do |f| - .control-group + = render 'error_messages', target: @user + .control-group class=(@user.errors[:email].any? ? 'error' : nil) = f.label :email, class: 'control-label' .controls = f.text_field :email, class: 'text_field' - .control-group + .control-group class=(@user.errors[:encrypted_password].any? ? 'error' : nil) = f.label :encrypted_password, class: 'control-label' .controls = f.text_field :encrypted_password, class: 'text_field' - .control-group + .control-group class=(@user.errors[:remember_token].any? ? 'error' : nil) = f.label :remember_token, class: 'control-label' .controls = f.text_field :remember_token, class: 'text_field' - .control-group + .control-group class=(@user.errors[:remember_created_at].any? ? 'error' : nil) = f.label :remember_created_at, class: 'control-label' .controls = f.text_field :remember_created_at, class: 'text_field' - .control-group + .control-group class=(@user.errors[:reset_password_token].any? ? 'error' : nil) = f.label :reset_password_token, class: 'control-label' .controls = f.text_field :reset_password_token, class: 'text_field' - .control-group + .control-group class=(@user.errors[:sign_in_count].any? ? 'error' : nil) = f.label :sign_in_count, class: 'control-label' .controls = f.text_field :sign_in_count, class: 'text_field' - .control-group + .control-group class=(@user.errors[:current_sign_in_at].any? ? 'error' : nil) = f.label :current_sign_in_at, class: 'control-label' .controls = f.text_field :current_sign_in_at, class: 'text_field' - .control-group + .control-group class=(@user.errors[:last_sign_in_at].any? ? 'error' : nil) = f.label :last_sign_in_at, class: 'control-label' .controls = f.text_field :last_sign_in_at, class: 'text_field' - .control-group + .control-group class=(@user.errors[:current_sign_in_ip].any? ? 'error' : nil) = f.label :current_sign_in_ip, class: 'control-label' .controls = f.text_field :current_sign_in_ip, class: 'text_field' - .control-group + .control-group class=(@user.errors[:last_sign_in_ip].any? ? 'error' : nil) = f.label :last_sign_in_ip, class: 'control-label' .controls = f.text_field :last_sign_in_ip, class: 'text_field' diff --git a/app/views/users/index.html.slim b/app/views/users/index.html.slim index c0e37557..669c9c8f 100644 --- a/app/views/users/index.html.slim +++ b/app/views/users/index.html.slim @@ -1,38 +1,22 @@ - model_class = User -div class="page-header"= title :index, model_class -table class="table table-striped" - thead - tr - th= model_class.human_attribute_name(:email) - th= model_class.human_attribute_name(:encrypted_password) - th= model_class.human_attribute_name(:remember_token) - th= model_class.human_attribute_name(:remember_created_at) - th= model_class.human_attribute_name(:reset_password_token) - th= model_class.human_attribute_name(:sign_in_count) - th= model_class.human_attribute_name(:current_sign_in_at) - th= model_class.human_attribute_name(:last_sign_in_at) - th= model_class.human_attribute_name(:current_sign_in_ip) - th= model_class.human_attribute_name(:last_sign_in_ip) - th= model_class.human_attribute_name(:created_at) - th=t 'helpers.actions' - tbody - - @users.each do |user| +div.page-header= title :index, model_class +- if @users.any? + table.table.table-striped + thead tr - td= link_to user.email, user - td= user.encrypted_password - td= user.remember_token - td= user.remember_created_at - td= user.reset_password_token - td= user.sign_in_count - td= user.current_sign_in_at - td= user.last_sign_in_at - td= user.current_sign_in_ip - td= user.last_sign_in_ip - td=l user.created_at, format: :short - td - = link_to t('helpers.links.edit'), [:edit, user], class: 'btn btn-mini' - ' - = link_to t("helpers.links.destroy"), user, method: :delete, data: {confirm: are_you_sure? }, class: 'btn btn-mini btn-danger' - + th= model_class.human_attribute_name(:email) + th= model_class.human_attribute_name(:created_at) + th=t 'helpers.actions' + tbody + - @users.each do |user| + tr + td= link_to user.email, user + td=l user.created_at, format: :short + td + = link_to t('helpers.links.edit'), [:edit, user], class: 'btn btn-mini' + ' + = link_to t("helpers.links.destroy"), user, method: :delete, data: {confirm: are_you_sure? }, class: 'btn btn-mini btn-danger' +- else + = no_content_given model_class = link_to t("helpers.links.new"), new_user_path, class: 'btn btn-primary' diff --git a/app/views/users/show.html.slim b/app/views/users/show.html.slim index c81d71eb..4efb1d07 100644 --- a/app/views/users/show.html.slim +++ b/app/views/users/show.html.slim @@ -1,27 +1,26 @@ - model_class = User -.page-header - = title :show, @user +.page-header= title :show, @user dl.dl-horizontal.show-list - dt= model_class.human_attribute_name(:email) + ':' + dt= model_class.human_attribute_name(:email) dd= @user.email - dt= model_class.human_attribute_name(:encrypted_password) + ':' + dt= model_class.human_attribute_name(:encrypted_password) dd= @user.encrypted_password - dt= model_class.human_attribute_name(:remember_token) + ':' + dt= model_class.human_attribute_name(:remember_token) dd= @user.remember_token - dt= model_class.human_attribute_name(:remember_created_at) + ':' + dt= model_class.human_attribute_name(:remember_created_at) dd= @user.remember_created_at - dt= model_class.human_attribute_name(:reset_password_token) + ':' + dt= model_class.human_attribute_name(:reset_password_token) dd= @user.reset_password_token - dt= model_class.human_attribute_name(:sign_in_count) + ':' + dt= model_class.human_attribute_name(:sign_in_count) dd= @user.sign_in_count - dt= model_class.human_attribute_name(:current_sign_in_at) + ':' + dt= model_class.human_attribute_name(:current_sign_in_at) dd= @user.current_sign_in_at - dt= model_class.human_attribute_name(:last_sign_in_at) + ':' + dt= model_class.human_attribute_name(:last_sign_in_at) dd= @user.last_sign_in_at - dt= model_class.human_attribute_name(:current_sign_in_ip) + ':' + dt= model_class.human_attribute_name(:current_sign_in_ip) dd= @user.current_sign_in_ip - dt= model_class.human_attribute_name(:last_sign_in_ip) + ':' + dt= model_class.human_attribute_name(:last_sign_in_ip) dd= @user.last_sign_in_ip .form-actions diff --git a/config/locales/en.yml b/config/locales/en.yml index 4db28813..81b22893 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,6 +1,5 @@ # Sample localization file for English. Add more files in this directory for other locales. # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. - en: hello: "Hello world" helpers: @@ -9,6 +8,11 @@ en: forms: errors: title: There are problems found during saving (%{count}) + messages: + cannot_order_without_list_id: You cannot place an order without specifying a list + 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 + the_list_has_been_closed: The list has been closed action: index: label: Listing %{models} diff --git a/config/routes.rb b/config/routes.rb index 37f14237..ed62b2f1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -5,16 +5,30 @@ Qrammer::Application.routes.draw do get :qrcode end end + resources :orders do + member do + post :is_being_processed + post :is_delivered + end + end resources :suppliers do member do get :product_list + get :active_order_list + get :active_lists + end + end + resources :lists do + member do + get :current + post :is_closed end end - resources :lists resources :products resources :product_categories match "/:action", controller: 'dashboard' + match '/view_active_list' => 'dashboard#view_active_list', as: :view_active_list # The priority is based upon order of creation: # first created -> highest priority. diff --git a/stories b/stories index f334df26..b2e16f50 100644 --- a/stories +++ b/stories @@ -12,6 +12,7 @@ Person actions: When no list is open: - Open list - Subscribe to existing list + - Request menu General actions - View history @@ -21,3 +22,17 @@ Person actions: Alleen restaurant kan rekening afsluiten, als dit nog niet is gebeurd voor een tafel kan een nieuwe persoon geen lijst openen. Alert melding bij restaurant als iemand dit probeert Eén lijst tegelijk actief? (wel handig en duidelijk!!!) + + +Sales arguments: +- Safer because of personalized ordering, less incentive to leave without payment +- No installation required, just internet +- Plaats een overzicht op meerdere plaatsen voor een optimaal service level + +Actielijst: +- Real life test @ flex@diem +- Hoe omgaan met delivered -> on the way +- processen noteren en observeren (reverse) in cafe +- Bewoordingen critisch en klantgericht doornemen +- Plaats omgevingen in ihpone / ipad omgeving (gerelateerd) +- Barman en vaste tafels