├── .autotest
├── test
├── integration
│ └── spree
│ │ ├── admin
│ │ ├── untitled file
│ │ └── wholesalers_test.rb
│ │ └── wholesalers_test.rb
├── dummy_hooks
│ ├── templates
│ │ ├── admin
│ │ │ ├── all.js
│ │ │ └── all.css
│ │ └── store
│ │ │ ├── all.js
│ │ │ ├── all.css
│ │ │ └── screen.css
│ ├── after_migrate.rb.sample
│ └── before_migrate.rb
├── fixtures
│ └── spree
│ │ ├── roles.yml
│ │ ├── wholesalers.yml
│ │ ├── addresses.yml
│ │ ├── orders.yml
│ │ ├── variants.yml
│ │ ├── states.yml
│ │ ├── products.yml
│ │ └── countries.yml
├── support
│ ├── helper_methods.rb
│ └── integration_case.rb
├── unit
│ └── spree
│ │ ├── roles_test.rb
│ │ ├── product_test.rb
│ │ ├── order_test.rb
│ │ └── wholesaler_test.rb
├── test_helper.rb
└── factories.rb
├── Gemfile
├── app
├── views
│ └── spree
│ │ ├── admin
│ │ ├── hooks
│ │ │ ├── _wholesale_tab.html.erb
│ │ │ ├── _admin_orders_index_rows.html.erb
│ │ │ ├── _admin_orders_index_headers.html.erb
│ │ │ ├── _admin_orders_index_search.html.erb
│ │ │ └── _product_form_right.html.erb
│ │ ├── wholesalers
│ │ │ ├── _user_options.html.erb
│ │ │ ├── new.html.erb
│ │ │ ├── edit.html.erb
│ │ │ ├── show.html.erb
│ │ │ ├── _form.html.erb
│ │ │ └── index.html.erb
│ │ └── variants
│ │ │ └── _form.html.erb
│ │ ├── hooks
│ │ ├── _cart_item_price.html.erb
│ │ ├── _cart_item_total.html.erb
│ │ ├── _wholesale_customer_id.html.erb
│ │ ├── _products_wholesale_price.html.erb
│ │ ├── _wholesale_customer.html.erb
│ │ ├── _product_wholesale_price.html.erb
│ │ └── _wholesale_payment_options.html.erb
│ │ ├── shared
│ │ ├── _store_menu.html.erb
│ │ ├── _wholesale_static_content.html.erb
│ │ └── _address_form.html.erb
│ │ ├── wholesalers
│ │ ├── edit.html.erb
│ │ ├── new.html.erb
│ │ ├── index.html.erb
│ │ ├── show.html.erb
│ │ └── _fields.html.erb
│ │ ├── orders
│ │ └── show.html.erb
│ │ └── checkout
│ │ └── _summary.html.erb
├── application_helper_decorator.rb
├── assets
│ ├── stylesheets
│ │ ├── store
│ │ │ └── wholesale.css
│ │ └── admin
│ │ │ └── wholesalers.css
│ └── javascripts
│ │ └── wholesaler_address.js
├── overrides
│ ├── product_wholesale_price.rb
│ ├── products_wholesale_price.rb
│ ├── cart_item_total.rb
│ ├── admin
│ │ ├── admin-wholesale-tab.rb
│ │ ├── admin-orders-search.rb
│ │ ├── admin_product_form_right.rb
│ │ ├── admin-order-show-buttons.rb
│ │ ├── admin-orders-rows.rb
│ │ └── admin-orders-headers.rb
│ ├── wholesale-my-orders.rb
│ ├── cart_item_price.rb
│ ├── id_inside_cart_form.rb
│ └── checkout_payment_step.rb
├── models
│ └── spree
│ │ ├── variant_decorator.rb
│ │ ├── line_item_decorator.rb
│ │ ├── user_decorator.rb
│ │ ├── product_decorator.rb
│ │ ├── spree_current_order_decorator.rb
│ │ ├── order_decorator.rb
│ │ └── wholesaler.rb
└── controllers
│ └── spree
│ ├── admin
│ ├── base_controller_decorator.rb
│ └── wholesalers_controller.rb
│ ├── checkout_controller_decorator.rb
│ └── wholesalers_controller.rb
├── lib
├── spree_wholesale
│ ├── version.rb
│ └── engine.rb
├── spree_wholesale.rb
├── tasks
│ └── spree_wholesale.rake
└── generators
│ └── spree_wholesale
│ └── install_generator.rb
├── .gitignore
├── .travis.yml
├── Versionfile
├── config
├── routes.rb
└── locales
│ └── en.yml
├── Rakefile
├── db
└── migrate
│ └── 20120113164801_install_spree_wholesale.rb
├── spree_wholesale.gemspec
├── LICENSE
└── README.md
/.autotest:
--------------------------------------------------------------------------------
1 | require "autotest/growl"
2 |
--------------------------------------------------------------------------------
/test/integration/spree/admin/untitled file:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "http://rubygems.org"
2 | gemspec
3 |
--------------------------------------------------------------------------------
/test/dummy_hooks/templates/admin/all.js:
--------------------------------------------------------------------------------
1 | //= require admin/spree_core
2 |
--------------------------------------------------------------------------------
/test/dummy_hooks/templates/store/all.js:
--------------------------------------------------------------------------------
1 | //= require store/spree_core
2 |
--------------------------------------------------------------------------------
/app/views/spree/admin/hooks/_wholesale_tab.html.erb:
--------------------------------------------------------------------------------
1 | <%= tab :wholesalers %>
2 |
--------------------------------------------------------------------------------
/app/views/spree/hooks/_cart_item_price.html.erb:
--------------------------------------------------------------------------------
1 | <%= format_price(line_item.price) %>
2 |
--------------------------------------------------------------------------------
/test/dummy_hooks/templates/admin/all.css:
--------------------------------------------------------------------------------
1 | /*
2 | *= require admin/spree_core
3 | */
4 |
--------------------------------------------------------------------------------
/test/dummy_hooks/templates/store/all.css:
--------------------------------------------------------------------------------
1 | /*
2 | *= require store/spree_core
3 | */
4 |
--------------------------------------------------------------------------------
/lib/spree_wholesale/version.rb:
--------------------------------------------------------------------------------
1 | module SpreeWholesale
2 | VERSION = "0.70.3"
3 | end
4 |
--------------------------------------------------------------------------------
/app/views/spree/admin/hooks/_admin_orders_index_rows.html.erb:
--------------------------------------------------------------------------------
1 |
<%= order.is_wholesale? ? 'yes' : 'no' %>
2 |
--------------------------------------------------------------------------------
/app/views/spree/admin/hooks/_admin_orders_index_headers.html.erb:
--------------------------------------------------------------------------------
1 | <%= sort_link @search, :wholesale, t("wholesale") %>
2 |
--------------------------------------------------------------------------------
/test/fixtures/spree/roles.yml:
--------------------------------------------------------------------------------
1 | admin:
2 | name: admin
3 |
4 | user:
5 | name: user
6 |
7 | wholesaler:
8 | name: wholesaler
9 |
--------------------------------------------------------------------------------
/app/views/spree/hooks/_cart_item_total.html.erb:
--------------------------------------------------------------------------------
1 | <%= format_price(line_item.price * line_item.quantity) unless line_item.quantity.nil? %>
2 |
--------------------------------------------------------------------------------
/app/application_helper_decorator.rb:
--------------------------------------------------------------------------------
1 | ApplicationHelper.module_eval do
2 |
3 | def wholesaler_signed_in?
4 | current_user && current_user.has_role?("wholesaler")
5 | end
6 |
7 | end
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | \#*
2 | *~
3 | .#*
4 | .DS_Store
5 | .idea
6 | .project
7 | coverage/
8 | Gemfile.lock
9 | pkg/*.gem
10 | test/dummy_hooks/after_migrate.rb
11 | test/dummy
12 | tmp/**/*
13 | *.swp
14 |
--------------------------------------------------------------------------------
/lib/spree_wholesale.rb:
--------------------------------------------------------------------------------
1 | require "spree_core"
2 | require "spree_auth"
3 | require "spree_sample" unless Rails.env == "production"
4 |
5 | require "spree_wholesale/engine"
6 | require "spree_wholesale/engine"
7 |
--------------------------------------------------------------------------------
/test/dummy_hooks/after_migrate.rb.sample:
--------------------------------------------------------------------------------
1 | # assume wholesale prices
2 | rake "db:migrate db:seed spree_sample:load spree_wholesale:create_role spree_wholesale:assume_wholesale_prices", :env => "development"
3 |
--------------------------------------------------------------------------------
/app/views/spree/shared/_store_menu.html.erb:
--------------------------------------------------------------------------------
1 | <%= link_to t("home") , root_path %>
2 | <%= link_to t("wholesalers") , spree.wholesalers_path %>
3 | <%= link_to_cart %>
4 |
5 |
--------------------------------------------------------------------------------
/app/views/spree/admin/hooks/_admin_orders_index_search.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= f.check_box :wholesale_eq, { :style => "vertical-align:middle;" } %>
3 |
4 | <%= t(".show_wholesale_orders") %>
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/store/wholesale.css:
--------------------------------------------------------------------------------
1 | span.price_msrp,
2 | span.price_wholesale {
3 | display: block;
4 | }
5 | span.price_msrp {
6 | color: #c00e0e;
7 | }
8 | span.price_wholesale {
9 | color: #68962c;
10 | }
11 |
--------------------------------------------------------------------------------
/app/views/spree/hooks/_wholesale_customer_id.html.erb:
--------------------------------------------------------------------------------
1 | <% order ||= @order %>
2 | <% if order && order.is_wholesale? %>
3 | <%= t('wholesale_customer', { :id => order.user_id }) %>
4 | <% end %>
5 |
--------------------------------------------------------------------------------
/app/views/spree/hooks/_products_wholesale_price.html.erb:
--------------------------------------------------------------------------------
1 | <% if current_user && current_user.has_role?(:wholesaler) %>
2 | <% if product.is_wholesaleable? %>
3 | <%= number_to_currency(product.wholesale_price) %>
4 | <% end %>
5 | <% end %>
6 |
--------------------------------------------------------------------------------
/app/overrides/product_wholesale_price.rb:
--------------------------------------------------------------------------------
1 | Deface::Override.new(
2 | :virtual_path => 'spree/products/_cart_form',
3 | :name => 'product_wholesale_price',
4 | :insert_bottom => "#product-price",
5 | :partial => "spree/hooks/product_wholesale_price",
6 | :disabled => false
7 | )
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | before_script:
2 | - "sh -e /etc/init.d/xvfb start"
3 | - "bundle exec dummier"
4 |
5 | script: "DISPLAY=:99.0 bundle exec rake"
6 |
7 | branches:
8 | only:
9 | - master
10 |
11 | rvm:
12 | - 1.8.7
13 | - 1.9.2
14 | - 1.9.3
15 | - ree
16 | - rbx
17 |
--------------------------------------------------------------------------------
/app/views/spree/admin/wholesalers/_user_options.html.erb:
--------------------------------------------------------------------------------
1 | <% wholesaler ||= @wholesaler %>
2 | <% if wholesaler.active? %>
3 | <%= link_to "deny", reject_admin_wholesaler_path(wholesaler) %>
4 | <% else %>
5 | <%= link_to "approve", approve_admin_wholesaler_path(wholesaler) %>
6 | <% end %>
7 |
--------------------------------------------------------------------------------
/test/support/helper_methods.rb:
--------------------------------------------------------------------------------
1 | module HelperMethods
2 |
3 | def random_email
4 | random_token.split("").insert(random_token.length / 2, "@").push(".com").join("")
5 | end
6 |
7 | def random_token
8 | Digest::SHA1.hexdigest((Time.now.to_i * rand).to_s)
9 | end
10 |
11 | end
12 |
--------------------------------------------------------------------------------
/app/overrides/products_wholesale_price.rb:
--------------------------------------------------------------------------------
1 | Deface::Override.new(
2 | :virtual_path => 'spree/shared/_products',
3 | :name => 'products_wholesale_price',
4 | :insert_after => "[data-hook='products_list_item'] .price.selling",
5 | :partial => "spree/hooks/products_wholesale_price",
6 | :disabled => false
7 | )
8 |
--------------------------------------------------------------------------------
/app/models/spree/variant_decorator.rb:
--------------------------------------------------------------------------------
1 | Spree::Variant.instance_eval do
2 | attr_accessible :wholesale_price
3 | end
4 |
5 | Spree::Variant.class_eval do
6 | scope :wholesales, where("spree_variants.wholesale_price > 0")
7 |
8 | def is_wholesaleable?
9 | 0 < wholesale_price
10 | end
11 |
12 | end
13 |
--------------------------------------------------------------------------------
/test/unit/spree/roles_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class Spree::RolesTest < ActiveSupport::TestCase
4 |
5 | should "find or create wholesale role" do
6 | role = Spree::Role.find_or_create_by_name("wholesaler")
7 | assert !role.nil?, "Wholesale role does not exist."
8 | end
9 |
10 | end
11 |
--------------------------------------------------------------------------------
/Versionfile:
--------------------------------------------------------------------------------
1 | "1.2.x" => { :branch => "master" }
2 | "1.1.x" => { :branch => "1.1.x" }
3 | "1.0.x" => { :branch => "1.0.x" }
4 | "0.70.x" => { :branch => "0.70.x" }
5 | "0.60.x" => { :branch => "0.60.x" }
6 | "0.50.x" => { :branch => "0.50.x" }
7 | "0.40.x" => { :version => "0.40.2.2" }
8 | "0.30.x" => { :version => "0.40.2.2" }
9 |
--------------------------------------------------------------------------------
/app/controllers/spree/admin/base_controller_decorator.rb:
--------------------------------------------------------------------------------
1 | [Spree::BaseController, Spree::Admin::BaseController].each do |controller|
2 |
3 | controller.class_eval do
4 |
5 | def default_country
6 | @default_country ||= Spree::Country.find Spree::Config[:default_country_id]
7 | end
8 |
9 | end
10 |
11 | end
12 |
--------------------------------------------------------------------------------
/app/views/spree/hooks/_wholesale_customer.html.erb:
--------------------------------------------------------------------------------
1 | <% if @user.wholesaler? %>
2 | Wholesaler
3 | <%= t('wholesale_customer', { :id => @user.id }) %>
4 | <%= t('wholesale_customer_since', { :time => @user.wholesaler.created_at }) %>
5 | <% end %>
6 |
--------------------------------------------------------------------------------
/app/overrides/cart_item_total.rb:
--------------------------------------------------------------------------------
1 | #replace :cart_item_total, 'hooks/cart_item_total'
2 | Deface::Override.new(:virtual_path => 'spree/orders/_line_item',
3 | :name => 'cart_item_total',
4 | :replace_contents => "[data-hook='cart_item_total'], #cart_item_total[data-hook]",
5 | :partial => "spree/hooks/cart_item_total",
6 | :disabled => false)
7 |
--------------------------------------------------------------------------------
/app/overrides/admin/admin-wholesale-tab.rb:
--------------------------------------------------------------------------------
1 | # insert_after :admin_tabs, 'admin/hooks/wholesale_tab'
2 | Deface::Override.new(
3 | :virtual_path => "spree/layouts/admin",
4 | :name => "admin-wholesale-tab",
5 | :insert_bottom => "[data-hook='admin_tabs']",
6 | :partial => "spree/admin/hooks/wholesale_tab",
7 | :disabled => false
8 | )
9 |
--------------------------------------------------------------------------------
/app/overrides/wholesale-my-orders.rb:
--------------------------------------------------------------------------------
1 | #insert_before :account_my_orders, 'hooks/wholesale_customer'
2 | Deface::Override.new(:virtual_path => 'spree/users/show',
3 | :name => 'wholesale-my-orders',
4 | :insert_before => "[data-hook='account_my_orders'], #account_my_orders[data-hook]",
5 | :partial => "spree/hooks/wholesale_customer",
6 | :disabled => false)
7 |
--------------------------------------------------------------------------------
/app/views/spree/admin/wholesalers/new.html.erb:
--------------------------------------------------------------------------------
1 | <%= t("new_wholesaler") %>
2 |
3 | <%= form_for [:admin, @wholesaler], :html => { :class => "wholesaler-form" } do |f| %>
4 | <%= render "spree/shared/error_messages", :target => @wholesaler %>
5 | <%= render "form", :form => f %>
6 | <%= render "spree/admin/shared/new_resource_links" %>
7 | <% end %>
8 |
--------------------------------------------------------------------------------
/app/views/spree/wholesalers/edit.html.erb:
--------------------------------------------------------------------------------
1 | <%= t('wholesale_update') %>
2 |
3 | <%= form_for @wholesaler do |form| %>
4 | <%= render "spree/shared/error_messages", :target => @wholesaler %>
5 | <%= render 'fields', :form => form %>
6 |
7 |
8 | <%= form.submit t("update"), :class => 'button' %>
9 |
10 | <% end %>
11 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | Spree::Core::Engine.routes.draw do
2 |
3 | get "/wholesaler/states" => "spree/wholesaler_states#index"
4 |
5 | resources :wholesalers
6 |
7 | namespace(:admin) do
8 |
9 | resources :wholesalers do
10 | member do
11 | get :approve
12 | get :reject
13 | end
14 | end
15 |
16 | end
17 |
18 | end
19 |
--------------------------------------------------------------------------------
/test/fixtures/spree/wholesalers.yml:
--------------------------------------------------------------------------------
1 | new_wholesaler:
2 | company: Test Company,
3 | buyer_contact: Mr Contacter
4 | manager_contact: Mr Manager
5 | phone: 555-555-5555
6 | fax: 555-555-5555 ext 1
7 | resale_number: 123456789
8 | taxid: 555-55-5555
9 | web_address: testcompany.com
10 | terms: Credit Card
11 | notes: What a guy!
12 |
--------------------------------------------------------------------------------
/app/views/spree/admin/wholesalers/edit.html.erb:
--------------------------------------------------------------------------------
1 | <%= t("editing_wholesaler") %>
2 |
3 | <%= form_for [:admin, @wholesaler], :html => { :class => "wholesaler-form" } do |f| %>
4 | <%= render "spree/shared/error_messages", :target => @wholesaler %>
5 | <%= render "form", :form => f %>
6 | <%= render "spree/admin/shared/edit_resource_links" %>
7 | <% end %>
8 |
--------------------------------------------------------------------------------
/app/overrides/cart_item_price.rb:
--------------------------------------------------------------------------------
1 | #replace :cart_item_price, 'hooks/cart_item_price'
2 | Deface::Override.new(
3 | :virtual_path => 'spree/orders/_line_item',
4 | :name => 'cart_item_price',
5 | :replace_contents => "[data-hook='cart_item_price'], #cart_item_price[data-hook]",
6 | :partial => "spree/hooks/cart_item_price",
7 | :disabled => false
8 | )
9 |
--------------------------------------------------------------------------------
/app/views/spree/wholesalers/new.html.erb:
--------------------------------------------------------------------------------
1 | <%= t('wholesale_signup') %>
2 |
3 | <%= form_for @wholesaler do |form| %>
4 | <%= render "spree/shared/error_messages", :target => @wholesaler %>
5 | <%= render 'fields', :form => form %>
6 |
7 |
8 | <%= form.submit t("wholesale_apply"), :class => 'button' %>
9 |
10 | <% end %>
11 |
--------------------------------------------------------------------------------
/app/views/spree/admin/hooks/_product_form_right.html.erb:
--------------------------------------------------------------------------------
1 | <%= f.field_container :wholesale_price do %>
2 | <%= f.label :wholesale_price, t(".master_wholesale_price")%> *
3 | <%= f.text_field :wholesale_price, :value => number_with_precision(@product.wholesale_price, :precision => 2) %>
4 | <%= f.error_message_on :wholesale_price %>
5 | <% end %>
6 |
--------------------------------------------------------------------------------
/app/overrides/admin/admin-orders-search.rb:
--------------------------------------------------------------------------------
1 | #insert_after :admin_orders_index_search, 'admin/hooks/admin_orders_index_search'
2 | Deface::Override.new(:virtual_path => 'spree/admin/orders/index',
3 | :name => 'admin-orders-search',
4 | :insert_before => "[data-hook='admin_orders_index_search_buttons']",
5 | :partial => "spree/admin/hooks/admin_orders_index_search",
6 | :disabled => false)
7 |
--------------------------------------------------------------------------------
/app/overrides/id_inside_cart_form.rb:
--------------------------------------------------------------------------------
1 | #insert_before :inside_cart_form, 'hooks/wholesale_customer_id'
2 | Deface::Override.new(
3 | :virtual_path => 'spree/orders/edit',
4 | :name => 'id_inside_cartform',
5 | :insert_before => "[data-hook='inside_cart_form'], #inside_cart_form[data-hook]",
6 | :partial => "spree/hooks/wholesale_customer_id",
7 | :disabled => false
8 | )
9 |
--------------------------------------------------------------------------------
/app/models/spree/line_item_decorator.rb:
--------------------------------------------------------------------------------
1 | Spree::LineItem.class_eval do
2 |
3 | delegate_belongs_to :variant, :wholesale_price
4 | delegate_belongs_to :variant, :is_wholesaleable?
5 |
6 | def copy_price
7 |
8 | self.price = (order.is_wholesale? && variant.is_wholesaleable? ? variant.wholesale_price : variant.price) if variant && self.price.nil?
9 |
10 | end
11 |
12 | end
13 |
--------------------------------------------------------------------------------
/app/overrides/admin/admin_product_form_right.rb:
--------------------------------------------------------------------------------
1 | #replace :admin_product_form_right, 'admin/hooks/product_form_right'
2 | Deface::Override.new(
3 | :virtual_path => 'spree/admin/products/_form',
4 | :name => 'admin_product_form_right',
5 | :insert_top => "[data-hook='admin_product_form_right']",
6 | :partial => "spree/admin/hooks/product_form_right",
7 | :disabled => false
8 | )
9 |
--------------------------------------------------------------------------------
/app/models/spree/user_decorator.rb:
--------------------------------------------------------------------------------
1 | Spree::User.instance_eval do
2 |
3 | has_one :wholesaler, :class_name => "Spree::Wholesaler"
4 |
5 | scope :wholesale, lambda { includes(:roles).where("spree_roles.name" => "wholesaler") }
6 |
7 |
8 | end
9 |
10 | Spree::User.class_eval do
11 |
12 | def wholesaler?
13 | has_role?("wholesaler") && !wholesaler.nil?
14 | end
15 |
16 | end
17 |
--------------------------------------------------------------------------------
/app/overrides/admin/admin-order-show-buttons.rb:
--------------------------------------------------------------------------------
1 | #insert_after :admin_order_show_buttons, 'hooks/wholesale_customer_id'
2 | Deface::Override.new(:virtual_path => 'spree/orders/show',
3 | :name => 'admin-order-show-buttons',
4 | :insert_after => "[data-hook='admin_order_show_buttons'], #admin_order_show_buttons[data-hook]",
5 | :partial => "spree/hooks/wholesale_customer_id",
6 | :disabled => false)
7 |
--------------------------------------------------------------------------------
/app/overrides/admin/admin-orders-rows.rb:
--------------------------------------------------------------------------------
1 | # insert_after :admin_orders_index_rows, 'admin/hooks/admin_orders_index_rows'
2 | Deface::Override.new(:virtual_path => 'spree/admin/orders/index',
3 | :name => 'admin-orders-rows',
4 | :insert_bottom => "[data-hook='admin_orders_index_rows'], #admin_orders_index_rows[data-hook]",
5 | :partial => "spree/admin/hooks/admin_orders_index_rows",
6 | :disabled => false)
7 |
--------------------------------------------------------------------------------
/app/overrides/checkout_payment_step.rb:
--------------------------------------------------------------------------------
1 | #insert_before :checkout_payment_step, 'hooks/wholesale_payment_options'
2 | Deface::Override.new(
3 | :virtual_path => 'spree/checkout/_payment',
4 | :name => 'checkout_payment_step',
5 | :insert_before => "[data-hook='checkout_payment_step'], #customer_payment_step[data-hook]",
6 | :partial => "spree/hooks/wholesale_payment_options",
7 | :disabled => false
8 | )
9 |
--------------------------------------------------------------------------------
/app/views/spree/hooks/_product_wholesale_price.html.erb:
--------------------------------------------------------------------------------
1 | <% if current_user && current_user.has_role?(:wholesaler) %>
2 | <% if @product.try(:wholesale_price) && 0 < @product.try(:wholesale_price) %>
3 | <%= t(:wholesale_price) %>
4 | <%= number_to_currency(@product.wholesale_price) %>
5 | <% end %>
6 | <% end %>
7 |
--------------------------------------------------------------------------------
/app/models/spree/product_decorator.rb:
--------------------------------------------------------------------------------
1 | Spree::Product.instance_eval do
2 |
3 | delegate_belongs_to :master, :wholesale_price if Spree::Variant.table_exists? && Spree::Variant.column_names.include?("wholesale_price")
4 |
5 | attr_accessible :wholesale_price
6 |
7 | end
8 |
9 | Spree::Product.class_eval do
10 |
11 | def is_wholesaleable?
12 | 0 < master.wholesale_price
13 | end
14 |
15 | end
16 |
--------------------------------------------------------------------------------
/app/overrides/admin/admin-orders-headers.rb:
--------------------------------------------------------------------------------
1 | #insert_after :admin_orders_index_headers, 'admin/hooks/admin_orders_index_headers'
2 | Deface::Override.new(:virtual_path => 'spree/admin/orders/index',
3 | :name => 'admin-orders-headers',
4 | :insert_bottom => "[data-hook='admin_orders_index_headers'], #admin_orders_index_headers[data-hook]",
5 | :partial => "spree/admin/hooks/admin_orders_index_headers",
6 | :disabled => false)
7 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/admin/wholesalers.css:
--------------------------------------------------------------------------------
1 | .wholesaler-form input[type=text],
2 | .wholesaler-form select {
3 | font-size: 1.1em;
4 | font-weight: normal;
5 | padding: 2px 3px;
6 | }
7 |
8 | input.required, select.required {
9 | color: #222;
10 | }
11 |
12 | .leftie, .rightie {
13 | display: block;
14 | width: 49%;
15 | }
16 | .leftie {
17 | float: left;
18 | }
19 | .rightie {
20 | float: right;
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/test/fixtures/spree/addresses.yml:
--------------------------------------------------------------------------------
1 | billing:
2 | firstname: Bill
3 | lastname: Billerman
4 | address1: 1027 State St
5 | address2:
6 | city: Santa Barbara
7 | state_id: 889445952
8 | zipcode: 16804
9 | country_id: 214
10 | phone: 555-555-1027
11 |
12 |
13 | shipping:
14 | firstname: Boxy
15 | lastname: Shipperman
16 | address1: 1000 State St
17 | address2:
18 | city: Santa Barbara
19 | state_id: 889445952
20 | zipcode: 16804
21 | country_id: 214
22 | phone: 555-555-5555
23 |
24 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # encoding: UTF-8
2 | require 'rubygems'
3 | begin
4 | require 'bundler/setup'
5 | rescue LoadError
6 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7 | end
8 |
9 | require 'rake'
10 | require 'rake/testtask'
11 | #require 'rake/rdoctask'
12 |
13 | Bundler::GemHelper.install_tasks
14 |
15 | Rake::TestTask.new(:test) do |t|
16 | t.libs << 'lib'
17 | t.libs << 'test'
18 | t.pattern = 'test/**/*_test.rb'
19 | t.verbose = false
20 | end
21 |
22 | task :default => :test
23 |
--------------------------------------------------------------------------------
/test/unit/spree/product_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class Spree::ProductTest < ActiveSupport::TestCase
4 |
5 | fixtures :products
6 |
7 | should "respond to wolesale price" do
8 | product = products(:wholesale)
9 | assert product.master.respond_to?(:wholesale_price), "Product is not wholesale ready. Try running `rake db:migrate` first."
10 | end
11 |
12 | should "be wholesaleble" do
13 | product = products(:wholesale)
14 | assert product.is_wholesaleable?
15 | end
16 |
17 |
18 | end
19 |
--------------------------------------------------------------------------------
/app/views/spree/orders/show.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= link_to t('back_to_store'), products_path %>
3 |
4 | <%= render 'spree/hooks/wholesale_customer_id' %>
5 |
6 | <% if params.has_key? :checkout_complete %>
7 |
8 |
<%= t('thank_you_for_your_order') %>
9 | <% else %>
10 | <%= link_to t('my_account'), account_path if current_user%>
11 | <% end %>
12 |
13 |
14 | <%= render :partial => 'shared/order_details', :locals => {:order => @order} %>
15 |
16 |
17 | <%= link_to t('back_to_store'), products_path %>
18 |
19 |
--------------------------------------------------------------------------------
/app/views/spree/wholesalers/index.html.erb:
--------------------------------------------------------------------------------
1 | <%= render 'spree/shared/wholesale_static_content' %>
2 |
3 |
4 |
<%= t('wholesale_apply') %>
5 |
Maecenas quis tortor arcu. Vivamus rutrum nunc non neque consectetur quis placerat neque lobortis. Nam vestibulum, arcu sodales feugiat consectetur, nisl orci bibendum elit, eu euismod magna sapien ut nibh.
6 | <%= link_to 'Apply Now!', spree.new_wholesaler_path, :class => 'button' %>
7 |
8 |
9 |
10 |
<%= t('wholesale_login') %>
11 | <%= render 'spree/shared/login' %>
12 |
13 |
--------------------------------------------------------------------------------
/test/dummy_hooks/before_migrate.rb:
--------------------------------------------------------------------------------
1 | run "rake spree:install:migrations"
2 | run "rake spree_auth:install:migrations"
3 |
4 | # Mount the Spree::Core routes
5 | insert_into_file File.join('config', 'routes.rb'), :after => "Application.routes.draw do\n" do
6 | " # Mount Spree's routes\n mount Spree::Core::Engine, :at => '/'\n"
7 | end
8 |
9 | # remove all stylesheets except core
10 | %w(admin store).each do |ns|
11 | template "#{ns}/all.js", "app/assets/javascripts/#{ns}/all.js", :force => true
12 | template "#{ns}/all.css", "app/assets/stylesheets/#{ns}/all.css", :force => true
13 | end
14 |
15 | # Fix sass load error by using the converted css file
16 | template "store/screen.css", "app/assets/stylesheets/store/screen.css"
17 |
18 | # Install spree_wholesale
19 | run "rails g spree_wholesale:install"
20 |
--------------------------------------------------------------------------------
/app/controllers/spree/checkout_controller_decorator.rb:
--------------------------------------------------------------------------------
1 | Spree::CheckoutController.instance_eval do
2 |
3 | before_filter :get_addresses
4 | before_filter :remove_payments_attributes
5 | end
6 |
7 | Spree::CheckoutController.class_eval do
8 |
9 | def get_addresses
10 | return unless current_user && current_user.wholesaler? && !current_user.wholesaler.nil?
11 | @order.bill_address = current_user.wholesaler.bill_address
12 | @order.ship_address = current_user.wholesaler.ship_address
13 | end
14 |
15 | def remove_payments_attributes
16 | if @order.is_wholesale? && @order.payment? && @order.wholesaler.terms != "Credit Card" && params[:order_pay_at] == "later"
17 | params.delete :payment_source if params[:payment_source].present?
18 | params[:order].delete :payments_attributes if params[:order][:payments_attributes].present?
19 | end
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/app/views/spree/checkout/_summary.html.erb:
--------------------------------------------------------------------------------
1 | <%= t(:order_summary) %>
2 | <% if order.is_wholesale? %>
3 | <%= render 'spree/hooks/wholesale_customer_id' %>
4 | <% end %>
5 |
6 |
7 |
8 |
9 | <%= t('item_total') %>:
10 | <%= number_to_currency order.item_total %>
11 |
12 |
13 | <% order.adjustments.each do |adjustment| %>
14 |
15 | <%= adjustment.label %>:
16 | <%= number_to_currency adjustment.amount %>
17 |
18 | <% end %>
19 |
20 |
21 | <%= t('order_total') %>:
22 | <%= number_to_currency @order.total %>
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/lib/tasks/spree_wholesale.rake:
--------------------------------------------------------------------------------
1 | namespace :spree_wholesale do
2 | def load_environment
3 | puts "Loading environment..."
4 | require File.join(Rails.root, 'config', 'environment')
5 | end
6 |
7 | desc "Creates wholesale role"
8 | task :create_role do
9 | load_environment
10 |
11 | name = "wholesaler"
12 | role = Spree::Role.find_by_name(name) rescue nil
13 | if role
14 | puts "Role exists!"
15 | else
16 | role = Spree::Role.create(:name => name)
17 | puts "Role created!"
18 | end
19 |
20 | puts role.inspect
21 | end
22 |
23 | desc "Assumes 50% wholesale discount for each variant"
24 | task :assume_wholesale_prices do
25 | load_environment
26 |
27 | Spree::Variant.all.each do |variant|
28 | price = variant.price * 0.5
29 | ActiveRecord::Base.connection.execute("UPDATE spree_variants SET wholesale_price = #{price} WHERE id = #{variant.id}")
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/lib/generators/spree_wholesale/install_generator.rb:
--------------------------------------------------------------------------------
1 | module SpreeWholesale
2 | module Generators
3 | class InstallGenerator < Rails::Generators::Base
4 |
5 | class_option :skip_migrations, :type => :boolean, :default => false, :description => "Skips the `run_migrations` step"
6 |
7 | desc "Installs required stylesheets, javascripts and migrations for spree_wholesale"
8 |
9 | def add_javascripts
10 | append_file "app/assets/javascripts/store/all.js", "//= require wholesaler_address\n"
11 | append_file "app/assets/javascripts/admin/all.js", "//= require wholesaler_address\n"
12 | end
13 |
14 | def add_stylesheets
15 | inject_into_file "app/assets/stylesheets/store/all.css", " *= require store/wholesale\n", :before => /\*\//, :verbose => true
16 | inject_into_file "app/assets/stylesheets/admin/all.css", " *= require admin/wholesalers\n", :before => /\*\//, :verbose => true
17 | end
18 |
19 | def install_migrations
20 | rake "spree_wholesale:install:migrations"
21 | end
22 |
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/db/migrate/20120113164801_install_spree_wholesale.rb:
--------------------------------------------------------------------------------
1 | class InstallSpreeWholesale < ActiveRecord::Migration
2 |
3 | def self.up
4 | create_table :spree_wholesalers do |t|
5 | t.references :user
6 | t.integer :billing_address_id
7 | t.integer :shipping_address_id
8 | t.string :company
9 | t.string :buyer_contact
10 | t.string :manager_contact
11 | t.string :phone
12 | t.string :fax
13 | t.string :resale_number
14 | t.string :taxid
15 | t.string :web_address
16 | t.string :terms
17 | t.string :alternate_email
18 | t.text :notes
19 | t.timestamps
20 | end
21 | add_index :spree_wholesalers, [:billing_address_id, :shipping_address_id], :name => "wholesalers_addresses"
22 | add_column :spree_orders, :wholesale, :boolean, :default => false
23 | add_column :spree_variants, :wholesale_price, :decimal, :precision => 8, :scale => 2, :null => false, :default => 0
24 | end
25 |
26 | def self.down
27 | remove_column :spree_variants, :wholesale_price
28 | remove_column :spree_orders, :wholesale
29 | drop_table :spree_wholesalers
30 | end
31 |
32 | end
33 |
--------------------------------------------------------------------------------
/app/views/spree/wholesalers/show.html.erb:
--------------------------------------------------------------------------------
1 | <%= t("wholesaler_account") %>
2 |
3 |
4 |
5 |
Company:
6 | <%= @wholesaler.company %>
7 |
8 | Buyer_contact:
9 | <%= @wholesaler.buyer_contact %>
10 |
11 | Manager_contact:
12 | <%= @wholesaler.manager_contact %>
13 |
14 | Phone:
15 | <%= @wholesaler.phone %>
16 |
17 | Fax:
18 | <%= @wholesaler.fax %>
19 |
20 | Resale_number:
21 | <%= @wholesaler.resale_number %>
22 |
23 | Taxid:
24 | <%= @wholesaler.taxid %>
25 |
26 | Web_address:
27 | <%= @wholesaler.web_address %>
28 |
29 | Terms:
30 | <%= @wholesaler.terms %>
31 |
32 | Notes:
33 | <%= simple_format @wholesaler.notes %>
34 |
35 |
36 |
37 |
38 |
39 |
40 |
<%= t("bill_address") %>
41 | <%= render 'spree/admin/shared/address', :address => @wholesaler.bill_address %>
42 |
43 |
44 |
<%= t("ship_address") %>
45 | <%= render 'spree/admin/shared/address', :address => @wholesaler.ship_address %>
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/lib/spree_wholesale/engine.rb:
--------------------------------------------------------------------------------
1 | module SpreeWholesale
2 | class Engine < Rails::Engine
3 |
4 | engine_name "spree_wholesale"
5 |
6 | config.autoload_paths += %W(#{config.root}/lib)
7 |
8 | class WholesalerAbility
9 | include CanCan::Ability
10 |
11 | def initialize(user)
12 | user ||= User.new
13 | can :index, Spree::Wholesaler
14 | can :new, Spree::Wholesaler
15 | can :create, Spree::Wholesaler
16 | can :read, Spree::Wholesaler do |resource|
17 | resource.user == user || user.has_role?(:admin)
18 | end
19 | can :update, Spree::Wholesaler do |resource|
20 | resource.user == user || user.has_role?(:admin)
21 | end
22 |
23 | end
24 | end
25 |
26 | def self.activate
27 | Dir.glob(File.join(File.dirname(__FILE__), "../../app/**/*_decorator*.rb")) do |c|
28 | Rails.application.config.cache_classes ? require(c) : load(c)
29 | end
30 |
31 | Dir.glob(File.join(File.dirname(__FILE__), "../../app/overrides/**/*.rb")) do |c|
32 | Rails.application.config.cache_classes ? require(c) : load(c)
33 | end
34 |
35 | Spree::Ability.register_ability(WholesalerAbility)
36 | end
37 |
38 | config.to_prepare &method(:activate).to_proc
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/app/views/spree/shared/_wholesale_static_content.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
<%= t('wholesalers') %>
3 |
4 |
Aenean facilisis nulla vitae urna tincidunt congue sed ut dui. Morbi malesuada nulla nec purus convallis consequat. Vivamus id mollis quam. Morbi ac commodo nulla. In condimentum orci id nisl volutpat bibendum. Quisque commodo hendrerit lorem quis egestas. Maecenas quis tortor arcu. Vivamus rutrum nunc non neque consectetur quis placerat neque lobortis. Nam vestibulum, arcu sodales feugiat consectetur, nisl orci bibendum elit, eu euismod magna sapien ut nibh. Donec semper quam scelerisque tortor dictum gravida. In hac habitasse platea dictumst. Nam pulvinar, odio sed rhoncus suscipit, sem diam ultrices mauris, eu consequat purus metus eu velit. Proin metus odio, aliquam eget molestie nec, gravida ut sapien. Phasellus quis est sed turpis sollicitudin venenatis sed eu odio. Praesent eget neque eu eros interdum malesuada non vel leo. Sed fringilla porta ligula egestas tincidunt. Nullam risus magna, ornare vitae varius eget, scelerisque a libero. Morbi eu porttitor ipsum. Nullam lorem nisi, posuere quis volutpat eget, luctus nec massa. Pellentesque aliquam lacinia tellus sit amet bibendum. Ut posuere justo in enim pretium scelerisque. Etiam ornare vehicula euismod. Vestibulum at risus augue. Sed non semper dolor. Sed fringilla consequat.
5 |
6 |
--------------------------------------------------------------------------------
/spree_wholesale.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | $:.push File.expand_path("../lib", __FILE__)
3 | require "spree_wholesale/version"
4 |
5 | Gem::Specification.new do |s|
6 | s.name = "spree_wholesale"
7 | s.version = SpreeWholesale::VERSION
8 | s.platform = Gem::Platform::RUBY
9 | s.authors = ["Spencer Steffen"]
10 | s.email = ["spencer@citrusme.com"]
11 | s.homepage = "https://github.com/citrus/spree_wholesale"
12 | s.summary = %q{Wholesale accounts for Spree Commerce.}
13 | s.description = %q{Spree Wholesale adds a wholesale_price field to variants and allows users with a "wholesaler" role to access these prices.}
14 |
15 | s.files = `git ls-files`.split("\n")
16 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18 |
19 | s.require_paths = ["lib"]
20 |
21 | s.add_dependency('spree_core', '~> 1.1.0.beta')
22 | s.add_dependency('spree_auth', '~> 1.1.0.beta')
23 |
24 | s.add_development_dependency('spree_sample', '~> 1.1.0')
25 | s.add_development_dependency('shoulda', '~> 3.0.0')
26 | s.add_development_dependency('dummier', '~> 0.3.2')
27 | s.add_development_dependency('factory_girl', '~> 2.6.0')
28 | s.add_development_dependency('capybara', '~> 1.1.2')
29 | s.add_development_dependency('sqlite3', '~> 1.3.4')
30 | #s.add_development_dependency('simplecov', '~> 0.6.1')
31 |
32 | end
33 |
--------------------------------------------------------------------------------
/app/models/spree/spree_current_order_decorator.rb:
--------------------------------------------------------------------------------
1 | Spree::Core::CurrentOrder.module_eval do
2 |
3 | # Associate the new order with the currently authenticated user before saving
4 | def before_save_new_order
5 | @current_order.user ||= current_user
6 | @current_order.wholesale = current_user.wholesaler? if current_user
7 | end
8 |
9 | def after_save_new_order
10 | # make sure the user has permission to access the order (if they are a guest)
11 | return if current_user
12 | session[:access_token] = @current_order.token
13 | end
14 |
15 | # The current incomplete order from the session for use in cart and during checkout
16 | def current_order(create_order_if_necessary = false)
17 | return @current_order if @current_order
18 | @current_order ||= Spree::Order.find_by_id(session[:order_id], :include => :adjustments)
19 | if create_order_if_necessary and (@current_order.nil? or @current_order.completed?)
20 | @current_order = Spree::Order.new
21 | before_save_new_order
22 | @current_order.save!
23 | after_save_new_order
24 | end
25 |
26 | if current_user && @current_order
27 | if current_user.wholesaler? && !@current_order.is_wholesale?
28 | @current_order.to_wholesale!
29 | elsif !current_user.wholesaler? && @current_order.is_wholesale?
30 | @current_order.to_fullsale!
31 | end
32 | end
33 |
34 | session[:order_id] = @current_order ? @current_order.id : nil
35 | @current_order
36 | end
37 |
38 | end
39 |
--------------------------------------------------------------------------------
/test/unit/spree/order_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class Spree::OrderTest < ActiveSupport::TestCase
4 |
5 | PRICE = BigDecimal.new("19.99")
6 | WHOLESALE = BigDecimal.new("18.00")
7 |
8 | fixtures :orders, :products
9 |
10 | def setup
11 | @wholesaler = Factory.create(:wholesaler)
12 | end
13 |
14 | should "respond to wholesale" do
15 | order = Spree::Order.new
16 | assert order.respond_to?(:wholesale)
17 | end
18 |
19 | should "be wholesale" do
20 | order = Factory.create(:order, :user => @wholesaler.user, :wholesale => true)
21 | assert order.is_wholesale?
22 | end
23 |
24 | should "convert to wholesale" do
25 | order = Factory.create(:order, :user => Factory.create(:user))
26 | assert !order.is_wholesale?
27 | assert !order.to_wholesale!
28 | assert !order.is_wholesale?
29 | order.user.wholesaler = @wholesaler
30 | assert order.to_wholesale!
31 | assert order.is_wholesale?
32 | end
33 |
34 | should "get regular price" do
35 | order = Factory.create(:order)
36 | assert_equal 0, order.item_total
37 | order.add_variant(products(:wholesale).master)
38 | order.update!
39 | assert_equal PRICE, order.item_total
40 | end
41 |
42 | should "get wholesale price" do
43 | order = Factory.create(:order, :user => @wholesaler.user, :wholesale => true)
44 | assert_equal 0, order.item_total
45 | order.add_variant(products(:wholesale).master)
46 | order.update!
47 | assert_equal WHOLESALE, order.item_total
48 | end
49 |
50 | end
51 |
--------------------------------------------------------------------------------
/app/controllers/spree/wholesalers_controller.rb:
--------------------------------------------------------------------------------
1 | class Spree::WholesalersController < Spree::BaseController
2 | respond_to :html, :xml
3 |
4 | def index
5 | end
6 |
7 | def show
8 | @wholesaler = Spree::Wholesaler.find(params[:id])
9 | respond_with(@wholesaler)
10 | end
11 |
12 | def new
13 | @wholesaler = Spree::Wholesaler.new
14 | @wholesaler.build_user
15 | @wholesaler.bill_address = Spree::Address.default
16 | @wholesaler.ship_address = Spree::Address.default
17 | respond_with(@wholesaler)
18 | end
19 |
20 | def create
21 | @wholesaler = Spree::Wholesaler.new(params[:wholesaler])
22 | if @wholesaler.save
23 | flash[:notice] = I18n.t('spree.wholesaler.signup_success')
24 | redirect_to spree.wholesalers_path
25 | else
26 | flash[:error] = I18n.t('spree.wholesaler.signup_failed')
27 | render :action => "new"
28 | end
29 | end
30 |
31 | def edit
32 | @wholesaler = Spree::Wholesaler.find(params[:id])
33 | respond_with(@wholesaler)
34 | end
35 |
36 | def update
37 | @wholesaler = Spree::Wholesaler.find(params[:id])
38 |
39 | if @wholesaler.update_attributes(params[:wholesaler])
40 | flash[:notice] = I18n.t('spree.wholesaler.update_success')
41 | else
42 | flash[:error] = I18n.t('spree.wholesaler.update_failed')
43 | end
44 | respond_with(@wholesaler)
45 | end
46 |
47 | def destroy
48 | @wholesaler = Spree::Wholesaler.find(params[:id])
49 | @wholesaler.destroy
50 | flash[:notice] = I18n.t('spree.wholesaler.destroy_success')
51 | respond_with(@wholesaler)
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/app/views/spree/admin/variants/_form.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <% @product.options.each do |option| %>
5 |
6 | <%= label :new_variant, option.option_type.presentation %>
7 | <% if @variant.new_record? %>
8 | <%= select(:new_variant, option.option_type.presentation,
9 | option.option_type.option_values.collect {|ov| [ ov.presentation, ov.id ] },
10 | {})
11 | %>
12 | <% else %>
13 | <% opt = @variant.option_values.detect {|o| o.option_type == option.option_type }.presentation %>
14 | <%= text_field(:new_variant, option.option_type.presentation, :value => opt, :disabled => 'disabled') %>
15 | <% end %>
16 |
17 | <% end %>
18 |
19 |
<%= f.label :sku, t("sku") %>
20 | <%= f.text_field :sku %>
21 |
22 |
<%= f.label :price, t("price") %>:
23 | <%= f.text_field :price, :value => number_with_precision(@variant.price, :precision => 2) %>
24 |
25 |
<%= f.label :wholesale_price, t(".wholesale_price") %>:
26 | <%= f.text_field :wholesale_price, :value => number_with_precision(@variant.wholesale_price, :precision => 2) %>
27 |
28 |
<%= f.label :cost_price, t("cost_price") %>:
29 | <%= f.text_field :cost_price, :value => number_with_precision(@variant.cost_price, :precision => 2) %>
30 |
31 | <% if Spree::Config[:track_inventory_levels] %>
32 |
<%= f.label :on_hand, t("on_hand") %>:
33 | <%= f.text_field :on_hand %>
34 | <% end %>
35 |
36 |
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2011 Spencer Steffen and Citrus Media Group.
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification,
5 | are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice,
8 | this list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of Citrus Media Group nor the names of its
15 | contributors may be used to endorse or promote products derived from this
16 | software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/test/fixtures/spree/orders.yml:
--------------------------------------------------------------------------------
1 | incomplete:
2 | id: 1069267039
3 | user_id: 1057526560
4 | number: R107687410
5 | item_total: 29.01
6 | total: 29.01
7 | created_at: 2011-01-12 03:07:39
8 | updated_at: 2011-01-12 03:07:39
9 | state: cart
10 | adjustment_total: 0.00
11 | credit_total: 0.00
12 | completed_at: NULL
13 | bill_address_id: NULL
14 | ship_address_id: NULL
15 | payment_total: 0.00
16 | shipping_method_id: NULL
17 | shipment_state: NULL
18 | payment_state: 'balance_due'
19 | email: 'spree@example.com'
20 | special_instructions: NULL
21 | wholesale: 0
22 |
23 | complete:
24 | id: 1069267040
25 | user_id: 1057526560
26 | number: R107687411
27 | item_total: 29.01
28 | total: 29.01
29 | created_at: 2011-01-12 03:07:39
30 | updated_at: 2011-01-12 03:07:39
31 | state: cart
32 | adjustment_total: 0.00
33 | credit_total: 0.00
34 | completed_at: NULL
35 | bill_address_id: NULL
36 | ship_address_id: NULL
37 | payment_total: 0.00
38 | shipping_method_id: NULL
39 | shipment_state: NULL
40 | payment_state: 'balance_due'
41 | email: 'spree@example.com'
42 | special_instructions: NULL
43 | wholesale: 0
44 |
45 | wholesale:
46 | id: 1069267041
47 | user_id: 1
48 | number: R107687412
49 | item_total: 18.00
50 | total: 18.00
51 | created_at: 2011-01-12 03:07:39
52 | updated_at: 2011-01-12 03:07:39
53 | state: complete
54 | adjustment_total: 0.00
55 | credit_total: 0.00
56 | completed_at: 2011-01-12 03:10:48
57 | bill_address_id: NULL
58 | ship_address_id: NULL
59 | payment_total: 0.00
60 | shipping_method_id: NULL
61 | shipment_state: NULL
62 | payment_state: 'balance_due'
63 | email: 'spree@example.com'
64 | special_instructions: NULL
65 | wholesale: 1
66 |
67 |
--------------------------------------------------------------------------------
/app/views/spree/admin/wholesalers/show.html.erb:
--------------------------------------------------------------------------------
1 | <%= t("wholesaler_account") %>
2 |
3 |
4 |
5 |
Company:
6 | <%= @wholesaler.company %>
7 |
8 | Buyer_contact:
9 | <%= @wholesaler.buyer_contact %>
10 |
11 | Manager_contact:
12 | <%= @wholesaler.manager_contact %>
13 |
14 | Phone:
15 | <%= @wholesaler.phone %>
16 |
17 | Fax:
18 | <%= @wholesaler.fax %>
19 |
20 | Resale_number:
21 | <%= @wholesaler.resale_number %>
22 |
23 | Taxid:
24 | <%= @wholesaler.taxid %>
25 |
26 | Web_address:
27 | <%= @wholesaler.web_address %>
28 |
29 | Terms:
30 | <%= @wholesaler.terms %>
31 |
32 | Notes:
33 | <%= simple_format @wholesaler.notes %>
34 |
35 |
36 |
37 |
38 |
39 |
40 |
<%= t("bill_address") %>
41 | <%= render 'spree/admin/shared/address', :address => @wholesaler.bill_address %>
42 |
43 |
44 |
<%= t("ship_address") %>
45 | <%= render 'spree/admin/shared/address', :address => @wholesaler.ship_address %>
46 |
47 |
48 |
49 |
<%= t("user_details") %>
50 |
51 | ID: <%= @wholesaler.user.id %>
52 |
53 | Email: <%= @wholesaler.user.email %>
54 |
55 | <%= link_to "view user", admin_user_path(@wholesaler.user) %> /
56 | <%= link_to "edit user", edit_admin_user_path(@wholesaler.user) %> /
57 | <%= render "user_options", :user => @wholesaler.user %>
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | <%= link_to_edit @wholesaler %> <%= t('or') %>
67 | <%= link_to t('back'), collection_url %>
68 |
69 |
--------------------------------------------------------------------------------
/app/views/spree/hooks/_wholesale_payment_options.html.erb:
--------------------------------------------------------------------------------
1 | <% order = (@order || order) %>
2 | <% if order.is_wholesale? %>
3 |
4 |
5 |
6 |
Your wholesale terms are <%= @order.user.wholesaler.terms %> which means
7 | <% if @order.user.wholesaler.terms == "Credit Card" %>
8 | that you'll have to pay for this order now.
9 | <% else %>
10 | that you can pay for this order now or
11 | <% if @order.user.wholesaler.terms == "COD" %>
12 | when it arrives.
13 | <% else %>
14 | at the end of your
<%= @order.user.wholesaler.terms.sub("Net ", "") %> day cycle.
15 | <% end %>
16 |
17 |
18 | <%= radio_button_tag "order_pay_at", "now" %>
19 | <%= label_tag "order_pay_at_now", "Pay Now" %>
20 |
21 | <%= radio_button_tag "order_pay_at", "later" %>
22 | <%= label_tag "order_pay_at_later", "Pay Later" %>
23 |
24 | <% content_for :head do %>
25 |
39 | <% end %>
40 | <% end %>
41 |
42 |
43 |
44 |
45 | <% end %>
46 |
--------------------------------------------------------------------------------
/test/unit/spree/wholesaler_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class Spree::WholesalerTest < ActiveSupport::TestCase
4 |
5 | def setup
6 | # nada
7 | end
8 |
9 | should belong_to(:user)
10 | should belong_to(:bill_address)
11 | should belong_to(:ship_address)
12 |
13 | should validate_presence_of(:company)
14 | should validate_presence_of(:buyer_contact)
15 | should validate_presence_of(:manager_contact)
16 | should validate_presence_of(:phone)
17 | should validate_presence_of(:taxid)
18 |
19 | context "with a new wholesaler" do
20 |
21 | setup do
22 | @wholesaler = Factory.build(:wholesaler, :user => nil, :ship_address => nil, :bill_address => nil)
23 | end
24 |
25 | should "create valid wholesaler" do
26 | @wholesaler.user = Factory.create(:wholesale_user)
27 | @wholesaler.bill_address = @wholesaler.ship_address = Factory.create(:address)
28 | assert @wholesaler.valid?
29 | assert @wholesaler.save
30 | end
31 |
32 | end
33 |
34 | context "with an existing wholesaler" do
35 |
36 | setup do
37 | @wholesaler = Factory.create(:wholesaler,
38 | :user => Factory.create(:wholesale_user),
39 | :bill_address => Factory.create(:address),
40 | :ship_address => Factory.create(:address)
41 | )
42 | end
43 |
44 | should "activate" do
45 | @wholesaler.roles = [Spree::Role.find_by_name("user")]
46 |
47 | assert !@wholesaler.active?
48 | @wholesaler.activate!
49 | assert @wholesaler.active?
50 | end
51 |
52 | should "deactivate" do
53 | @wholesaler.roles = [Spree::Role.find_by_name("wholesaler")]
54 |
55 | assert @wholesaler.active?
56 | @wholesaler.deactivate!
57 | assert !@wholesaler.active?
58 | end
59 |
60 | end
61 |
62 |
63 | #should "activate and deactivate" do
64 | #
65 | # @wholesaler.deactivate!
66 | # assert !@wholesaler.active?
67 | #end
68 |
69 | end
70 |
--------------------------------------------------------------------------------
/app/models/spree/order_decorator.rb:
--------------------------------------------------------------------------------
1 | Spree::Order.class_eval do
2 |
3 | def wholesale
4 | read_attribute(:wholesale) && !wholesaler.nil?
5 | end
6 |
7 | def wholesaler
8 | user && user.wholesaler
9 | end
10 |
11 | def is_wholesale?
12 | wholesale
13 | end
14 |
15 | def set_line_item_prices(use_price=:price)
16 | line_items.includes(:variant).each do |line_item|
17 | line_item.price = line_item.variant.send(use_price)
18 | line_item.save
19 | end
20 | end
21 |
22 | def to_fullsale!
23 | self.wholesale = false
24 | set_line_item_prices(:price)
25 | update!
26 | save
27 | end
28 |
29 | def to_wholesale!
30 | return false unless user.wholesaler.present?
31 | self.wholesale = true
32 | set_line_item_prices(:wholesale_price)
33 | update!
34 | save
35 | end
36 |
37 | def add_variant(variant, quantity = 1)
38 | current_item = contains?(variant)
39 | if current_item
40 | current_item.quantity += quantity
41 | current_item.save
42 | else
43 | current_item = Spree::LineItem.new(:quantity => quantity)
44 | current_item.variant = variant
45 | current_item.price = is_wholesale? ? variant.wholesale_price : variant.price
46 | self.line_items << current_item
47 | end
48 |
49 | # populate line_items attributes for additional_fields entries
50 | # that have populate => [:line_item]
51 | # Spree::Variant.additional_fields.select{|f| !f[:populate].nil? && f[:populate].include?(:line_item) }.each do |field|
52 | # value = ""
53 |
54 | # if field[:only].nil? || field[:only].include?(:variant)
55 | # value = variant.send(field[:name].gsub(" ", "_").downcase)
56 | # elsif field[:only].include?(:product)
57 | # value = variant.product.send(field[:name].gsub(" ", "_").downcase)
58 | # end
59 | # current_item.update_attribute(field[:name].gsub(" ", "_").downcase, value)
60 | # end
61 |
62 | current_item
63 | end
64 |
65 | end
66 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | # Configure Rails Envinronment
2 | ENV["RAILS_ENV"] = "test"
3 |
4 | env = File.expand_path("../dummy/config/environment.rb", __FILE__)
5 | if File.exists?(env)
6 | require env
7 | else
8 | raise LoadError, "Please create the dummy app before running tests. Try running `bundle exec dummier`"
9 | end
10 |
11 | require 'rails/test_help'
12 | require 'shoulda'
13 | require 'factory_girl'
14 | require 'capybara/rails'
15 |
16 | # Load support files
17 | Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
18 |
19 | include HelperMethods
20 |
21 | ActionMailer::Base.delivery_method = :test
22 | ActionMailer::Base.perform_deliveries = false
23 | ActionMailer::Base.default_url_options[:host] = "example.com"
24 |
25 | Rails.backtrace_cleaner.remove_silencers!
26 |
27 | # Configure capybara for integration testing
28 | Capybara.default_driver = :selenium
29 | Capybara.default_selector = :css
30 |
31 | # Run any available migration
32 | ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
33 |
34 | module FixturesHelper
35 |
36 | extend ActiveSupport::Concern
37 |
38 | included do
39 | self.fixture_path = File.expand_path('../fixtures/spree', __FILE__)
40 | set_fixture_class :addresses => Spree::Address
41 | set_fixture_class :countries => Spree::Country
42 | set_fixture_class :orders => Spree::Order
43 | set_fixture_class :products => Spree::Product
44 | set_fixture_class :roles => Spree::Role
45 | set_fixture_class :states => Spree::State
46 | set_fixture_class :variants => Spree::Variant
47 | set_fixture_class :wholesalers => Spree::Wholesaler
48 | fixtures :all
49 | end
50 |
51 | end
52 |
53 | class ActionController::TestCase
54 | include Devise::TestHelpers
55 | include FixturesHelper
56 | end
57 |
58 | class ActiveSupport::TestCase
59 | include FixturesHelper
60 | end
61 |
62 | # Default to US
63 | Spree::Config.set(:default_country_id => 214)
64 | FactoryGirl.reload
65 |
--------------------------------------------------------------------------------
/app/views/spree/wholesalers/_fields.html.erb:
--------------------------------------------------------------------------------
1 | <% content_for :head do %>
2 |
3 | <% end %>
4 |
5 |
6 |
7 |
8 |
9 | User
10 | <%= form.fields_for :user do |uf| %>
11 | <%= render 'spree/shared/user_form', :f => uf %>
12 | <% end %>
13 |
14 |
15 |
16 | Company Information
17 |
18 |
19 | <%= form.label :company %>
20 | <%= form.text_field :company, :class => 'required' %>*
21 |
22 |
23 | <%= form.label :buyer_contact %>
24 | <%= form.text_field :buyer_contact, :class => 'required' %>*
25 |
26 |
27 | <%= form.label :manager_contact %>
28 | <%= form.text_field :manager_contact, :class => 'required' %>*
29 |
30 |
31 | <%= form.label :phone %>
32 | <%= form.text_field :phone, :class => 'required' %>*
33 |
34 |
35 | <%= form.label :fax %>
36 | <%= form.text_field :fax %>
37 |
38 |
39 | <%= form.label :resale_number %>
40 | <%= form.text_field :resale_number %>
41 |
42 |
43 | <%= form.label :taxid %>
44 | <%= form.text_field :taxid, :class => 'required' %>*
45 |
46 |
47 | <%= form.label :web_address %>
48 | <%= form.text_field :web_address %>
49 |
50 |
51 | <%= form.label :terms %>
52 | <%= form.select :terms, Spree::Wholesaler.term_options, :class => 'required' %>*
53 |
54 |
55 | <%= form.label :notes %>
56 | <%= form.text_area :notes %>
57 |
58 |
59 |
60 |
61 |
62 | <%= render "spree/shared/address_form", :form => form %>
63 |
64 |
--------------------------------------------------------------------------------
/app/models/spree/wholesaler.rb:
--------------------------------------------------------------------------------
1 | class Spree::Wholesaler < ActiveRecord::Base
2 | partial_updates = false
3 |
4 | attr_accessible :bill_address_attributes, :ship_address_attributes, :user_attributes,
5 | :ship_address, :bill_address,
6 | :company, :buyer_contact, :manager_contact, :phone, :fax, :resale_number,
7 | :taxid, :web_address, :terms, :notes, :use_billing
8 |
9 | belongs_to :user, :class_name => "Spree::User"
10 | belongs_to :bill_address, :foreign_key => "billing_address_id", :class_name => "Spree::Address", :dependent => :destroy
11 | belongs_to :ship_address, :foreign_key => "shipping_address_id", :class_name => "Spree::Address", :dependent => :destroy
12 |
13 | accepts_nested_attributes_for :bill_address
14 | accepts_nested_attributes_for :ship_address
15 | accepts_nested_attributes_for :user
16 |
17 | attr_accessor :use_billing
18 | before_validation :clone_billing_address, :if => "@use_billing"
19 | validates :company, :buyer_contact, :manager_contact, :phone, :taxid, :presence => true
20 |
21 | delegate_belongs_to :user, :roles
22 | delegate_belongs_to :user, :email
23 |
24 | def activate!
25 | get_wholesale_role
26 | return false if user.roles.include?(@role)
27 | user.roles << @role
28 | user.save
29 | end
30 |
31 | def deactivate!
32 | get_wholesale_role
33 | return false unless user.roles.include?(@role)
34 | user.roles.delete(@role)
35 | user.save
36 | end
37 |
38 | def active?
39 | user && user.has_role?("wholesaler")
40 | end
41 |
42 | def self.term_options
43 | %(Net 10, Net 15, Net 30, COD, Credit Card).split(", ")
44 | end
45 |
46 | private
47 |
48 | def get_wholesale_role
49 | @role = Spree::Role.find_or_create_by_name("wholesaler")
50 | end
51 |
52 | def clone_billing_address
53 | if bill_address and self.ship_address.nil?
54 | self.ship_address = bill_address.clone
55 | else
56 | self.ship_address.attributes = bill_address.attributes.except("id", "updated_at", "created_at")
57 | end
58 | true
59 | end
60 | end
61 |
--------------------------------------------------------------------------------
/test/factories.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 |
3 | factory :state, :class => Spree::State do
4 | name "California"
5 | abbr "CA"
6 | country { Spree::Country.find_by_iso("US") || Factory.create(:country) }
7 | end
8 |
9 | factory :country, :class => Spree::Country do
10 | name "United States"
11 | iso3 "USA"
12 | iso "US"
13 | iso_name { name.upcase }
14 | numcode 840
15 | end
16 |
17 | factory :address, :class => Spree::Address do
18 | firstname "Addy"
19 | lastname "Streetston"
20 | address1 { "#{100 + rand(1000)} State St" }
21 | city "Santa Barbara"
22 | phone "555-555-5555"
23 | zipcode "93101"
24 | state { Spree::State.find_by_name("California") || Factory.create(:state) }
25 | country { Spree::Country.find_by_name("United States") || Factory.create(:country) }
26 | end
27 |
28 |
29 | factory :wholesaler, :class => Spree::Wholesaler do
30 | company "Test Company"
31 | buyer_contact "Mr Contacter"
32 | manager_contact "Mr Manager"
33 | phone "555-555-5555"
34 | fax "555-555-5555 ext 1"
35 | resale_number "123456789"
36 | taxid "555-55-5555"
37 | web_address "testcompany.com"
38 | terms "Credit Card"
39 | notes "What a guy!"
40 | user { Spree::User.wholesale.last || Factory.create(:wholesale_user) }
41 | bill_address { Factory.create(:address) }
42 | ship_address { Factory.create(:address) }
43 | end
44 |
45 |
46 | factory :user, :class => Spree::User do
47 | email { random_email }
48 | password "spree123"
49 | password_confirmation "spree123"
50 | roles { [Spree::Role.find_or_create_by_name("user")] }
51 | end
52 |
53 | factory :admin_user, :parent => :user do
54 | roles { [Spree::Role.find_or_create_by_name("admin")] }
55 | end
56 |
57 | factory :wholesale_user, :parent => :user do
58 | roles { [Spree::Role.find_or_create_by_name("wholesaler")] }
59 | #wholesaler { Factory.create(:wholesaler) }
60 | end
61 |
62 | factory :order, :class => Spree::Order do
63 | user { Spree::User.last || Factory.create(:user) }
64 | state 'cart'
65 | payment_state 'balance_due'
66 | email { random_email }
67 | wholesale false
68 | end
69 |
70 | #factory :wholesale_order, :parent => :order do
71 | # #user { Factory.create(:wholesale_user) }
72 | # wholesale true
73 | #end
74 |
75 | end
76 |
--------------------------------------------------------------------------------
/app/assets/javascripts/wholesaler_address.js:
--------------------------------------------------------------------------------
1 | (function($){
2 | $(document).ready(function(){
3 | if($('.wholesaler-form, .new_wholesaler').is('*')){
4 |
5 | // $('.wholesaler-form, .new_wholesaler').validate();
6 |
7 | var get_states = function(region){
8 | country = $('p#' + region + 'country' + ' span#' + region + 'country :only-child').val();
9 | return state_mapper[country];
10 | }
11 |
12 | var update_state = function(region) {
13 | states = get_states(region);
14 |
15 | state_select = $('p#' + region + 'state select');
16 | state_input = $('p#' + region + 'state input');
17 |
18 | if(states) {
19 | selected = state_select.val();
20 | state_select.html('');
21 | states_with_blank = [["",""]].concat(states);
22 | $.each(states_with_blank, function(pos,id_nm) {
23 | var opt = $(document.createElement('option'))
24 | .attr('value', id_nm[0])
25 | .html(id_nm[1]);
26 | if(selected==id_nm[0]){
27 | opt.prop("selected", true);
28 | }
29 | state_select.append(opt);
30 | });
31 | state_select.prop("disabled", false).show();
32 | state_input.hide().prop("disabled", true);
33 |
34 | } else {
35 | state_input.prop("disabled", false).show();
36 | state_select.hide().prop("disabled", true);
37 | }
38 |
39 | };
40 |
41 | $('p#bcountry select').change(function() { update_state('b'); });
42 | $('p#scountry select').change(function() { update_state('s'); });
43 | update_state('b');
44 | update_state('s');
45 |
46 | $('input#wholesaler_use_billing').click(function() {
47 | if($(this).is(':checked')) {
48 | $('#shipping .inner').hide();
49 | $('#shipping .inner input, #shipping .inner select').prop("disabled", true);
50 | } else {
51 | $('#shipping .inner').show();
52 | $('#shipping .inner input, #shipping .inner select').prop("disabled", false);
53 | //only want to enable relevant field
54 | if(get_states('s')){
55 | $('span#sstate input').hide().prop("disabled", true);
56 | }else{
57 | $('span#sstate select').hide().prop("disabled", true);
58 | }
59 |
60 | }
61 | }).triggerHandler('click');
62 |
63 | }
64 |
65 | });
66 | })(jQuery);
67 |
--------------------------------------------------------------------------------
/app/views/spree/admin/wholesalers/_form.html.erb:
--------------------------------------------------------------------------------
1 | <% content_for :head do %>
2 |
3 | <% end %>
4 |
5 |
6 |
7 | Company Information
8 |
9 |
10 | <%= form.label :company %>
11 | <%= form.text_field :company, :class => 'required' %>*
12 |
13 |
14 | <%= form.label :buyer_contact %>
15 | <%= form.text_field :buyer_contact, :class => 'required' %>*
16 |
17 |
18 | <%= form.label :manager_contact %>
19 | <%= form.text_field :manager_contact, :class => 'required' %>*
20 |
21 |
22 | <%= form.label :phone %>
23 | <%= form.text_field :phone, :class => 'required' %>*
24 |
25 |
26 | <%= form.label :fax %>
27 | <%= form.text_field :fax %>
28 |
29 |
30 | <%= form.label :resale_number %>
31 | <%= form.text_field :resale_number %>
32 |
33 |
34 | <%= form.label :taxid %>
35 | <%= form.text_field :taxid, :class => 'required' %>*
36 |
37 |
38 | <%= form.label :web_address %>
39 | <%= form.text_field :web_address %>
40 |
41 |
42 | <%= form.label :terms %>
43 | <%= form.select :terms, Spree::Wholesaler.term_options, :class => 'required' %>*
44 |
45 |
46 | <%= form.label :notes %>
47 | <%= form.text_area :notes %>
48 |
49 |
50 |
51 |
52 | User Details:
53 | <% if @wholesaler.new_record? %>
54 | <%= form.fields_for :user do |uf| %>
55 | <%= render 'spree/shared/user_form', :f => uf %>
56 | <% end %>
57 | <% else %>
58 |
59 | User Id:
60 | <%= link_to @wholesaler.user.id, admin_user_path(@wholesaler.user) %>
61 |
62 | <%= link_to "view user", admin_user_path(@wholesaler.user) %> /
63 | <%= link_to "edit user", edit_admin_user_path(@wholesaler.user) %> /
64 | <%= render "user_options" %>
65 |
66 | <% end %>
67 |
68 |
69 |
70 |
71 | <%= render "spree/shared/address_form", :form => form %>
72 |
73 |
--------------------------------------------------------------------------------
/app/views/spree/admin/wholesalers/index.html.erb:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 | <%= t("listing_wholesalers") %>
12 |
13 |
14 |
15 |
16 |
17 | <%= sort_link @search, :company, t('wholesaler') %>
18 | <%= sort_link @search, :buyer_contact, t('buyer_contact') %>
19 | <%= sort_link @search, :user_email, t('email') %>
20 | <%= sort_link @search, :phone, t('phone') %>
21 | <%= t('active') %>
22 |
23 |
24 |
25 |
26 |
27 | <% @wholesalers.each do |wholesaler|%>
28 |
29 | <%- locals = {:wholesaler => wholesaler} %>
30 | <%=link_to wholesaler.company, object_url(wholesaler) %>
31 | <%= wholesaler.buyer_contact %>
32 | <%= mail_to wholesaler.email %>
33 | <%= wholesaler.phone %>
34 | <%= wholesaler.roles.include?("wholesale") ? 'yes' : 'no' %>
35 |
36 | <%= link_to_edit wholesaler %>
37 | <%= link_to_delete wholesaler %>
38 | <%= render 'user_options', :wholesaler => wholesaler %>
39 |
40 |
41 | <% end %>
42 |
43 |
44 |
45 | <%= paginate @wholesalers %>
46 |
47 |
48 |
49 | <% content_for :sidebar do %>
50 |
51 |
<%= t('search') %>
52 |
53 | <% @wholesaler = Spree::Wholesaler.search %>
54 |
55 | <%= search_form_for [:admin, @wholesaler] do |f| %>
56 | <%- locals = {:f => f} %>
57 |
58 | <%= t(".company") %>
59 | <%= f.text_field :company_cont, :size=>18 %>
60 |
61 |
62 | <%= t(".buyer_contact") %>
63 | <%= f.text_field :buyer_contact_cont, :size=>18 %>
64 |
65 |
66 | <%= t(".manager_contact") %>
67 | <%= f.text_field :manager_contact_cont, :size=>18 %>
68 |
69 |
70 | <%= t("phone") %>
71 | <%= f.text_field :phone_cont, :size=>18 %>
72 |
73 |
74 | <%= t(".notes") %>
75 | <%= f.text_field :notes_cont, :size=>18 %>
76 |
77 |
78 |
<%= button t("search") %>
79 | <% end %>
80 |
81 | <% end %>
82 |
--------------------------------------------------------------------------------
/app/controllers/spree/admin/wholesalers_controller.rb:
--------------------------------------------------------------------------------
1 | class Spree::Admin::WholesalersController < Spree::Admin::ResourceController
2 | respond_to :html, :xml
3 | before_filter :approval_setup, :only => [ :approve, :reject ]
4 |
5 | def index
6 | end
7 |
8 | def show
9 | @wholesaler = Spree::Wholesaler.find(params[:id])
10 | respond_with(@wholesaler)
11 | end
12 |
13 | def new
14 | @wholesaler = Spree::Wholesaler.new
15 | @wholesaler.build_user
16 | @wholesaler.bill_address = Spree::Address.default
17 | @wholesaler.ship_address = Spree::Address.default
18 | respond_with(@wholesaler)
19 | end
20 |
21 | def create
22 | @wholesaler = Spree::Wholesaler.new(params[:wholesaler])
23 | if @wholesaler.save
24 | flash[:notice] = I18n.t('spree.admin.wholesaler.success')
25 | redirect_to spree.admin_wholesalers_path
26 | else
27 | flash[:error] = I18n.t('spree.admin.wholesaler.failed')
28 | render :action => "new"
29 | end
30 | end
31 |
32 | def edit
33 | @wholesaler = Spree::Wholesaler.find(params[:id])
34 | respond_with(@wholesaler)
35 | end
36 |
37 | def update
38 | @wholesaler = Spree::Wholesaler.find(params[:id])
39 |
40 | if @wholesaler.update_attributes(params[:wholesaler])
41 | flash[:notice] = I18n.t('spree.admin.wholesaler.update_success')
42 | else
43 | flash[:error] = I18n.t('spree.admin.wholesaler.update_failed')
44 | end
45 | respond_with(@wholesaler)
46 | end
47 |
48 | def destroy
49 | @wholesaler = Spree::Wholesaler.find(params[:id])
50 | @wholesaler.destroy
51 | flash[:notice] = I18n.t('spree.admin.wholesaler.destroy_success')
52 | respond_with(@wholesaler)
53 | end
54 |
55 | def approve
56 | return redirect_to request.referer, :flash => { :error => "Wholesaler is already active." } if @wholesaler.active?
57 | @wholesaler.activate!
58 | redirect_to request.referer, :flash => { :notice => "Wholesaler was successfully approved." }
59 | end
60 |
61 | def reject
62 | return redirect_to request.referer, :flash => { :error => "Wholesaler is already rejected." } unless @wholesaler.active?
63 | @wholesaler.deactivate!
64 | redirect_to request.referer, :flash => { :notice => "Wholesaler was successfully rejected." }
65 | end
66 |
67 | private
68 |
69 | def approval_setup
70 | @wholesaler = Spree::Wholesaler.find(params[:id])
71 | @role = Spree::Role.find_or_create_by_name("wholesaler")
72 | end
73 |
74 | def collection
75 | return @collection if @collection.present?
76 |
77 | params[:search] ||= {}
78 | params[:search][:meta_sort] ||= "company.asc"
79 | @search = Spree::Wholesaler.ransack(params[:q])
80 | @collection = @search.result.page(params[:page]).per(Spree::Config[:admin_products_per_page])
81 | end
82 | end
83 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | billing_firstname: "Billing First Name"
3 | billing_lastname: "Billing Last Name"
4 | shipping_firstname: "Shipping First Name"
5 | shipping_lastname: "Shipping Last Name"
6 |
7 | buyer_contact: "Buyer Contact"
8 |
9 | wholesale: "Wholesale"
10 | wholesaler: "Wholesaler"
11 | wholesalers: "Wholesalers"
12 | new_wholesaler: "New Wholesaler"
13 | editing_wholesaler: "Edit Wholesaler"
14 | wholesaler_account: "Wholesaler Account"
15 | listing_wholesalers: "Listing Wholesaler"
16 | wholesale_login: "Wholesale Login"
17 | wholesale_apply: "Apply for a wholesale account"
18 | wholesale_signup: "Wholesale Signup"
19 | wholesale_update: "Wholesale Update"
20 | wholesale_price: "Wholesale Price"
21 |
22 | actions:
23 | cancel: "Cancel"
24 |
25 | shared:
26 | address_form:
27 | use_for_shipping: "Use billing address for shipping"
28 |
29 | wholesale_customer: "Wholesale Customer ID: #%{id}"
30 |
31 | spree:
32 |
33 | wholesaler:
34 | signup_success: Thank you for your interest in becoming a wholesaler! We'll be in touch shortly.
35 | signup_failed: Wholesale account could not be created
36 | parts_error_message: There are errors with the user or addresses
37 | success: Wholesale account was successfully created
38 | update_success: Wholesale account was successfully updated
39 | failed: Wholesale account could not be created
40 | update_failed: Wholesale account could not be updated
41 | destroy_success: Wholesale account was successfully deleted
42 |
43 | admin:
44 |
45 | hooks:
46 | product_form_right:
47 | master_wholesale_price: "Master Wholesale Price"
48 | admin_orders_index_search:
49 | show_wholesale_orders: "Show only wholesale orders"
50 |
51 | variants:
52 | form:
53 | wholesale_price: "Wholesale Price"
54 |
55 |
56 | wholesaler:
57 | success: Wholesale account was successfully created
58 | update_success: Wholesale account was successfully updated
59 | failed: Wholesale account could not be created
60 | update_failed: Wholesale account could not be updated
61 | destroy_success: Wholesale account was successfully deleted
62 |
63 | wholesalers:
64 | index:
65 | company: "Company"
66 | buyer_contact: "Buyer contact"
67 | manager_contact: "Manager contact"
68 | notes: "Notes"
69 | form:
70 | company: "Company"
71 | buyer_contact: "Buyer contact"
72 | manager_contact: "Manager contact"
73 | phone: "Phone"
74 | fax: "Fax"
75 | resale_number: "Resale number"
76 | taxid: "Taxid"
77 | web_address: "Web address"
78 | terms: "Terms"
79 | notes: "Notes"
80 |
--------------------------------------------------------------------------------
/test/integration/spree/wholesalers_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class Spree::WholesalersTest < ActiveSupport::IntegrationCase
4 |
5 | def setup
6 | Factory.create(:state)
7 |
8 | @user = Factory.create(:user)
9 | login_as @user
10 |
11 | @labels = %(Company, Buyer contact, Manager contact, Phone, Fax, Resale number, Taxid, Web address, Notes).split(', ')
12 | @values = %(Some Company, Buyer contact, Manager contact, 555-555-5555, 555-555-5555 ext 1, 12345, 123-45-6789, example.com, Yippee!).split(', ')
13 | @address_labels = %(First Name, Last Name, Street Address, City, Zip, Phone).split(', ')
14 | @address_values = %(Billy, Billerton, 111 State St, Santa Barbara, 93101, 555-555-5555).split(', ')
15 | end
16 |
17 | should "have a link to new wholesaler" do
18 | visit spree.wholesalers_path
19 | within ".login" do
20 | assert page.has_field?("Email")
21 | assert page.has_field?("Password")
22 | end
23 | assert page.has_link?("Apply Now!")
24 | click_link "Apply Now!"
25 | assert_equal spree.new_wholesaler_path, current_path
26 | end
27 |
28 | should "get new wholesaler" do
29 | visit spree.new_wholesaler_path
30 | assert page.has_content?(I18n.t('wholesale_signup'))
31 | within "#new_wholesaler" do
32 | @labels.each do |f|
33 | assert page.has_field?(f)
34 | end
35 | assert page.has_field?('Terms')
36 | end
37 | assert has_button?(I18n.t('wholesale_apply'))
38 | end
39 |
40 | should "validate wholesaler and parts" do
41 | visit spree.new_wholesaler_path
42 | click_button I18n.t('wholesale_apply')
43 |
44 | assert page.has_content?(I18n.t('spree.wholesaler.signup_failed'))
45 | assert page.has_content?('21 errors prohibited this record from being saved:')
46 | end
47 |
48 | should "be a valid wholesaler but invalid parts" do
49 | visit spree.new_wholesaler_path
50 | @labels.each_with_index do |label, index|
51 | fill_in label, :with => @values[index]
52 | end
53 | select 'Credit Card', :from => 'Terms'
54 | click_button I18n.t('wholesale_apply')
55 | assert page.has_content?(I18n.t('spree.wholesaler.signup_failed'))
56 | end
57 |
58 | should "create wholesaler and parts" do
59 | visit spree.new_wholesaler_path
60 | within ".wholesaler-details" do
61 | @labels.each_with_index do |label, index|
62 | fill_in label, :with => @values[index]
63 | end
64 | select 'Credit Card', :from => 'Terms'
65 | end
66 | within ".user-details" do
67 | fill_in "Email", :with => random_email
68 | fill_in "Password", :with => "password"
69 | fill_in "Password Confirmation", :with => "password"
70 | end
71 | within "#billing" do
72 | @address_labels.each_with_index do |label, index|
73 | fill_in label, :with => @address_values[index]
74 | end
75 | select 'California', :from => 'State'
76 | select 'United States', :from => 'Country'
77 | end
78 |
79 | within "#shipping" do
80 | check "Use Billing Address"
81 | end
82 |
83 | click_button I18n.t('wholesale_apply')
84 | assert page.has_content?(I18n.t('spree.wholesaler.signup_success'))
85 | end
86 |
87 | end
88 |
--------------------------------------------------------------------------------
/test/fixtures/spree/variants.yml:
--------------------------------------------------------------------------------
1 | small-red-baseball:
2 | product: wholesale
3 | option_values: s, red
4 | sku: ROR-00001
5 | price: 19.99
6 | wholesale_price: 18.00
7 | cost_price: 17.00
8 | count_on_hand: 10
9 | small-blue-baseball:
10 | product: wholesale
11 | option_values: s, blue
12 | sku: ROR-00002
13 | price: 19.99
14 | wholesale_price: 18.00
15 | cost_price: 17.00
16 | count_on_hand: 10
17 | small-green-baseball:
18 | product: wholesale
19 | option_values: s, green
20 | sku: ROR-00003
21 | price: 19.99
22 | wholesale_price: 18.00
23 | cost_price: 17.00
24 | count_on_hand: 10
25 | med-red-baseball:
26 | product: wholesale
27 | option_values: m, red
28 | sku: ROR-00004
29 | price: 19.99
30 | wholesale_price: 18.00
31 | cost_price: 17.00
32 | count_on_hand: 3
33 | med-blue-baseball:
34 | product: wholesale
35 | option_values: m, blue
36 | sku: ROR-00005
37 | price: 19.99
38 | wholesale_price: 18.00
39 | cost_price: 17.00
40 | count_on_hand: 10
41 | med-green-baseball:
42 | product: wholesale
43 | option_values: m, green
44 | sku: ROR-00006
45 | price: 19.99
46 | wholesale_price: 18.00
47 | cost_price: 17.00
48 | count_on_hand: 14
49 | large-red-baseball:
50 | product: wholesale
51 | option_values: l, red
52 | sku: ROR-00007
53 | price: 19.99
54 | wholesale_price: 18.00
55 | cost_price: 17.00
56 | count_on_hand: 1
57 | large-blue-baseball:
58 | product: wholesale
59 | option_values: l, blue
60 | sku: ROR-00008
61 | price: 19.99
62 | wholesale_price: 18.00
63 | cost_price: 17.00
64 | count_on_hand: 10
65 | large-green-baseball:
66 | product: wholesale
67 | option_values: l, green
68 | sku: ROR-00009
69 | price: 19.99
70 | wholesale_price: 18.00
71 | cost_price: 17.00
72 | count_on_hand: 10
73 | xlarge-green-baseball:
74 | product: wholesale
75 | option_values: xl, red
76 | sku: ROR-00010
77 | price: 21.99
78 | cost_price: 20.00
79 | count_on_hand: 10
80 | wholesale:
81 | product: wholesale
82 | sku: ROR-001
83 | price: 19.99
84 | wholesale_price: 18.00
85 | cost_price: 17.00
86 | is_master: true
87 | count_on_hand: 10
88 | ror_tote_v:
89 | product: ror_tote
90 | sku: ROR-00011
91 | price: 15.99
92 | cost_price: 13.00
93 | is_master: true
94 | count_on_hand: 10
95 | ror_bag_v:
96 | product: ror_bag
97 | sku: ROR-00012
98 | price: 22.99
99 | cost_price: 21.00
100 | is_master: true
101 | count_on_hand: 10
102 | ror_jr_spaghetti_v:
103 | product: ror_jr_spaghetti
104 | sku: ROR-00013
105 | price: 19.99
106 | cost_price: 17.00
107 | is_master: true
108 | count_on_hand: 10
109 | ror_mug_v:
110 | product: ror_mug
111 | sku: ROR-00014
112 | price: 13.99
113 | cost_price: 11.00
114 | is_master: true
115 | count_on_hand: 10
116 | ror_ringer_v:
117 | product: ror_ringer
118 | sku: ROR-00015
119 | price: 17.99
120 | cost_price: 17.00
121 | is_master: true
122 | count_on_hand: 10
123 | ror_stein_v:
124 | product: ror_stein
125 | sku: ROR-00016
126 | price: 16.99
127 | cost_price: 15.00
128 | is_master: true
129 | count_on_hand: 10
130 | apache_baseball_v:
131 | product: apache_baseball_jersey
132 | sku: APC-00001
133 | price: 19.99
134 | cost_price: 17.00
135 | is_master: true
136 | count_on_hand: 10
137 | ruby_baseball_v:
138 | product: ruby_baseball_jersey
139 | sku: RUB-00001
140 | price: 19.99
141 | cost_price: 17.00
142 | is_master: true
143 | count_on_hand: 10
144 |
--------------------------------------------------------------------------------
/test/support/integration_case.rb:
--------------------------------------------------------------------------------
1 | class ActiveSupport::IntegrationCase < ActiveSupport::TestCase
2 |
3 | include Capybara::DSL
4 | include Rails.application.routes.url_helpers
5 | include Warden::Test::Helpers
6 |
7 | # Extreme hax! wtf is this for anyways.. and why is it erroring?
8 | def testmail_admin_mail_method_url(*args)
9 | "#wtf"
10 | end
11 | alias :testmail_admin_mail_method_path :testmail_admin_mail_method_url
12 |
13 |
14 | self.use_transactional_fixtures = false
15 |
16 | # Checks for missing translations after each test
17 | teardown do
18 | unless source.blank?
19 | matches = source.match(/translation[\s-]+missing[^"<]*/) || []
20 | assert_equal 0, matches.length, "** #{matches[0]}"
21 | end
22 | end
23 |
24 | # By defining this we don't need to depend on spree, just spree_core since the
25 | # included url helper lives in the spree root
26 | def spree
27 | Spree::Core::Engine.routes.url_helpers
28 | end
29 |
30 | # An assertion for ensuring content has made it to the page.
31 | #
32 | # assert_seen "Site Title"
33 | # assert_seen "Peanut Butter Jelly Time", :within => ".post-title h1"
34 | #
35 | def assert_seen(text, opts={})
36 | if opts[:within]
37 | within(opts[:within]) do
38 | assert has_content?(text)
39 | end
40 | else
41 | assert has_content?(text)
42 | end
43 | end
44 |
45 | # Asserts the proper flash message
46 | #
47 | # assert_flash :notice, "Post was successfully saved!"
48 | # assert_flash :error, "Oh No, bad things happened!"
49 | #
50 | def assert_flash(key, text)
51 | within(".flash.#{key}") do
52 | assert_seen(text)
53 | end
54 | end
55 |
56 | # Asserts the proper browser title
57 | #
58 | # assert_title "My Site - Is super cool"
59 | #
60 | def assert_title(title)
61 | assert_seen title, :within => "head title"
62 | end
63 |
64 | # Asserts meta tags have proper content
65 | #
66 | # assert_meta :description, "So let me tell you about this one time..."
67 | # assert_meta :keywords, "seo, is, fun, jk."
68 | #
69 | def assert_meta(tag, text)
70 | tag = find(:xpath, "//head/meta[@name='#{tag.to_s}']")
71 | assert_equal text, tag.native.attribute("content")
72 | end
73 |
74 | end
75 |
76 |
77 | # # Define a bare test case to use with Capybara
78 | #
79 | # class ActiveSupport::IntegrationCase < ActiveSupport::TestCase
80 | #
81 | # include Capybara::DSL
82 | # include Rails.application.routes.url_helpers
83 | # include Warden::Test::Helpers
84 | #
85 | # self.use_transactional_fixtures = false
86 | # self.fixture_path = File.expand_path('../../fixtures', __FILE__)
87 | #
88 | # # Extreme hax! wtf is this for anyways.. and why is it erroring?
89 | # def testmail_admin_mail_method_url(*args)
90 | # "#wtf"
91 | # end
92 | # alias :testmail_admin_mail_method_path :testmail_admin_mail_method_url
93 | #
94 | # teardown do
95 | # Capybara.reset_sessions! # Forget the (simulated) browser state
96 | # Capybara.use_default_driver # Revert Capybara.current_driver to Capybara.default_driver
97 | # end
98 | #
99 | # def assert_seen(text, opts={})
100 | # if opts[:within]
101 | # within(opts[:within]) do
102 | # assert page.has_content?(text)
103 | # end
104 | # else
105 | # assert page.has_content?(text)
106 | # end
107 | # end
108 | #
109 | # def assert_flash(key, text)
110 | # within(".errorExplanation") do
111 | # assert_seen(text)
112 | # end
113 | # end
114 | #
115 | # end
116 |
--------------------------------------------------------------------------------
/test/integration/spree/admin/wholesalers_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class Spree::Admin::WholesalersTest < ActiveSupport::IntegrationCase
4 |
5 | def setup
6 | Factory.create(:state)
7 |
8 | @user = Factory.create(:admin_user)
9 | login_as @user
10 |
11 | @labels = %(Company, Buyer contact, Manager contact, Phone, Fax, Resale number, Taxid, Web address, Notes).split(', ')
12 | @values = %(Some Company, Buyer contact, Manager contact, 555-555-5555, 555-555-5555 ext 1, 12345, 123-45-6789, example.com, Yippee!).split(', ')
13 | @address_labels = %(First Name, Last Name, Street Address, City, Zip, Phone).split(', ')
14 | @address_values = %(Billy, Billerton, 111 State St, Santa Barbara, 93101, 555-555-5555).split(', ')
15 | end
16 |
17 | should "have a link to new wholesaler" do
18 | visit spree.admin_wholesalers_path
19 | btn = find(".actions a.button").native
20 | assert_match(/#{spree.new_admin_wholesaler_path}$/, btn.attribute('href'))
21 | assert_equal "New Wholesaler", btn.text
22 | end
23 |
24 | should "get new wholesaler" do
25 | visit spree.new_admin_wholesaler_path
26 | # assert has_content?("New Wholesaler")
27 | assert page.has_content?('New Wholesaler')
28 | within "#new_wholesaler" do
29 | @labels.each do |f|
30 | assert has_field?(f)
31 | end
32 | assert has_field?('Terms')
33 | end
34 | end
35 |
36 | should "validate wholesaler and parts" do
37 | visit spree.new_admin_wholesaler_path
38 | click_button "Create"
39 | assert page.has_content?(I18n.t('spree.admin.wholesaler.failed'))
40 | end
41 |
42 | should "be a valid wholesaler but invalid parts" do
43 | visit spree.new_admin_wholesaler_path
44 | @labels.each_with_index do |label, index|
45 | fill_in label, :with => @values[index]
46 | end
47 | select 'Credit Card', :from => 'Terms'
48 | click_button "Create"
49 | assert page.has_content?(I18n.t('spree.admin.wholesaler.failed'))
50 | end
51 |
52 | should "create wholesaler and parts" do
53 | visit spree.new_admin_wholesaler_path
54 |
55 | within ".wholesaler-details" do
56 | @labels.each_with_index do |label, index|
57 | fill_in label, :with => @values[index]
58 | end
59 | select 'Credit Card', :from => 'Terms'
60 | end
61 |
62 | within ".user-details" do
63 | fill_in "Email", :with => random_email
64 | fill_in "Password", :with => "password"
65 | fill_in "Password Confirmation", :with => "password"
66 | end
67 |
68 | within "#billing" do
69 | @address_labels.each_with_index do |label, index|
70 | fill_in label, :with => @address_values[index]
71 | end
72 | select 'California', :from => 'State'
73 | select 'United States', :from => 'Country'
74 | end
75 |
76 | within "#shipping" do
77 | check "Use Billing Address"
78 | end
79 |
80 | click_button "Create"
81 | assert page.has_content?(I18n.t('spree.admin.wholesaler.success'))
82 | end
83 |
84 |
85 | context "an existing wholesaler" do
86 |
87 | setup do
88 | @wholesaler = Factory.create(:wholesaler)
89 | end
90 |
91 | should "update wholesaler, user and addresses" do
92 | visit spree.edit_admin_wholesaler_path(@wholesaler)
93 | within ".wholesaler-details" do
94 | @labels.each_with_index do |label, index|
95 | fill_in label, :with => @values[index].reverse
96 | end
97 | select 'Credit Card', :from => 'Terms'
98 | end
99 | within "#billing" do
100 | @address_labels.each_with_index do |label, index|
101 | fill_in label, :with => @address_values[index].reverse
102 | end
103 | select 'California', :from => 'State'
104 | select 'United States', :from => 'Country'
105 | end
106 | within "#shipping" do
107 | uncheck "Use Billing Address"
108 | @address_labels.each_with_index do |label, index|
109 | fill_in label.sub('Billing', 'Shipping'), :with => @address_values[index]
110 | end
111 | select 'California', :from => 'State'
112 | select 'United States', :from => 'Country'
113 | end
114 | click_button "Update"
115 | assert page.has_content?(I18n.t('spree.admin.wholesaler.update_success'))
116 | assert page.has_content?('ylliB notrelliB')
117 | end
118 |
119 | end
120 |
121 | end
122 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Spree Wholesale [](http://travis-ci.org/citrus/spree_wholesale)
2 |
3 | Spree wholesale is a simple wholesale solution for Spree Commerce. Spree wholesale adds a wholesaler login and signup page as well as an admin to approve and deny applicants.
4 |
5 |
6 | ------------------------------------------------------------------------------
7 | Installation
8 | ------------------------------------------------------------------------------
9 |
10 | If you're on Spree 0.50.0 and above, you'll have to install Spree Wholesale from the source since I haven't released it yet. Just add this to your Gemfile:
11 |
12 | ```ruby
13 | # spree 1.2.x
14 | gem 'spree_wholesale', :git => 'git://github.com/citrus/spree_wholesale', :branch => 'master'
15 |
16 | # spree 1.1.x
17 | gem 'spree_wholesale', :git => 'git://github.com/citrus/spree_wholesale', :branch => '1.1.x'
18 |
19 | # spree 1.0.x
20 | gem 'spree_wholesale', :git => 'git://github.com/citrus/spree_wholesale', :branch => '1.0.x'
21 |
22 | # spree 0.70.x
23 | gem 'spree_wholesale', :git => 'git://github.com/citrus/spree_wholesale', :branch => '0.70.x'
24 |
25 | # spree 0.60.x
26 | gem 'spree_wholesale', :git => 'git://github.com/citrus/spree_wholesale', :branch => '0.60.x'
27 |
28 | # spree 0.50.x
29 | gem 'spree_wholesale', :git => 'git://github.com/citrus/spree_wholesale', :branch => '0.50.x'
30 | ```
31 |
32 |
33 | Otherwise just use the last stable release:
34 |
35 | ```ruby
36 | gem 'spree_wholesale', '0.40.2.2'
37 | ```
38 |
39 |
40 | Then install the necessary migrations, db:migrate, and create the wholesale role:
41 |
42 | ```bash
43 | # spree 0.50.x and above
44 | rails g spree_wholesale:install
45 | rake db:migrate spree_wholesale:create_role
46 |
47 | # legacy spree
48 | rake spree_wholesale:install
49 | rake db:migrate spree_wholesale:create_role
50 | ```
51 |
52 |
53 | If you'd like to generate sample wholesale prices based on a 66% discount:
54 |
55 | ```bash
56 | rake spree_wholesale:assume_wholesale_prices
57 | ```
58 |
59 |
60 | ------------------------------------------------------------------------------
61 | Testing
62 | ------------------------------------------------------------------------------
63 |
64 | If you'd like to run tests:
65 |
66 | ```bash
67 | git clone git://github.com/citrus/spree_wholesale.git
68 | cd spree_wholesale
69 | bundle install
70 | bundle exec dummier
71 | bundle exec rake
72 | ```
73 |
74 |
75 | ------------------------------------------------------------------------------
76 | Demo
77 | ------------------------------------------------------------------------------
78 |
79 | If you'd like a demo of spree_wholesale:
80 |
81 | ```bash
82 | git clone git://github.com/citrus/spree_wholesale.git
83 | cd spree_wholesale
84 | cp test/dummy_hooks/after_migrate.rb.sample test/dummy_hooks/after_migrate.rb
85 | bundle install
86 | bundle exec dummier
87 | cd test/dummy
88 | rails s
89 | ```
90 |
91 |
92 | ------------------------------------------------------------------------------
93 | To Do
94 | ------------------------------------------------------------------------------
95 |
96 | * Write more/better tests
97 | * Finish i18n implementation
98 |
99 |
100 | ------------------------------------------------------------------------------
101 | Known Issues
102 | ------------------------------------------------------------------------------
103 |
104 | * A user created in the 'user' tab, or an already existing user with an added 'wholesaler' flag will not be able to purchase at wholesale price. They will see the retail and wholesale price, but when added to cart will purchase at retail price. Only accounts created using wholesale interface work properly.
105 | * Deface override for admin_tabs (Adds wholesalers tab to admin interface) isn't targeting hook correctly, and has been set to insert to bottom of the div#store-menu ul instead.
106 |
107 |
108 | ------------------------------------------------------------------------------
109 | Contributors
110 | ------------------------------------------------------------------------------
111 |
112 | * Spencer Steffen ([@citrus](https://github.com/citrus))
113 | * John Hwang ([@tavon](https://github.com/tavon))
114 | * Cameron Carroll ([@sanarothe](https://github.com/sanarothe))
115 | * Les Cochrane ([@oldtinroof](https://github.com/oldtinroof))
116 |
117 |
118 | ------------------------------------------------------------------------------
119 | License
120 | ------------------------------------------------------------------------------
121 |
122 | Copyright (c) 2011 - 2012 Spencer Steffen and Citrus, released under the New BSD License All rights reserved.
123 |
--------------------------------------------------------------------------------
/test/fixtures/spree/states.yml:
--------------------------------------------------------------------------------
1 | ---
2 | states_043:
3 | name: Michigan
4 | country_id: "214"
5 | id: "931624400"
6 | abbr: MI
7 | states_032:
8 | name: South Dakota
9 | country_id: "214"
10 | id: "615306087"
11 | abbr: SD
12 | states_021:
13 | name: Washington
14 | country_id: "214"
15 | id: "414569975"
16 | abbr: WA
17 | states_010:
18 | name: Wisconsin
19 | country_id: "214"
20 | id: "103680699"
21 | abbr: WI
22 | states_044:
23 | name: Arizona
24 | country_id: "214"
25 | id: "948208802"
26 | abbr: AZ
27 | states_033:
28 | name: Illinois
29 | country_id: "214"
30 | id: "625629523"
31 | abbr: IL
32 | states_022:
33 | name: New Hampshire
34 | country_id: "214"
35 | id: "426832442"
36 | abbr: NH
37 | states_011:
38 | name: North Carolina
39 | country_id: "214"
40 | id: "177087202"
41 | abbr: NC
42 | states_045:
43 | name: Kansas
44 | country_id: "214"
45 | id: "969722173"
46 | abbr: KS
47 | states_034:
48 | name: Missouri
49 | country_id: "214"
50 | id: "653576146"
51 | abbr: MO
52 | states_023:
53 | name: Arkansas
54 | country_id: "214"
55 | id: "471470972"
56 | abbr: AR
57 | states_012:
58 | name: Nevada
59 | country_id: "214"
60 | id: "179539703"
61 | abbr: NV
62 | states_001:
63 | name: District of Columbia
64 | country_id: "214"
65 | id: "6764998"
66 | abbr: DC
67 | states_046:
68 | name: Idaho
69 | country_id: "214"
70 | id: "982433740"
71 | abbr: ID
72 | states_035:
73 | name: Nebraska
74 | country_id: "214"
75 | id: "673350891"
76 | abbr: NE
77 | states_024:
78 | name: Pennsylvania
79 | country_id: "214"
80 | id: "471711976"
81 | abbr: PA
82 | states_013:
83 | name: Hawaii
84 | country_id: "214"
85 | id: "199950338"
86 | abbr: HI
87 | states_002:
88 | name: Utah
89 | country_id: "214"
90 | id: "17199670"
91 | abbr: UT
92 | states_047:
93 | name: Vermont
94 | country_id: "214"
95 | id: "989115415"
96 | abbr: VT
97 | states_036:
98 | name: Delaware
99 | country_id: "214"
100 | id: "721598219"
101 | abbr: DE
102 | states_025:
103 | name: Rhode Island
104 | country_id: "214"
105 | id: "474001862"
106 | abbr: RI
107 | states_014:
108 | name: Oklahoma
109 | country_id: "214"
110 | id: "248548169"
111 | abbr: OK
112 | states_003:
113 | name: Louisiana
114 | country_id: "214"
115 | id: "37199952"
116 | abbr: LA
117 | states_048:
118 | name: Montana
119 | country_id: "214"
120 | id: "999156632"
121 | abbr: MT
122 | states_037:
123 | name: Tennessee
124 | country_id: "214"
125 | id: "726305632"
126 | abbr: TN
127 | states_026:
128 | name: Maryland
129 | country_id: "214"
130 | id: "480368357"
131 | abbr: MD
132 | states_015:
133 | name: Florida
134 | country_id: "214"
135 | id: "267271847"
136 | abbr: FL
137 | states_004:
138 | name: Virginia
139 | country_id: "214"
140 | id: "41111624"
141 | abbr: VA
142 | states_049:
143 | name: Minnesota
144 | country_id: "214"
145 | id: "1032288924"
146 | abbr: MN
147 | states_038:
148 | name: New Jersey
149 | country_id: "214"
150 | id: "750950030"
151 | abbr: NJ
152 | states_027:
153 | name: Ohio
154 | country_id: "214"
155 | id: "485193526"
156 | abbr: OH
157 | states_016:
158 | name: California
159 | country_id: "214"
160 | id: "276110813"
161 | abbr: CA
162 | states_005:
163 | name: North Dakota
164 | country_id: "214"
165 | id: "51943165"
166 | abbr: ND
167 | states_050:
168 | name: Maine
169 | country_id: "214"
170 | id: "1055056709"
171 | abbr: ME
172 | states_039:
173 | name: Indiana
174 | country_id: "214"
175 | id: "769938586"
176 | abbr: IN
177 | states_028:
178 | name: Texas
179 | country_id: "214"
180 | id: "525212995"
181 | abbr: TX
182 | states_017:
183 | name: Oregon
184 | country_id: "214"
185 | id: "298914262"
186 | abbr: OR
187 | states_006:
188 | name: Wyoming
189 | country_id: "214"
190 | id: "66390489"
191 | abbr: WY
192 | states_051:
193 | name: Alabama
194 | country_id: "214"
195 | id: "1061493585"
196 | abbr: AL
197 | states_040:
198 | name: Iowa
199 | country_id: "214"
200 | id: "825306985"
201 | abbr: IA
202 | states_029:
203 | name: Mississippi
204 | country_id: "214"
205 | id: "532363768"
206 | abbr: MS
207 | states_018:
208 | name: Kentucky
209 | country_id: "214"
210 | id: "308473843"
211 | abbr: KY
212 | states_007:
213 | name: New Mexico
214 | country_id: "214"
215 | id: "69729944"
216 | abbr: NM
217 | states_041:
218 | name: Georgia
219 | country_id: "214"
220 | id: "876916760"
221 | abbr: GA
222 | states_030:
223 | name: Colorado
224 | country_id: "214"
225 | id: "536031023"
226 | abbr: CO
227 | states_019:
228 | name: Massachusetts
229 | country_id: "214"
230 | id: "385551075"
231 | abbr: MA
232 | states_008:
233 | name: Connecticut
234 | country_id: "214"
235 | id: "69870734"
236 | abbr: CT
237 | states_042:
238 | name: New York
239 | country_id: "214"
240 | id: "889445952"
241 | abbr: NY
242 | states_031:
243 | name: South Carolina
244 | country_id: "214"
245 | id: "597434151"
246 | abbr: SC
247 | states_020:
248 | name: Alaska
249 | country_id: "214"
250 | id: "403740659"
251 | abbr: AK
252 | states_009:
253 | name: West Virginia
254 | country_id: "214"
255 | id: "91367981"
256 | abbr: WV
257 |
--------------------------------------------------------------------------------
/app/views/spree/shared/_address_form.html.erb:
--------------------------------------------------------------------------------
1 |
2 | <%= form.fields_for :bill_address do |bill_form| %>
3 | <%= t(:billing_address)%>
4 |
5 |
6 | <%= bill_form.label :firstname, t(:first_name) %>*
7 | <%= bill_form.text_field :firstname, :class => 'required' %>
8 |
9 |
10 | <%= bill_form.label :lastname, t(:last_name) %>*
11 | <%= bill_form.text_field :lastname, :class => 'required' %>
12 |
13 |
14 | <%= bill_form.label :address1, t(:street_address) %>*
15 | <%= bill_form.text_field :address1, :class => 'required' %>
16 |
17 |
18 | <%= bill_form.label :address2, t(:street_address_2) %>
19 | <%= bill_form.text_field :address2 %>
20 |
21 |
22 | <%= bill_form.label :city, t(:city) %>*
23 | <%= bill_form.text_field :city, :class => 'required' %>
24 |
25 |
26 | <% if Spree::Config[:address_requires_state] %>
27 |
28 | <% have_states = !@wholesaler.bill_address.country.states.empty? %>
29 | <%= bill_form.label :state_id, t(:state) %>*
30 |
31 | <%= bill_form.text_field :state_name, :class => 'required' %>
32 |
33 | <% state_elements = [
34 | bill_form.collection_select(:state_id, @wholesaler.bill_address.country.states,
35 | :id, :name,
36 | {:include_blank => true},
37 | {:class => have_states ? 'required' : 'hidden',
38 | :disabled => !have_states}) +
39 | bill_form.text_field(:state_name,
40 | :class => !have_states ? 'required' : 'hidden',
41 | :disabled => have_states)
42 | ].join.gsub('"', "'").gsub("\n", "")
43 | %>
44 | <%= javascript_tag do -%>
45 | document.write("<%== state_elements %>");
46 | <% end -%>
47 |
48 | <% end %>
49 |
50 |
51 | <%= bill_form.label :zipcode, t(:zip) %>*
52 | <%= bill_form.text_field :zipcode, :class => 'required' %>
53 |
54 |
55 | <%= bill_form.label :country_id, t(:country) %>*
56 |
57 | <%= bill_form.collection_select :country_id, available_countries, :id, :name, {}, {:class => 'required'} %>
58 |
59 |
60 |
61 | <%= bill_form.label :phone, t(:phone) %>*
62 | <%= bill_form.text_field :phone, :class => 'required' %>
63 |
64 | <% if Spree::Config[:alternative_billing_phone] %>
65 |
66 | <%= bill_form.label :alternative_phone, t(:alternative_phone) %>
67 | <%= bill_form.text_field :alternative_phone %>
68 |
69 | <% end %>
70 |
71 | <% end %>
72 |
73 |
74 |
75 | <%= form.fields_for :ship_address do |ship_form| %>
76 | <%= t(:shipping_address)%>
77 |
78 | <%= check_box_tag 'wholesaler[use_billing]', '1', (!(@wholesaler.bill_address.empty? && @wholesaler.ship_address.empty?) && @wholesaler.bill_address.eql?(@wholesaler.ship_address)) %>
79 | <%= label_tag :wholesaler_use_billing, t(:use_billing_address) %>
80 |
81 |
82 |
83 | <%= ship_form.label :firstname, t(:first_name) %>*
84 | <%= ship_form.text_field :firstname, :class => 'required' %>
85 |
86 |
87 | <%= ship_form.label :lastname, t(:last_name) %>*
88 | <%= ship_form.text_field :lastname, :class => 'required' %>
89 |
90 |
91 | <%= ship_form.label :address1, t(:street_address) %>*
92 | <%= ship_form.text_field :address1, :class => 'required' %>
93 |
94 |
95 | <%= ship_form.label :address2, t(:street_address_2) %>
96 | <%= ship_form.text_field :address2 %>
97 |
98 |
99 | <%= ship_form.label :city, t(:city) %>*
100 | <%= ship_form.text_field :city, :class => 'required' %>
101 |
102 |
103 | <% if Spree::Config[:address_requires_state] %>
104 |
105 | <% have_states = !@wholesaler.ship_address.country.states.empty? %>
106 | <%= ship_form.label :state_id, t(:state) %>*
107 |
108 | <%= ship_form.text_field :state_name, :class => 'required' %>
109 |
110 | <% state_elements = [
111 | ship_form.collection_select(:state_id, @wholesaler.ship_address.country.states,
112 | :id, :name,
113 | {:include_blank => true},
114 | {:class => have_states ? 'required' : 'hidden',
115 | :disabled => !have_states}) +
116 | ship_form.text_field(:state_name,
117 | :class => !have_states ? 'required' : 'hidden',
118 | :disabled => have_states)
119 | ].join.gsub('"', "'").gsub("\n", "")
120 | %>
121 | <%= javascript_tag do -%>
122 | document.write("<%== state_elements %>");
123 | <% end %>
124 |
125 | <% end %>
126 |
127 |
128 | <%= ship_form.label :zipcode, t(:zip) %>*
129 | <%= ship_form.text_field :zipcode, :class => 'required' %>
130 |
131 |
132 | <%= ship_form.label :country_id, t(:country) %>*
133 |
134 | <%= ship_form.collection_select :country_id, available_countries, :id, :name, {}, {:class => 'required'} %>
135 |
136 |
137 |
138 | <%= ship_form.label :phone, t(:phone) %>*
139 | <%= ship_form.text_field :phone, :class => 'required' %>
140 |
141 | <% if Spree::Config[:alternative_shipping_phone] %>
142 |
143 | <%= ship_form.label :alternative_phone, t(:alternative_phone) %>
144 | <%= ship_form.text_field :alternative_phone %>
145 |
146 | <% end %>
147 |
148 | <% end %>
149 |
150 |
--------------------------------------------------------------------------------
/test/fixtures/spree/products.yml:
--------------------------------------------------------------------------------
1 | ror_tote:
2 | name: Ruby on Rails Tote
3 | description: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla nonummy aliquet mi. Proin lacus. Ut placerat. Proin consequat, justo sit amet tempus consequat, elit est adipiscing odio, ut egestas pede eros in diam. Proin varius, lacus vitae suscipit varius, ipsum eros convallis nisi, sit amet sodales lectus pede non est. Duis augue. Suspendisse hendrerit pharetra metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur nec pede. Quisque volutpat, neque ac porttitor sodales, sem lacus rutrum nulla, ullamcorper placerat ante tortor ac odio. Suspendisse vel libero. Nullam volutpat magna vel ligula. Suspendisse sit amet metus. Nunc quis massa. Nulla facilisi. In enim. In venenatis nisi id eros. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc sit amet felis sed lectus tincidunt egestas. Mauris nibh.
4 | available_on: <%= Time.zone.now.to_s(:db) %>
5 | permalink: ruby-on-rails-tote
6 | count_on_hand: 45
7 |
8 | ror_bag:
9 | name: Ruby on Rails Bag
10 | description: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla nonummy aliquet mi. Proin lacus. Ut placerat. Proin consequat, justo sit amet tempus consequat, elit est adipiscing odio, ut egestas pede eros in diam. Proin varius, lacus vitae suscipit varius, ipsum eros convallis nisi, sit amet sodales lectus pede non est. Duis augue. Suspendisse hendrerit pharetra metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur nec pede. Quisque volutpat, neque ac porttitor sodales, sem lacus rutrum nulla, ullamcorper placerat ante tortor ac odio. Suspendisse vel libero. Nullam volutpat magna vel ligula. Suspendisse sit amet metus. Nunc quis massa. Nulla facilisi. In enim. In venenatis nisi id eros. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc sit amet felis sed lectus tincidunt egestas. Mauris nibh.
11 | available_on: <%= Time.zone.now.to_s(:db) %>
12 | permalink: ruby-on-rails-bag
13 | count_on_hand: 45
14 |
15 |
16 | wholesale:
17 | name: Ruby on Rails Baseball Jersey
18 | description: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla nonummy aliquet mi. Proin lacus. Ut placerat. Proin consequat, justo sit amet tempus consequat, elit est adipiscing odio, ut egestas pede eros in diam. Proin varius, lacus vitae suscipit varius, ipsum eros convallis nisi, sit amet sodales lectus pede non est. Duis augue. Suspendisse hendrerit pharetra metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur nec pede. Quisque volutpat, neque ac porttitor sodales, sem lacus rutrum nulla, ullamcorper placerat ante tortor ac odio. Suspendisse vel libero. Nullam volutpat magna vel ligula. Suspendisse sit amet metus. Nunc quis massa. Nulla facilisi. In enim. In venenatis nisi id eros. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc sit amet felis sed lectus tincidunt egestas. Mauris nibh.
19 | available_on: <%= Time.zone.now.to_s(:db) %>
20 | permalink: ruby-on-rails-baseball-jersey
21 |
22 |
23 | ror_jr_spaghetti:
24 | name: Ruby on Rails Jr. Spaghetti
25 | description: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla nonummy aliquet mi. Proin lacus. Ut placerat. Proin consequat, justo sit amet tempus consequat, elit est adipiscing odio, ut egestas pede eros in diam. Proin varius, lacus vitae suscipit varius, ipsum eros convallis nisi, sit amet sodales lectus pede non est. Duis augue. Suspendisse hendrerit pharetra metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur nec pede. Quisque volutpat, neque ac porttitor sodales, sem lacus rutrum nulla, ullamcorper placerat ante tortor ac odio. Suspendisse vel libero. Nullam volutpat magna vel ligula. Suspendisse sit amet metus. Nunc quis massa. Nulla facilisi. In enim. In venenatis nisi id eros. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc sit amet felis sed lectus tincidunt egestas. Mauris nibh.
26 | available_on: <%= Time.zone.now.to_s(:db) %>
27 | permalink: ruby-on-rails-jr-spaghetti
28 | count_on_hand: 75
29 |
30 |
31 | ror_mug:
32 | name: Ruby on Rails Mug
33 | description: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla nonummy aliquet mi. Proin lacus. Ut placerat. Proin consequat, justo sit amet tempus consequat, elit est adipiscing odio, ut egestas pede eros in diam. Proin varius, lacus vitae suscipit varius, ipsum eros convallis nisi, sit amet sodales lectus pede non est. Duis augue. Suspendisse hendrerit pharetra metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur nec pede. Quisque volutpat, neque ac porttitor sodales, sem lacus rutrum nulla, ullamcorper placerat ante tortor ac odio. Suspendisse vel libero. Nullam volutpat magna vel ligula. Suspendisse sit amet metus. Nunc quis massa. Nulla facilisi. In enim. In venenatis nisi id eros. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc sit amet felis sed lectus tincidunt egestas. Mauris nibh.
34 | available_on: <%= Time.zone.now.to_s(:db) %>
35 | permalink: ruby-on-rails-mug
36 | count_on_hand: 75
37 |
38 |
39 | ror_ringer:
40 | name: Ruby on Rails Ringer T-Shirt
41 | description: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla nonummy aliquet mi. Proin lacus. Ut placerat. Proin consequat, justo sit amet tempus consequat, elit est adipiscing odio, ut egestas pede eros in diam. Proin varius, lacus vitae suscipit varius, ipsum eros convallis nisi, sit amet sodales lectus pede non est. Duis augue. Suspendisse hendrerit pharetra metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur nec pede. Quisque volutpat, neque ac porttitor sodales, sem lacus rutrum nulla, ullamcorper placerat ante tortor ac odio. Suspendisse vel libero. Nullam volutpat magna vel ligula. Suspendisse sit amet metus. Nunc quis massa. Nulla facilisi. In enim. In venenatis nisi id eros. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc sit amet felis sed lectus tincidunt egestas. Mauris nibh.
42 | available_on: <%= Time.zone.now.to_s(:db) %>
43 | permalink: ruby-on-rails-ringer-t-shirt
44 | count_on_hand: 75
45 |
46 |
47 | ror_stein:
48 | name: Ruby on Rails Stein
49 | description: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla nonummy aliquet mi. Proin lacus. Ut placerat. Proin consequat, justo sit amet tempus consequat, elit est adipiscing odio, ut egestas pede eros in diam. Proin varius, lacus vitae suscipit varius, ipsum eros convallis nisi, sit amet sodales lectus pede non est. Duis augue. Suspendisse hendrerit pharetra metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur nec pede. Quisque volutpat, neque ac porttitor sodales, sem lacus rutrum nulla, ullamcorper placerat ante tortor ac odio. Suspendisse vel libero. Nullam volutpat magna vel ligula. Suspendisse sit amet metus. Nunc quis massa. Nulla facilisi. In enim. In venenatis nisi id eros. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc sit amet felis sed lectus tincidunt egestas. Mauris nibh.
50 | available_on: <%= Time.zone.now.to_s(:db) %>
51 | permalink: ruby-on-rails-stein
52 | count_on_hand: 75
53 |
54 |
55 | ruby_baseball_jersey:
56 | name: Ruby Baseball Jersey
57 | description: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla nonummy aliquet mi. Proin lacus. Ut placerat. Proin consequat, justo sit amet tempus consequat, elit est adipiscing odio, ut egestas pede eros in diam. Proin varius, lacus vitae suscipit varius, ipsum eros convallis nisi, sit amet sodales lectus pede non est. Duis augue. Suspendisse hendrerit pharetra metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur nec pede. Quisque volutpat, neque ac porttitor sodales, sem lacus rutrum nulla, ullamcorper placerat ante tortor ac odio. Suspendisse vel libero. Nullam volutpat magna vel ligula. Suspendisse sit amet metus. Nunc quis massa. Nulla facilisi. In enim. In venenatis nisi id eros. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc sit amet felis sed lectus tincidunt egestas. Mauris nibh.
58 | available_on: <%= Time.zone.now.to_s(:db) %>
59 | permalink: ruby-baseball-jersey
60 | count_on_hand: 75
61 |
62 |
63 | apache_baseball_jersey:
64 | name: Apache Baseball Jersey
65 | description: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nulla nonummy aliquet mi. Proin lacus. Ut placerat. Proin consequat, justo sit amet tempus consequat, elit est adipiscing odio, ut egestas pede eros in diam. Proin varius, lacus vitae suscipit varius, ipsum eros convallis nisi, sit amet sodales lectus pede non est. Duis augue. Suspendisse hendrerit pharetra metus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur nec pede. Quisque volutpat, neque ac porttitor sodales, sem lacus rutrum nulla, ullamcorper placerat ante tortor ac odio. Suspendisse vel libero. Nullam volutpat magna vel ligula. Suspendisse sit amet metus. Nunc quis massa. Nulla facilisi. In enim. In venenatis nisi id eros. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc sit amet felis sed lectus tincidunt egestas. Mauris nibh.
66 | available_on: <%= Time.zone.now.to_s(:db) %>
67 | permalink: apache-baseball-jersey
68 | count_on_hand: 0
69 |
70 |
71 |
--------------------------------------------------------------------------------
/test/dummy_hooks/templates/store/screen.css:
--------------------------------------------------------------------------------
1 | @import url(http://fonts.googleapis.com/css?family=Ubuntu:400,700,400italic,700italic|&subset=latin,cyrillic,greek,greek-ext,latin-ext,cyrillic-ext);
2 | /*--------------------------------------*/
3 | /* Colors
4 | /*--------------------------------------*/
5 | /* Dark gray */
6 | /* Mid light gray */
7 | /* Light blue */
8 | /* Lighter blue */
9 | /* Light gray */
10 | /* Spree green */
11 | /* Error red */
12 | /*--------------------------------------*/
13 | /* Fonts
14 | /*--------------------------------------*/
15 | /*--------------------------------------*/
16 | /* Basic styles
17 | /*--------------------------------------*/
18 | body {
19 | font-family: 'Ubuntu', sans-serif;
20 | color: #404042;
21 | line-height: 18px;
22 | font-size: 12px; }
23 |
24 | /* Line style */
25 | hr {
26 | border-color: #dedede; }
27 |
28 | /* Custom text-selection colors (remove any text shadows: twitter.com/miketaylr/status/12228805301) */
29 | ::-moz-selection {
30 | background: #00adee;
31 | color: white;
32 | text-shadow: none; }
33 |
34 | ::selection {
35 | background: #00adee;
36 | color: white;
37 | text-shadow: none; }
38 |
39 | /* j.mp/webkit-tap-highlight-color */
40 | a:link {
41 | -webkit-tap-highlight-color: #00adee; }
42 |
43 | ins {
44 | background-color: #00adee;
45 | color: white;
46 | text-decoration: none; }
47 |
48 | mark {
49 | background-color: #00adee;
50 | color: white;
51 | font-style: italic;
52 | font-weight: bold; }
53 |
54 | /*--------------------------------------*/
55 | /* Links
56 | /*--------------------------------------*/
57 | a {
58 | text-decoration: none;
59 | color: #404042; }
60 | a:hover {
61 | color: #00adee !important; }
62 |
63 | /*--------------------------------------*/
64 | /* Lists
65 | /*--------------------------------------*/
66 | ul.inline li, ol.inline li {
67 | display: inline-block; }
68 |
69 | dl dt, dl dd {
70 | display: inline-block;
71 | width: 50%;
72 | padding: 5px; }
73 | dl dt.odd, dl dd.odd {
74 | background-color: #dedede; }
75 | dl dt {
76 | font-weight: bold;
77 | text-transform: uppercase; }
78 | dl dd {
79 | margin-left: -23px; }
80 |
81 | /*--------------------------------------*/
82 | /* Headers
83 | /*--------------------------------------*/
84 | h1, h2, h3, h4, h5, h6 {
85 | font-weight: bold; }
86 |
87 | h1 {
88 | font-size: 24px;
89 | line-height: 34px; }
90 |
91 | h2 {
92 | font-size: 23px;
93 | line-height: 32px; }
94 |
95 | h3 {
96 | font-size: 20px;
97 | line-height: 30px; }
98 |
99 | h4 {
100 | font-size: 18px;
101 | line-height: 28px; }
102 |
103 | h5 {
104 | font-size: 16px;
105 | line-height: 26px; }
106 |
107 | h6 {
108 | font-size: 14px;
109 | line-height: 24px; }
110 |
111 | /*--------------------------------------*/
112 | /* Forms
113 | /*--------------------------------------*/
114 | textarea, input[type="date"],
115 | input[type="datetime"], input[type="datetime-local"],
116 | input[type="email"], input[type="month"], input[type="number"],
117 | input[type="password"], input[type="search"], input[type="tel"],
118 | input[type="text"], input[type="time"], input[type="url"],
119 | input[type="week"] {
120 | border: 1px solid #dedede;
121 | padding: 2px 5px;
122 | font-family: "Ubuntu", sans-serif; }
123 | textarea:active, textarea:focus, input[type="date"]:active, input[type="date"]:focus,
124 | input[type="datetime"]:active,
125 | input[type="datetime"]:focus, input[type="datetime-local"]:active, input[type="datetime-local"]:focus,
126 | input[type="email"]:active,
127 | input[type="email"]:focus, input[type="month"]:active, input[type="month"]:focus, input[type="number"]:active, input[type="number"]:focus,
128 | input[type="password"]:active,
129 | input[type="password"]:focus, input[type="search"]:active, input[type="search"]:focus, input[type="tel"]:active, input[type="tel"]:focus,
130 | input[type="text"]:active,
131 | input[type="text"]:focus,
132 | select:active,
133 | select:focus, input[type="time"]:active, input[type="time"]:focus, input[type="url"]:active, input[type="url"]:focus,
134 | input[type="week"]:active,
135 | input[type="week"]:focus {
136 | border-color: #00adee;
137 | outline: none;
138 | -webkit-box-shadow: none;
139 | -moz-box-shadow: none;
140 | -o-box-shadow: none;
141 | box-shadow: none; }
142 | textarea.error, input[type="date"].error,
143 | input[type="datetime"].error, input[type="datetime-local"].error,
144 | input[type="email"].error, input[type="month"].error, input[type="number"].error,
145 | input[type="password"].error, input[type="search"].error, input[type="tel"].error,
146 | input[type="text"].error, input[type="time"].error, input[type="url"].error,
147 | input[type="week"].error {
148 | border-color: #e45353; }
149 |
150 | select {
151 | border: 1px solid #dedede;
152 | font-family: "Ubuntu", sans-serif;
153 | background-image: url("select_arrow.gif");
154 | background-repeat: no-repeat;
155 | background-position: right center; }
156 |
157 | label.error {
158 | display: block;
159 | font-size: 11px;
160 | color: #e45353;
161 | margin-top: 3px; }
162 |
163 | input[type="submit"], input[type="button"],
164 | input[type="reset"], button, a.button {
165 | background-color: #00adee;
166 | background-image: none;
167 | text-shadow: none;
168 | color: white;
169 | font-weight: bold;
170 | font-family: "Ubuntu", sans-serif;
171 | border: 1px solid rgba(0, 138, 189, 0.75);
172 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4);
173 | -khtml-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4);
174 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4);
175 | -o-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4);
176 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4);
177 | -webkit-border-radius: 0px;
178 | -khtml-border-radius: 0px;
179 | -moz-border-radius: 0px;
180 | -ms-border-radius: 0px;
181 | -o-border-radius: 0px;
182 | border-radius: 0px;
183 | vertical-align: text-top; }
184 | input[type="submit"].large, input[type="button"].large,
185 | input[type="reset"].large, button.large, a.button.large {
186 | padding: 7px 10px;
187 | font-size: 14px; }
188 | input[type="submit"]:hover, input[type="button"]:hover,
189 | input[type="reset"]:hover, button:hover, a.button:hover {
190 | background-image: none;
191 | background-color: #404042;
192 | border-color: #404042;
193 | color: white !important; }
194 |
195 | .ie8 a.button {
196 | line-height: 16px; }
197 |
198 | input[type="checkbox"], input[type="button"],
199 | input[type="submit"], input[type="reset"],
200 | button, label {
201 | vertical-align: middle; }
202 |
203 | a.button {
204 | display: inline-block;
205 | line-height: 15px;
206 | margin-top: -2px;
207 | vertical-align: bottom; }
208 |
209 | /*--------------------------------------*/
210 | /* Footer
211 | /*--------------------------------------*/
212 | footer#footer {
213 | padding: 10px 0;
214 | border-top: 1px solid #dedede; }
215 |
216 | /*--------------------------------------*/
217 | /* Paragraphs
218 | /*--------------------------------------*/
219 | p {
220 | padding: 10px 0; }
221 |
222 | /*--------------------------------------*/
223 | /* Tables
224 | /*--------------------------------------*/
225 | table thead {
226 | background-color: #dedede;
227 | text-transform: uppercase; }
228 | table thead tr th {
229 | padding: 5px 10px; }
230 | table tbody tr, table tfoot tr {
231 | border-bottom: 1px solid #dedede; }
232 | table tbody tr td, table tfoot tr td {
233 | vertical-align: middle;
234 | padding: 5px 10px; }
235 | table tbody tr.alt, table tbody tr.odd, table tfoot tr.alt, table tfoot tr.odd {
236 | background-color: #f0f8ff; }
237 |
238 | /*--------------------------------------*/
239 | /* Navigation
240 | /*--------------------------------------*/
241 | nav#top-nav-bar {
242 | text-align: right;
243 | margin-top: 20px; }
244 | nav#top-nav-bar ul li {
245 | margin-bottom: 5px;
246 | padding-left: 10px; }
247 | nav#top-nav-bar ul li a {
248 | font-weight: bold;
249 | font-size: 14px;
250 | text-transform: uppercase; }
251 |
252 | nav #main-nav-bar {
253 | text-transform: uppercase;
254 | font-weight: bold;
255 | margin-top: 20px;
256 | border-bottom: 1px solid #dedede;
257 | padding-bottom: 6px; }
258 | nav #main-nav-bar li a {
259 | font-size: 16px;
260 | padding: 5px; }
261 | nav #main-nav-bar li#link-to-cart {
262 | float: right;
263 | padding-left: 24px;
264 | background: url("cart.png") no-repeat left center; }
265 | nav #main-nav-bar li#link-to-cart:hover {
266 | border-color: #00adee; }
267 | nav #main-nav-bar li#link-to-cart:hover .amount {
268 | border-color: #00adee; }
269 | nav #main-nav-bar li#link-to-cart a {
270 | font-weight: normal;
271 | font-size: 16px;
272 | color: #00adee; }
273 | nav #main-nav-bar li#link-to-cart a .amount {
274 | font-size: 18px;
275 | font-weight: bold;
276 | border-left: 1px solid #dedede;
277 | padding-left: 5px;
278 | padding-bottom: 5px; }
279 |
280 | nav#taxonomies .taxonomy-root {
281 | text-transform: uppercase;
282 | border-bottom: 1px solid #dedede;
283 | margin-bottom: 5px;
284 | color: #00adee; }
285 | nav#taxonomies .taxons-list {
286 | padding-left: 20px;
287 | margin-bottom: 20px;
288 | list-style: disc outside; }
289 |
290 | #breadcrumbs {
291 | border-bottom: 1px solid #dedede;
292 | padding: 3px 0;
293 | margin-bottom: 15px; }
294 | #breadcrumbs li a {
295 | color: #00adee; }
296 | #breadcrumbs li span {
297 | text-transform: uppercase;
298 | font-weight: bold; }
299 |
300 | /*--------------------------------------*/
301 | /* Flash notices & errors
302 | /*--------------------------------------*/
303 | .flash, .errorExplanation {
304 | padding: 10px;
305 | color: white;
306 | font-weight: bold;
307 | margin-bottom: 10px; }
308 | .flash.notice, .notice.errorExplanation {
309 | background-color: #00adee; }
310 | .flash.success, .success.errorExplanation {
311 | background-color: #8dba53; }
312 | .flash.error, .errorExplanation, .error.errorExplanation {
313 | background-color: #e45353; }
314 |
315 | .errorExplanation p {
316 | font-weight: normal; }
317 | .errorExplanation ul {
318 | list-style: disc outside;
319 | margin-left: 30px; }
320 | .errorExplanation ul li {
321 | font-weight: normal; }
322 |
323 | /*--------------------------------------*/
324 | /* Main search bar
325 | /*--------------------------------------*/
326 | #search-bar {
327 | display: block; }
328 |
329 | /*--------------------------------------*/
330 | /* Products
331 | /*--------------------------------------*/
332 | .product-section-title {
333 | text-transform: uppercase;
334 | color: #00adee;
335 | margin-top: 15px; }
336 |
337 | .add-to-cart {
338 | margin-top: 15px; }
339 | .add-to-cart input[type="number"] {
340 | width: 60px;
341 | vertical-align: middle;
342 | padding: 5px;
343 | height: 35px; }
344 |
345 | span.price, #checkout-summary table tr[data-hook="item_total"] td:last-child strong, #checkout-summary table #summary-order-total, #order_details td.price span, #order_details td.total span, #order_summary td.price span, #order_summary td.total span, table#cart-detail tbody#line_items tr td[data-hook="cart_item_price"], table#cart-detail tbody#line_items tr td[data-hook="cart_item_total"], div[data-hook="inside_cart_form"] #subtotal span.order-total {
346 | font-weight: bold;
347 | color: #00adee; }
348 | span.price.selling, #checkout-summary table tr[data-hook="item_total"] td:last-child strong.selling, #checkout-summary table .selling#summary-order-total, #order_details td.price span.selling, #order_details td.total span.selling, #order_summary td.price span.selling, #order_summary td.total span.selling, table#cart-detail tbody#line_items tr td.selling[data-hook="cart_item_price"], table#cart-detail tbody#line_items tr td.selling[data-hook="cart_item_total"], table#cart-detail tbody#line_items tr td[data-hook="cart_item_price"], table#cart-detail tbody#line_items tr td[data-hook="cart_item_total"], div[data-hook="inside_cart_form"] #subtotal span.selling.order-total {
349 | font-size: 20px; }
350 | span.price.diff, #checkout-summary table tr[data-hook="item_total"] td:last-child strong.diff, #checkout-summary table .diff#summary-order-total, #order_details td.price span.diff, #order_details td.total span.diff, #order_summary td.price span.diff, #order_summary td.total span.diff, table#cart-detail tbody#line_items tr td.diff[data-hook="cart_item_price"], table#cart-detail tbody#line_items tr td.diff[data-hook="cart_item_total"], div[data-hook="inside_cart_form"] #subtotal span.diff.order-total {
351 | font-weight: bold; }
352 |
353 | ul#products {
354 | margin-left: -10px;
355 | margin-right: -10px; }
356 | ul#products li {
357 | text-align: center;
358 | font-weight: bold;
359 | margin-bottom: 20px; }
360 | ul#products li a {
361 | display: block; }
362 | ul#products li a.info {
363 | height: 35px;
364 | margin-top: 5px;
365 | color: #bbbbbb;
366 | border-bottom: 1px solid #dedede; }
367 | ul#products li .product-image {
368 | border: 1px solid #dedede;
369 | padding: 5px;
370 | min-height: 110px; }
371 | ul#products li .product-image:hover {
372 | border-color: #00adee; }
373 | ul#products li .price {
374 | color: #00adee;
375 | font-size: 16px;
376 | padding-top: 5px;
377 | display: block; }
378 |
379 | .subtaxon-title {
380 | text-transform: uppercase; }
381 | .subtaxon-title a {
382 | color: #00adee; }
383 |
384 | .search-results-title {
385 | text-transform: uppercase;
386 | border-bottom: 1px solid #dedede;
387 | margin-bottom: 10px; }
388 |
389 | #sidebar_products_search .navigation {
390 | margin-bottom: 15px; }
391 | #sidebar_products_search span.category {
392 | display: block;
393 | font-weight: bold;
394 | text-transform: uppercase;
395 | border-bottom: 1px solid #ededed;
396 | margin-bottom: 5px;
397 | color: #00adee;
398 | font-size: 14px;
399 | line-height: 24px; }
400 |
401 | .taxon {
402 | overflow: hidden; }
403 |
404 | #product-images #main-image {
405 | text-align: center;
406 | border: 1px solid #dedede; }
407 |
408 | #product-description .product-title {
409 | border-bottom: 1px solid #dedede;
410 | margin-bottom: 15px; }
411 |
412 | #product-thumbnails {
413 | margin-top: 10px; }
414 | #product-thumbnails li {
415 | margin-right: 6px;
416 | border: 1px solid #dedede; }
417 | #product-thumbnails li img {
418 | padding: 5px; }
419 | #product-thumbnails li:hover, #product-thumbnails li.selected {
420 | border-color: #00adee; }
421 |
422 | #product-properties {
423 | border: 1px solid #dedede;
424 | padding: 10px; }
425 |
426 | #product-variants ul li {
427 | padding: 5px; }
428 |
429 | /*--------------------------------------*/
430 | /* Checkout
431 | /*--------------------------------------*/
432 | .progress-steps {
433 | list-style: decimal inside;
434 | overflow: auto; }
435 | .progress-steps li {
436 | float: left;
437 | margin-right: 20px;
438 | font-weight: bold;
439 | text-transform: uppercase;
440 | padding: 5px 20px;
441 | color: #bbbbbb; }
442 | .progress-steps li.current-first, .progress-steps li.current {
443 | background-color: #00adee;
444 | color: white; }
445 | .progress-steps li.completed-first, .progress-steps li.completed {
446 | background-color: #dedede;
447 | color: white; }
448 | .progress-steps li.completed-first a, .progress-steps li.completed a {
449 | color: white; }
450 | .progress-steps li.completed-first:hover, .progress-steps li.completed:hover {
451 | background-color: #00adee;
452 | color: white; }
453 | .progress-steps li.completed-first:hover a, .progress-steps li.completed:hover a {
454 | color: white; }
455 | .progress-steps li.completed-first:hover a:hover, .progress-steps li.completed:hover a:hover {
456 | color: white !important; }
457 |
458 | #checkout-summary {
459 | text-align: center;
460 | border: 1px solid #dedede;
461 | margin-top: 23px;
462 | margin-left: 0; }
463 | #checkout-summary h3 {
464 | text-transform: uppercase;
465 | font-size: 14px;
466 | color: #00adee;
467 | border-bottom: 1px solid #dedede; }
468 | #checkout-summary table {
469 | width: 100%; }
470 | #checkout-summary table tr[data-hook="order_total"] {
471 | border-bottom: none; }
472 | #checkout-summary table #summary-order-total {
473 | font-size: 14px; }
474 |
475 | #billing, #shipping, #shipping_method,
476 | #payment, #order_details, #order_summary {
477 | margin-top: 10px;
478 | border: 1px solid #dedede;
479 | padding: 10px; }
480 | #billing legend, #shipping legend, #shipping_method legend,
481 | #payment legend, #order_details legend, #order_summary legend {
482 | text-transform: uppercase;
483 | font-weight: bold;
484 | font-size: 14px;
485 | color: #00adee;
486 | padding: 5px;
487 | margin-left: 15px; }
488 |
489 | #order_details, #order_summary {
490 | padding: 0; }
491 | #order_details div:last-child, #order_summary div:last-child {
492 | margin-left: -1px; }
493 | #order_details .payment-info .cc-type img, #order_summary .payment-info .cc-type img {
494 | vertical-align: middle; }
495 | #order_details table tfoot, #order_summary table tfoot {
496 | text-align: right;
497 | color: #bbbbbb; }
498 | #order_details table tfoot tr, #order_summary table tfoot tr {
499 | border: none; }
500 | #order_details table tfoot#order-total, #order_summary table tfoot#order-total {
501 | text-transform: uppercase;
502 | font-size: 16px;
503 | color: #404042; }
504 | #order_details table tfoot#order-total tr, #order_summary table tfoot#order-total tr {
505 | border-top: 1px solid #dedede; }
506 | #order_details table tfoot#order-total tr td, #order_summary table tfoot#order-total tr td {
507 | padding: 10px; }
508 | #order_details .steps-data, #order_summary .steps-data {
509 | padding: 10px; }
510 | #order_details .steps-data h6, #order_summary .steps-data h6 {
511 | border-bottom: 1px solid #dedede;
512 | margin-bottom: 5px; }
513 |
514 | #shipping_method p label {
515 | float: left;
516 | font-weight: bold;
517 | font-size: 14px;
518 | margin-right: 40px;
519 | padding: 5px; }
520 |
521 | p[data-hook="use_billing"] {
522 | float: right;
523 | margin-top: -38px;
524 | background-color: white;
525 | padding: 5px; }
526 |
527 | /*--------------------------------------*/
528 | /* Cart
529 | /*--------------------------------------*/
530 | table#cart-detail {
531 | width: 100%; }
532 | table#cart-detail tbody#line_items tr td[data-hook="cart_item_quantity"] .line_item_quantity {
533 | width: 40px; }
534 | table#cart-detail tbody#line_items tr td[data-hook="cart_item_delete"] .delete {
535 | display: block;
536 | width: 20px; }
537 |
538 | div[data-hook="inside_cart_form"] .links {
539 | margin-top: 15px; }
540 | div[data-hook="inside_cart_form"] #subtotal {
541 | text-align: right;
542 | text-transform: uppercase;
543 | margin-top: 15px; }
544 |
545 | #empty-cart {
546 | margin-top: 15px;
547 | float: right; }
548 |
549 | /*--------------------------------------*/
550 | /* Account
551 | /*--------------------------------------*/
552 | #existing-customer h6, #new-customer h6, #forgot-password h6 {
553 | text-transform: uppercase;
554 | color: #00adee; }
555 |
556 | #registration h6 {
557 | text-transform: uppercase;
558 | color: #00adee; }
559 | #registration #existing-customer {
560 | width: auto;
561 | text-align: left; }
562 |
563 | #user-info {
564 | margin-bottom: 15px;
565 | border: 1px solid #dedede;
566 | padding: 10px; }
567 |
568 | /*--------------------------------------*/
569 | /* Order
570 | /*--------------------------------------*/
571 | #order_summary {
572 | margin-top: 0; }
573 |
574 | #order p[data-hook="links"] {
575 | margin-left: 10px;
576 | overflow: auto; }
577 |
578 | table.order-summary tbody tr td {
579 | width: 10%;
580 | text-align: center; }
581 | table.order-summary tbody tr td:first-child a {
582 | text-transform: uppercase;
583 | font-weight: bold;
584 | color: #00adee; }
585 |
586 | /* #Media Queries
587 | ================================================== */
588 | /* Smaller than standard 960 (devices and browsers) */
589 | /* Tablet Portrait size to standard 960 (devices and browsers) */
590 | @media only screen and (min-width: 768px) and (max-width: 959px) {
591 | .container {
592 | padding-left: 10px;
593 | width: 758px; }
594 |
595 | footer#footer {
596 | width: 748px; }
597 |
598 | p[data-hook="use_billing"] {
599 | margin-top: -15px; } }
600 | /* All Mobile Sizes (devices and browser) */
601 | @media only screen and (max-width: 767px) {
602 | html {
603 | -webkit-text-size-adjust: none; }
604 |
605 | nav#taxonomies {
606 | text-align: center; }
607 | nav#taxonomies ul {
608 | padding-left: 0 !important;
609 | list-style: none !important; }
610 |
611 | ul#nav-bar {
612 | text-align: center; }
613 |
614 | .steps-data div.columns {
615 | margin-bottom: 15px;
616 | text-align: center; }
617 |
618 | #order_details table[data-hook="order_details"], #order table[data-hook="order_details"] {
619 | width: 100%; }
620 |
621 | #update-cart #subtotal, #update-cart .links {
622 | width: 50%;
623 | float: left;
624 | text-align: left; }
625 | #update-cart #subtotal {
626 | text-align: right; } }
627 | /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */
628 | @media only screen and (min-width: 480px) and (max-width: 767px) {
629 | footer#footer {
630 | width: auto !important; }
631 |
632 | input, select {
633 | vertical-align: baseline !important; }
634 |
635 | figure#logo {
636 | text-align: center; }
637 |
638 | #link-to-login {
639 | display: block;
640 | text-align: center; }
641 |
642 | #search-bar {
643 | display: block;
644 | text-align: center; }
645 | #search-bar select {
646 | margin-bottom: 10px; }
647 |
648 | ul#products {
649 | margin-left: 0;
650 | margin-right: -20px; }
651 | ul#products li {
652 | width: 133px;
653 | margin-right: 10px; }
654 |
655 | table#cart-detail tbody tr td[data-hook="cart_item_description"], table#cart-detail tbody tr td[data-hook="order_item_description"], table[data-hook="order_details"] tbody tr td[data-hook="cart_item_description"], table[data-hook="order_details"] tbody tr td[data-hook="order_item_description"] {
656 | font-size: 11px;
657 | line-height: 15px;
658 | width: 100px; }
659 | table#cart-detail tbody tr td[data-hook="cart_item_description"] h4, table#cart-detail tbody tr td[data-hook="order_item_description"] h4, table[data-hook="order_details"] tbody tr td[data-hook="cart_item_description"] h4, table[data-hook="order_details"] tbody tr td[data-hook="order_item_description"] h4 {
660 | font-size: 14px;
661 | line-height: 17px;
662 | margin-bottom: 10px; }
663 | table#cart-detail tbody tr td[data-hook="cart_item_price"], table#cart-detail tbody tr td[data-hook="cart_item_total"],
664 | table#cart-detail tbody tr td[data-hook="order_item_price"], table#cart-detail tbody tr td[data-hook="order_item_total"], table[data-hook="order_details"] tbody tr td[data-hook="cart_item_price"], table[data-hook="order_details"] tbody tr td[data-hook="cart_item_total"], table[data-hook="order_details"] tbody tr td[data-hook="order_item_price"], table[data-hook="order_details"] tbody tr td[data-hook="order_item_total"] {
665 | font-size: 12px !important; }
666 | table#cart-detail tbody tr td[data-hook="cart_item_image"] img, table#cart-detail tbody tr td[data-hook="order_item_image"] img, table[data-hook="order_details"] tbody tr td[data-hook="cart_item_image"] img, table[data-hook="order_details"] tbody tr td[data-hook="order_item_image"] img {
667 | width: 70px; } }
668 | /* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */
669 | @media only screen and (max-width: 479px) {
670 | .progress-steps li {
671 | padding: 0;
672 | margin: 0;
673 | width: 50%; }
674 | .progress-steps li span {
675 | display: block;
676 | padding: 10px 20px; }
677 |
678 | #shipping_method p label {
679 | float: none;
680 | display: block;
681 | text-align: center;
682 | margin-right: 0; }
683 |
684 | p[data-hook="use_billing"] {
685 | float: none;
686 | margin-top: 0; }
687 |
688 | table#cart-detail tbody tr td[data-hook="cart_item_description"], table#cart-detail tbody tr td[data-hook="order_item_description"], table[data-hook="order_details"] tbody tr td[data-hook="cart_item_description"], table[data-hook="order_details"] tbody tr td[data-hook="order_item_description"] {
689 | padding: 0 !important;
690 | text-indent: -9999px; }
691 | table#cart-detail tbody tr td[data-hook="cart_item_description"] h4, table#cart-detail tbody tr td[data-hook="order_item_description"] h4, table[data-hook="order_details"] tbody tr td[data-hook="cart_item_description"] h4, table[data-hook="order_details"] tbody tr td[data-hook="order_item_description"] h4 {
692 | display: none; }
693 | table#cart-detail tbody tr td[data-hook="cart_item_image"] img, table#cart-detail tbody tr td[data-hook="order_item_image"] img, table[data-hook="order_details"] tbody tr td[data-hook="cart_item_image"] img, table[data-hook="order_details"] tbody tr td[data-hook="order_item_image"] img {
694 | width: 70px; }
695 | table#cart-detail tbody tr td[data-hook="cart_item_price"], table#cart-detail tbody tr td[data-hook="cart_item_total"], table[data-hook="order_details"] tbody tr td[data-hook="cart_item_price"], table[data-hook="order_details"] tbody tr td[data-hook="cart_item_total"] {
696 | font-size: 14px !important; }
697 |
698 | table.order-summary {
699 | display: block;
700 | position: relative;
701 | width: 100%; }
702 | table.order-summary thead {
703 | display: block;
704 | float: left; }
705 | table.order-summary tbody {
706 | display: block;
707 | width: auto;
708 | position: relative;
709 | overflow-x: auto;
710 | white-space: nowrap; }
711 | table.order-summary thead tr {
712 | display: block; }
713 | table.order-summary th {
714 | display: block; }
715 | table.order-summary tbody tr {
716 | display: inline-block;
717 | vertical-align: top; }
718 | table.order-summary td {
719 | display: block;
720 | min-height: 1.25em; }
721 |
722 | figure#logo {
723 | text-align: center; }
724 |
725 | #link-to-login {
726 | display: block;
727 | text-align: center; }
728 |
729 | #search-bar {
730 | display: block;
731 | text-align: center; }
732 | #search-bar select {
733 | margin-bottom: 10px; }
734 |
735 | aside#sidebar {
736 | text-align: center; }
737 | aside#sidebar ul {
738 | padding-left: 0 !important; }
739 | aside#sidebar ul li {
740 | list-style-type: none; }
741 |
742 | ul#products {
743 | margin-left: 0; }
744 | ul#products li {
745 | width: 140px;
746 | margin-right: 15px; }
747 |
748 | #content {
749 | text-align: center; } }
750 |
--------------------------------------------------------------------------------
/test/fixtures/spree/countries.yml:
--------------------------------------------------------------------------------
1 | ---
2 | countries_039:
3 | name: Chad
4 | iso3: TCD
5 | iso: TD
6 | iso_name: CHAD
7 | id: "39"
8 | numcode: "148"
9 | countries_065:
10 | name: Faroe Islands
11 | iso3: FRO
12 | iso: FO
13 | iso_name: FAROE ISLANDS
14 | id: "65"
15 | numcode: "234"
16 | countries_092:
17 | name: India
18 | iso3: IND
19 | iso: IN
20 | iso_name: INDIA
21 | id: "92"
22 | numcode: "356"
23 | countries_146:
24 | name: Nicaragua
25 | iso3: NIC
26 | iso: NI
27 | iso_name: NICARAGUA
28 | id: "146"
29 | numcode: "558"
30 | countries_172:
31 | name: Saint Lucia
32 | iso3: LCA
33 | iso: LC
34 | iso_name: SAINT LUCIA
35 | id: "172"
36 | numcode: "662"
37 | countries_066:
38 | name: Fiji
39 | iso3: FJI
40 | iso: FJ
41 | iso_name: FIJI
42 | id: "66"
43 | numcode: "242"
44 | countries_093:
45 | name: Indonesia
46 | iso3: IDN
47 | iso: ID
48 | iso_name: INDONESIA
49 | id: "93"
50 | numcode: "360"
51 | countries_147:
52 | name: Niger
53 | iso3: NER
54 | iso: NE
55 | iso_name: NIGER
56 | id: "147"
57 | numcode: "562"
58 | countries_173:
59 | name: Saint Pierre and Miquelon
60 | iso3: SPM
61 | iso: PM
62 | iso_name: SAINT PIERRE AND MIQUELON
63 | id: "173"
64 | numcode: "666"
65 | countries_067:
66 | name: Finland
67 | iso3: FIN
68 | iso: FI
69 | iso_name: FINLAND
70 | id: "67"
71 | numcode: "246"
72 | countries_148:
73 | name: Nigeria
74 | iso3: NGA
75 | iso: NG
76 | iso_name: NIGERIA
77 | id: "148"
78 | numcode: "566"
79 | countries_174:
80 | name: Saint Vincent and the Grenadines
81 | iso3: VCT
82 | iso: VC
83 | iso_name: SAINT VINCENT AND THE GRENADINES
84 | id: "174"
85 | numcode: "670"
86 | countries_068:
87 | name: France
88 | iso3: FRA
89 | iso: FR
90 | iso_name: FRANCE
91 | id: "68"
92 | numcode: "250"
93 | countries_094:
94 | name: Iran, Islamic Republic of
95 | iso3: IRN
96 | iso: IR
97 | iso_name: IRAN, ISLAMIC REPUBLIC OF
98 | id: "94"
99 | numcode: "364"
100 | countries_149:
101 | name: Niue
102 | iso3: NIU
103 | iso: NU
104 | iso_name: NIUE
105 | id: "149"
106 | numcode: "570"
107 | countries_175:
108 | name: Samoa
109 | iso3: WSM
110 | iso: WS
111 | iso_name: SAMOA
112 | id: "175"
113 | numcode: "882"
114 | countries_069:
115 | name: French Guiana
116 | iso3: GUF
117 | iso: GF
118 | iso_name: FRENCH GUIANA
119 | id: "69"
120 | numcode: "254"
121 | countries_095:
122 | name: Iraq
123 | iso3: IRQ
124 | iso: IQ
125 | iso_name: IRAQ
126 | id: "95"
127 | numcode: "368"
128 | countries_176:
129 | name: San Marino
130 | iso3: SMR
131 | iso: SM
132 | iso_name: SAN MARINO
133 | id: "176"
134 | numcode: "674"
135 | countries_096:
136 | name: Ireland
137 | iso3: IRL
138 | iso: IE
139 | iso_name: IRELAND
140 | id: "96"
141 | numcode: "372"
142 | countries_177:
143 | name: Sao Tome and Principe
144 | iso3: STP
145 | iso: ST
146 | iso_name: SAO TOME AND PRINCIPE
147 | id: "177"
148 | numcode: "678"
149 | countries_097:
150 | name: Israel
151 | iso3: ISR
152 | iso: IL
153 | iso_name: ISRAEL
154 | id: "97"
155 | numcode: "376"
156 | countries_178:
157 | name: Saudi Arabia
158 | iso3: SAU
159 | iso: SA
160 | iso_name: SAUDI ARABIA
161 | id: "178"
162 | numcode: "682"
163 | countries_098:
164 | name: Italy
165 | iso3: ITA
166 | iso: IT
167 | iso_name: ITALY
168 | id: "98"
169 | numcode: "380"
170 | countries_179:
171 | name: Senegal
172 | iso3: SEN
173 | iso: SN
174 | iso_name: SENEGAL
175 | id: "179"
176 | numcode: "686"
177 | countries_099:
178 | name: Jamaica
179 | iso3: JAM
180 | iso: JM
181 | iso_name: JAMAICA
182 | id: "99"
183 | numcode: "388"
184 | countries_100:
185 | name: Japan
186 | iso3: JPN
187 | iso: JP
188 | iso_name: JAPAN
189 | id: "100"
190 | numcode: "392"
191 | countries_101:
192 | name: Jordan
193 | iso3: JOR
194 | iso: JO
195 | iso_name: JORDAN
196 | id: "101"
197 | numcode: "400"
198 | countries_020:
199 | name: Belgium
200 | iso3: BEL
201 | iso: BE
202 | iso_name: BELGIUM
203 | id: "20"
204 | numcode: "56"
205 | countries_021:
206 | name: Belize
207 | iso3: BLZ
208 | iso: BZ
209 | iso_name: BELIZE
210 | id: "21"
211 | numcode: "84"
212 | countries_102:
213 | name: Kazakhstan
214 | iso3: KAZ
215 | iso: KZ
216 | iso_name: KAZAKHSTAN
217 | id: "102"
218 | numcode: "398"
219 | countries_210:
220 | name: Uganda
221 | iso3: UGA
222 | iso: UG
223 | iso_name: UGANDA
224 | id: "210"
225 | numcode: "800"
226 | countries_022:
227 | name: Benin
228 | iso3: BEN
229 | iso: BJ
230 | iso_name: BENIN
231 | id: "22"
232 | numcode: "204"
233 | countries_103:
234 | name: Kenya
235 | iso3: KEN
236 | iso: KE
237 | iso_name: KENYA
238 | id: "103"
239 | numcode: "404"
240 | countries_211:
241 | name: Ukraine
242 | iso3: UKR
243 | iso: UA
244 | iso_name: UKRAINE
245 | id: "211"
246 | numcode: "804"
247 | countries_023:
248 | name: Bermuda
249 | iso3: BMU
250 | iso: BM
251 | iso_name: BERMUDA
252 | id: "23"
253 | numcode: "60"
254 | countries_104:
255 | name: Kiribati
256 | iso3: KIR
257 | iso: KI
258 | iso_name: KIRIBATI
259 | id: "104"
260 | numcode: "296"
261 | countries_130:
262 | name: Mexico
263 | iso3: MEX
264 | iso: MX
265 | iso_name: MEXICO
266 | id: "130"
267 | numcode: "484"
268 | countries_212:
269 | name: United Arab Emirates
270 | iso3: ARE
271 | iso: AE
272 | iso_name: UNITED ARAB EMIRATES
273 | id: "212"
274 | numcode: "784"
275 | countries_024:
276 | name: Bhutan
277 | iso3: BTN
278 | iso: BT
279 | iso_name: BHUTAN
280 | id: "24"
281 | numcode: "64"
282 | countries_050:
283 | name: Cuba
284 | iso3: CUB
285 | iso: CU
286 | iso_name: CUBA
287 | id: "50"
288 | numcode: "192"
289 | countries_105:
290 | name: North Korea
291 | iso3: PRK
292 | iso: KP
293 | iso_name: KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF
294 | id: "105"
295 | numcode: "408"
296 | countries_131:
297 | name: Micronesia, Federated States of
298 | iso3: FSM
299 | iso: FM
300 | iso_name: MICRONESIA, FEDERATED STATES OF
301 | id: "131"
302 | numcode: "583"
303 | countries_213:
304 | name: United Kingdom
305 | iso3: GBR
306 | iso: GB
307 | iso_name: UNITED KINGDOM
308 | id: "213"
309 | numcode: "826"
310 | countries_025:
311 | name: Bolivia
312 | iso3: BOL
313 | iso: BO
314 | iso_name: BOLIVIA
315 | id: "25"
316 | numcode: "68"
317 | countries_051:
318 | name: Cyprus
319 | iso3: CYP
320 | iso: CY
321 | iso_name: CYPRUS
322 | id: "51"
323 | numcode: "196"
324 | countries_106:
325 | name: South Korea
326 | iso3: KOR
327 | iso: KR
328 | iso_name: KOREA, REPUBLIC OF
329 | id: "106"
330 | numcode: "410"
331 | countries_132:
332 | name: Moldova, Republic of
333 | iso3: MDA
334 | iso: MD
335 | iso_name: MOLDOVA, REPUBLIC OF
336 | id: "132"
337 | numcode: "498"
338 | countries_214:
339 | name: United States
340 | iso3: USA
341 | iso: US
342 | iso_name: UNITED STATES
343 | id: "214"
344 | numcode: "840"
345 | countries_026:
346 | name: Bosnia and Herzegovina
347 | iso3: BIH
348 | iso: BA
349 | iso_name: BOSNIA AND HERZEGOVINA
350 | id: "26"
351 | numcode: "70"
352 | countries_052:
353 | name: Czech Republic
354 | iso3: CZE
355 | iso: CZ
356 | iso_name: CZECH REPUBLIC
357 | id: "52"
358 | numcode: "203"
359 | countries_107:
360 | name: Kuwait
361 | iso3: KWT
362 | iso: KW
363 | iso_name: KUWAIT
364 | id: "107"
365 | numcode: "414"
366 | countries_133:
367 | name: Monaco
368 | iso3: MCO
369 | iso: MC
370 | iso_name: MONACO
371 | id: "133"
372 | numcode: "492"
373 | countries_215:
374 | name: Uruguay
375 | iso3: URY
376 | iso: UY
377 | iso_name: URUGUAY
378 | id: "215"
379 | numcode: "858"
380 | countries_027:
381 | name: Botswana
382 | iso3: BWA
383 | iso: BW
384 | iso_name: BOTSWANA
385 | id: "27"
386 | numcode: "72"
387 | countries_053:
388 | name: Denmark
389 | iso3: DNK
390 | iso: DK
391 | iso_name: DENMARK
392 | id: "53"
393 | numcode: "208"
394 | countries_080:
395 | name: Guadeloupe
396 | iso3: GLP
397 | iso: GP
398 | iso_name: GUADELOUPE
399 | id: "80"
400 | numcode: "312"
401 | countries_108:
402 | name: Kyrgyzstan
403 | iso3: KGZ
404 | iso: KG
405 | iso_name: KYRGYZSTAN
406 | id: "108"
407 | numcode: "417"
408 | countries_134:
409 | name: Mongolia
410 | iso3: MNG
411 | iso: MN
412 | iso_name: MONGOLIA
413 | id: "134"
414 | numcode: "496"
415 | countries_160:
416 | name: Philippines
417 | iso3: PHL
418 | iso: PH
419 | iso_name: PHILIPPINES
420 | id: "160"
421 | numcode: "608"
422 | countries_028:
423 | name: Brazil
424 | iso3: BRA
425 | iso: BR
426 | iso_name: BRAZIL
427 | id: "28"
428 | numcode: "76"
429 | countries_054:
430 | name: Djibouti
431 | iso3: DJI
432 | iso: DJ
433 | iso_name: DJIBOUTI
434 | id: "54"
435 | numcode: "262"
436 | countries_081:
437 | name: Guam
438 | iso3: GUM
439 | iso: GU
440 | iso_name: GUAM
441 | id: "81"
442 | numcode: "316"
443 | countries_109:
444 | name: Lao People's Democratic Republic
445 | iso3: LAO
446 | iso: LA
447 | iso_name: LAO PEOPLE'S DEMOCRATIC REPUBLIC
448 | id: "109"
449 | numcode: "418"
450 | countries_135:
451 | name: Montserrat
452 | iso3: MSR
453 | iso: MS
454 | iso_name: MONTSERRAT
455 | id: "135"
456 | numcode: "500"
457 | countries_161:
458 | name: Pitcairn
459 | iso3: PCN
460 | iso: PN
461 | iso_name: PITCAIRN
462 | id: "161"
463 | numcode: "612"
464 | countries_216:
465 | name: Uzbekistan
466 | iso3: UZB
467 | iso: UZ
468 | iso_name: UZBEKISTAN
469 | id: "216"
470 | numcode: "860"
471 | countries_029:
472 | name: Brunei Darussalam
473 | iso3: BRN
474 | iso: BN
475 | iso_name: BRUNEI DARUSSALAM
476 | id: "29"
477 | numcode: "96"
478 | countries_055:
479 | name: Dominica
480 | iso3: DMA
481 | iso: DM
482 | iso_name: DOMINICA
483 | id: "55"
484 | numcode: "212"
485 | countries_082:
486 | name: Guatemala
487 | iso3: GTM
488 | iso: GT
489 | iso_name: GUATEMALA
490 | id: "82"
491 | numcode: "320"
492 | countries_136:
493 | name: Morocco
494 | iso3: MAR
495 | iso: MA
496 | iso_name: MOROCCO
497 | id: "136"
498 | numcode: "504"
499 | countries_162:
500 | name: Poland
501 | iso3: POL
502 | iso: PL
503 | iso_name: POLAND
504 | id: "162"
505 | numcode: "616"
506 | countries_217:
507 | name: Vanuatu
508 | iso3: VUT
509 | iso: VU
510 | iso_name: VANUATU
511 | id: "217"
512 | numcode: "548"
513 | countries_056:
514 | name: Dominican Republic
515 | iso3: DOM
516 | iso: DO
517 | iso_name: DOMINICAN REPUBLIC
518 | id: "56"
519 | numcode: "214"
520 | countries_137:
521 | name: Mozambique
522 | iso3: MOZ
523 | iso: MZ
524 | iso_name: MOZAMBIQUE
525 | id: "137"
526 | numcode: "508"
527 | countries_163:
528 | name: Portugal
529 | iso3: PRT
530 | iso: PT
531 | iso_name: PORTUGAL
532 | id: "163"
533 | numcode: "620"
534 | countries_190:
535 | name: Sudan
536 | iso3: SDN
537 | iso: SD
538 | iso_name: SUDAN
539 | id: "190"
540 | numcode: "736"
541 | countries_218:
542 | name: Venezuela
543 | iso3: VEN
544 | iso: VE
545 | iso_name: VENEZUELA
546 | id: "218"
547 | numcode: "862"
548 | countries_057:
549 | name: Ecuador
550 | iso3: ECU
551 | iso: EC
552 | iso_name: ECUADOR
553 | id: "57"
554 | numcode: "218"
555 | countries_083:
556 | name: Guinea
557 | iso3: GIN
558 | iso: GN
559 | iso_name: GUINEA
560 | id: "83"
561 | numcode: "324"
562 | countries_138:
563 | name: Myanmar
564 | iso3: MMR
565 | iso: MM
566 | iso_name: MYANMAR
567 | id: "138"
568 | numcode: "104"
569 | countries_164:
570 | name: Puerto Rico
571 | iso3: PRI
572 | iso: PR
573 | iso_name: PUERTO RICO
574 | id: "164"
575 | numcode: "630"
576 | countries_191:
577 | name: Suriname
578 | iso3: SUR
579 | iso: SR
580 | iso_name: SURINAME
581 | id: "191"
582 | numcode: "740"
583 | countries_219:
584 | name: Viet Nam
585 | iso3: VNM
586 | iso: VN
587 | iso_name: VIET NAM
588 | id: "219"
589 | numcode: "704"
590 | countries_058:
591 | name: Egypt
592 | iso3: EGY
593 | iso: EG
594 | iso_name: EGYPT
595 | id: "58"
596 | numcode: "818"
597 | countries_084:
598 | name: Guinea-Bissau
599 | iso3: GNB
600 | iso: GW
601 | iso_name: GUINEA-BISSAU
602 | id: "84"
603 | numcode: "624"
604 | countries_139:
605 | name: Namibia
606 | iso3: NAM
607 | iso: NA
608 | iso_name: NAMIBIA
609 | id: "139"
610 | numcode: "516"
611 | countries_165:
612 | name: Qatar
613 | iso3: QAT
614 | iso: QA
615 | iso_name: QATAR
616 | id: "165"
617 | numcode: "634"
618 | countries_192:
619 | name: Svalbard and Jan Mayen
620 | iso3: SJM
621 | iso: SJ
622 | iso_name: SVALBARD AND JAN MAYEN
623 | id: "192"
624 | numcode: "744"
625 | countries_059:
626 | name: El Salvador
627 | iso3: SLV
628 | iso: SV
629 | iso_name: EL SALVADOR
630 | id: "59"
631 | numcode: "222"
632 | countries_085:
633 | name: Guyana
634 | iso3: GUY
635 | iso: GY
636 | iso_name: GUYANA
637 | id: "85"
638 | numcode: "328"
639 | countries_166:
640 | name: Reunion
641 | iso3: REU
642 | iso: RE
643 | iso_name: REUNION
644 | id: "166"
645 | numcode: "638"
646 | countries_086:
647 | name: Haiti
648 | iso3: HTI
649 | iso: HT
650 | iso_name: HAITI
651 | id: "86"
652 | numcode: "332"
653 | countries_167:
654 | name: Romania
655 | iso3: ROM
656 | iso: RO
657 | iso_name: ROMANIA
658 | id: "167"
659 | numcode: "642"
660 | countries_193:
661 | name: Swaziland
662 | iso3: SWZ
663 | iso: SZ
664 | iso_name: SWAZILAND
665 | id: "193"
666 | numcode: "748"
667 | countries_087:
668 | name: Holy See (Vatican City State)
669 | iso3: VAT
670 | iso: VA
671 | iso_name: HOLY SEE (VATICAN CITY STATE)
672 | id: "87"
673 | numcode: "336"
674 | countries_168:
675 | name: Russian Federation
676 | iso3: RUS
677 | iso: RU
678 | iso_name: RUSSIAN FEDERATION
679 | id: "168"
680 | numcode: "643"
681 | countries_194:
682 | name: Sweden
683 | iso3: SWE
684 | iso: SE
685 | iso_name: SWEDEN
686 | id: "194"
687 | numcode: "752"
688 | countries_088:
689 | name: Honduras
690 | iso3: HND
691 | iso: HN
692 | iso_name: HONDURAS
693 | id: "88"
694 | numcode: "340"
695 | countries_169:
696 | name: Rwanda
697 | iso3: RWA
698 | iso: RW
699 | iso_name: RWANDA
700 | id: "169"
701 | numcode: "646"
702 | countries_195:
703 | name: Switzerland
704 | iso3: CHE
705 | iso: CH
706 | iso_name: SWITZERLAND
707 | id: "195"
708 | numcode: "756"
709 | countries_089:
710 | name: Hong Kong
711 | iso3: HKG
712 | iso: HK
713 | iso_name: HONG KONG
714 | id: "89"
715 | numcode: "344"
716 | countries_196:
717 | name: Syrian Arab Republic
718 | iso3: SYR
719 | iso: SY
720 | iso_name: SYRIAN ARAB REPUBLIC
721 | id: "196"
722 | numcode: "760"
723 | countries_197:
724 | name: Taiwan
725 | iso3: TWN
726 | iso: TW
727 | iso_name: TAIWAN, PROVINCE OF CHINA
728 | id: "197"
729 | numcode: "158"
730 | countries_198:
731 | name: Tajikistan
732 | iso3: TJK
733 | iso: TJ
734 | iso_name: TAJIKISTAN
735 | id: "198"
736 | numcode: "762"
737 | countries_199:
738 | name: Tanzania, United Republic of
739 | iso3: TZA
740 | iso: TZ
741 | iso_name: TANZANIA, UNITED REPUBLIC OF
742 | id: "199"
743 | numcode: "834"
744 | countries_010:
745 | name: Armenia
746 | iso3: ARM
747 | iso: AM
748 | iso_name: ARMENIA
749 | id: "10"
750 | numcode: "51"
751 | countries_011:
752 | name: Aruba
753 | iso3: ABW
754 | iso: AW
755 | iso_name: ARUBA
756 | id: "11"
757 | numcode: "533"
758 | countries_012:
759 | name: Australia
760 | iso3: AUS
761 | iso: AU
762 | iso_name: AUSTRALIA
763 | id: "12"
764 | numcode: "36"
765 | countries_200:
766 | name: Thailand
767 | iso3: THA
768 | iso: TH
769 | iso_name: THAILAND
770 | id: "200"
771 | numcode: "764"
772 | countries_013:
773 | name: Austria
774 | iso3: AUT
775 | iso: AT
776 | iso_name: AUSTRIA
777 | id: "13"
778 | numcode: "40"
779 | countries_120:
780 | name: Madagascar
781 | iso3: MDG
782 | iso: MG
783 | iso_name: MADAGASCAR
784 | id: "120"
785 | numcode: "450"
786 | countries_201:
787 | name: Togo
788 | iso3: TGO
789 | iso: TG
790 | iso_name: TOGO
791 | id: "201"
792 | numcode: "768"
793 | countries_014:
794 | name: Azerbaijan
795 | iso3: AZE
796 | iso: AZ
797 | iso_name: AZERBAIJAN
798 | id: "14"
799 | numcode: "31"
800 | countries_040:
801 | name: Chile
802 | iso3: CHL
803 | iso: CL
804 | iso_name: CHILE
805 | id: "40"
806 | numcode: "152"
807 | countries_121:
808 | name: Malawi
809 | iso3: MWI
810 | iso: MW
811 | iso_name: MALAWI
812 | id: "121"
813 | numcode: "454"
814 | countries_202:
815 | name: Tokelau
816 | iso3: TKL
817 | iso: TK
818 | iso_name: TOKELAU
819 | id: "202"
820 | numcode: "772"
821 | countries_015:
822 | name: Bahamas
823 | iso3: BHS
824 | iso: BS
825 | iso_name: BAHAMAS
826 | id: "15"
827 | numcode: "44"
828 | countries_041:
829 | name: China
830 | iso3: CHN
831 | iso: CN
832 | iso_name: CHINA
833 | id: "41"
834 | numcode: "156"
835 | countries_122:
836 | name: Malaysia
837 | iso3: MYS
838 | iso: MY
839 | iso_name: MALAYSIA
840 | id: "122"
841 | numcode: "458"
842 | countries_203:
843 | name: Tonga
844 | iso3: TON
845 | iso: TO
846 | iso_name: TONGA
847 | id: "203"
848 | numcode: "776"
849 | countries_016:
850 | name: Bahrain
851 | iso3: BHR
852 | iso: BH
853 | iso_name: BAHRAIN
854 | id: "16"
855 | numcode: "48"
856 | countries_042:
857 | name: Colombia
858 | iso3: COL
859 | iso: CO
860 | iso_name: COLOMBIA
861 | id: "42"
862 | numcode: "170"
863 | countries_123:
864 | name: Maldives
865 | iso3: MDV
866 | iso: MV
867 | iso_name: MALDIVES
868 | id: "123"
869 | numcode: "462"
870 | countries_204:
871 | name: Trinidad and Tobago
872 | iso3: TTO
873 | iso: TT
874 | iso_name: TRINIDAD AND TOBAGO
875 | id: "204"
876 | numcode: "780"
877 | countries_017:
878 | name: Bangladesh
879 | iso3: BGD
880 | iso: BD
881 | iso_name: BANGLADESH
882 | id: "17"
883 | numcode: "50"
884 | countries_043:
885 | name: Comoros
886 | iso3: COM
887 | iso: KM
888 | iso_name: COMOROS
889 | id: "43"
890 | numcode: "174"
891 | countries_070:
892 | name: French Polynesia
893 | iso3: PYF
894 | iso: PF
895 | iso_name: FRENCH POLYNESIA
896 | id: "70"
897 | numcode: "258"
898 | countries_124:
899 | name: Mali
900 | iso3: MLI
901 | iso: ML
902 | iso_name: MALI
903 | id: "124"
904 | numcode: "466"
905 | countries_150:
906 | name: Norfolk Island
907 | iso3: NFK
908 | iso: NF
909 | iso_name: NORFOLK ISLAND
910 | id: "150"
911 | numcode: "574"
912 | countries_205:
913 | name: Tunisia
914 | iso3: TUN
915 | iso: TN
916 | iso_name: TUNISIA
917 | id: "205"
918 | numcode: "788"
919 | countries_018:
920 | name: Barbados
921 | iso3: BRB
922 | iso: BB
923 | iso_name: BARBADOS
924 | id: "18"
925 | numcode: "52"
926 | countries_044:
927 | name: Congo
928 | iso3: COG
929 | iso: CG
930 | iso_name: CONGO
931 | id: "44"
932 | numcode: "178"
933 | countries_071:
934 | name: Gabon
935 | iso3: GAB
936 | iso: GA
937 | iso_name: GABON
938 | id: "71"
939 | numcode: "266"
940 | countries_125:
941 | name: Malta
942 | iso3: MLT
943 | iso: MT
944 | iso_name: MALTA
945 | id: "125"
946 | numcode: "470"
947 | countries_151:
948 | name: Northern Mariana Islands
949 | iso3: MNP
950 | iso: MP
951 | iso_name: NORTHERN MARIANA ISLANDS
952 | id: "151"
953 | numcode: "580"
954 | countries_206:
955 | name: Turkey
956 | iso3: TUR
957 | iso: TR
958 | iso_name: TURKEY
959 | id: "206"
960 | numcode: "792"
961 | countries_045:
962 | name: Congo, the Democratic Republic of the
963 | iso3: COD
964 | iso: CD
965 | iso_name: CONGO, THE DEMOCRATIC REPUBLIC OF THE
966 | id: "45"
967 | numcode: "180"
968 | countries_126:
969 | name: Marshall Islands
970 | iso3: MHL
971 | iso: MH
972 | iso_name: MARSHALL ISLANDS
973 | id: "126"
974 | numcode: "584"
975 | countries_152:
976 | name: Norway
977 | iso3: NOR
978 | iso: "NO"
979 | iso_name: NORWAY
980 | id: "152"
981 | numcode: "578"
982 | countries_207:
983 | name: Turkmenistan
984 | iso3: TKM
985 | iso: TM
986 | iso_name: TURKMENISTAN
987 | id: "207"
988 | numcode: "795"
989 | countries_019:
990 | name: Belarus
991 | iso3: BLR
992 | iso: BY
993 | iso_name: BELARUS
994 | id: "19"
995 | numcode: "112"
996 | countries_046:
997 | name: Cook Islands
998 | iso3: COK
999 | iso: CK
1000 | iso_name: COOK ISLANDS
1001 | id: "46"
1002 | numcode: "184"
1003 | countries_072:
1004 | name: Gambia
1005 | iso3: GMB
1006 | iso: GM
1007 | iso_name: GAMBIA
1008 | id: "72"
1009 | numcode: "270"
1010 | countries_127:
1011 | name: Martinique
1012 | iso3: MTQ
1013 | iso: MQ
1014 | iso_name: MARTINIQUE
1015 | id: "127"
1016 | numcode: "474"
1017 | countries_153:
1018 | name: Oman
1019 | iso3: OMN
1020 | iso: OM
1021 | iso_name: OMAN
1022 | id: "153"
1023 | numcode: "512"
1024 | countries_180:
1025 | name: Seychelles
1026 | iso3: SYC
1027 | iso: SC
1028 | iso_name: SEYCHELLES
1029 | id: "180"
1030 | numcode: "690"
1031 | countries_208:
1032 | name: Turks and Caicos Islands
1033 | iso3: TCA
1034 | iso: TC
1035 | iso_name: TURKS AND CAICOS ISLANDS
1036 | id: "208"
1037 | numcode: "796"
1038 | countries_073:
1039 | name: Georgia
1040 | iso3: GEO
1041 | iso: GE
1042 | iso_name: GEORGIA
1043 | id: "73"
1044 | numcode: "268"
1045 | countries_128:
1046 | name: Mauritania
1047 | iso3: MRT
1048 | iso: MR
1049 | iso_name: MAURITANIA
1050 | id: "128"
1051 | numcode: "478"
1052 | countries_154:
1053 | name: Pakistan
1054 | iso3: PAK
1055 | iso: PK
1056 | iso_name: PAKISTAN
1057 | id: "154"
1058 | numcode: "586"
1059 | countries_181:
1060 | name: Sierra Leone
1061 | iso3: SLE
1062 | iso: SL
1063 | iso_name: SIERRA LEONE
1064 | id: "181"
1065 | numcode: "694"
1066 | countries_209:
1067 | name: Tuvalu
1068 | iso3: TUV
1069 | iso: TV
1070 | iso_name: TUVALU
1071 | id: "209"
1072 | numcode: "798"
1073 | countries_047:
1074 | name: Costa Rica
1075 | iso3: CRI
1076 | iso: CR
1077 | iso_name: COSTA RICA
1078 | id: "47"
1079 | numcode: "188"
1080 | countries_074:
1081 | name: Germany
1082 | iso3: DEU
1083 | iso: DE
1084 | iso_name: GERMANY
1085 | id: "74"
1086 | numcode: "276"
1087 | countries_129:
1088 | name: Mauritius
1089 | iso3: MUS
1090 | iso: MU
1091 | iso_name: MAURITIUS
1092 | id: "129"
1093 | numcode: "480"
1094 | countries_155:
1095 | name: Palau
1096 | iso3: PLW
1097 | iso: PW
1098 | iso_name: PALAU
1099 | id: "155"
1100 | numcode: "585"
1101 | countries_048:
1102 | name: Cote D'Ivoire
1103 | iso3: CIV
1104 | iso: CI
1105 | iso_name: COTE D'IVOIRE
1106 | id: "48"
1107 | numcode: "384"
1108 | countries_156:
1109 | name: Panama
1110 | iso3: PAN
1111 | iso: PA
1112 | iso_name: PANAMA
1113 | id: "156"
1114 | numcode: "591"
1115 | countries_182:
1116 | name: Singapore
1117 | iso3: SGP
1118 | iso: SG
1119 | iso_name: SINGAPORE
1120 | id: "182"
1121 | numcode: "702"
1122 | countries_049:
1123 | name: Croatia
1124 | iso3: HRV
1125 | iso: HR
1126 | iso_name: CROATIA
1127 | id: "49"
1128 | numcode: "191"
1129 | countries_075:
1130 | name: Ghana
1131 | iso3: GHA
1132 | iso: GH
1133 | iso_name: GHANA
1134 | id: "75"
1135 | numcode: "288"
1136 | countries_157:
1137 | name: Papua New Guinea
1138 | iso3: PNG
1139 | iso: PG
1140 | iso_name: PAPUA NEW GUINEA
1141 | id: "157"
1142 | numcode: "598"
1143 | countries_183:
1144 | name: Slovakia
1145 | iso3: SVK
1146 | iso: SK
1147 | iso_name: SLOVAKIA
1148 | id: "183"
1149 | numcode: "703"
1150 | countries_076:
1151 | name: Gibraltar
1152 | iso3: GIB
1153 | iso: GI
1154 | iso_name: GIBRALTAR
1155 | id: "76"
1156 | numcode: "292"
1157 | countries_158:
1158 | name: Paraguay
1159 | iso3: PRY
1160 | iso: PY
1161 | iso_name: PARAGUAY
1162 | id: "158"
1163 | numcode: "600"
1164 | countries_184:
1165 | name: Slovenia
1166 | iso3: SVN
1167 | iso: SI
1168 | iso_name: SLOVENIA
1169 | id: "184"
1170 | numcode: "705"
1171 | countries_077:
1172 | name: Greece
1173 | iso3: GRC
1174 | iso: GR
1175 | iso_name: GREECE
1176 | id: "77"
1177 | numcode: "300"
1178 | countries_159:
1179 | name: Peru
1180 | iso3: PER
1181 | iso: PE
1182 | iso_name: PERU
1183 | id: "159"
1184 | numcode: "604"
1185 | countries_185:
1186 | name: Solomon Islands
1187 | iso3: SLB
1188 | iso: SB
1189 | iso_name: SOLOMON ISLANDS
1190 | id: "185"
1191 | numcode: "90"
1192 | countries_078:
1193 | name: Greenland
1194 | iso3: GRL
1195 | iso: GL
1196 | iso_name: GREENLAND
1197 | id: "78"
1198 | numcode: "304"
1199 | countries_186:
1200 | name: Somalia
1201 | iso3: SOM
1202 | iso: SO
1203 | iso_name: SOMALIA
1204 | id: "186"
1205 | numcode: "706"
1206 | countries_079:
1207 | name: Grenada
1208 | iso3: GRD
1209 | iso: GD
1210 | iso_name: GRENADA
1211 | id: "79"
1212 | numcode: "308"
1213 | countries_187:
1214 | name: South Africa
1215 | iso3: ZAF
1216 | iso: ZA
1217 | iso_name: SOUTH AFRICA
1218 | id: "187"
1219 | numcode: "710"
1220 | countries_188:
1221 | name: Spain
1222 | iso3: ESP
1223 | iso: ES
1224 | iso_name: SPAIN
1225 | id: "188"
1226 | numcode: "724"
1227 | countries_189:
1228 | name: Sri Lanka
1229 | iso3: LKA
1230 | iso: LK
1231 | iso_name: SRI LANKA
1232 | id: "189"
1233 | numcode: "144"
1234 | countries_001:
1235 | name: Afghanistan
1236 | iso3: AFG
1237 | iso: AF
1238 | iso_name: AFGHANISTAN
1239 | id: "1"
1240 | numcode: "4"
1241 | countries_002:
1242 | name: Albania
1243 | iso3: ALB
1244 | iso: AL
1245 | iso_name: ALBANIA
1246 | id: "2"
1247 | numcode: "8"
1248 | countries_003:
1249 | name: Algeria
1250 | iso3: DZA
1251 | iso: DZ
1252 | iso_name: ALGERIA
1253 | id: "3"
1254 | numcode: "12"
1255 | countries_110:
1256 | name: Latvia
1257 | iso3: LVA
1258 | iso: LV
1259 | iso_name: LATVIA
1260 | id: "110"
1261 | numcode: "428"
1262 | countries_004:
1263 | name: American Samoa
1264 | iso3: ASM
1265 | iso: AS
1266 | iso_name: AMERICAN SAMOA
1267 | id: "4"
1268 | numcode: "16"
1269 | countries_030:
1270 | name: Bulgaria
1271 | iso3: BGR
1272 | iso: BG
1273 | iso_name: BULGARIA
1274 | id: "30"
1275 | numcode: "100"
1276 | countries_111:
1277 | name: Lebanon
1278 | iso3: LBN
1279 | iso: LB
1280 | iso_name: LEBANON
1281 | id: "111"
1282 | numcode: "422"
1283 | countries_005:
1284 | name: Andorra
1285 | iso3: AND
1286 | iso: AD
1287 | iso_name: ANDORRA
1288 | id: "5"
1289 | numcode: "20"
1290 | countries_031:
1291 | name: Burkina Faso
1292 | iso3: BFA
1293 | iso: BF
1294 | iso_name: BURKINA FASO
1295 | id: "31"
1296 | numcode: "854"
1297 | countries_112:
1298 | name: Lesotho
1299 | iso3: LSO
1300 | iso: LS
1301 | iso_name: LESOTHO
1302 | id: "112"
1303 | numcode: "426"
1304 | countries_006:
1305 | name: Angola
1306 | iso3: AGO
1307 | iso: AO
1308 | iso_name: ANGOLA
1309 | id: "6"
1310 | numcode: "24"
1311 | countries_032:
1312 | name: Burundi
1313 | iso3: BDI
1314 | iso: BI
1315 | iso_name: BURUNDI
1316 | id: "32"
1317 | numcode: "108"
1318 | countries_113:
1319 | name: Liberia
1320 | iso3: LBR
1321 | iso: LR
1322 | iso_name: LIBERIA
1323 | id: "113"
1324 | numcode: "430"
1325 | countries_220:
1326 | name: Virgin Islands, British
1327 | iso3: VGB
1328 | iso: VG
1329 | iso_name: VIRGIN ISLANDS, BRITISH
1330 | id: "220"
1331 | numcode: "92"
1332 | countries_007:
1333 | name: Anguilla
1334 | iso3: AIA
1335 | iso: AI
1336 | iso_name: ANGUILLA
1337 | id: "7"
1338 | numcode: "660"
1339 | countries_033:
1340 | name: Cambodia
1341 | iso3: KHM
1342 | iso: KH
1343 | iso_name: CAMBODIA
1344 | id: "33"
1345 | numcode: "116"
1346 | countries_060:
1347 | name: Equatorial Guinea
1348 | iso3: GNQ
1349 | iso: GQ
1350 | iso_name: EQUATORIAL GUINEA
1351 | id: "60"
1352 | numcode: "226"
1353 | countries_114:
1354 | name: Libyan Arab Jamahiriya
1355 | iso3: LBY
1356 | iso: LY
1357 | iso_name: LIBYAN ARAB JAMAHIRIYA
1358 | id: "114"
1359 | numcode: "434"
1360 | countries_140:
1361 | name: Nauru
1362 | iso3: NRU
1363 | iso: NR
1364 | iso_name: NAURU
1365 | id: "140"
1366 | numcode: "520"
1367 | countries_221:
1368 | name: Virgin Islands, U.S.
1369 | iso3: VIR
1370 | iso: VI
1371 | iso_name: VIRGIN ISLANDS, U.S.
1372 | id: "221"
1373 | numcode: "850"
1374 | countries_008:
1375 | name: Antigua and Barbuda
1376 | iso3: ATG
1377 | iso: AG
1378 | iso_name: ANTIGUA AND BARBUDA
1379 | id: "8"
1380 | numcode: "28"
1381 | countries_034:
1382 | name: Cameroon
1383 | iso3: CMR
1384 | iso: CM
1385 | iso_name: CAMEROON
1386 | id: "34"
1387 | numcode: "120"
1388 | countries_115:
1389 | name: Liechtenstein
1390 | iso3: LIE
1391 | iso: LI
1392 | iso_name: LIECHTENSTEIN
1393 | id: "115"
1394 | numcode: "438"
1395 | countries_141:
1396 | name: Nepal
1397 | iso3: NPL
1398 | iso: NP
1399 | iso_name: NEPAL
1400 | id: "141"
1401 | numcode: "524"
1402 | countries_222:
1403 | name: Wallis and Futuna
1404 | iso3: WLF
1405 | iso: WF
1406 | iso_name: WALLIS AND FUTUNA
1407 | id: "222"
1408 | numcode: "876"
1409 | countries_223:
1410 | name: Western Sahara
1411 | iso3: ESH
1412 | iso: EH
1413 | iso_name: WESTERN SAHARA
1414 | id: "223"
1415 | numcode: "732"
1416 | countries_009:
1417 | name: Argentina
1418 | iso3: ARG
1419 | iso: AR
1420 | iso_name: ARGENTINA
1421 | id: "9"
1422 | numcode: "32"
1423 | countries_035:
1424 | name: Canada
1425 | iso3: CAN
1426 | iso: CA
1427 | iso_name: CANADA
1428 | id: "35"
1429 | numcode: "124"
1430 | countries_061:
1431 | name: Eritrea
1432 | iso3: ERI
1433 | iso: ER
1434 | iso_name: ERITREA
1435 | id: "61"
1436 | numcode: "232"
1437 | countries_116:
1438 | name: Lithuania
1439 | iso3: LTU
1440 | iso: LT
1441 | iso_name: LITHUANIA
1442 | id: "116"
1443 | numcode: "440"
1444 | countries_142:
1445 | name: Netherlands
1446 | iso3: NLD
1447 | iso: NL
1448 | iso_name: NETHERLANDS
1449 | id: "142"
1450 | numcode: "528"
1451 | countries_224:
1452 | name: Yemen
1453 | iso3: YEM
1454 | iso: YE
1455 | iso_name: YEMEN
1456 | id: "224"
1457 | numcode: "887"
1458 | countries_036:
1459 | name: Cape Verde
1460 | iso3: CPV
1461 | iso: CV
1462 | iso_name: CAPE VERDE
1463 | id: "36"
1464 | numcode: "132"
1465 | countries_062:
1466 | name: Estonia
1467 | iso3: EST
1468 | iso: EE
1469 | iso_name: ESTONIA
1470 | id: "62"
1471 | numcode: "233"
1472 | countries_117:
1473 | name: Luxembourg
1474 | iso3: LUX
1475 | iso: LU
1476 | iso_name: LUXEMBOURG
1477 | id: "117"
1478 | numcode: "442"
1479 | countries_143:
1480 | name: Netherlands Antilles
1481 | iso3: ANT
1482 | iso: AN
1483 | iso_name: NETHERLANDS ANTILLES
1484 | id: "143"
1485 | numcode: "530"
1486 | countries_170:
1487 | name: Saint Helena
1488 | iso3: SHN
1489 | iso: SH
1490 | iso_name: SAINT HELENA
1491 | id: "170"
1492 | numcode: "654"
1493 | countries_225:
1494 | name: Zambia
1495 | iso3: ZMB
1496 | iso: ZM
1497 | iso_name: ZAMBIA
1498 | id: "225"
1499 | numcode: "894"
1500 | countries_037:
1501 | name: Cayman Islands
1502 | iso3: CYM
1503 | iso: KY
1504 | iso_name: CAYMAN ISLANDS
1505 | id: "37"
1506 | numcode: "136"
1507 | countries_063:
1508 | name: Ethiopia
1509 | iso3: ETH
1510 | iso: ET
1511 | iso_name: ETHIOPIA
1512 | id: "63"
1513 | numcode: "231"
1514 | countries_090:
1515 | name: Hungary
1516 | iso3: HUN
1517 | iso: HU
1518 | iso_name: HUNGARY
1519 | id: "90"
1520 | numcode: "348"
1521 | countries_118:
1522 | name: Macao
1523 | iso3: MAC
1524 | iso: MO
1525 | iso_name: MACAO
1526 | id: "118"
1527 | numcode: "446"
1528 | countries_144:
1529 | name: New Caledonia
1530 | iso3: NCL
1531 | iso: NC
1532 | iso_name: NEW CALEDONIA
1533 | id: "144"
1534 | numcode: "540"
1535 | countries_226:
1536 | name: Zimbabwe
1537 | iso3: ZWE
1538 | iso: ZW
1539 | iso_name: ZIMBABWE
1540 | id: "226"
1541 | numcode: "716"
1542 | countries_038:
1543 | name: Central African Republic
1544 | iso3: CAF
1545 | iso: CF
1546 | iso_name: CENTRAL AFRICAN REPUBLIC
1547 | id: "38"
1548 | numcode: "140"
1549 | countries_064:
1550 | name: Falkland Islands (Malvinas)
1551 | iso3: FLK
1552 | iso: FK
1553 | iso_name: FALKLAND ISLANDS (MALVINAS)
1554 | id: "64"
1555 | numcode: "238"
1556 | countries_091:
1557 | name: Iceland
1558 | iso3: ISL
1559 | iso: IS
1560 | iso_name: ICELAND
1561 | id: "91"
1562 | numcode: "352"
1563 | countries_119:
1564 | name: Macedonia
1565 | iso3: MKD
1566 | iso: MK
1567 | iso_name: MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF
1568 | id: "119"
1569 | numcode: "807"
1570 | countries_145:
1571 | name: New Zealand
1572 | iso3: NZL
1573 | iso: NZ
1574 | iso_name: NEW ZEALAND
1575 | id: "145"
1576 | numcode: "554"
1577 | countries_171:
1578 | name: Saint Kitts and Nevis
1579 | iso3: KNA
1580 | iso: KN
1581 | iso_name: SAINT KITTS AND NEVIS
1582 | id: "171"
1583 | numcode: "659"
1584 |
--------------------------------------------------------------------------------