Merge branch 'master' of uflows.com:/var/git/qwaiter
This commit is contained in:
@@ -44,3 +44,5 @@ erl_crash.dump
|
||||
/.project
|
||||
# dia
|
||||
/*.autosave
|
||||
/db/data
|
||||
/db/config
|
||||
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
GIT
|
||||
remote: git://github.com/bterkuile/cmtool.git
|
||||
revision: e937070277ae7d44e37de85864f91a1fc779f093
|
||||
revision: 1b82ab178409684e504e70b6403bc4eb8425c432
|
||||
specs:
|
||||
cmtool (1.0.0)
|
||||
bourbon
|
||||
@@ -101,7 +101,7 @@ GEM
|
||||
bcrypt (3.1.10)
|
||||
binding_of_caller (0.7.2)
|
||||
debug_inspector (>= 0.0.1)
|
||||
bourbon (4.2.1)
|
||||
bourbon (4.2.2)
|
||||
sass (~> 3.4)
|
||||
thor
|
||||
builder (3.2.2)
|
||||
@@ -239,7 +239,7 @@ GEM
|
||||
ruby-progressbar (~> 1.4)
|
||||
gherkin (2.12.2)
|
||||
multi_json (~> 1.3)
|
||||
globalid (0.3.3)
|
||||
globalid (0.3.4)
|
||||
activesupport (>= 4.1.0)
|
||||
handlebars-source (1.3.0)
|
||||
hashie (3.4.0)
|
||||
@@ -341,7 +341,7 @@ GEM
|
||||
rails-assets-qunit (1.17.1)
|
||||
rails-deprecated_sanitizer (1.0.3)
|
||||
activesupport (>= 4.2.0.alpha)
|
||||
rails-dom-testing (1.0.5)
|
||||
rails-dom-testing (1.0.6)
|
||||
activesupport (>= 4.2.0.beta, < 5.0)
|
||||
nokogiri (~> 1.6.0)
|
||||
rails-deprecated_sanitizer (>= 1.0.1)
|
||||
@@ -440,7 +440,7 @@ GEM
|
||||
eventmachine (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
thor (0.19.1)
|
||||
thread_safe (0.3.4)
|
||||
thread_safe (0.3.5)
|
||||
tilt (1.4.1)
|
||||
timers (4.0.1)
|
||||
hitimes
|
||||
|
||||
@@ -24,8 +24,11 @@ App.MenuProductComponent = Ember.Component.extend
|
||||
makeEditable: -> @set('editMode', true)
|
||||
save: ->
|
||||
return unless @get('product.isValid')
|
||||
@get('product.product_variants').forEach (product_variant)->
|
||||
product_variant.save() if product_variant.get('isDirty')
|
||||
if @get('product.isDirty')
|
||||
@get('product').save().then((=> @set 'editMode', false), (-> true))
|
||||
@get('product').save()
|
||||
@set 'editMode', false
|
||||
destroyProduct: (product)->
|
||||
if product.get('isNew')
|
||||
product.deleteRecord()
|
||||
@@ -38,8 +41,15 @@ App.MenuProductComponent = Ember.Component.extend
|
||||
if @get('product.isNew')
|
||||
@get('product').deleteRecord()
|
||||
else
|
||||
@get('product.product_variants').forEach (product_variant)->
|
||||
product_variant.rollback()
|
||||
@get('product').rollback()
|
||||
@set 'editMode', false
|
||||
addProductVariant: ->
|
||||
product_variant = @get('targetObject.store').createRecord('product_variant')
|
||||
@get('product.product_variants').addObject product_variant
|
||||
removeProductVariant: (product_variant)->
|
||||
product_variant.destroyRecord()
|
||||
didInsertElement: ->
|
||||
@set 'editMode', true if @get('product.isNew')
|
||||
namePlaceholder: (-> t "attributes.product.name").property()
|
||||
|
||||
@@ -34,9 +34,8 @@ App.Order = DS.Model.extend
|
||||
@get('product_orders').getEach('total').reduce(((sum, total) -> sum + total), 0)
|
||||
).property('product_orders.@each.total')
|
||||
|
||||
display: (->
|
||||
@get('product_orders').map((po) -> "#{po.get('quantity')} x #{po.get('product.name')}").join(', ')
|
||||
).property('product_orders.@each.quantity', 'product_orders.@each.product.@each.name')
|
||||
display: Ember.computed 'product_orders.@each.display', ->
|
||||
@get('product_orders').map((po) -> po.get('display')).join(', ')
|
||||
|
||||
display_with_table: (->
|
||||
table = t('models.table').toLowerCase()
|
||||
|
||||
@@ -10,6 +10,7 @@ App.Product = DS.Model.extend Ember.Validations.Mixin,
|
||||
image: attr()
|
||||
product_category: DS.belongsTo('product_category')
|
||||
product_orders: DS.hasMany('product_order')
|
||||
product_variants: DS.hasMany('product_variant')
|
||||
|
||||
image_src: (->
|
||||
image = @get('image')
|
||||
@@ -18,6 +19,12 @@ App.Product = DS.Model.extend Ember.Validations.Mixin,
|
||||
image
|
||||
).property('image')
|
||||
|
||||
sorted_product_variants: Ember.computed 'product_variants.@each.name', 'product_variants.@each.position', ->
|
||||
@get('product_variants').sortBy('position')
|
||||
|
||||
variantsDisplay: Ember.computed 'sorted_product_variants', ->
|
||||
@get('sorted_product_variants').mapBy('name').join(', ')
|
||||
|
||||
#isValid: (->
|
||||
#return false unless price = @get('price')
|
||||
#return false unless "#{price}".match(/^[+-]?\d+(\.?\d?\d)?$/)
|
||||
|
||||
@@ -2,8 +2,14 @@ attr = DS.attr
|
||||
App.ProductOrder = DS.Model.extend
|
||||
quantity: attr 'number', defaultValue: 1
|
||||
price: attr 'number'
|
||||
product_variant: attr('string')
|
||||
product: DS.belongsTo('product', async: true)
|
||||
order: DS.belongsTo('order')
|
||||
increment: ->
|
||||
@set('quantity', @get('quantity') + 1)
|
||||
total: (-> @get('quantity') * @get('price')).property('quantity', 'price')
|
||||
display: Ember.computed 'quantity', 'product_variant', 'product.name', ->
|
||||
disp = "#{@get('quantity')} x #{@get('product.name')}"
|
||||
if variant = @get('product_variant')
|
||||
disp = "#{disp} (#{variant})"
|
||||
disp.htmlSafe()
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
attr = DS.attr
|
||||
App.ProductVariant = DS.Model.extend Ember.Validations.Mixin,
|
||||
name: attr 'string'
|
||||
product: DS.belongsTo 'product'
|
||||
position: attr 'number', defaultValue: 0
|
||||
validations:
|
||||
name:
|
||||
presence: true
|
||||
@@ -3,14 +3,14 @@ if editMode
|
||||
.small-6.medium-3.columns.name
|
||||
= input value=product.name placeholder=namePlaceholder action="save"
|
||||
= errors product.errors.name
|
||||
.small-6.medium-3.columns.actions
|
||||
a.rollback-product-action{action "rollbackProduct"}: span
|
||||
a.destroy-product-action{action "destroyProduct" product}: span
|
||||
a.save-product-action{action "save"}: span
|
||||
.small-6.medium-3.columns.price
|
||||
= edit-currency value=product.price action="save"
|
||||
= errors product.errors.price
|
||||
.small-6.medium-3.columns.code= input value=product.code placeholder=codePlaceholder
|
||||
.small-6.medium-3.columns.actions
|
||||
a.rollback-product-action{action "rollbackProduct"}: span
|
||||
a.destroy-product-action{action "destroyProduct" product}: span
|
||||
a.save-product-action{action "save"}: span
|
||||
.row
|
||||
.small-3.columns= t 'attributes.product.active'
|
||||
.small-9.columns: view boolean-switch value=product.active
|
||||
@@ -21,6 +21,17 @@ if editMode
|
||||
.small-12.medium-6.columns
|
||||
= view "upload-file" name="image" accept="image/*" file=product.image
|
||||
img src=product.image_src
|
||||
each product_variant in product.product_variants
|
||||
.row
|
||||
.small-1.columns
|
||||
.small-8.medium-5.large-4.columns= input value=product_variant.name
|
||||
.small-2.medium-6.large-7.columns
|
||||
button.remove-product-variant{action "removeProductVariant" product_variant}: span
|
||||
.row
|
||||
.small-12.columns
|
||||
button.add-product-variant{ action "addProductVariant"}
|
||||
span.icon
|
||||
= t 'product_variant.add_product_variant'
|
||||
else
|
||||
if showProduct
|
||||
.row
|
||||
@@ -34,3 +45,6 @@ else
|
||||
.small-3.columns
|
||||
a.edit-product-action{action "makeEditable"}: span
|
||||
/img src=product.image_src
|
||||
if product.product_variants
|
||||
.row
|
||||
.small-12.columns= product.variantsDisplay
|
||||
|
||||
@@ -13,4 +13,4 @@ form.form-horizontal
|
||||
.form-field= number-field numericValue=number_end
|
||||
hr
|
||||
button.modal-close{action "close"}=t 'section.add_tables.modal.close_button'
|
||||
button.modal-confirm.right{action "addTables"}=t 'section.add_tables.modal.add_button'
|
||||
button.modal-confirm.right{action "ok"}=t 'section.add_tables.modal.add_button'
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
@ttry = (path, vars={})->
|
||||
@t(path, $.extend(vars, emptyWhenNotFound: true))
|
||||
|
||||
|
||||
# return translation in the form
|
||||
# <span data-t="models.table">Tafel</span>
|
||||
@tspan = (path, vars={}) -> "<span data-t='#{path}' class='translation' data-t-attributes='#{JSON.stringify(vars)}'>#{t(path, vars)}</span>"
|
||||
|
||||
@@ -4,11 +4,13 @@ App.MenuProductComponent = Ember.Component.extend
|
||||
specific_id: (-> "order-product-#{@get('product.id')}").property('product.id')
|
||||
orderProducts: false
|
||||
target: -> @get('parentView.targetObject')
|
||||
showDescriptionIcon: Ember.computed.or 'product.description', 'product.product_variants.length'
|
||||
|
||||
actions:
|
||||
addProduct: (product)->
|
||||
if existing = @target().store.all('product_order').find((po)-> po.get('product') == product and not po.get('order'))
|
||||
existing.increment()
|
||||
if product.get('product_variants.length')
|
||||
@target().modal 'product_variant_select', model: product
|
||||
else
|
||||
@target().store.createRecord 'product_order', product: product, price: product.get('price')
|
||||
product.addOrderItem()
|
||||
showProductDescription: (product)->
|
||||
@target().modal 'product_info', model: product, title: product.get('name')
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
@App.modals.ProductVariantSelectController = @App.modals.BaseController.extend
|
||||
actions:
|
||||
chooseProductVariant: (product_variant)->
|
||||
@get('model').addOrderItem(product_variant: product_variant.get('name'))
|
||||
@send 'close'
|
||||
@@ -31,10 +31,17 @@ App.ProductOrdersController = Ember.ArrayController.extend
|
||||
|
||||
#orders = @store.all('product_order').toArray()
|
||||
#data = @get('product_orders').map( (po)->po.serialize() )
|
||||
dataObject = order: {table_id: @get('controllers.table.model.id')}
|
||||
@get('product_orders').forEach (product_order)-> dataObject['order'][product_order.get('product.id')] = product_order.get('quantity')
|
||||
Ember.$.post "#{$data_host}/user/orders.json", dataObject, (response) =>
|
||||
@store.pushPayload('order', response) if response.order
|
||||
dataObject = {table_id: @get('controllers.table.model.id')}
|
||||
dataObject.product_orders = @get('product_orders').map( (po) -> po.serialize()).toArray()
|
||||
#@get('product_orders').forEach (product_order)-> dataObject['order'][product_order.get('product.id')] = product_order.get('quantity')
|
||||
Ember.$.ajax
|
||||
type: 'POST'
|
||||
dataType: 'json'
|
||||
contentType: 'application/json'
|
||||
url: "#{$data_host}/user/orders.json"
|
||||
data: JSON.stringify(dataObject)
|
||||
success: (response) =>
|
||||
@store.pushPayload('order', response) if response.order
|
||||
@transitionToRoute 'active_list'
|
||||
@get('product_orders').invoke 'unloadRecord'
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
attr = DS.attr
|
||||
App.ProductVariant = DS.Model.extend
|
||||
name: attr 'string'
|
||||
product: DS.belongsTo 'product'
|
||||
position: attr 'number', defaultValue: 0
|
||||
@@ -6,5 +6,26 @@ App.Product = DS.Model.extend
|
||||
position: attr('number', defaultValue: 0)
|
||||
active: attr 'boolean', defaultValue: true
|
||||
image: attr()
|
||||
product_category: DS.belongsTo('product_category')
|
||||
product_orders: DS.hasMany('product_order')
|
||||
product_category: DS.belongsTo('product-category')
|
||||
product_orders: DS.hasMany('product-order')
|
||||
product_variants: DS.hasMany 'product-variant'
|
||||
sorted_product_variants: Ember.computed 'product_variants.@each.name', 'product_variants.@each.position', ->
|
||||
@get('product_variants').sortBy('position')
|
||||
|
||||
variantsDisplay: Ember.computed 'sorted_product_variants', ->
|
||||
@get('sorted_product_variants').mapBy('name').join(', ')
|
||||
|
||||
addOrderItem: (options = {})->
|
||||
#if existing = @store.all('product_order').find((po)-> po.get('product') == product and not po.get('order'))
|
||||
if options.product_variant
|
||||
existing = @get('product_orders').find( (po)-> !po.get('order') and po.get('product_variant') is options.product_variant )
|
||||
else
|
||||
existing = @get('product_orders').find( (po)-> !po.get('order') )
|
||||
|
||||
if existing
|
||||
existing.increment()
|
||||
else
|
||||
@store.createRecord 'product_order',
|
||||
product: this
|
||||
price: @get('price')
|
||||
product_variant: options.product_variant
|
||||
|
||||
@@ -4,12 +4,17 @@ App.ProductOrder = DS.Model.extend
|
||||
price: attr 'number'
|
||||
product_name: attr('string')
|
||||
product: DS.belongsTo('product')
|
||||
product_variant: attr('string')
|
||||
order: DS.belongsTo('order')
|
||||
placed: attr('boolean', defaultValue: false) # virtual attribute for new orders to be placed, should be more elegant
|
||||
increment: ->
|
||||
@set('quantity', @get('quantity') + 1)
|
||||
total: (-> @get('quantity') * @get('price')).property('quantity', 'price')
|
||||
display: (-> "#{@get('quantity')} x #{@get('product.name')}").property('quantity', 'product.name')
|
||||
display: Ember.computed 'quantity', 'product_variant', 'product.name', ->
|
||||
disp = "#{@get('quantity')} x #{@get('product.name')}"
|
||||
if variant = @get('product_variant')
|
||||
disp = "#{disp} (#{variant})"
|
||||
disp.htmlSafe()
|
||||
setOrder: (order)->
|
||||
@set('placed', true)
|
||||
@set('order', order)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
if product.description
|
||||
if showDescriptionIcon
|
||||
button.show-product-description{action "showProductDescription" product}
|
||||
span
|
||||
else
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
if image
|
||||
.right: img src=image.small alt=""
|
||||
p==description
|
||||
if product_variants
|
||||
h4= t 'models.plural.product_variant'
|
||||
ul
|
||||
each product_variant in product_variants
|
||||
li= product_variant.name
|
||||
hr
|
||||
button{action "close"}= t 'modal.info.close'
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
if model.image
|
||||
.right: img src=model.image.small alt=""
|
||||
each product_variant in product_variants
|
||||
.row
|
||||
.small-8.columns: a{action "chooseProductVariant" product_variant}= product_variant.name
|
||||
.small-4.columns: a.choose-product-variant-button{action "chooseProductVariant" product_variant}= t 'product_variant.choose'
|
||||
hr
|
||||
button.modal-close{action "close"}= t 'modal.info.close'
|
||||
@@ -90,6 +90,15 @@
|
||||
@extend .fa
|
||||
@extend .fa-lg
|
||||
@extend .fa-trash
|
||||
.remove-product-variant
|
||||
+push-button($bg: $alert-color, $padding: 5px)
|
||||
span
|
||||
@extend .fa, .fa-trash
|
||||
.add-product-variant
|
||||
+button($bg: $success-color, $padding: $button-tny)
|
||||
.icon
|
||||
@extend .fa, .fa-plus
|
||||
margin-right: 6px
|
||||
.error
|
||||
color: $alert-color
|
||||
input
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
.modal
|
||||
margin: auto
|
||||
margin-top: 90px
|
||||
width: 300px
|
||||
width: 90%
|
||||
max-width: 756px
|
||||
background-color: #fff
|
||||
padding: 1em
|
||||
z-index: 9085
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
.choose-product-variant-button
|
||||
+button($padding: $button-tny)
|
||||
margin: 0
|
||||
margin-bottom: 6px
|
||||
@@ -0,0 +1,66 @@
|
||||
module Suppliers
|
||||
class ProductVariantsController < Suppliers::ApplicationController
|
||||
layout 'tablet'
|
||||
|
||||
# GET /product_variants
|
||||
# GET /product_variants.json
|
||||
def index
|
||||
end
|
||||
|
||||
# GET /product_variants/1
|
||||
# GET /product_variants/1.json
|
||||
def show
|
||||
end
|
||||
|
||||
# GET /product_variants/new
|
||||
# GET /product_variants/new.json
|
||||
def new
|
||||
end
|
||||
|
||||
# GET /product_variants/1/edit
|
||||
def edit
|
||||
end
|
||||
|
||||
# POST /product_variants
|
||||
# POST /product_variants.json
|
||||
def create
|
||||
@product_variant = ProductVariant.new(product_variant_params)
|
||||
@product_variant.supplier = current_supplier
|
||||
if @product_variant.save
|
||||
render json: @product_variant
|
||||
else
|
||||
render json: {errors: @product_variant.errors}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
# PUT /product_variants/1
|
||||
# PUT /product_variants/1.json
|
||||
def update
|
||||
@product_variant = ProductVariant.find(params[:id])
|
||||
head :unprocessable_entity and return unless product_id = product_variant_params[:product_id]
|
||||
product = Product.find(product_id)
|
||||
head :forbidden and return unless product.supplier_id == current_supplier.id
|
||||
|
||||
if @product_variant.update_attributes(product_variant_params)
|
||||
render json: @product_variant
|
||||
else
|
||||
render json: {errors: @product_variant.errors}, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE /product_variants/1
|
||||
# DELETE /product_variants/1.json
|
||||
def destroy
|
||||
#@product_variant = ProductVariant.find_by_supplier_id_and_id!(current_supplier.id, params[:id])
|
||||
@product_variant = ProductVariant.find(params[:id])
|
||||
@product_variant.destroy
|
||||
render json: {}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def product_variant_params
|
||||
params.require(:product_variant).permit(:name, :product_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,7 +5,7 @@ module Suppliers
|
||||
end
|
||||
|
||||
def show
|
||||
[current_supplier].include_relations(sections: :tables, product_categories: :products)
|
||||
[current_supplier].include_relations(sections: :tables, product_categories: {products: :product_variants})
|
||||
render json: current_supplier, serializer: Suppliers::SupplierSerializer #.new(current_supplier).as_json
|
||||
end
|
||||
|
||||
|
||||
@@ -6,9 +6,6 @@ module Users
|
||||
# POST /user/orders
|
||||
def create
|
||||
# render json: {}, status: :unprocessable_entity and return unless params[:order].present? && params[:order][:product_orders].present?
|
||||
# converted_order = params[:order][:product_orders].each_with_object({}){|po, o| o[po[:product_id]] = po[:quantity] }
|
||||
converted_order = params[:order]
|
||||
table_id = params[:order].delete('table_id')
|
||||
if list = current_user.active_list
|
||||
render json: {}, status: :not_acceptable and return unless list.supplier.open?
|
||||
else
|
||||
@@ -16,8 +13,8 @@ module Users
|
||||
#NOTE: security bug here!!!!!!
|
||||
# - supplier.open?
|
||||
# - etc....
|
||||
render json: {}, status: :unprocessable_entity and return unless table_id.present?
|
||||
table = Table.find(table_id)
|
||||
render json: {}, status: :unprocessable_entity and return unless params[:table_id].present?
|
||||
table = Table.find(params[:table_id])
|
||||
render json: {}, status: :not_acceptable and return unless table.supplier.open?
|
||||
|
||||
if table.occupied?
|
||||
@@ -27,8 +24,8 @@ module Users
|
||||
|
||||
list = List.from_table( table, current_user )
|
||||
end
|
||||
order = list.place_order products: converted_order, user: current_user
|
||||
render json: order, serializer: OrderSerializer
|
||||
order = list.place_order product_orders: params[:product_orders], user: current_user
|
||||
render json: order, serializer: OrderSerializer
|
||||
#render nothing: true
|
||||
end
|
||||
end
|
||||
|
||||
+10
-6
@@ -9,7 +9,10 @@ class Employee
|
||||
}
|
||||
DEFAULT_SETTINGS.each do |attribute, default_value|
|
||||
define_method(attribute) { settings.public_send attribute }
|
||||
define_method("#{attribute}=") { |value| settings.set attribute, value }
|
||||
define_method("#{attribute}=") do |value|
|
||||
is_dirty
|
||||
settings.set attribute, value
|
||||
end
|
||||
if default_value == true or default_value == false # boolean
|
||||
define_method(:"#{attribute}?"){ public_send attribute }
|
||||
end
|
||||
@@ -44,11 +47,12 @@ class Employee
|
||||
end
|
||||
alias_method :settings=, :enrich_with_settings
|
||||
|
||||
alias_method :orig_save, :save
|
||||
def save(*args)
|
||||
settings.persist!
|
||||
orig_save(*args)
|
||||
end
|
||||
#alias_method :orig_save, :save
|
||||
#def save(*args)
|
||||
#settings.persist!
|
||||
#orig_save(*args)
|
||||
#end
|
||||
before_save { settings.persist! }
|
||||
|
||||
def settings
|
||||
@settings || SupplierEmployeesSettings.new(Supplier.new).for_employee(self)
|
||||
|
||||
+20
-7
@@ -17,6 +17,7 @@ class List
|
||||
belongs_to :table
|
||||
belongs_to :supplier
|
||||
belongs_to :section
|
||||
has_many :list_payments
|
||||
has_and_belongs_to_many :users, storing_keys: true
|
||||
has_and_belongs_to_many :employees, storing_keys: true
|
||||
|
||||
@@ -274,16 +275,28 @@ class List
|
||||
state == 'active'
|
||||
end
|
||||
|
||||
def place_order(products: {}, user: nil, employee: nil)
|
||||
return false unless products.any?
|
||||
def closed?
|
||||
state == 'closed'
|
||||
end
|
||||
|
||||
def place_order(product_orders: [], user: nil, employee: nil)
|
||||
return false unless product_orders.any?
|
||||
order = Order.create list: self, supplier: supplier, user: user, employee: employee, section_id: section_id, table_id: table_id
|
||||
return unless order.id
|
||||
orders_placed_count = supplier.increment_orders_placed_count!
|
||||
loaded_products = self.class.database.load_document products.keys
|
||||
products.each do |product_id, quantity|
|
||||
product = loaded_products.find{|p| p.id == product_id} # to get the price
|
||||
if quantity.to_i > 0
|
||||
ProductOrder.create(order: order, product_id: product_id, quantity: quantity, price: product.price, product_name: product.name)
|
||||
loaded_products = self.class.database.load_document product_orders.map{|po| po['product_id']}
|
||||
product_orders.each do |product_order|
|
||||
next unless product = loaded_products.find{|p| p.id == product_order['product_id']} # to get the price
|
||||
quantity = product_order['quantity'].to_i
|
||||
if quantity > 0
|
||||
ProductOrder.create(
|
||||
order: order,
|
||||
product_id: product.id,
|
||||
quantity: quantity,
|
||||
price: product.price,
|
||||
product_name: product.name,
|
||||
product_variant: product_order['product_variant']
|
||||
)
|
||||
end
|
||||
end
|
||||
set_price
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
class ListPayment
|
||||
include SimplyStored::Couch
|
||||
include ActiveModel::SerializerSupport
|
||||
property :amount
|
||||
property :source # bitcoin, apple_pay, etc...
|
||||
belongs_to :list
|
||||
belongs_to :user
|
||||
|
||||
after_save :close_list_when_is_paid
|
||||
validates :list_id, presence: true
|
||||
|
||||
def close_list_when_is_paid
|
||||
amount_paid = list.list_payments.inject(0.0){|sum, payment| sum + payment.amount}
|
||||
list.close! if amount_paid >= list.price
|
||||
end
|
||||
end
|
||||
@@ -15,6 +15,7 @@ class Product
|
||||
#has_and_belongs_to_many :product_categories, storing_keys: false
|
||||
belongs_to :supplier # direct! category is an aid
|
||||
has_many :product_orders
|
||||
has_many :product_variants, dependent: :destroy
|
||||
|
||||
attr_protected :supplier_id
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ class ProductOrder
|
||||
property :quantity, type: Fixnum
|
||||
property :price, type: Float
|
||||
property :product_name
|
||||
property :product_variant
|
||||
|
||||
belongs_to :product
|
||||
belongs_to :order
|
||||
@@ -14,7 +15,8 @@ class ProductOrder
|
||||
|
||||
# Getter for product name. If a supplier deletes a product, that has product_orders, the product
|
||||
# will become nil. This method should handle this case.
|
||||
alias_method :direct_product_name, :product_name
|
||||
def product_name
|
||||
product.try(:name) || '[deleted]'
|
||||
direct_product_name.presence || product.try(:name) || '[deleted]'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
class ProductVariant
|
||||
include SimplyStored::Couch
|
||||
include ActiveModel::SerializerSupport
|
||||
property :name
|
||||
property :position, type: Fixnum, default: 0
|
||||
belongs_to :product
|
||||
belongs_to :supplier
|
||||
end
|
||||
@@ -20,6 +20,10 @@ class Supplier
|
||||
property :week_starts_on_monday, type: :boolean, default: true
|
||||
property :employee_settings_storage
|
||||
|
||||
# PAYMENT
|
||||
property :accept_bitpay, type: :boolean, default: false
|
||||
property :bitpay_number
|
||||
|
||||
#LOCATION
|
||||
property :lat, type: Float #, default: 52.08062426379751
|
||||
property :lng, type: Float #, default: 4.312562942504883
|
||||
@@ -35,6 +39,7 @@ class Supplier
|
||||
|
||||
#has_many :orders, through: :lists
|
||||
has_many :products, dependent: :destroy
|
||||
has_many :product_variants
|
||||
has_many :product_categories, dependent: :destroy
|
||||
has_many :tables, dependent: :destroy
|
||||
has_many :lists, dependent: :destroy
|
||||
|
||||
@@ -19,6 +19,7 @@ class User
|
||||
|
||||
has_and_belongs_to_many :lists, storing_keys: false
|
||||
has_many :orders
|
||||
has_many :list_payments
|
||||
|
||||
validates_uniqueness_of :email
|
||||
before_save :ensure_authentication_token
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Used for user ember1
|
||||
class ProductOrderSerializer < Qwaiter::Serializer
|
||||
attributes :order_id, :product_id, :quantity, :price, :product_name
|
||||
attributes :order_id, :product_id, :quantity, :price, :product_name, :product_variant
|
||||
end
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
class ProductSerializer < Qwaiter::Serializer
|
||||
root 'product'
|
||||
attributes :name, :price, :description, :image, :code, :position, :visible, :active, :product_category_id
|
||||
|
||||
has_many :product_variants
|
||||
|
||||
def image
|
||||
if object.image.present?
|
||||
{small: object.image.url(:small)}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
class ProductVariantSerializer < Qwaiter::Serializer
|
||||
root 'product_variant'
|
||||
attributes :name
|
||||
end
|
||||
@@ -78,3 +78,5 @@ en:
|
||||
selected_products:
|
||||
clear: Clear
|
||||
order: Order
|
||||
product_variant:
|
||||
add_product_variant: Add ${models.product_variant}
|
||||
|
||||
@@ -9,6 +9,7 @@ en:
|
||||
product: Product
|
||||
order: Order
|
||||
product_category: Product category
|
||||
product_variant: Variant
|
||||
section: Section
|
||||
join_request: Join request
|
||||
user_feedback: User feedback
|
||||
@@ -26,6 +27,7 @@ en:
|
||||
product: Products
|
||||
order: Orders
|
||||
product_category: Product categories
|
||||
product_variant: Variants
|
||||
section: Sections
|
||||
join_request: Join requests
|
||||
user_feedback: User feedbacks
|
||||
@@ -52,6 +54,8 @@ en:
|
||||
visible: Visible?
|
||||
created_at: Created
|
||||
image: Image
|
||||
product_variant:
|
||||
name: Name
|
||||
list:
|
||||
created_at: Created
|
||||
state: Status
|
||||
|
||||
@@ -9,6 +9,7 @@ nl:
|
||||
product: Product
|
||||
order: Bestelling
|
||||
product_category: Product categorie
|
||||
product_variant: Variant
|
||||
section: Afdeling
|
||||
join_request: Deelname verzoek
|
||||
employee: Werknemer
|
||||
@@ -25,6 +26,7 @@ nl:
|
||||
product: Producten
|
||||
order: Bestellingen
|
||||
product_category: Product categorieen
|
||||
product_variant: Varianten
|
||||
section: Afdelingen
|
||||
join_request: Deelname verzoeken
|
||||
employee: Werknemers
|
||||
@@ -50,6 +52,8 @@ nl:
|
||||
active: "Actief?"
|
||||
created_at: Aangemaakt
|
||||
image: Afbeelding
|
||||
product_variant:
|
||||
name: Naam
|
||||
list:
|
||||
created_at: Aangemaakt
|
||||
state: Status
|
||||
|
||||
@@ -76,6 +76,8 @@ nl:
|
||||
selected_products:
|
||||
clear: Leegmaken
|
||||
order: Bestellen
|
||||
product_variant:
|
||||
add_product_variant: ${models.product_variant} toevoegen
|
||||
views:
|
||||
pagination:
|
||||
first: "« Eerste"
|
||||
|
||||
@@ -139,6 +139,7 @@ Qwaiter::Application.routes.draw do
|
||||
get :preview_products
|
||||
end
|
||||
end
|
||||
resources :product_variants
|
||||
resources :lists do
|
||||
collection do
|
||||
get :active
|
||||
|
||||
-12183
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,8 @@
|
||||
db:
|
||||
image: bterkuile/couchdb
|
||||
volumes:
|
||||
- db:/usr/local/var/lib/couchdb
|
||||
- db/data:/usr/local/var/lib/couchdb
|
||||
- db/config:/usr/local/etc/couchdb
|
||||
expose:
|
||||
- 5984
|
||||
net: host
|
||||
|
||||
@@ -20,5 +20,5 @@ step 'a new order on a table in another section is created' do
|
||||
# @new_section = create :section, title: 'Terrace', supplier: @supplier
|
||||
# @new_table = create :table, number: 59, section: @new_section, supplier: @supplier
|
||||
@new_list = create :list, section: @other_section, table: @other_table, supplier: @supplier, user_ids: [@user.id]
|
||||
@new_order = @new_list.place_order(products: {@product.id => 3}, user: @user)
|
||||
@new_order = @new_list.place_order(product_orders: [ {'product_id' => @product.id, 'quantity' => 3}], user: @user)
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
step "A new order is placed" do
|
||||
@user ||= create :user
|
||||
@list = create :list, state: 'active', supplier: @supplier, table: @table, section: @section, user_ids: [@user.id]
|
||||
@order = @list.place_order products: {@product.id => 2}, user: @user
|
||||
@order = @list.place_order product_orders: [{ 'product_id' => @product.id, 'quantity' => 2}], user: @user
|
||||
end
|
||||
|
||||
step "an order with :quantity products :product_name should have been created" do |quantity, product_name|
|
||||
|
||||
@@ -9,7 +9,7 @@ step "the order should be marked as delivered" do
|
||||
end
|
||||
|
||||
step "another order is placed" do
|
||||
@new_order = @list.place_order(products: {@product.id => 5}, user: @user)
|
||||
@new_order = @list.place_order(product_orders: [{ 'product_id' => @product.id, 'quantity' => 5}], user: @user)
|
||||
end
|
||||
|
||||
step "the user order should be created as a new order" do
|
||||
|
||||
@@ -43,7 +43,7 @@ step "there is another signed in user on the same list" do
|
||||
end
|
||||
|
||||
step 'the other user orders a product :count times' do |count|
|
||||
@list.place_order products: {@product.id => count.to_i}, user: @other_user
|
||||
@list.place_order product_orders: [{'product_id' => @product.id, 'quantity' => count.to_i}], user: @other_user
|
||||
end
|
||||
|
||||
step 'the other user is part of the list' do
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
FactoryGirl.define do
|
||||
factory :list_payment do
|
||||
|
||||
end
|
||||
end
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
Logo-bigMozo.bar is een systeem om bestellingen te doen met je smartphone. Als je wel eens op een terras of een afgelegen deel van een horeca gelegenheid hebt gezeten en vond dat het te lang duurde voordat er iemand aan je kwam vragen wat je wil bestellen dan weet je dat er nog veel te verbeteren is.
|
||||
|
||||
Om horeca gelegenheden te helpen de vraag van klanten beter te kunnen verwerken is mozo.bar ontstaan. Mozo.bar is een toevoeging voor horeca gelegenheden om klanten met hun smartphone te laten bestellen. Dit is de focus van Mozo.bar! Om het gemak en de sfeer waar mensen aan gewend zijn te handhaven integreert Mozo.bar zo goed mogelijk met de ervaring van mensen. Klanten kunnen gewoon op een lijstje bestellen en bij ondersteunde systemen komt de bestelling gewoon achter de bar of in de keuken uitgeprint.
|
||||
|
||||
Mozo.bar is gratis om in gebruik te nemen en in een handomdraai toegevoegd als extra dienst. Maak als horeca gelegenheid een account aan. Richt deze in en je kan aan de slag!
|
||||
|
||||
Heb je een ervaring of idee waardoor we de ervaring voor zowel de horeca bezoeker als de horeca gelegenheid kunnen verbeteren mail dit dan naar: experience@mozo.bar dan kunnen wij ervoor zorgen dat het gaan naar een horeca gelegenheid leuk en makkelijk wordt!
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
<div style="position: absolute; right: 0; top: -170px; z-index: 2222;"><img src="/assets/site/tablet-phone.png" alt="" width="249" height="166" /></div>
|
||||
<p><img class="home-qr" src="/assets/qr.png" alt="Qr" width="124" height="124" />Welkom bij de mozo.bar website! Mozo.bar is een mobiele app waarmee je gemakkelijk bestellingen kan doen op terrassen, in bars of restaurants. Scan een Qr code op de tafel, en krijg meteen het menu te zien. Klik aan wat je wilt hebben en bestel. Dat is alles!</p>
|
||||
<p>Momenteel is mozo.bar in de ontwikkelingsfase. Dit houdt in dat er nog veel moet gebeuren en dat we volledig open staan voor alle input die we kunnen krijgen. Onze missie is om zowel klant als kroegeigenaar blij te maken met de mogelijkheden die deze tijd ons biedt.</p>
|
||||
<p>Schrijf je in op <a style="color: #7bb459; text-decoration: none;" href="https://www.facebook.com/mozo.bar" target="_blank">Facebook</a> of <a style="color: #7bb459; text-decoration: none;" href="https://www.twitter.com/Qwaiter" target="_blank">Twitter</a> om op de hoogte te worden gehouden.</p>
|
||||
@@ -0,0 +1,13 @@
|
||||
moduleForModel 'product', 'Product model',
|
||||
needs: [
|
||||
'model:product_variant',
|
||||
'model:product_category',
|
||||
'model:section_area',
|
||||
'model:product_order',
|
||||
'model:order',
|
||||
'model:supplier'
|
||||
]
|
||||
|
||||
#test "Nothing yet", ->
|
||||
#element = @subject()
|
||||
#assert 2, 2
|
||||
@@ -1,5 +1,5 @@
|
||||
moduleForModel 'section-element', 'Section element model',
|
||||
needs: ['model:section', 'model:table']
|
||||
needs: ['model:section', 'model:table', 'model:section-area']
|
||||
|
||||
test "box_size", ->
|
||||
element = @subject
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe ListPayment do
|
||||
it "does completes a list if amount is equal to the list amount" do
|
||||
list = create :list, price: 10.22
|
||||
create :list_payment, amount: 10.22, list: list
|
||||
list.should be_closed
|
||||
end
|
||||
it "does completes a list if amount is greater than the list amount" do
|
||||
list = create :list, price: 10.22
|
||||
create :list_payment, amount: 12, list: list
|
||||
list.should be_closed
|
||||
end
|
||||
it "does completes a list if amount is less than the list amount, but total payments on list bigger" do
|
||||
list = create :list, price: 10.22
|
||||
create :list_payment, amount: 7, list: list
|
||||
list.should be_active
|
||||
create :list_payment, amount: 7, list: list
|
||||
list.should be_closed
|
||||
end
|
||||
end
|
||||
@@ -126,30 +126,30 @@ describe List do
|
||||
describe '#place_order' do
|
||||
|
||||
it 'returns an order object' do
|
||||
list.place_order(products: {product.id => 7}, user: user).should be_a Order
|
||||
list.place_order(product_orders: [{'product_id' => product.id, 'quantity' => 7}], user: user).should be_a Order
|
||||
end
|
||||
|
||||
it 'creates an order' do
|
||||
expect{ list.place_order(products: {product.id => 7}, user: user) }.to change{ Order.count }.by(1)
|
||||
expect{ list.place_order(product_orders: [{'product_id' => product.id, 'quantity' => 7}], user: user) }.to change{ Order.count }.by(1)
|
||||
end
|
||||
|
||||
describe 'broadcasting' do
|
||||
it 'broadcasts to the user and the supplier the active order counter' do
|
||||
# create existing order
|
||||
list.place_order(products: {product.id => 7}, user: user)
|
||||
list.place_order(product_orders: [{'product_id' => product.id, 'quantity' => 7}], user: user)
|
||||
|
||||
# expect{
|
||||
# list.place_order(products: {product.id => 3}, user: user)
|
||||
# list.place_order(product_orders: [{product_id: product.id, quantity: 5}], user: user)
|
||||
# }.to broadcast_to_user(user.id).message('orders_placed_count').with(count: 2)
|
||||
|
||||
expect{
|
||||
list.place_order(products: {product.id => 5}, user: user)
|
||||
list.place_order(product_orders: [{'product_id' => product.id, 'quantity' => 5}], user: user)
|
||||
}.to broadcast_to_supplier(supplier.id).message('orders_placed_count').with(count: 2)
|
||||
end
|
||||
end
|
||||
|
||||
it 'sets the list price as kind of caching' do
|
||||
list.place_order(products: {product.id => 7}, user: user)
|
||||
list.place_order(product_orders: [{'product_id' => product.id, 'quantity' => 7}], user: user)
|
||||
list.reload
|
||||
list.price.should == 15.54
|
||||
end
|
||||
|
||||
@@ -106,6 +106,7 @@ RSpec.configure do |config|
|
||||
config.infer_base_class_for_anonymous_controllers = true
|
||||
config.filter_run_excluding broken: true
|
||||
config.render_views = true
|
||||
config.expect_with(:rspec) { |c| c.syntax = [:expect, :should] }
|
||||
|
||||
OmniAuth.config.test_mode = true
|
||||
OmniAuth.config.add_mock :facebook, {
|
||||
|
||||
Reference in New Issue
Block a user