mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-27 01:43:22 +00:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d3afe80c6 | ||
|
|
28e75d6467 | ||
|
|
b0fa05df0c | ||
|
|
f3ffba378a | ||
|
|
2d89640271 | ||
|
|
e6ee6b5164 | ||
|
|
768a170bb8 | ||
|
|
8834268970 | ||
|
|
fe61b4aab1 | ||
|
|
a6c2490597 | ||
|
|
9110dc6414 | ||
|
|
77be0dd6eb | ||
|
|
40544eb27b | ||
|
|
306cb5b089 | ||
|
|
c46613877c | ||
|
|
2db2fbcade | ||
|
|
ea05f05576 | ||
|
|
361a87f580 | ||
|
|
330c62716c | ||
|
|
63bf25293d | ||
|
|
93867682bb | ||
|
|
7d5c158021 | ||
|
|
06c6422591 | ||
|
|
5e04032797 | ||
|
|
f716176361 | ||
|
|
2826f62497 | ||
|
|
7172fe0c87 | ||
|
|
7e9a84087e | ||
|
|
58e9cd3eeb | ||
|
|
54559c4a5f | ||
|
|
8f5b5e7ae4 | ||
|
|
759ceae23f | ||
|
|
32b37a1390 | ||
|
|
0e43fcfaa1 | ||
|
|
6a27f8da32 | ||
|
|
c24543c237 | ||
|
|
44314ccb99 | ||
|
|
9ad42a3966 | ||
|
|
d34e6570fc | ||
|
|
b5b35491cc |
29
.gitignore
vendored
29
.gitignore
vendored
@@ -10,48 +10,19 @@ log/*.log.lck
|
||||
log/*.log.*
|
||||
tmp/
|
||||
.idea/*
|
||||
solr/data/
|
||||
solr/pids/
|
||||
\#*
|
||||
.#*
|
||||
*~
|
||||
*.~lock.*
|
||||
.emacs.desktop
|
||||
.DS_Store
|
||||
.emacs.desktop.lock*
|
||||
coverage
|
||||
merged_coverage
|
||||
upstream_coverage
|
||||
true/
|
||||
reports
|
||||
*.tmproj
|
||||
*tags
|
||||
dump.rdb
|
||||
bin/
|
||||
spec/javascripts/generated/*
|
||||
db/development_structure.sql
|
||||
db/test_structure.sql
|
||||
db/staging_structure.sql
|
||||
db/production_structure.sql
|
||||
db/bootstrap/*.sql
|
||||
db/bootstrap/*.dump
|
||||
db/bootstrap/*.bak
|
||||
db/bootstrap/*.pgz
|
||||
db/bootstrap/image_fixtures/*
|
||||
db/bootstrap/image_fixtures/properties/*
|
||||
public/system
|
||||
public/stylesheets
|
||||
public/images
|
||||
vendor/bundle
|
||||
config/database.Tom-Meiers-MacBook-Pro.local.yml
|
||||
config/abr.yml
|
||||
vendor/ruby
|
||||
ey-cloud-recipes/db/bootstrap/*.dump
|
||||
ey-cloud-recipes/db/bootstrap/*.pgz
|
||||
ey-cloud-recipes/db/bootstrap/image_fixtures/*
|
||||
ey-cloud-recipes/.idea/*
|
||||
chromedriver.log
|
||||
financial_reports/*.csv
|
||||
NERD_tree*
|
||||
spec/reference_images/*
|
||||
public/search
|
||||
|
||||
16
Gemfile
16
Gemfile
@@ -1,9 +1,10 @@
|
||||
source 'http://rubygems.org'
|
||||
ruby "1.9.3"
|
||||
|
||||
gem 'rails', '3.2.3'
|
||||
|
||||
gem 'pg'
|
||||
gem 'spree'
|
||||
gem 'spree', '1.1.1'
|
||||
gem 'spree_i18n', :git => 'git://github.com/spree/spree_i18n.git'
|
||||
gem 'spree_paypal_express', :git => 'git://github.com/spree/spree_paypal_express.git'
|
||||
gem 'spree_last_address', :git => 'git://github.com/dancinglightning/spree-last-address.git'
|
||||
@@ -14,6 +15,7 @@ gem 'spree_last_address', :git => 'git://github.com/dancinglightning/spree-last-
|
||||
gem 'simple_form', :git => 'git://github.com/RohanM/simple_form.git'
|
||||
|
||||
gem 'unicorn'
|
||||
gem 'bugsnag'
|
||||
gem 'spree_heroku', :git => 'git://github.com/joneslee85/spree-heroku.git'
|
||||
gem 'haml'
|
||||
gem 'aws-s3'
|
||||
@@ -33,17 +35,6 @@ end
|
||||
|
||||
gem 'jquery-rails'
|
||||
|
||||
# To use ActiveModel has_secure_password
|
||||
# gem 'bcrypt-ruby', '~> 3.0.0'
|
||||
|
||||
# Use unicorn as the web server
|
||||
# gem 'unicorn'
|
||||
|
||||
# Deploy with Capistrano
|
||||
# gem 'capistrano'
|
||||
|
||||
# To use debugger
|
||||
# gem 'ruby-debug19', :require => 'ruby-debug'
|
||||
|
||||
group :test, :development do
|
||||
# Pretty printed test output
|
||||
@@ -56,5 +47,6 @@ group :test, :development do
|
||||
gem 'database_cleaner', '0.7.1', :require => false
|
||||
gem 'spork', '~> 1.0rc'
|
||||
gem 'pry'
|
||||
gem 'awesome_print'
|
||||
end
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@ GEM
|
||||
andand (1.3.3)
|
||||
ansi (1.4.2)
|
||||
arel (3.0.2)
|
||||
awesome_print (1.0.2)
|
||||
aws-s3 (0.6.3)
|
||||
builder
|
||||
mime-types
|
||||
@@ -94,6 +95,9 @@ GEM
|
||||
bcrypt-ruby (3.0.1)
|
||||
braintree (2.16.0)
|
||||
builder (>= 2.0.0)
|
||||
bugsnag (1.1.2)
|
||||
httparty (~> 0.8.3)
|
||||
multi_json (~> 1.3.4)
|
||||
builder (3.0.0)
|
||||
cancan (1.6.7)
|
||||
capybara (1.1.2)
|
||||
@@ -322,7 +326,9 @@ PLATFORMS
|
||||
|
||||
DEPENDENCIES
|
||||
andand
|
||||
awesome_print
|
||||
aws-s3
|
||||
bugsnag
|
||||
capybara
|
||||
coffee-rails (~> 3.2.1)
|
||||
database_cleaner (= 0.7.1)
|
||||
@@ -338,7 +344,7 @@ DEPENDENCIES
|
||||
shoulda-matchers
|
||||
simple_form!
|
||||
spork (~> 1.0rc)
|
||||
spree
|
||||
spree (= 1.1.1)
|
||||
spree_heroku!
|
||||
spree_i18n!
|
||||
spree_last_address!
|
||||
|
||||
@@ -9,7 +9,7 @@ $(document).ready(function() {
|
||||
$("#quantity").change();
|
||||
|
||||
// Product page with master price only
|
||||
$(".add-to-cart input.title:not(#quantity)").change(products_update_price_without_variant).change();
|
||||
$(".add-to-cart input.title:not(#quantity):not(#max_quantity)").change(products_update_price_without_variant).change();
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ class ApplicationController < ActionController::Base
|
||||
private
|
||||
def load_data_for_sidebar
|
||||
@suppliers = Spree::Supplier.all
|
||||
@distributors = Spree::Distributor.all
|
||||
@distributors = Spree::Distributor.with_products_on_hand.by_name
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
37
app/controllers/spree/admin/reports_controller_decorator.rb
Normal file
37
app/controllers/spree/admin/reports_controller_decorator.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
require 'csv'
|
||||
require 'open_food_web/order_and_distributor_report'
|
||||
|
||||
Spree::Admin::ReportsController.class_eval do
|
||||
|
||||
Spree::Admin::ReportsController::AVAILABLE_REPORTS.merge!({:orders_and_distributors => {:name => "Orders And Distributors", :description => "Orders with distributor details"}})
|
||||
|
||||
def orders_and_distributors
|
||||
params[:q] = {} unless params[:q]
|
||||
|
||||
if params[:q][:created_at_gt].blank?
|
||||
params[:q][:created_at_gt] = Time.zone.now.beginning_of_month
|
||||
else
|
||||
params[:q][:created_at_gt] = Time.zone.parse(params[:q][:created_at_gt]).beginning_of_day rescue Time.zone.now.beginning_of_month
|
||||
end
|
||||
|
||||
if params[:q] && !params[:q][:created_at_lt].blank?
|
||||
params[:q][:created_at_lt] = Time.zone.parse(params[:q][:created_at_lt]).end_of_day rescue ""
|
||||
end
|
||||
params[:q][:meta_sort] ||= "created_at.desc"
|
||||
|
||||
@search = Spree::Order.complete.search(params[:q])
|
||||
orders = @search.result
|
||||
|
||||
@report = OpenFoodWeb::OrderAndDistributorReport.new orders
|
||||
if(!params[:csv])
|
||||
render :html => @report
|
||||
else
|
||||
csv_string = CSV.generate do |csv|
|
||||
csv << @report.header
|
||||
@report.table.each { |row| csv << row }
|
||||
end
|
||||
send_data csv_string, :filename => "orders_and_distributors.csv"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,5 +1,6 @@
|
||||
Spree::OrdersController.class_eval do
|
||||
before_filter :populate_order_distributor, :only => :populate
|
||||
after_filter :populate_variant_attributes, :only => :populate
|
||||
|
||||
def populate_order_distributor
|
||||
@distributor = params.key?(:distributor_id) ? Spree::Distributor.find(params[:distributor_id]) : nil
|
||||
@@ -14,6 +15,22 @@ Spree::OrdersController.class_eval do
|
||||
end
|
||||
end
|
||||
|
||||
def populate_variant_attributes
|
||||
if params.key? :variant_attributes
|
||||
params[:variant_attributes].each do |variant_id, attributes|
|
||||
@order.set_variant_attributes(Spree::Variant.find(variant_id), attributes)
|
||||
end
|
||||
end
|
||||
|
||||
if params.key? :quantity
|
||||
params[:products].each do |product_id, variant_id|
|
||||
max_quantity = params[:max_quantity].to_i
|
||||
@order.set_variant_attributes(Spree::Variant.find(variant_id), {:max_quantity => max_quantity})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def populate_valid? distributor
|
||||
# -- Distributor must be specified
|
||||
|
||||
@@ -7,7 +7,7 @@ module OpenFoodWeb
|
||||
|
||||
def compute(object)
|
||||
# Given an order, sum the shipping on each individual item
|
||||
object.line_items.map { |li| li.itemwise_shipping_cost }.inject(:+)
|
||||
object.line_items.map { |li| li.itemwise_shipping_cost }.inject(:+) || 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,7 +8,7 @@ module OpenFoodWeb
|
||||
end
|
||||
|
||||
def compute(object)
|
||||
total_weight = object.line_items.inject(0) { |sum, li| sum+li.variant.weight }
|
||||
total_weight = object.line_items.inject(0) { |sum, li| sum + (li.variant.weight * li.quantity) }
|
||||
total_weight * self.preferred_per_kg
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,6 +13,7 @@ module Spree
|
||||
validates_associated :pickup_address
|
||||
|
||||
scope :by_name, order('name')
|
||||
scope :with_products_on_hand, joins(:products).where('spree_products.count_on_hand > 0').select('distinct(distributors.*)')
|
||||
|
||||
after_initialize :initialize_country
|
||||
before_validation :set_unused_address_fields
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
Spree::LineItem.class_eval do
|
||||
attr_accessible :max_quantity
|
||||
|
||||
def shipping_method
|
||||
self.product.shipping_method_for_distributor(self.order.distributor)
|
||||
end
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
Spree::Order.class_eval do
|
||||
belongs_to :distributor
|
||||
|
||||
after_create :set_default_shipping_method
|
||||
|
||||
|
||||
def can_change_distributor?
|
||||
# Distributor may not be changed once an item has been added to the cart/order
|
||||
line_items.empty?
|
||||
@@ -15,11 +18,38 @@ Spree::Order.class_eval do
|
||||
can_change_distributor? || product.distributors.include?(distributor)
|
||||
end
|
||||
|
||||
def set_variant_attributes(variant, attributes)
|
||||
line_item = contains?(variant)
|
||||
|
||||
if attributes.key?(:max_quantity) && attributes[:max_quantity].to_i < line_item.quantity
|
||||
attributes[:max_quantity] = line_item.quantity
|
||||
end
|
||||
|
||||
line_item.assign_attributes(attributes)
|
||||
line_item.save!
|
||||
end
|
||||
|
||||
|
||||
|
||||
before_validation :shipping_address_from_distributor
|
||||
|
||||
private
|
||||
|
||||
# On creation of the order (when the first item is added to the user's cart), set the
|
||||
# shipping method to the first one available and create a shipment.
|
||||
# order.create_shipment! creates an adjustment for the shipping cost on the order,
|
||||
# which means that the customer can see their shipping cost at every step of the
|
||||
# checkout process, not just after the delivery step.
|
||||
# This is based on the assumption that there's only one shipping method visible to the user,
|
||||
# which is a method using the itemwise shipping calculator.
|
||||
def set_default_shipping_method
|
||||
self.shipping_method = Spree::ShippingMethod.where("display_on != 'back_end'").first
|
||||
if self.shipping_method
|
||||
self.save!
|
||||
self.create_shipment!
|
||||
end
|
||||
end
|
||||
|
||||
def shipping_address_from_distributor
|
||||
if distributor
|
||||
self.ship_address = distributor.pickup_address.clone
|
||||
|
||||
@@ -6,7 +6,7 @@ Spree::Product.class_eval do
|
||||
|
||||
accepts_nested_attributes_for :product_distributions, :allow_destroy => true
|
||||
|
||||
attr_accessible :supplier_id, :distributor_ids, :product_distributions_attributes
|
||||
attr_accessible :supplier_id, :distributor_ids, :product_distributions_attributes, :group_buy
|
||||
|
||||
validates_presence_of :supplier
|
||||
|
||||
|
||||
9
app/overrides/add_group_buy_to_admin_product.rb
Normal file
9
app/overrides/add_group_buy_to_admin_product.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
Deface::Override.new(:virtual_path => "spree/admin/products/_form",
|
||||
:insert_top => "[data-hook='admin_product_form_right']",
|
||||
:partial => "spree/admin/products/group_buy_form",
|
||||
:name => "group buy")
|
||||
|
||||
Deface::Override.new(:virtual_path => "spree/admin/products/new",
|
||||
:insert_bottom => ".right",
|
||||
:partial => "spree/admin/products/group_buy_form",
|
||||
:name => "group buy")
|
||||
@@ -33,4 +33,4 @@
|
||||
%td Regular pickup times:
|
||||
%td= f.text_field :pickup_times
|
||||
= f.fields_for :pickup_address do |pickup_address_form|
|
||||
= render 'spree/admin/shared/address_form', :form => pickup_address_form
|
||||
= render 'spree/admin/shared/address_form', :f => pickup_address_form
|
||||
|
||||
7
app/views/spree/admin/products/_group_buy_form.html.haml
Normal file
7
app/views/spree/admin/products/_group_buy_form.html.haml
Normal file
@@ -0,0 +1,7 @@
|
||||
= f.field_container :group_buy do
|
||||
= f.label :group_buy, 'Group buy?'
|
||||
%br
|
||||
= f.radio_button :group_buy, '1', :checked => f.object.group_buy
|
||||
= f.label :group_buy_1, 'Yes'
|
||||
= f.radio_button :group_buy, '0', :checked => !f.object.group_buy
|
||||
= f.label :group_buy_0, 'No'
|
||||
@@ -0,0 +1,32 @@
|
||||
= form_for @search, :url => spree.orders_and_distributors_admin_reports_path do |s|
|
||||
= label_tag nil, t(:date_range)
|
||||
%br
|
||||
.date-range-filter
|
||||
%div{"class" => "left sub-field"}
|
||||
= s.text_field :created_at_gt, :class => 'datepicker'
|
||||
%br
|
||||
= label_tag nil, t(:start), :class => 'sub'
|
||||
%div{"class" => "right sub-field"}
|
||||
= s.text_field :created_at_lt, :class => 'datepicker'
|
||||
%br
|
||||
= label_tag nil, t(:stop)
|
||||
= check_box_tag :csv
|
||||
= label_tag :csv, "Download as csv"
|
||||
%br
|
||||
= button t(:search)
|
||||
%br
|
||||
%br
|
||||
%table#listing_orders.index
|
||||
%thead
|
||||
%tr{'data-hook' => "orders_header"}
|
||||
- @report.header.each do |heading|
|
||||
%th=heading
|
||||
%tbody
|
||||
- @report.table.each do |row|
|
||||
%tr
|
||||
- row.each do |column|
|
||||
%td= column
|
||||
- if @report.table.empty?
|
||||
%tr
|
||||
%td{:colspan => "2"}= t(:none)
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
%tr{"data-hook" => "address1"}
|
||||
%td Address:
|
||||
%td= form.text_field :address1
|
||||
%td= f.text_field :address1
|
||||
%tr{"data-hook" => "address2"}
|
||||
%td Address (cont.):
|
||||
%td= form.text_field :address2
|
||||
%td= f.text_field :address2
|
||||
%tr{"data-hook" => "city"}
|
||||
%td City:
|
||||
%td= form.text_field :city
|
||||
%td= f.text_field :city
|
||||
%tr{"data-hook" => "zipcode"}
|
||||
%td Postcode:
|
||||
%td= form.text_field :zipcode
|
||||
%td= f.text_field :zipcode
|
||||
%tr{"data-hook" => "country"}
|
||||
%td Country:
|
||||
%td= form.collection_select(:country_id, available_countries, :id, :name)
|
||||
%td= f.collection_select(:country_id, available_countries, :id, :name)
|
||||
%tr{"data-hook" => "state"}
|
||||
%td State:
|
||||
%td= form.collection_select(:state_id, form.object.country.states, :id, :name)
|
||||
%td= f.collection_select(:state_id, f.object.country.states, :id, :name)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
%td Description:
|
||||
%td= f.text_field :description
|
||||
= f.fields_for :address do |address_form|
|
||||
= render 'spree/admin/shared/address_form', :form => address_form
|
||||
= render 'spree/admin/shared/address_form', :f => address_form
|
||||
%tr{'data-hook' => "email"}
|
||||
%td Email:
|
||||
%td= f.text_field :email
|
||||
|
||||
33
app/views/spree/order_mailer/confirm_email.text.erb
Normal file
33
app/views/spree/order_mailer/confirm_email.text.erb
Normal file
@@ -0,0 +1,33 @@
|
||||
Dear Customer,
|
||||
|
||||
Please review and retain the following order information for your records.
|
||||
|
||||
============================================================
|
||||
Order Summary
|
||||
============================================================
|
||||
<% @order.line_items.each do |item| %>
|
||||
<%= item.variant.sku %> <%= raw(item.variant.product.name) %> <%= raw(item.variant.options_text) -%> (<%=item.quantity%>) @ <%= number_to_currency item.price %> = <%= number_to_currency(item.price * item.quantity) %>
|
||||
<% end %>
|
||||
============================================================
|
||||
Subtotal: <%= number_to_currency @order.item_total %>
|
||||
<% @order.adjustments.each do |adjustment| %>
|
||||
<%= raw(adjustment.label) %> <%= number_to_currency(adjustment.amount) %>
|
||||
<% end %>
|
||||
Order Total: <%= number_to_currency(@order.total) %>
|
||||
|
||||
============================================================
|
||||
Delivery Details
|
||||
============================================================
|
||||
Address:
|
||||
<%= @order.distributor.name %>
|
||||
<% address = @order.distributor.pickup_address %>
|
||||
<%= address.address1 %> <%= ",\n #{address.address2}" unless address.address2.blank? %>
|
||||
<%= [address.city, address.state_text, address.zipcode, address.country.name].compact.join ', ' %>
|
||||
Colection time:
|
||||
<%= @order.distributor.next_collection_at %>
|
||||
Contact:
|
||||
<%= @order.distributor.contact %>
|
||||
<%= "Phone: #{@order.distributor.phone}" %>
|
||||
<%= "Email: #{@order.distributor.email}" %>
|
||||
|
||||
Thank you for your business.
|
||||
@@ -11,6 +11,9 @@
|
||||
- else
|
||||
%p Quantity
|
||||
= number_field_tag (@product.has_variants? ? :quantity : "variants[#{@product.master.id}]"), 1, :class => 'title', :in => 1..@product.on_hand
|
||||
- if @product.group_buy
|
||||
%p Max quantity
|
||||
= number_field_tag (@product.has_variants? ? :max_quantity : "variant_attributes[#{@product.master.id}][max_quantity]"), 1, :class => 'title', :in => 1..@product.on_hand
|
||||
- order = current_order(false)
|
||||
- if order.nil? || order.can_change_distributor?
|
||||
%p Distributor
|
||||
|
||||
@@ -64,5 +64,7 @@ module Openfoodweb
|
||||
|
||||
# Version of your assets, change this if you want to expire all your assets
|
||||
config.assets.version = '1.0'
|
||||
|
||||
config.assets.initialize_on_precompile = true
|
||||
end
|
||||
end
|
||||
|
||||
3
config/initializers/bugsnag.rb
Normal file
3
config/initializers/bugsnag.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
Bugsnag.configure do |config|
|
||||
config.api_key = "937a200f492fad600b4cc29dddda5f71"
|
||||
end
|
||||
@@ -13,10 +13,14 @@ require 'open_food_web/searcher'
|
||||
Spree.config do |config|
|
||||
config.site_name = "Open Food Web"
|
||||
|
||||
# config.shipping_instructions = true
|
||||
config.shipping_instructions = true
|
||||
config.checkout_zone = 'Australia'
|
||||
config.address_requires_state = true
|
||||
config.default_country_id = 12 # This should be Australia, see: spree/core/db/default/spree/countries.yml
|
||||
|
||||
config.searcher_class = OpenFoodWeb::Searcher
|
||||
|
||||
# -- spree_paypal_express
|
||||
# Auto-capture payments. Without this option, payments must be manually captured in the paypal interface.
|
||||
config.auto_capture = true
|
||||
end
|
||||
|
||||
@@ -17,4 +17,6 @@ Spree::Core::Engine.routes.prepend do
|
||||
end
|
||||
resources :suppliers
|
||||
end
|
||||
|
||||
match '/admin/reports/orders_and_distributors' => 'admin/reports#orders_and_distributors', :as => "orders_and_distributors_admin_reports", :via => [:get, :post]
|
||||
end
|
||||
|
||||
6
db/migrate/20120802031147_add_group_buy_fields.rb
Normal file
6
db/migrate/20120802031147_add_group_buy_fields.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
class AddGroupBuyFields < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :spree_products, :group_buy, :boolean
|
||||
add_column :spree_line_items, :max_quantity, :integer
|
||||
end
|
||||
end
|
||||
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20120702020402) do
|
||||
ActiveRecord::Schema.define(:version => 20120802031147) do
|
||||
|
||||
create_table "distributors", :force => true do |t|
|
||||
t.string "name"
|
||||
@@ -180,10 +180,11 @@ ActiveRecord::Schema.define(:version => 20120702020402) do
|
||||
create_table "spree_line_items", :force => true do |t|
|
||||
t.integer "order_id"
|
||||
t.integer "variant_id"
|
||||
t.integer "quantity", :null => false
|
||||
t.decimal "price", :precision => 8, :scale => 2, :null => false
|
||||
t.integer "quantity", :null => false
|
||||
t.decimal "price", :precision => 8, :scale => 2, :null => false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "max_quantity"
|
||||
end
|
||||
|
||||
add_index "spree_line_items", ["order_id"], :name => "index_line_items_on_order_id"
|
||||
@@ -366,6 +367,7 @@ ActiveRecord::Schema.define(:version => 20120702020402) do
|
||||
t.datetime "updated_at"
|
||||
t.integer "count_on_hand", :default => 0, :null => false
|
||||
t.integer "supplier_id"
|
||||
t.boolean "group_buy"
|
||||
end
|
||||
|
||||
add_index "spree_products", ["available_on"], :name => "index_products_on_available_on"
|
||||
|
||||
31
lib/open_food_web/order_and_distributor_report.rb
Normal file
31
lib/open_food_web/order_and_distributor_report.rb
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
module OpenFoodWeb
|
||||
class OrderAndDistributorReport
|
||||
|
||||
def initialize orders
|
||||
@orders = orders
|
||||
end
|
||||
|
||||
def header
|
||||
["Order date", "Order Id",
|
||||
"Customer Name","Customer Email", "Customer Phone", "Customer City",
|
||||
"SKU", "Item name", "Variant", "Quantity", "Max Quantity", "Cost", "Shipping cost",
|
||||
"Payment method",
|
||||
"Distributor", "Distributor address", "Distributor city", "Distributor postcode", "Shipping instructions"]
|
||||
end
|
||||
|
||||
def table
|
||||
order_and_distributor_details = []
|
||||
@orders.each do |order|
|
||||
order.line_items.each do |line_item|
|
||||
order_and_distributor_details << [order.created_at, order.id,
|
||||
order.bill_address.full_name, order.email, order.bill_address.phone, order.bill_address.city,
|
||||
line_item.product.sku, line_item.product.name, line_item.variant.options_text, line_item.quantity, line_item.max_quantity, line_item.price * line_item.quantity, line_item.itemwise_shipping_cost,
|
||||
order.payments.first.payment_method.name,
|
||||
order.distributor.name, order.distributor.pickup_address.address1, order.distributor.pickup_address.city, order.distributor.pickup_address.zipcode, order.special_instructions ]
|
||||
end
|
||||
end
|
||||
order_and_distributor_details
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,6 +3,14 @@ require 'spree/core/search/base'
|
||||
module OpenFoodWeb
|
||||
class Searcher < Spree::Core::Search::Base
|
||||
|
||||
# Do not perform pagination
|
||||
def retrieve_products
|
||||
@products_scope = get_base_scope
|
||||
curr_page = page || 1
|
||||
|
||||
@products = @products_scope.includes([:master])
|
||||
end
|
||||
|
||||
def get_base_scope
|
||||
base_scope = super
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ describe Spree::OrdersController do
|
||||
p = create(:product)
|
||||
|
||||
expect do
|
||||
spree_put :populate, :variants => {p.id => 1}
|
||||
spree_post :populate, :variants => {p.master.id => 1}
|
||||
end.to change(Spree::LineItem, :count).by(0)
|
||||
end
|
||||
|
||||
@@ -25,7 +25,7 @@ describe Spree::OrdersController do
|
||||
p = create(:product, :distributors => [distributor_product])
|
||||
|
||||
expect do
|
||||
spree_put :populate, :variants => {p.id => 1}, :distributor_id => distributor_no_product.id
|
||||
spree_post :populate, :variants => {p.master.id => 1}, :distributor_id => distributor_no_product.id
|
||||
end.to change(Spree::LineItem, :count).by(0)
|
||||
end
|
||||
|
||||
@@ -39,7 +39,7 @@ describe Spree::OrdersController do
|
||||
order.save!
|
||||
|
||||
expect do
|
||||
spree_put :populate, :variants => {p.id => 1}, :distributor_id => distributor_product.id
|
||||
spree_post :populate, :variants => {p.master.id => 1}, :distributor_id => distributor_product.id
|
||||
end.to change(Spree::LineItem, :count).by(1)
|
||||
|
||||
order.reload.distributor.should == distributor_product
|
||||
@@ -51,7 +51,7 @@ describe Spree::OrdersController do
|
||||
p = create(:product, :distributors => [d])
|
||||
|
||||
# When we add the product to our cart
|
||||
spree_put :populate, :variants => {p.id => 1}, :distributor_id => d.id
|
||||
spree_post :populate, :variants => {p.master.id => 1}, :distributor_id => d.id
|
||||
|
||||
# Then our order should have its distributor set to the chosen distributor
|
||||
current_order(false).distributor.should == d
|
||||
@@ -65,7 +65,7 @@ describe Spree::OrdersController do
|
||||
@product = create(:product, :distributors => [@distributor])
|
||||
|
||||
# And the product is in the cart
|
||||
spree_put :populate, :variants => {@product.id => 1}, :distributor_id => @distributor.id
|
||||
spree_post :populate, :variants => {@product.master.id => 1}, :distributor_id => @distributor.id
|
||||
current_order(false).line_items.reload.map { |li| li.product }.should == [@product]
|
||||
current_order(false).distributor.reload.should == @distributor
|
||||
end
|
||||
@@ -76,7 +76,7 @@ describe Spree::OrdersController do
|
||||
p2 = create(:product, :distributors => [d2])
|
||||
|
||||
# When I attempt to add the product to the cart
|
||||
spree_put :populate, :variants => {p2.id => 1}, :distributor_id => d2.id
|
||||
spree_post :populate, :variants => {p2.master.id => 1}, :distributor_id => d2.id
|
||||
|
||||
# Then the product should not be added to the cart
|
||||
current_order(false).line_items.reload.map { |li| li.product }.should == [@product]
|
||||
@@ -89,7 +89,7 @@ describe Spree::OrdersController do
|
||||
p2 = create(:product, :distributors => [d2])
|
||||
|
||||
# When I attempt to add the product to the cart with a fake distributor_id
|
||||
spree_put :populate, :variants => {p2.id => 1}, :distributor_id => @distributor.id
|
||||
spree_post :populate, :variants => {p2.master.id => 1}, :distributor_id => @distributor.id
|
||||
|
||||
# Then the product should not be added to the cart
|
||||
current_order(false).line_items.reload.map { |li| li.product }.should == [@product]
|
||||
@@ -102,11 +102,26 @@ describe Spree::OrdersController do
|
||||
p2 = create(:product, :distributors => [@distributor, d2])
|
||||
|
||||
# When I attempt to add the product to the cart with the alternate distributor
|
||||
spree_put :populate, :variants => {p2.id => 1}, :distributor_id => d2
|
||||
spree_post :populate, :variants => {p2.master.id => 1}, :distributor_id => d2
|
||||
|
||||
# Then the product should not be added to the cart
|
||||
current_order(false).line_items.reload.map { |li| li.product }.should == [@product]
|
||||
current_order(false).distributor.reload.should == @distributor
|
||||
end
|
||||
end
|
||||
|
||||
context "adding a group buy product to the cart" do
|
||||
it "sets a variant attribute for the max quantity" do
|
||||
distributor_product = create(:distributor)
|
||||
p = create(:product, :distributors => [distributor_product], :group_buy => true)
|
||||
|
||||
order = current_order(true)
|
||||
order.should_receive(:set_variant_attributes).with(p.master, {'max_quantity' => '3'})
|
||||
controller.stub(:current_order).and_return(order)
|
||||
|
||||
expect do
|
||||
spree_post :populate, :variants => {p.master.id => 1}, :variant_attributes => {p.master.id => {:max_quantity => 3}}, :distributor_id => distributor_product.id
|
||||
end.to change(Spree::LineItem, :count).by(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -40,6 +40,7 @@ end
|
||||
FactoryGirl.modify do
|
||||
factory :simple_product do
|
||||
supplier { Spree::Supplier.first || FactoryGirl.create(:supplier) }
|
||||
on_hand 3
|
||||
|
||||
# before(:create) do |product, evaluator|
|
||||
# product.product_distributions = [FactoryGirl.create(:product_distribution, :product => product)]
|
||||
|
||||
51
spec/lib/open_food_web/order_and_distributor_report_spec.rb
Normal file
51
spec/lib/open_food_web/order_and_distributor_report_spec.rb
Normal file
@@ -0,0 +1,51 @@
|
||||
require 'spec_helper'
|
||||
|
||||
|
||||
module OpenFoodWeb
|
||||
describe OrderAndDistributorReport do
|
||||
|
||||
describe "orders and distributors report" do
|
||||
|
||||
before(:each) do
|
||||
@bill_address = create(:address)
|
||||
@distributor_address = create(:address, :address1 => "distributor address", :city => 'The Shire', :zipcode => "1234")
|
||||
@distributor = create(:distributor, :pickup_address => @distributor_address)
|
||||
product = create(:product)
|
||||
product_distribution = create(:product_distribution, :product => product, :distributor => @distributor, :shipping_method => create(:shipping_method))
|
||||
@shipping_instructions = "pick up on thursday please!"
|
||||
@order = create(:order, :distributor => @distributor, :bill_address => @bill_address, :special_instructions => @shipping_instructions)
|
||||
@payment_method = create(:payment_method)
|
||||
payment = create(:payment, :payment_method => @payment_method, :order => @order )
|
||||
@order.payments << payment
|
||||
@line_item = create(:line_item, :product => product, :order => @order)
|
||||
@order.line_items << @line_item
|
||||
end
|
||||
|
||||
it "should return a header row describing the report" do
|
||||
subject = OrderAndDistributorReport.new [@order]
|
||||
|
||||
header = subject.header
|
||||
header.should == ["Order date", "Order Id",
|
||||
"Customer Name","Customer Email", "Customer Phone", "Customer City",
|
||||
"SKU", "Item name", "Variant", "Quantity", "Max Quantity", "Cost", "Shipping cost",
|
||||
"Payment method",
|
||||
"Distributor", "Distributor address", "Distributor city", "Distributor postcode", "Shipping instructions"]
|
||||
end
|
||||
|
||||
it "should denormalise order and distributor details for display as csv" do
|
||||
subject = OrderAndDistributorReport.new [@order]
|
||||
|
||||
table = subject.table
|
||||
|
||||
table[0].should == [@order.created_at, @order.id,
|
||||
@bill_address.full_name, @order.email, @bill_address.phone, @bill_address.city,
|
||||
@line_item.product.sku, @line_item.product.name, @line_item.variant.options_text, @line_item.quantity, @line_item.max_quantity, @line_item.price * @line_item.quantity, @line_item.itemwise_shipping_cost,
|
||||
@payment_method.name,
|
||||
@distributor.name, @distributor.pickup_address.address1, @distributor.pickup_address.city, @distributor.pickup_address.zipcode, @shipping_instructions ]
|
||||
end
|
||||
|
||||
it "should include breakdown an order into each line item"
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -10,4 +10,11 @@ describe OpenFoodWeb::Calculator::Itemwise do
|
||||
|
||||
subject.compute(order).should == 30
|
||||
end
|
||||
|
||||
it "returns zero for an order with no items" do
|
||||
order = double(:order)
|
||||
order.stub(:line_items).and_return([])
|
||||
|
||||
subject.compute(order).should == 0
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,12 +5,12 @@ describe OpenFoodWeb::Calculator::Weight do
|
||||
variant_1 = double(:variant, :weight => 10)
|
||||
variant_2 = double(:variant, :weight => 20)
|
||||
|
||||
line_item_1 = double(:line_item, :variant => variant_1)
|
||||
line_item_2 = double(:line_item, :variant => variant_2)
|
||||
line_item_1 = double(:line_item, :variant => variant_1, :quantity => 1)
|
||||
line_item_2 = double(:line_item, :variant => variant_2, :quantity => 3)
|
||||
|
||||
order = double(:order, :line_items => [line_item_1, line_item_2])
|
||||
|
||||
subject.set_preference(:per_kg, 10)
|
||||
subject.compute(order).should == 300
|
||||
subject.compute(order).should == (10*1 + 20*3) * 10
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,13 +9,28 @@ module Spree
|
||||
it { should have_many(:orders) }
|
||||
end
|
||||
|
||||
describe "validations" do
|
||||
it { should validate_presence_of(:name) }
|
||||
end
|
||||
|
||||
it "should default country to system country" do
|
||||
distributor = Distributor.new
|
||||
distributor.pickup_address.country.should == Country.find_by_id(Config[:default_country_id])
|
||||
end
|
||||
|
||||
describe "validations" do
|
||||
it { should validate_presence_of(:name) }
|
||||
describe "scopes" do
|
||||
it "returns distributors with products in stock" do
|
||||
d1 = create(:distributor)
|
||||
d2 = create(:distributor)
|
||||
d3 = create(:distributor)
|
||||
d4 = create(:distributor)
|
||||
create(:product, :distributors => [d1, d2], :on_hand => 5)
|
||||
create(:product, :distributors => [d1], :on_hand => 5)
|
||||
create(:product, :distributors => [d3], :on_hand => 0)
|
||||
|
||||
Distributor.with_products_on_hand.sort.should == [d1, d2]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::Order do
|
||||
it "initialises a default shipping method after creation" do
|
||||
shipping_method_back_end = create(:shipping_method, :display_on => :back_end)
|
||||
shipping_method_both = create(:shipping_method, :display_on => :both)
|
||||
|
||||
subject.shipping_method.should be_nil
|
||||
subject.adjustments.should be_empty
|
||||
|
||||
subject.save!
|
||||
|
||||
subject.shipping_method.should == shipping_method_both
|
||||
subject.adjustments.where(:label => "Shipping").should be_present
|
||||
end
|
||||
|
||||
it "reveals permission for changing distributor" do
|
||||
p = build(:product)
|
||||
|
||||
@@ -46,4 +59,17 @@ describe Spree::Order do
|
||||
# And cannot be added if it does not match
|
||||
subject.can_add_product_to_cart?(p_subsequent_other_dist).should be_false
|
||||
end
|
||||
|
||||
it "sets attributes on line items for variants" do
|
||||
subject.save!
|
||||
d = create(:distributor)
|
||||
p = create(:product, :distributors => [d])
|
||||
|
||||
subject.distributor = d
|
||||
subject.add_variant(p.master, 1)
|
||||
subject.set_variant_attributes(p.master, {'max_quantity' => '3'})
|
||||
|
||||
li = Spree::LineItem.last
|
||||
li.max_quantity.should == 3
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,6 +36,26 @@ feature %q{
|
||||
product.supplier.should == @supplier
|
||||
product.distributors.should == [@distributors[0], @distributors[2]]
|
||||
product.product_distributions.map { |pd| pd.shipping_method }.should == [@shipping_method, @shipping_method]
|
||||
product.group_buy.should be_false
|
||||
end
|
||||
|
||||
scenario "making a group buy product" do
|
||||
login_to_admin_section
|
||||
|
||||
click_link 'Products'
|
||||
click_link 'New Product'
|
||||
|
||||
fill_in 'product_name', :with => 'A new product !!!'
|
||||
fill_in 'product_price', :with => '19.99'
|
||||
select 'New supplier', :from => 'product_supplier_id'
|
||||
choose 'product_group_buy_1'
|
||||
|
||||
click_button 'Create'
|
||||
|
||||
flash_message.should == 'Product "A new product !!!" has been successfully created!'
|
||||
product = Spree::Product.find_by_name('A new product !!!')
|
||||
product.group_buy.should be_true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,6 +13,7 @@ feature %q{
|
||||
d1 = create(:distributor)
|
||||
d2 = create(:distributor)
|
||||
p = create(:product, :distributors => [d1])
|
||||
create(:product, :distributors => [d2])
|
||||
|
||||
# When I choose a distributor
|
||||
visit spree.root_path
|
||||
@@ -104,4 +105,74 @@ feature %q{
|
||||
page.should have_selector 'h4 a', :text => p2.name
|
||||
end
|
||||
end
|
||||
|
||||
scenario "adding a product to the cart for a group buy" do
|
||||
# Given a group buy product and a distributor
|
||||
d = create(:distributor)
|
||||
p = create(:product, :distributors => [d], :group_buy => true)
|
||||
|
||||
# When I add the item to my cart
|
||||
visit spree.product_path p
|
||||
fill_in "variants_#{p.master.id}", :with => 2
|
||||
fill_in "variant_attributes_#{p.master.id}_max_quantity", :with => 3
|
||||
click_button 'Add To Cart'
|
||||
|
||||
# Then the item should be in my cart with correct quantities
|
||||
order = Spree::Order.last
|
||||
li = order.line_items.first
|
||||
li.product.should == p
|
||||
li.quantity.should == 2
|
||||
li.max_quantity.should == 3
|
||||
end
|
||||
|
||||
scenario "adding a product with variants to the cart for a group buy" do
|
||||
# Given a group buy product with variants and a distributor
|
||||
d = create(:distributor)
|
||||
p = create(:product, :distributors => [d], :group_buy => true)
|
||||
create(:variant, :product => p)
|
||||
|
||||
# When I add the item to my cart
|
||||
visit spree.product_path p
|
||||
fill_in "quantity", :with => 2
|
||||
fill_in "max_quantity", :with => 3
|
||||
click_button 'Add To Cart'
|
||||
|
||||
# Then the item should be in my cart with correct quantities
|
||||
order = Spree::Order.last
|
||||
li = order.line_items.first
|
||||
li.product.should == p
|
||||
li.quantity.should == 2
|
||||
li.max_quantity.should == 3
|
||||
end
|
||||
|
||||
scenario "adding a product to cart that is not a group buy does not show max quantity field" do
|
||||
# Given a group buy product and a distributor
|
||||
d = create(:distributor)
|
||||
p = create(:product, :distributors => [d], :group_buy => false)
|
||||
|
||||
# When I view the add to cart form, there should not be a max quantity field
|
||||
visit spree.product_path p
|
||||
|
||||
page.should_not have_selector "#variant_attributes_#{p.master.id}_max_quantity"
|
||||
end
|
||||
|
||||
scenario "adding a product with a max quantity less than quantity results in max_quantity==quantity" do
|
||||
# Given a group buy product and a distributor
|
||||
d = create(:distributor)
|
||||
p = create(:product, :distributors => [d], :group_buy => true)
|
||||
|
||||
# When I add the item to my cart
|
||||
visit spree.product_path p
|
||||
fill_in "variants_#{p.master.id}", :with => 2
|
||||
fill_in "variant_attributes_#{p.master.id}_max_quantity", :with => 1
|
||||
click_button 'Add To Cart'
|
||||
|
||||
# Then the item should be in my cart with correct quantities
|
||||
order = Spree::Order.last
|
||||
li = order.line_items.first
|
||||
li.product.should == p
|
||||
li.quantity.should == 2
|
||||
li.max_quantity.should == 2
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -10,22 +10,28 @@ feature %q{
|
||||
|
||||
scenario "viewing a list of distributors" do
|
||||
# Given some distributors
|
||||
3.times { create(:distributor) }
|
||||
d1 = create(:distributor)
|
||||
d2 = create(:distributor)
|
||||
d3 = create(:distributor)
|
||||
|
||||
# And some of those distributors have a product
|
||||
create(:product, :distributors => [d1, d2])
|
||||
|
||||
# When I go to the home page
|
||||
visit spree.root_path
|
||||
|
||||
# Then I should see a list containing all distributors
|
||||
Spree::Distributor.all.each do |distributor|
|
||||
page.should have_selector 'a', :text => distributor.name
|
||||
end
|
||||
# Then I should see a list containing the distributors that have products
|
||||
page.should have_selector 'a', :text => d1.name
|
||||
page.should have_selector 'a', :text => d2.name
|
||||
page.should_not have_selector 'a', :text => d3.name
|
||||
end
|
||||
|
||||
|
||||
context "when a distributor is selected" do
|
||||
it "displays the distributor's name" do
|
||||
# Given a distributor
|
||||
# Given a distributor with a product
|
||||
d = create(:distributor, :name => 'Melb Uni Co-op')
|
||||
create(:product, :distributors => [d])
|
||||
|
||||
# When I select the distributor
|
||||
visit spree.root_path
|
||||
@@ -65,8 +71,9 @@ feature %q{
|
||||
end
|
||||
|
||||
it "allows the user to leave the distributor" do
|
||||
# Given a distributor
|
||||
# Given a distributor with a product
|
||||
d = create(:distributor, :name => 'Melb Uni Co-op')
|
||||
create(:product, :distributors => [d])
|
||||
|
||||
# When I select the distributor and then leave it
|
||||
visit spree.root_path
|
||||
@@ -106,10 +113,11 @@ feature %q{
|
||||
end
|
||||
|
||||
it "works when viewing a product from a remote distributor" do
|
||||
# Given two distributors and a product under one
|
||||
# Given two distributors and our product under one
|
||||
distributor_product = create(:distributor)
|
||||
distributor_no_product = create(:distributor)
|
||||
product = create(:product, :distributors => [distributor_product])
|
||||
create(:product, :distributors => [distributor_no_product])
|
||||
|
||||
# When we select the distributor without the product and then view the product
|
||||
visit spree.root_path
|
||||
|
||||
Reference in New Issue
Block a user