From 6c2427e082b03c120d05ba617983f16d93286aef Mon Sep 17 00:00:00 2001 From: Benjamin ter Kuile Date: Mon, 24 Mar 2014 10:02:57 +0100 Subject: [PATCH] Implement waiter ordering and improvements --- .../{application.js => application.js.erb} | 4 ++ .../{supplier => }/translations.js.erb | 4 +- .../product_categories_controller.js.coffee | 5 +- .../controllers/section_controller.js.coffee | 1 + .../controllers/sections_controller.js.coffee | 3 +- .../controllers/table_controller.js.coffee | 17 +++++- .../javascripts/waiter/app/router.js.coffee | 2 +- .../app/templates/product_categories.emblem | 1 - .../waiter/app/templates/section.emblem | 1 - .../app/templates/section_header.emblem | 2 + .../waiter/app/templates/sections.emblem | 6 +-- .../waiter/app/templates/table.emblem | 5 +- .../app/views/section_header_view.js.coffee | 8 +++ .../javascripts/waiter/application.js.coffee | 7 --- .../waiter/application.js.coffee.erb | 15 ++++++ app/controllers/user_controller.rb | 4 +- app/controllers/waiter_controller.rb | 15 ++++++ app/models/employee.rb | 10 ++++ app/models/list.rb | 54 +++++++++++-------- app/models/order.rb | 2 +- app/models/supplier.rb | 1 + config/locales/waiter.en.yml | 4 ++ config/locales/waiter.nl.yml | 4 ++ config/routes.rb | 1 + 24 files changed, 128 insertions(+), 48 deletions(-) rename app/assets/javascripts/supplier/{application.js => application.js.erb} (90%) rename app/assets/javascripts/{supplier => }/translations.js.erb (94%) create mode 100644 app/assets/javascripts/waiter/app/controllers/section_controller.js.coffee create mode 100644 app/assets/javascripts/waiter/app/templates/section_header.emblem create mode 100644 app/assets/javascripts/waiter/app/views/section_header_view.js.coffee delete mode 100644 app/assets/javascripts/waiter/application.js.coffee create mode 100644 app/assets/javascripts/waiter/application.js.coffee.erb create mode 100644 app/models/employee.rb create mode 100644 config/locales/waiter.en.yml create mode 100644 config/locales/waiter.nl.yml diff --git a/app/assets/javascripts/supplier/application.js b/app/assets/javascripts/supplier/application.js.erb similarity index 90% rename from app/assets/javascripts/supplier/application.js rename to app/assets/javascripts/supplier/application.js.erb index 059a4cc4..9b13e5fb 100644 --- a/app/assets/javascripts/supplier/application.js +++ b/app/assets/javascripts/supplier/application.js.erb @@ -18,6 +18,7 @@ // require bootstrap-typeahead //= require bootstrap //= require js-routes +//= require translations //= require qwaiter //= require ./qsupplier //= require handlebars @@ -28,6 +29,9 @@ //= require_self //= require moment var Qstorage = localStorage; + +$.extend($translations.en, <%= I18n.t('supplier', locale: :en).to_json %>); +$.extend($translations.nl, <%= I18n.t('supplier', locale: :nl).to_json %>); String.prototype.capitalize = function() { return this.charAt(0).toUpperCase() + this.slice(1); } diff --git a/app/assets/javascripts/supplier/translations.js.erb b/app/assets/javascripts/translations.js.erb similarity index 94% rename from app/assets/javascripts/supplier/translations.js.erb rename to app/assets/javascripts/translations.js.erb index d9ad6b6b..e68b1013 100644 --- a/app/assets/javascripts/supplier/translations.js.erb +++ b/app/assets/javascripts/translations.js.erb @@ -1,17 +1,15 @@ -var $translations = { +$translations = { en: { models: <%= I18n.t('activemodel.models', locale: :en).to_json %>, attributes: <%= I18n.t('activemodel.attributes', locale: :en).to_json %>, helpers: <%= I18n.t('helpers', locale: :en).to_json %>, pagination: <%= I18n.t('views.pagination', locale: :en).to_json %>, - <%= I18n.t('supplier', locale: :en).to_json[1..-2] %> }, nl: { models: <%= I18n.t('activemodel.models', locale: :nl).to_json %>, attributes: <%= I18n.t('activemodel.attributes', locale: :nl).to_json %>, helpers: <%= I18n.t('helpers', locale: :nl).to_json %>, pagination: <%= I18n.t('views.pagination', locale: :nl).to_json %>, - <%= I18n.t('supplier', locale: :nl).to_json[1..-2] %> } } diff --git a/app/assets/javascripts/waiter/app/controllers/product_categories_controller.js.coffee b/app/assets/javascripts/waiter/app/controllers/product_categories_controller.js.coffee index f9175dda..f7433282 100644 --- a/app/assets/javascripts/waiter/app/controllers/product_categories_controller.js.coffee +++ b/app/assets/javascripts/waiter/app/controllers/product_categories_controller.js.coffee @@ -1,8 +1,9 @@ App.ProductCategoriesController = Ember.ArrayController.extend - needs: ['table'] + #needs: ['table'] actions: addProduct: (product)-> - if table = @get('controllers.table.model') + if table_route = App.Router.router.currentHandlerInfos.find((r) -> r.name == 'table') + table = table_route.context if existing = @store.all('product_order').find((po)->po.get('table') == table and po.get('product') == product) existing.increment() else diff --git a/app/assets/javascripts/waiter/app/controllers/section_controller.js.coffee b/app/assets/javascripts/waiter/app/controllers/section_controller.js.coffee new file mode 100644 index 00000000..8fa0090f --- /dev/null +++ b/app/assets/javascripts/waiter/app/controllers/section_controller.js.coffee @@ -0,0 +1 @@ +App.SectionController = Ember.ObjectController.extend {} diff --git a/app/assets/javascripts/waiter/app/controllers/sections_controller.js.coffee b/app/assets/javascripts/waiter/app/controllers/sections_controller.js.coffee index d00a25da..c2ea38a5 100644 --- a/app/assets/javascripts/waiter/app/controllers/sections_controller.js.coffee +++ b/app/assets/javascripts/waiter/app/controllers/sections_controller.js.coffee @@ -1 +1,2 @@ -App.SectionsController = Ember.ArrayController.extend {} +App.SectionsController = Ember.ArrayController.extend + needs: ['section'] diff --git a/app/assets/javascripts/waiter/app/controllers/table_controller.js.coffee b/app/assets/javascripts/waiter/app/controllers/table_controller.js.coffee index 01e34c87..065427dc 100644 --- a/app/assets/javascripts/waiter/app/controllers/table_controller.js.coffee +++ b/app/assets/javascripts/waiter/app/controllers/table_controller.js.coffee @@ -5,4 +5,19 @@ App.TableController = Ember.ObjectController.extend actions: clearProductOrders: -> - @get('product_orders').every (product_order)->product_order.deleteRecord() + @get('product_orders').toArray().forEach (product_order)-> + product_order.unloadRecord() + orderProducts: -> + orders = @get('product_orders').toArray() + data = orders.map( (order)->order.serialize() ) + dataObject = {order: {}} + for product_order in data + dataObject['table_id'] = product_order.table_id + dataObject['order'][product_order.product_id] = product_order.quantity + $.ajax + url: Routes.order_products_waiter_path(), + type: "POST", + data: JSON.stringify(dataObject), + contentType: "application/json", + dataType: 'json' + orders.invoke 'unloadRecord' diff --git a/app/assets/javascripts/waiter/app/router.js.coffee b/app/assets/javascripts/waiter/app/router.js.coffee index 3ad4b076..6cab8ec3 100644 --- a/app/assets/javascripts/waiter/app/router.js.coffee +++ b/app/assets/javascripts/waiter/app/router.js.coffee @@ -1,7 +1,7 @@ # For more information see: http://emberjs.com/guides/routing/ # and for queryParams: https://github.com/alexspeller/website/blob/a96d9afe4506454b155cc64299e86e558ce3c9f1/source/guides/routing/query-params.md App.Router.reopen - location: 'history' + #location: 'history' rootURL: '/waiter' App.Router.map -> diff --git a/app/assets/javascripts/waiter/app/templates/product_categories.emblem b/app/assets/javascripts/waiter/app/templates/product_categories.emblem index 8e63726c..72916756 100644 --- a/app/assets/javascripts/waiter/app/templates/product_categories.emblem +++ b/app/assets/javascripts/waiter/app/templates/product_categories.emblem @@ -1,4 +1,3 @@ -h2 Food! each product_category in controller if product_category.products h5= product_category.name diff --git a/app/assets/javascripts/waiter/app/templates/section.emblem b/app/assets/javascripts/waiter/app/templates/section.emblem index 270aee71..3472b409 100644 --- a/app/assets/javascripts/waiter/app/templates/section.emblem +++ b/app/assets/javascripts/waiter/app/templates/section.emblem @@ -1,6 +1,5 @@ .row .section-tables.small-12.medium-6.large-4.columns - h2 Tables each table in tables = link-to 'table' table class="panel section-table" = table.number diff --git a/app/assets/javascripts/waiter/app/templates/section_header.emblem b/app/assets/javascripts/waiter/app/templates/section_header.emblem new file mode 100644 index 00000000..c55e588f --- /dev/null +++ b/app/assets/javascripts/waiter/app/templates/section_header.emblem @@ -0,0 +1,2 @@ += link-to 'section' this + = title diff --git a/app/assets/javascripts/waiter/app/templates/sections.emblem b/app/assets/javascripts/waiter/app/templates/sections.emblem index d9c6747f..b76488fa 100644 --- a/app/assets/javascripts/waiter/app/templates/sections.emblem +++ b/app/assets/javascripts/waiter/app/templates/sections.emblem @@ -1,9 +1,7 @@ dl.sub-nav - dt Section: + dt= t 'model.section' each section in controller - dd - = link-to 'section' section - = section.title + view App.SectionHeaderView context=section else dd No available sections hr diff --git a/app/assets/javascripts/waiter/app/templates/table.emblem b/app/assets/javascripts/waiter/app/templates/table.emblem index 3a4d633c..2024fc78 100644 --- a/app/assets/javascripts/waiter/app/templates/table.emblem +++ b/app/assets/javascripts/waiter/app/templates/table.emblem @@ -2,7 +2,8 @@ hr.hide-for-large-up if product_orders a.tiny.button.right{action clearProductOrders} href="#" x h4 - | Table + = t 'models.table' + | = number .panel ul.product-orders @@ -17,3 +18,5 @@ h4 li.total | Total span.currency=currency orderTotal +if product_orders + a.tiny.button.right{action orderProducts} href="#" = t 'product_orders.order_button' diff --git a/app/assets/javascripts/waiter/app/views/section_header_view.js.coffee b/app/assets/javascripts/waiter/app/views/section_header_view.js.coffee new file mode 100644 index 00000000..3ba1f968 --- /dev/null +++ b/app/assets/javascripts/waiter/app/views/section_header_view.js.coffee @@ -0,0 +1,8 @@ +App.SectionHeaderView = Ember.View.extend + templateName: 'section_header' + tagName: 'dd' + classNameBindings: ['active'] + + active: (-> + if @get('context.id') == @get('controller.controllers.section.model.id') then 'active' else '' + ).property('controller.controllers.section.model.id') diff --git a/app/assets/javascripts/waiter/application.js.coffee b/app/assets/javascripts/waiter/application.js.coffee deleted file mode 100644 index ff2f0a05..00000000 --- a/app/assets/javascripts/waiter/application.js.coffee +++ /dev/null @@ -1,7 +0,0 @@ -#= require jquery -#= require jquery_ujs -#= require ./app/application -#= require foundation -#= require_directory . -#= require_self -$(document).foundation() diff --git a/app/assets/javascripts/waiter/application.js.coffee.erb b/app/assets/javascripts/waiter/application.js.coffee.erb new file mode 100644 index 00000000..e72abda6 --- /dev/null +++ b/app/assets/javascripts/waiter/application.js.coffee.erb @@ -0,0 +1,15 @@ +#= require jquery +#= require jquery_ujs +#= require ./app/application +#= require foundation +#= require moment +#= require jquery.ui.datepicker +#= require translations +#= require js-routes +#= require_directory . +#= require_self +@Qstorage = localStorage +$.extend($translations.en, <%= I18n.t('waiter', locale: :en).to_json %>); +$.extend($translations.nl, <%= I18n.t('waiter', locale: :nl).to_json %>); +$(document).foundation() +setLocale('en') diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index e0888c9e..1d8d0d59 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -286,12 +286,12 @@ class UserController < ApplicationController respond_to do |format| format.html do redirect_to(user_root_path, alert: t('messages.cannot_order_on_non_active_list')) and return unless @list.active? - @list.place_order current_user, params[:products] + @list.place_order params[:products], user: current_user redirect_to user_root_path, notice: t('messages.order_is_placed') end format.json do render json: json_alert('messages.cannot_order_on_non_active_list') and return unless @list.active? - @list.place_order current_user, params[:products] + @list.place_order params[:products], user: current_user render json: json_notice('messages.order_is_placed', location: :active_list) end end diff --git a/app/controllers/waiter_controller.rb b/app/controllers/waiter_controller.rb index ebd287fc..0c21c13c 100644 --- a/app/controllers/waiter_controller.rb +++ b/app/controllers/waiter_controller.rb @@ -18,4 +18,19 @@ class WaiterController < ApplicationController format.json { render json: ProductCategory.all.include_relation(:product), root: 'product_categories', each_serializer: ProductCategorySerializer } end end + + def order_products + @table= Table.find_by_supplier_id_and_id!(current_supplier.id, params[:table_id]) + @list = List.from_table_by_employee(@table, current_employee) + @list.place_order params[:order], employee: current_employee + render nothing: true + end + + def current_supplier + @current_supplier ||= Supplier.first + end + + def current_employee + @current_employee ||= current_supplier.employees.first + end end diff --git a/app/models/employee.rb b/app/models/employee.rb new file mode 100644 index 00000000..fe1db8b0 --- /dev/null +++ b/app/models/employee.rb @@ -0,0 +1,10 @@ +class Employee + include SimplyStored::Couch + + devise :database_authenticatable, :recoverable, :rememberable, :trackable #, :omniauthable, :omniauth_providers => [:facebook] #, :token_authenticatable , :registerable + + belongs_to :supplier + has_many :orders + has_and_belongs_to_many :lists, storing_keys: false + +end diff --git a/app/models/list.rb b/app/models/list.rb index 7f8b7f6a..9ed27682 100644 --- a/app/models/list.rb +++ b/app/models/list.rb @@ -17,6 +17,7 @@ class List belongs_to :supplier belongs_to :section has_and_belongs_to_many :users, storing_keys: true + has_and_belongs_to_many :employees, storing_keys: true attr_protected :supplier_id @@ -76,6 +77,17 @@ class List list end + # Create, a list given a table and a employee + def self.from_table_by_employee table, employee + unless list = table.active_list + list = new table: table, section_id: table.section_id + list.supplier_id = table.supplier_id + list.add_employee employee + list.save + end + list + end + def self.for_supplier(supplier, options = {}) total_entries = database.view(for_supplier_view({startkey: ["#{supplier.id}\u9999"], endkey: [supplier.id], include_docs: false, reduce: true, descending: true})) options[:total_entries] = total_entries @@ -142,9 +154,7 @@ class List def needs_help! self.needs_help = true if save - for user_id in user_ids - broadcast_user user_id, 'list_needs_help', id: id - end + broadcast_users 'list_needs_help', id: id broadcast_supplier(supplier_id, 'list_needs_help', id: id) end end @@ -152,9 +162,7 @@ class List def is_helped! self.needs_help = false if save - for user_id in user_ids - broadcast_user user_id, 'list_helped', id: id - end + broadcast_users 'list_helped', id: id broadcast_supplier supplier_id, 'list_helped', id: id end end @@ -162,9 +170,7 @@ class List def needs_payment! self.needs_payment = true if save - for user_id in user_ids - broadcast_user user_id, 'list_needs_payment', id: id - end + broadcast_users 'list_needs_payment', id: id broadcast_supplier supplier_id, 'list_needs_payment', id: id end end @@ -173,9 +179,7 @@ class List self.is_paid = true self.paid_at ||= Time.now if save - for user_id in user_ids - broadcast_user user_id, 'list_is_paid', id: id - end + broadcast_users 'list_is_paid', id: id broadcast_supplier supplier_id, 'list_is_paid', id: id end end @@ -192,9 +196,7 @@ class List order.section_id = self.section_id order.save end - for user_id in user_ids - broadcast_user user_id, 'list_changed_table', list: as_json, section_title: to_table.section.try(:title), from_table_id: from_table - end + broadcast_users 'list_changed_table', list: as_json, section_title: to_table.section.try(:title), from_table_id: from_table broadcast_supplier supplier_id, 'list_changed_table', list: as_json, section_title: to_table.section.try(:title), from_table_id: from_table end end @@ -214,7 +216,7 @@ class List def unlink_user(user) changed = join_requests.delete(user.id) - changed ||= user_ids.delete(user.id) + changed ||= Array.wrap(user_ids).delete(user.id) if user.active_list_id == id user.active_list_id = nil user.save @@ -265,10 +267,9 @@ class List state == 'active' end - def place_order(user, products) + def place_order(products, user: nil, employee: nil) return false unless products.any? - return false unless user - order = Order.create list: self, supplier: supplier, user: user, section_id: section_id + order = Order.create list: self, supplier: supplier, user: user, employee: employee, section_id: section_id return unless order.id orders_placed_count = supplier.increment_orders_placed_count! loaded_products = self.class.database.load_document products.keys @@ -279,16 +280,23 @@ class List end set_price save - for user_id in user_ids - broadcast_user user_id, 'new_order', order: order.with_products_as_json, total_amount: price - broadcast_user user_id, 'orders_placed_count', count: orders_placed_count - end + + + broadcast_users 'new_order', order: order.with_products_as_json, total_amount: price + broadcast_users 'orders_placed_count', count: orders_placed_count + broadcast_supplier supplier.id, 'list_update', active_model_serializer.new(self).as_json broadcast_supplier supplier.id, 'new_order', OrderSerializer.new(order) broadcast_supplier supplier.id, 'orders_placed_count', count: orders_placed_count order end + def broadcast_users(message, content = {}) + for user_id in Array.wrap(user_ids) + broadcast_user user_id, message, content + end + end + def as_json(*args) super.merge(id: id, table_number: table_number, has_active_orders: has_active_orders? ) end diff --git a/app/models/order.rb b/app/models/order.rb index 66db8fe3..7f871dad 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -8,11 +8,11 @@ class Order belongs_to :user belongs_to :supplier belongs_to :section + belongs_to :employee has_many :product_orders, dependent: :destroy #has_many :products, through: :product_orders validates :supplier_id, presence: true - validates :user_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')){ diff --git a/app/models/supplier.rb b/app/models/supplier.rb index 88db232c..16159e95 100644 --- a/app/models/supplier.rb +++ b/app/models/supplier.rb @@ -29,6 +29,7 @@ class Supplier #has_many :lists, through: :tables has_many :orders, dependent: :destroy has_many :sections, dependent: :destroy + has_many :employees after_create :add_section_on_create diff --git a/config/locales/waiter.en.yml b/config/locales/waiter.en.yml new file mode 100644 index 00000000..8cd5e6f7 --- /dev/null +++ b/config/locales/waiter.en.yml @@ -0,0 +1,4 @@ +en: + waiter: + product_orders: + order_button: Order diff --git a/config/locales/waiter.nl.yml b/config/locales/waiter.nl.yml new file mode 100644 index 00000000..76045c62 --- /dev/null +++ b/config/locales/waiter.nl.yml @@ -0,0 +1,4 @@ +nl: + waiter: + product_orders: + order_button: Bestel diff --git a/config/routes.rb b/config/routes.rb index 22a28146..930809cd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -30,6 +30,7 @@ Qwaiter::Application.routes.draw do get '/waiter/sections' => 'waiter#sections' get '/waiter/product_categories' => 'waiter#product_categories' get '/waiter/*rest' => redirect('/waiter') # Ember app refresh + post '/waiter/order_products' => 'waiter#order_products', as: :order_products_waiter post '/supplier/close_list' => 'supplier#close_list', as: :supplier_close_list