Merge branch 'master' of github.com:foodcoops/foodsoft

This commit is contained in:
Benjamin Meichsner 2013-09-18 15:19:04 +02:00
commit c597d70596
42 changed files with 2825 additions and 73 deletions

14
.travis.yml Normal file
View file

@ -0,0 +1,14 @@
language: ruby
rvm:
- 1.9.3
services:
- redis-server
before_install:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
before_script:
- "bundle exec rake foodsoft:setup:stock_config"
- "mysql -e 'create database foodsoft_test;'"
- 'printf "test:\n adapter: mysql2\n database: foodsoft_test\n username: travis\n encoding: utf8\n" >config/database.yml'
- 'bundle exec rake db:schema:load RAILS_ENV=test'
script: bundle exec rake spec

24
Gemfile
View file

@ -54,10 +54,6 @@ group :development do
gem 'binding_of_caller' gem 'binding_of_caller'
# gem "rails-i18n-debug" # gem "rails-i18n-debug"
# Re-enable rails benchmarker/profiler
gem 'ruby-prof'
gem 'test-unit'
# Get infos when not using proper eager loading # Get infos when not using proper eager loading
gem 'bullet' gem 'bullet'
@ -71,3 +67,23 @@ group :development do
# Avoid having content-length warnings # Avoid having content-length warnings
gem 'thin' gem 'thin'
end end
group :development, :test do
gem 'ruby-prof'
end
group :test do
gem 'rspec-rails'
gem 'factory_girl_rails', '~> 4.0'
gem 'faker'
# version requirements to avoid problem http://stackoverflow.com/questions/18114544
gem 'capybara', '~> 2.1.0'
# webkit and poltergeist don't seem to work yet
gem 'selenium-webdriver', '~> 2.35.1'
gem 'database_cleaner'
gem 'simplecov', require: false
# need to include rspec components before i18n-spec or rake fails in test environment
gem 'rspec-core'
gem 'rspec-expectations'
gem 'i18n-spec'
end

View file

@ -62,6 +62,14 @@ GEM
net-ssh-gateway (>= 1.1.0) net-ssh-gateway (>= 1.1.0)
capistrano-ext (1.2.1) capistrano-ext (1.2.1)
capistrano (>= 1.0.0) capistrano (>= 1.0.0)
capybara (2.1.0)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
childprocess (0.3.9)
ffi (~> 1.0, >= 1.0.11)
chronic (0.9.0) chronic (0.9.0)
client_side_validations (3.1.4) client_side_validations (3.1.4)
coderay (1.0.8) coderay (1.0.8)
@ -74,6 +82,8 @@ GEM
coffee-script-source (1.3.3) coffee-script-source (1.3.3)
commonjs (0.2.6) commonjs (0.2.6)
daemons (1.1.9) daemons (1.1.9)
database_cleaner (0.7.1)
diff-lcs (1.2.4)
erubis (2.7.0) erubis (2.7.0)
eventmachine (1.0.3) eventmachine (1.0.3)
exception_notification (2.6.1) exception_notification (2.6.1)
@ -81,6 +91,14 @@ GEM
execjs (1.4.0) execjs (1.4.0)
multi_json (~> 1.0) multi_json (~> 1.0)
expression_parser (0.9.0) expression_parser (0.9.0)
factory_girl (4.2.0)
activesupport (>= 3.0.0)
factory_girl_rails (4.2.1)
factory_girl (~> 4.2.0)
railties (>= 3.0.0)
faker (1.1.2)
i18n (~> 0.5)
ffi (1.9.0)
haml (3.1.7) haml (3.1.7)
haml-rails (0.3.5) haml-rails (0.3.5)
actionpack (>= 3.1, < 4.1) actionpack (>= 3.1, < 4.1)
@ -92,9 +110,13 @@ GEM
highline (1.6.19) highline (1.6.19)
hike (1.2.3) hike (1.2.3)
i18n (0.6.1) i18n (0.6.1)
i18n-spec (0.4.0)
iso
inherited_resources (1.3.1) inherited_resources (1.3.1)
has_scope (~> 0.5.0) has_scope (~> 0.5.0)
responders (~> 0.6) responders (~> 0.6)
iso (0.2.0)
i18n
journey (1.0.4) journey (1.0.4)
jquery-rails (2.1.3) jquery-rails (2.1.3)
railties (>= 3.1.0, < 5.0) railties (>= 3.1.0, < 5.0)
@ -128,8 +150,9 @@ GEM
activesupport (~> 3.1) activesupport (~> 3.1)
polyamorous (~> 0.5.0) polyamorous (~> 0.5.0)
mime-types (1.21) mime-types (1.21)
mini_portile (0.5.1)
mono_logger (1.1.0) mono_logger (1.1.0)
multi_json (1.7.6) multi_json (1.7.9)
mysql2 (0.3.11) mysql2 (0.3.11)
net-scp (1.1.1) net-scp (1.1.1)
net-ssh (>= 2.6.5) net-ssh (>= 2.6.5)
@ -138,6 +161,8 @@ GEM
net-ssh (2.6.7) net-ssh (2.6.7)
net-ssh-gateway (1.2.0) net-ssh-gateway (1.2.0)
net-ssh (>= 2.6.5) net-ssh (>= 2.6.5)
nokogiri (1.6.0)
mini_portile (~> 0.5.0)
pdf-reader (1.2.0) pdf-reader (1.2.0)
Ascii85 (~> 1.0.0) Ascii85 (~> 1.0.0)
hashery (~> 2.0) hashery (~> 2.0)
@ -180,7 +205,7 @@ GEM
rdoc (3.12.2) rdoc (3.12.2)
json (~> 1.4) json (~> 1.4)
redis (3.0.4) redis (3.0.4)
redis-namespace (1.3.0) redis-namespace (1.3.1)
redis (~> 3.0.0) redis (~> 3.0.0)
responders (0.9.3) responders (0.9.3)
railties (~> 3.1) railties (~> 3.1)
@ -190,8 +215,20 @@ GEM
redis-namespace (~> 1.2) redis-namespace (~> 1.2)
sinatra (>= 0.9.2) sinatra (>= 0.9.2)
vegas (~> 0.1.2) vegas (~> 0.1.2)
ruby-prof (0.11.2) rspec-core (2.14.2)
rspec-expectations (2.14.0)
diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.14.1)
rspec-rails (2.14.0)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
ruby-prof (0.13.0)
ruby-rc4 (0.1.5) ruby-rc4 (0.1.5)
rubyzip (0.9.9)
sass (3.2.1) sass (3.2.1)
sass-rails (3.2.5) sass-rails (3.2.5)
railties (~> 3.2.0) railties (~> 3.2.0)
@ -200,6 +237,11 @@ GEM
select2-rails (3.4.2) select2-rails (3.4.2)
sass-rails sass-rails
thor (~> 0.14) thor (~> 0.14)
selenium-webdriver (2.35.1)
childprocess (>= 0.2.5)
multi_json (~> 1.0)
rubyzip (< 1.0.0)
websocket (~> 1.0.4)
simple-navigation (3.9.0) simple-navigation (3.9.0)
activesupport (>= 2.3.2) activesupport (>= 2.3.2)
simple-navigation-bootstrap (0.0.4) simple-navigation-bootstrap (0.0.4)
@ -207,6 +249,10 @@ GEM
simple_form (2.1.0) simple_form (2.1.0)
actionpack (~> 3.0) actionpack (~> 3.0)
activemodel (~> 3.0) activemodel (~> 3.0)
simplecov (0.7.1)
multi_json (~> 1.0)
simplecov-html (~> 0.7.1)
simplecov-html (0.7.1)
sinatra (1.3.6) sinatra (1.3.6)
rack (~> 1.4) rack (~> 1.4)
rack-protection (~> 1.3) rack-protection (~> 1.3)
@ -220,7 +266,6 @@ GEM
rack (~> 1.0) rack (~> 1.0)
tilt (~> 1.1, != 1.3.0) tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.6) sqlite3 (1.3.6)
test-unit (2.5.3)
therubyracer (0.10.2) therubyracer (0.10.2)
libv8 (~> 3.3.10) libv8 (~> 3.3.10)
thin (1.5.1) thin (1.5.1)
@ -245,12 +290,15 @@ GEM
uniform_notifier (1.1.1) uniform_notifier (1.1.1)
vegas (0.1.11) vegas (0.1.11)
rack (>= 1.0.0) rack (>= 1.0.0)
websocket (1.0.7)
whenever (0.8.1) whenever (0.8.1)
activesupport (>= 2.3.4) activesupport (>= 2.3.4)
chronic (>= 0.6.3) chronic (>= 0.6.3)
wikicloth (0.8.0) wikicloth (0.8.0)
builder builder
expression_parser expression_parser
xpath (2.0.0)
nokogiri (~> 1.3)
PLATFORMS PLATFORMS
ruby ruby
@ -264,11 +312,16 @@ DEPENDENCIES
bullet bullet
capistrano (= 2.13.5) capistrano (= 2.13.5)
capistrano-ext capistrano-ext
capybara (~> 2.1.0)
client_side_validations client_side_validations
coffee-rails (~> 3.2.1) coffee-rails (~> 3.2.1)
daemons daemons
database_cleaner
exception_notification exception_notification
factory_girl_rails (~> 4.0)
faker
haml-rails haml-rails
i18n-spec
inherited_resources inherited_resources
jquery-rails jquery-rails
kaminari kaminari
@ -281,14 +334,18 @@ DEPENDENCIES
rails (~> 3.2.9) rails (~> 3.2.9)
rails-settings-cached (= 0.2.4) rails-settings-cached (= 0.2.4)
resque resque
rspec-core
rspec-expectations
rspec-rails
ruby-prof ruby-prof
sass-rails (~> 3.2.3) sass-rails (~> 3.2.3)
select2-rails select2-rails
selenium-webdriver (~> 2.35.1)
simple-navigation simple-navigation
simple-navigation-bootstrap simple-navigation-bootstrap
simple_form simple_form
simplecov
sqlite3 sqlite3
test-unit
therubyracer therubyracer
thin thin
twitter-bootstrap-rails twitter-bootstrap-rails

View file

@ -1,5 +1,6 @@
FoodSoft FoodSoft
========= =========
[![Build Status](https://travis-ci.org/foodcoops/foodsoft.png?branch=tests-rspec)](https://travis-ci.org/foodcoops/foodsoft)
[![Code Climate](https://codeclimate.com/github/foodcoops/foodsoft.png)](https://codeclimate.com/github/foodcoops/foodsoft) [![Code Climate](https://codeclimate.com/github/foodcoops/foodsoft.png)](https://codeclimate.com/github/foodcoops/foodsoft)
[![Dependency Status](https://gemnasium.com/foodcoops/foodsoft.png)](https://gemnasium.com/foodcoops/foodsoft) [![Dependency Status](https://gemnasium.com/foodcoops/foodsoft.png)](https://gemnasium.com/foodcoops/foodsoft)

View file

@ -20,20 +20,28 @@ class OrderFax < OrderPdf
move_down 5 move_down 5
text "#{contact[:zip_code]} #{contact[:city]}", size: 9, align: :right text "#{contact[:zip_code]} #{contact[:city]}", size: 9, align: :right
move_down 5 move_down 5
text "#{I18n.t('simple_form.labels.supplier.customer_number')}: #{@order.supplier.try(:customer_number)}", size: 9, align: :right unless @order.supplier.try(:customer_number).blank?
text "#{I18n.t('simple_form.labels.supplier.customer_number')}: #{@order.supplier[:customer_number]}", size: 9, align: :right
move_down 5 move_down 5
end
unless contact[:phone].blank?
text "#{I18n.t('simple_form.labels.supplier.phone')}: #{contact[:phone]}", size: 9, align: :right text "#{I18n.t('simple_form.labels.supplier.phone')}: #{contact[:phone]}", size: 9, align: :right
move_down 5 move_down 5
end
unless contact[:email].blank?
text "#{I18n.t('simple_form.labels.supplier.email')}: #{contact[:email]}", size: 9, align: :right text "#{I18n.t('simple_form.labels.supplier.email')}: #{contact[:email]}", size: 9, align: :right
end end
end
# Recipient # Recipient
bounding_box [margin_box.left,margin_box.top-60], width: 200 do bounding_box [margin_box.left,margin_box.top-60], width: 200 do
text @order.name text @order.name
move_down 5 move_down 5
text @order.supplier.try(:address).to_s text @order.supplier.try(:address).to_s
unless @order.supplier.try(:fax).blank?
move_down 5 move_down 5
text "#{I18n.t('simple_form.labels.supplier.fax')}: #{@order.supplier.try(:fax)}" text "#{I18n.t('simple_form.labels.supplier.fax')}: #{@order.supplier[:fax]}"
end
end end
move_down 5 move_down 5
@ -42,25 +50,37 @@ class OrderFax < OrderPdf
move_down 10 move_down 10
text "#{I18n.t('simple_form.labels.delivery.delivered_on')}:" text "#{I18n.t('simple_form.labels.delivery.delivered_on')}:"
move_down 10 move_down 10
text "#{I18n.t('simple_form.labels.supplier.contact_person')}: #{@order.supplier.try(:contact_person)}" unless @order.supplier.try(:contact_person).blank?
text "#{I18n.t('simple_form.labels.supplier.contact_person')}: #{@order.supplier[:contact_person]}"
move_down 10 move_down 10
end
# Articles # Articles
total = 0
data = [I18n.t('documents.order_fax.rows')] data = [I18n.t('documents.order_fax.rows')]
data += @order.order_articles.ordered.all(include: :article).collect do |a| data += @order.order_articles.ordered.all(include: :article).collect do |a|
subtotal = a.units_to_order * a.price.unit_quantity * a.price.price
total += subtotal
[a.article.order_number, [a.article.order_number,
a.units_to_order, a.units_to_order,
a.article.name, a.article.name,
a.price.unit_quantity, a.price.unit_quantity,
a.article.unit, a.article.unit,
a.price.price] number_to_currency(a.price.price),
number_to_currency(subtotal)]
end end
data << [I18n.t('documents.order_fax.total'), nil, nil, nil, nil, nil, number_to_currency(total)]
table data, cell_style: {size: 8, overflow: :shrink_to_fit} do |table| table data, cell_style: {size: 8, overflow: :shrink_to_fit} do |table|
table.header = true
table.cells.border_width = 1 table.cells.border_width = 1
table.cells.border_color = '666666' table.cells.border_color = '666666'
table.row(0).border_bottom_width = 2
table.columns(1).align = :right table.columns(1).align = :right
table.columns(3..5).align = :right table.columns(3..6).align = :right
table.row(data.length-1).columns(0..5).borders = [:top, :bottom]
table.row(data.length-1).columns(0).borders = [:top, :bottom, :left]
table.row(data.length-1).border_top_width = 2
end end
#font_size: 8, #font_size: 8,
#vertical_padding: 3, #vertical_padding: 3,

View file

@ -13,11 +13,9 @@ class Supplier < ActiveRecord::Base
:delivery_days, :order_howto, :note, :shared_supplier_id, :min_order_quantity :delivery_days, :order_howto, :note, :shared_supplier_id, :min_order_quantity
validates :name, :presence => true, :length => { :in => 4..30 } validates :name, :presence => true, :length => { :in => 4..30 }
validates :phone, :presence => true, :length => { :in => 8..20 } validates :phone, :presence => true, :length => { :in => 8..25 }
validates :address, :presence => true, :length => { :in => 8..50 } validates :address, :presence => true, :length => { :in => 8..50 }
validates_length_of :order_howto, :note, maximum: 250 validates_length_of :order_howto, :note, maximum: 250
validates_length_of :phone, :in => 8..20
validates_length_of :address, :in => 8..50
validate :uniqueness_of_name validate :uniqueness_of_name
scope :undeleted, -> { where(deleted_at: nil) } scope :undeleted, -> { where(deleted_at: nil) }

View file

@ -3,7 +3,7 @@ class Workgroup < Group
has_many :tasks has_many :tasks
# returns all non-finished tasks # returns all non-finished tasks
has_many :open_tasks, :class_name => 'Task', :conditions => ['done = ?', false], :order => 'due_date ASC' has_many :open_tasks, :class_name => 'Task', :conditions => ['done = ?', false], order: 'due_date ASC, name ASC'
validates_uniqueness_of :name validates_uniqueness_of :name
validate :last_admin_on_earth, :on => :update validate :last_admin_on_earth, :on => :update

View file

@ -12,7 +12,7 @@
.well.well-small .well.well-small
%h3= t('.notes_and_journal') %h3= t('.notes_and_journal')
#note #note
- unless @order.note.empty? - unless @order.note.blank?
= simple_format @order.note = simple_format @order.note
- else - else
%p= t('.comment_on_transaction') %p= t('.comment_on_transaction')

View file

@ -5,7 +5,7 @@
%thead %thead
%tr %tr
%th= sort_link_helper t('.name'), "name", :per_page => @per_page %th= sort_link_helper t('.name'), "name", :per_page => @per_page
%th Kontakt %th= t '.contact'
%th.numeric= sort_link_helper t('.account_balance'), "account_balance", :per_page => @per_page %th.numeric= sort_link_helper t('.account_balance'), "account_balance", :per_page => @per_page
%th %th
%tbody %tbody

View file

@ -56,7 +56,7 @@
%pre %pre
* #{t '.help.list_item_1'} * #{t '.help.list_item_1'}
%pre %pre
** #{t '.help_list_item_2'} ** #{t '.help.list_item_2'}
%tr %tr
%td= t '.help.ordered_list' %td= t '.help.ordered_list'
%td %td

View file

@ -4,4 +4,4 @@
= f.input :date = f.input :date
= f.input :note = f.input :note
= f.submit = f.submit
= link_to t('ui.cancel'), stock_takings_path = link_to t('ui.or_cancel'), stock_takings_path

View file

@ -14,4 +14,4 @@
= render :partial => 'stock_change', :collection => @stock_taking.stock_changes = render :partial => 'stock_change', :collection => @stock_taking.stock_changes
.form-actions .form-actions
= f.submit class: 'btn' = f.submit class: 'btn'
= link_to t('ui.cancel'), stock_takings_path = link_to t('ui.or_cancel'), stock_takings_path

View file

@ -1,4 +1,4 @@
- title "Lager (#{StockArticle.available.count})" - title t('.title', article_count: StockArticle.available.count)
- content_for :javascript do - content_for :javascript do
:javascript :javascript
$(function() { $(function() {

View file

@ -4,7 +4,7 @@
- content_for :sidebar do - content_for :sidebar do
.well.well-small .well.well-small
%ul.nav.nav-list %ul.nav.nav-list
%li.nav-header Seiten %li.nav-header= t '.pages'
%li= link_to t('.my_tasks'), user_tasks_path %li= link_to t('.my_tasks'), user_tasks_path
%li= link_to t('.all_tasks'), tasks_path %li= link_to t('.all_tasks'), tasks_path
%li= link_to t('.archive'), archive_tasks_path %li= link_to t('.archive'), archive_tasks_path

View file

@ -1,4 +1,4 @@
- title "Meine Aufgaben" - title t('.title')
= render 'nav' = render 'nav'
- unless @unaccepted_tasks.empty? - unless @unaccepted_tasks.empty?

View file

@ -505,6 +505,7 @@ de:
- Gebinde - Gebinde
- Einheit - Einheit
- Preis/Einheit - Preis/Einheit
total: Gesamtpreis
order_matrix: order_matrix:
filename: Bestellung %{name}-%{date} - Sortiermatrix filename: Bestellung %{name}-%{date} - Sortiermatrix
heading: Artikelübersicht heading: Artikelübersicht
@ -719,6 +720,7 @@ de:
ordergroups: ordergroups:
account_balance: Kontostand account_balance: Kontostand
account_statement: Kontoauszug account_statement: Kontoauszug
contact: Kontakt
name: Name name: Name
new_transaction: Neue Transaktion new_transaction: Neue Transaktion
update: update:
@ -1602,6 +1604,7 @@ de:
contact_person: Kontaktperson contact_person: Kontaktperson
contact_phone: Telefon contact_phone: Telefon
ignore_apple_restriction: Bestellstop bei zu wenig Äpfeln ignorieren ignore_apple_restriction: Bestellstop bei zu wenig Äpfeln ignorieren
name: Name
page: page:
body: Inhalt body: Inhalt
parent_id: Oberseite parent_id: Oberseite
@ -1669,6 +1672,7 @@ de:
language: language:
de: Deutsch de: Deutsch
en: English en: English
fr: Französisch
nl: Niederländisch nl: Niederländisch
required: required:
mark: ! '*' mark: ! '*'
@ -1742,6 +1746,7 @@ de:
show_stock_takings: Inventurübersicht show_stock_takings: Inventurübersicht
stock_count: ! 'Artikelanzahl:' stock_count: ! 'Artikelanzahl:'
stock_worth: ! 'Aktueller Lagerwert:' stock_worth: ! 'Aktueller Lagerwert:'
title: Lager (%{article_count})
toggle_unavailable: Nicht verfügbare Artikel zeigen/verstecken toggle_unavailable: Nicht verfügbare Artikel zeigen/verstecken
view_options: Ansichtsoptionen view_options: Ansichtsoptionen
new: new:
@ -1833,6 +1838,7 @@ de:
group_tasks: Gruppenaufgaben group_tasks: Gruppenaufgaben
my_tasks: Meine Aufgaben my_tasks: Meine Aufgaben
new_task: Neue Aufgabe erstellen new_task: Neue Aufgabe erstellen
pages: Seiten
new: new:
title: Neue Aufgabe erstellen title: Neue Aufgabe erstellen
repeated: Aufgabe wird wöchentlich wiederholt repeated: Aufgabe wird wöchentlich wiederholt

View file

@ -493,7 +493,7 @@ en:
- Article - Article
- Amount - Amount
- Price - Price
- Unit Quantity - Unit quantity
- Unit - Unit
- Sum - Sum
sum: Sum sum: Sum
@ -504,20 +504,24 @@ en:
- Order Number - Order Number
- Amount - Amount
- Name - Name
- Barrel - Unit quantity
- Unit - Unit
- Price/Unit - Price/Unit
- Subtotal
total: Total
order_matrix: order_matrix:
filename: Order %{name}-%{date} - sorting matrix filename: Order %{name}-%{date} - sorting matrix
heading: Article overview heading: Article overview
rows: rows:
- Article - Article
- Unit - Unit
- Barrel - Unit quantity
- FC-Price - FC-Price
- Amount - Amount
title: ! 'Order sorting matrix: %{name}, closed at %{date}' title: ! 'Order sorting matrix: %{name}, closed at %{date}'
total: ! '%{count} articles in total' total:
one: One article in total
other: ! '%{count} articles in total'
errors: errors:
format: ! '%{attribute} %{message}' format: ! '%{attribute} %{message}'
general: A problem has occured. general: A problem has occured.
@ -721,6 +725,7 @@ en:
ordergroups: ordergroups:
account_balance: Account balance account_balance: Account balance
account_statement: Account statement account_statement: Account statement
contact: Contact
name: Name name: Name
new_transaction: New transaction new_transaction: New transaction
update: update:
@ -1604,6 +1609,7 @@ en:
contact_person: Contact person contact_person: Contact person
contact_phone: Phone contact_phone: Phone
ignore_apple_restriction: Ignore order stop by apple points restriction ignore_apple_restriction: Ignore order stop by apple points restriction
name: Name
page: page:
body: Body body: Body
parent_id: Parent page parent_id: Parent page
@ -1671,6 +1677,7 @@ en:
language: language:
de: German de: German
en: English en: English
fr: French
nl: Dutch nl: Dutch
required: required:
mark: ! '*' mark: ! '*'
@ -1744,6 +1751,7 @@ en:
show_stock_takings: Inventory overview show_stock_takings: Inventory overview
stock_count: ! 'Number of articles:' stock_count: ! 'Number of articles:'
stock_worth: ! 'Current stock value:' stock_worth: ! 'Current stock value:'
title: Stock (%{article_count})
toggle_unavailable: Show/hide unavailable articles toggle_unavailable: Show/hide unavailable articles
view_options: View options view_options: View options
new: new:
@ -1835,6 +1843,7 @@ en:
group_tasks: Group tasks group_tasks: Group tasks
my_tasks: My tasks my_tasks: My tasks
new_task: Create new task new_task: Create new task
pages: Pages
new: new:
title: Create new tasks title: Create new tasks
repeated: Task is repeated weekly repeated: Task is repeated weekly

1919
config/locales/fr.yml Normal file

File diff suppressed because it is too large Load diff

View file

@ -479,48 +479,60 @@ nl:
notice: notice:
documents: documents:
order_by_articles: order_by_articles:
filename: filename: Bestelling %{name}-%{date} - Artikellijst
rows: rows:
title: - Huishouden
- Hoeveelheid
- Prijs
title: ! 'Artikellijst van bestelling: %{name}, gesloten op %{date}'
order_by_groups: order_by_groups:
filename: filename: Bestelling %{name}-%{date} - Huishoudenslijst
rows: rows:
sum: - Artikel
title: - Hoeveelheid
- Prijs
- Gr.Eenh.
- Eenheid
- Som
sum: Som
title: ! 'Huishoudenslijst van bestelling: %{name}, gesloten op %{date}'
order_fax: order_fax:
filename: filename: Bestelling %{name}-%{date} - Fax
rows: rows: ! '[]'
total: Totaal
order_matrix: order_matrix:
filename: filename: Bestelling %{name}-%{date} - Sorteermatrix
heading: heading: Artikeloverzicht
rows: rows:
title: title: ! 'Sorteermatrix van bestelling: %{name}, gesloten op %{date}'
total: total:
one: In totaal éen artikel
other: In totaal %{count} artikelen
errors: errors:
format: format:
general: general: Er is een probleem opgetreden.
general_again: general_again:
general_msg: general_msg: ! 'Er is een probleem opgetreden: %{msg}'
messages: messages:
accepted: accepted: moet geaccepteerd worden
blank: blank: moet ingevuld worden
confirmation: confirmation:
empty: empty: moet ingevuld worden
equal_to: equal_to: moet precies %{count} zijn
even: even:
exclusion: exclusion: moet even zijn
greater_than: greater_than: moet groter dan %{count} zijn
greater_than_or_equal_to: greater_than_or_equal_to:
inclusion: inclusion:
invalid: invalid:
less_than: less_than: moet kleiner dan %{count} zijn
less_than_or_equal_to: less_than_or_equal_to: moet groter of gelijk aan %{count} zijn
not_a_number: not_a_number: is geen getal
not_an_integer: not_an_integer: moet een geheel getal zijn
odd: odd: moet oneven zijn
record_invalid: record_invalid:
taken: taken: is al in gebruik
taken_with_deleted: taken_with_deleted: is al in gebruik (verwijderde groep)
too_long: too_long:
too_short: too_short:
wrong_length: wrong_length:
@ -697,6 +709,7 @@ nl:
ordergroups: ordergroups:
account_balance: Tegoed account_balance: Tegoed
account_statement: account_statement:
contact:
name: Naam name: Naam
new_transaction: Nieuwe transactie new_transaction: Nieuwe transactie
update: update:
@ -1493,6 +1506,7 @@ nl:
contact_person: Contactpersoon contact_person: Contactpersoon
contact_phone: Telefoon contact_phone: Telefoon
ignore_apple_restriction: ignore_apple_restriction:
name:
page: page:
body: body:
parent_id: parent_id:
@ -1560,6 +1574,7 @@ nl:
language: language:
de: Duits de: Duits
en: Engels en: Engels
fr: Frans
nl: Nederlands nl: Nederlands
required: required:
mark: ! '*' mark: ! '*'
@ -1633,6 +1648,7 @@ nl:
show_stock_takings: show_stock_takings:
stock_count: stock_count:
stock_worth: stock_worth:
title:
toggle_unavailable: toggle_unavailable:
view_options: view_options:
new: new:
@ -1724,6 +1740,7 @@ nl:
group_tasks: group_tasks:
my_tasks: my_tasks:
new_task: new_task:
pages:
new: new:
title: title:
repeated: repeated:
@ -1764,9 +1781,9 @@ nl:
history: history:
marks: marks:
close: ! '&times;' close: ! '&times;'
success: success: <i class="icon icon-ok"></i>
or_cancel: of annuleren or_cancel: of annuleren
please_wait: please_wait: Een moment alstublieft...
save: Opslaan save: Opslaan
show: Tonen show: Tonen
views: views:

View file

@ -38,6 +38,15 @@ namespace :foodsoft do
puts yellow "All done! Your foodcoft should be running smoothly." puts yellow "All done! Your foodcoft should be running smoothly."
start_server start_server
end end
namespace :setup do
desc "Initialize stock configuration"
task :stock_config do
setup_app_config
setup_development
setup_secret_token
end
end
end end
def setup_bundler def setup_bundler

3
lib/tasks/rspec.rake Normal file
View file

@ -0,0 +1,3 @@
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec)
task :default => :spec

View file

@ -55,12 +55,16 @@ fi
sed -i "s|^\\(\\s*gem\\s\\+'sqlite3'\\)|#\1|" Gemfile sed -i "s|^\\(\\s*gem\\s\\+'sqlite3'\\)|#\1|" Gemfile
sed -i "s|^\\(\\s*sqlite3\\b\)|#\1|" Gemfile.lock sed -i "s|^\\(\\s*sqlite3\\b\)|#\1|" Gemfile.lock
# make sure postgresql db is present, as it is the default heroku db # make sure postgresql db is present, as it is the default heroku db
echo $'\ngem "pg"' >>Gemfile echo "
echo $'\ngem "localeapp"' >>Gemfile gem 'pg'" >>Gemfile
# always use unicorn # always use unicorn
echo $'\ngem "unicorn"' >>Gemfile echo "
gem 'unicorn'" >>Gemfile
echo 'web: bundle exec unicorn -p $PORT -E $RACK_ENV' >Procfile echo 'web: bundle exec unicorn -p $PORT -E $RACK_ENV' >Procfile
bundle install --quiet # to update Gemfile.lock # don't complain when mail cannot be sent,
# XXX when you're hosting a production instance, use a real smtp server instead
sed -i 's|\(#\s*\)\?\(config\.action_mailer\.raise_delivery_errors\)\s*=.*|\2 = false|' config/environments/${RAILS_ENV}.rb
sed -i 's|\(#\s*\)\?\(config\.action_mailer\.delivery_method\)\s*=.*|\2 = :smtp|' config/environments/${RAILS_ENV}.rb
# do not ignore deployment files # do not ignore deployment files
sed -i 's|^\(config/\*.yml\)|#\1|' .gitignore sed -i 's|^\(config/\*.yml\)|#\1|' .gitignore
sed -i 's|^\(config/initializers/secret_token.rb\)|#\1|' .gitignore sed -i 's|^\(config/initializers/secret_token.rb\)|#\1|' .gitignore
@ -92,9 +96,13 @@ Localeapp.configure do |config|
config.polling_environments = ['$RAILS_ENV'] config.polling_environments = ['$RAILS_ENV']
end end
EOF EOF
echo "
gem 'localeapp'" >>Gemfile
# also do not cache so we get locale updates # also do not cache so we get locale updates
sed -i 's|config\.cache_classes\s*=.*|config.cache_classes = false|' config/environments/${RAILS_ENV}.rb sed -i 's|\(#\s*\)\?\(config\.cache_classes\)\s*=.*|\2 = false|' config/environments/${RAILS_ENV}.rb
fi fi
# update Gemfile.lock after Gemfile updates (required by heroku)
bundle install --quiet
# TODO add more extensive database seed # TODO add more extensive database seed
# and push = deploy # and push = deploy

20
spec/factories/article.rb Normal file
View file

@ -0,0 +1,20 @@
require 'factory_girl'
FactoryGirl.define do
factory :article do
sequence(:name) { |n| Faker::Lorem.words(rand(2..4)).join(' ') + " ##{n}" }
unit { Faker::Unit.unit }
price { rand(2600) / 100 }
tax { [6, 21].sample }
deposit { rand(10) < 8 ? 0 : [0.0, 0.80, 1.20, 12.00].sample }
unit_quantity { rand(5) < 3 ? 1 : rand(1..20) }
#supplier_id
article_category { FactoryGirl.create :article_category }
end
factory :article_category do
sequence(:name) { |n| Faker::Lorem.characters(rand(2..12)) + " ##{n}" }
end
end

View file

@ -0,0 +1,10 @@
require 'factory_girl'
FactoryGirl.define do
# requires order
factory :group_order do
ordergroup { FactoryGirl.create(:user, groups: [FactoryGirl.create(:ordergroup)]).ordergroup }
end
end

View file

@ -0,0 +1,9 @@
require 'factory_girl'
FactoryGirl.define do
# requires order_article
factory :group_order_article do
end
end

31
spec/factories/order.rb Normal file
View file

@ -0,0 +1,31 @@
require 'factory_girl'
FactoryGirl.define do
factory :order do
starts { Time.now }
supplier { FactoryGirl.create :supplier, article_count: (article_count.nil? ? true : article_count) }
article_ids { supplier.articles.map(&:id) unless supplier.nil? }
ignore do
article_count true
end
# for an order from stock; need to add articles
factory :stock_order do
supplier_id 0
# article_ids needs to be supplied
end
# In the order's after_save callback order articles are created, so
# until the order is saved, these articles do not yet exist.
after :create do |order|
order.reload
end
end
# requires order and article
factory :order_article do
end
end

View file

@ -0,0 +1,21 @@
require 'factory_girl'
FactoryGirl.define do
factory :supplier do
name { Faker::Company.name.truncate(30) }
phone { Faker::PhoneNumber.phone_number }
address { Faker::Address.street_address }
ignore do
article_count 0
end
after :create do |supplier, evaluator|
article_count = evaluator.article_count
article_count = rand(1..99) if article_count == true
FactoryGirl.create_list :article, article_count, supplier: supplier
end
end
end

36
spec/factories/user.rb Normal file
View file

@ -0,0 +1,36 @@
require 'factory_girl'
FactoryGirl.define do
factory :user do
sequence(:nick) { |n| "user#{n}"}
first_name { Faker::Name.first_name }
email { Faker::Internet.email }
password { new_random_password }
factory :admin do
sequence(:nick) { |n| "admin#{n}" }
first_name 'Administrator'
after :create do |user, evaluator|
FactoryGirl.create :workgroup, role_admin: true, user_ids: [user.id]
end
end
end
factory :group do
sequence(:name) {|n| "Group ##{n}"}
factory :workgroup do
type ''
end
factory :ordergroup do
type 'Ordergroup'
sequence(:name) {|n| "Order group ##{n}"}
# workaround to avoid needing to save the ordergroup
# avoids e.g. error after logging in related to applebar
after :create do |group| Ordergroup.find(group.id).update_stats! end
end
end
end

12
spec/i18n_spec.rb Normal file
View file

@ -0,0 +1,12 @@
require 'spec_helper'
require 'i18n-spec'
Dir.glob('config/locales/*.yml').each do |locale_file|
describe "#{locale_file}" do
it_behaves_like 'a valid locale file', locale_file
# We're currently allowing both German and English as source language
# besides, we're using localeapp, so that it's ok if pull requests
# don't have this - a localapp pull will fix that right away.
#it { expect(locale_file).to be_a_subset_of 'config/locales/en.yml' }
end
end

View file

@ -0,0 +1,55 @@
require 'spec_helper'
describe 'settling an order', :type => :feature do
let(:admin) { FactoryGirl.create :user, groups:[FactoryGirl.create(:workgroup, role_finance: true)] }
let(:supplier) { FactoryGirl.create :supplier }
let(:article) { FactoryGirl.create :article, supplier: supplier, unit_quantity: 1 }
let(:order) { FactoryGirl.create :order, supplier: supplier, article_ids: [article.id] } # need to ref article
let(:go1) { FactoryGirl.create :group_order, order: order }
let(:go2) { FactoryGirl.create :group_order, order: order }
let(:oa) { order.order_articles.find_by_article_id(article.id) }
let(:goa1) { FactoryGirl.create :group_order_article, group_order: go1, order_article: oa }
let(:goa2) { FactoryGirl.create :group_order_article, group_order: go2, order_article: oa }
before do
goa1.update_quantities(3, 0)
goa2.update_quantities(1, 0)
oa.update_results!
order.finish!(admin)
goa1.reload
goa2.reload
end
it 'has correct order result' do
expect(oa.quantity).to eq(4)
expect(oa.tolerance).to eq(0)
expect(goa1.result).to eq(3)
expect(goa2.result).to eq(1)
end
describe :type => :feature, :js => true do
before { login admin }
before { visit new_finance_order_path(order_id: order.id) }
it 'has product ordered visible' do
expect(page).to have_content(article.name)
expect(page).to have_selector("#order_article_#{oa.id}")
end
it 'shows order result' do
click_link article.name
expect(page).to have_selector("#group_order_articles_#{oa.id}")
within("#group_order_articles_#{oa.id}") do
# make sure these ordergroup names are in the list for this product
expect(page).to have_content(go1.ordergroup.name)
expect(page).to have_content(go2.ordergroup.name)
# and that their order results match what we expect
expect(page).to have_selector("#group_order_article_#{goa1.id}_quantity")
expect(find("#group_order_article_#{goa1.id}_quantity").text.to_f).to eq(3)
expect(page).to have_selector("#group_order_article_#{goa2.id}_quantity")
expect(find("#group_order_article_#{goa2.id}_quantity").text.to_f).to eq(1)
end
end
end
end

View file

@ -0,0 +1,57 @@
require 'spec_helper'
describe 'product distribution', :type => :feature do
let(:admin) { FactoryGirl.create :admin }
let(:user_a) { FactoryGirl.create :user, groups: [FactoryGirl.create(:ordergroup)] }
let(:user_b) { FactoryGirl.create :user, groups: [FactoryGirl.create(:ordergroup)] }
let(:supplier) { FactoryGirl.create :supplier }
let(:article) { FactoryGirl.create :article, supplier: supplier, unit_quantity: 5 }
let(:order) { FactoryGirl.create(:order, supplier: supplier, article_ids: [article.id]) }
let(:oa) { order.order_articles.first }
describe :type => :feature do
# make sure users have enough money to order
before do
[user_a, user_b].each do |user|
ordergroup = Ordergroup.find(user.ordergroup.id)
ordergroup.add_financial_transaction! 5000, 'for ordering', admin
end
end
it 'agrees to documented example', :js => true do
# gruppe a bestellt 2(3), weil sie auf jeden fall was von x bekommen will
login user_a
visit new_group_order_path(:order_id => order.id)
2.times { find("[data-increase_quantity='#{oa.id}']").click }
3.times { find("[data-increase_tolerance='#{oa.id}']").click }
find('input[type=submit]').click
expect(page).to have_selector('body')
# gruppe b bestellt 2(0)
login user_b
visit new_group_order_path(:order_id => order.id)
2.times { find("[data-increase_quantity='#{oa.id}']").click }
find('input[type=submit]').click
expect(page).to have_selector('body')
# gruppe a faellt ein dass sie doch noch mehr braucht von x und aendert auf 4(1).
login user_a
visit edit_group_order_path(order.group_order(user_a.ordergroup), :order_id => order.id)
2.times { find("[data-increase_quantity='#{oa.id}']").click }
2.times { find("[data-decrease_tolerance='#{oa.id}']").click }
find('input[type=submit]').click
expect(page).to have_selector('body')
# die zuteilung
order.finish!(admin)
oa.reload
# Endstand: insg. Bestellt wurden 6(1)
expect(oa.quantity).to eq(6)
expect(oa.tolerance).to eq(1)
# Gruppe a bekommt 3 einheiten.
goa_a = oa.group_order_articles.joins(:group_order).where(:group_orders => {:ordergroup_id => user_a.ordergroup.id}).first
expect(goa_a.result).to eq(3)
# gruppe b bekommt 2 einheiten.
goa_b = oa.group_order_articles.joins(:group_order).where(:group_orders => {:ordergroup_id => user_b.ordergroup.id}).first
expect(goa_b.result).to eq(2)
end
end
end

View file

@ -0,0 +1,21 @@
require 'spec_helper'
describe 'the session', :type => :feature do
let(:user) { FactoryGirl.create :user }
describe 'login page', :type => :feature do
it 'is accesible' do
get login_path
expect(response).to be_success
end
it 'logs me in' do
login user
expect(page).to_not have_selector('.alert-error')
end
it 'does not log me in with wrong password' do
login user.nick, 'XX'+user.password
expect(page).to have_selector('.alert-error')
end
end
end

View file

@ -0,0 +1,63 @@
require 'spec_helper'
describe 'supplier', :type => :feature do
let(:supplier) { FactoryGirl.create :supplier }
describe :type => :feature, :js => true do
let(:user) { FactoryGirl.create :user, groups:[FactoryGirl.create(:workgroup, role_suppliers: true)] }
before { login user }
it 'can be created' do
visit suppliers_path
click_on I18n.t('suppliers.index.action_new')
supplier = FactoryGirl.build :supplier
within('#new_supplier') do
fill_in 'supplier_name', :with => supplier.name
fill_in 'supplier_address', :with => supplier.address
fill_in 'supplier_phone', :with => supplier.phone
find('input[type="submit"]').click
end
expect(page).to have_content(supplier.name)
end
it 'is included in supplier list' do
supplier
visit suppliers_path
expect(page).to have_content(supplier.name)
end
end
describe :type => :feature, :js => true do
let(:article_category) { FactoryGirl.create :article_category }
let(:user) { FactoryGirl.create :user, groups:[FactoryGirl.create(:workgroup, role_article_meta: true)] }
before { login user }
it 'can visit supplier articles path' do
visit supplier_articles_path(supplier)
expect(page).to have_content(supplier.name)
expect(page).to have_content(I18n.t('articles.index.edit_all'))
end
it 'can create a new article' do
article_category.save!
visit supplier_articles_path(supplier)
click_on I18n.t('articles.index.new')
expect(page).to have_selector('form#new_article')
article = FactoryGirl.build :article, supplier: supplier, article_category: article_category
within('#new_article') do
fill_in 'article_name', :with => article.name
fill_in 'article_unit', :with => article.unit
select article.article_category.name, :from => 'article_article_category_id'
fill_in 'article_price', :with => article.price
fill_in 'article_unit_quantity', :with => article.unit_quantity
fill_in 'article_tax', :with => article.tax
fill_in 'article_deposit', :with => article.deposit
# "Element cannot be scrolled into view" error, js as workaround
#find('input[type="submit"]').click
page.execute_script('$("form#new_article").submit();')
end
expect(page).to have_content(article.name)
end
end
end

View file

@ -0,0 +1,47 @@
require 'spec_helper'
describe Article do
let(:supplier) { FactoryGirl.create :supplier }
let(:article) { FactoryGirl.create :article, supplier: supplier }
it 'has a unique name' do
article2 = FactoryGirl.build :article, supplier: supplier, name: article.name
expect(article2).to be_invalid
end
it 'computes the gross price correctly' do
article.deposit = 0
article.tax = 12
expect(article.gross_price).to eq((article.price * 1.12).round(2))
article.deposit = 1.20
expect(article.gross_price).to eq(((article.price + 1.20) * 1.12).round(2))
end
it 'gross price >= net price' do
expect(article.gross_price).to be >= article.price
end
it 'fc-price >= gross price' do
if article.gross_price > 0
expect(article.fc_price).to be > article.gross_price
else
expect(article.fc_price).to be >= article.gross_price
end
end
it 'knows when it is deleted' do
expect(supplier.deleted?).to be_false
supplier.mark_as_deleted
expect(supplier.deleted?).to be_true
end
it 'keeps a price history' do
expect(article.article_prices.all.map(&:price)).to eq([article.price])
oldprice = article.price
sleep 1 # so that the new price really has a later creation time
article.price += 1
article.save!
expect(article.article_prices.all.map(&:price)).to eq([article.price, oldprice])
end
end

View file

@ -0,0 +1,48 @@
require 'spec_helper'
describe GroupOrderArticle do
let(:user) { FactoryGirl.create :user, groups: [FactoryGirl.create(:ordergroup)] }
let(:order) { FactoryGirl.create(:order).reload }
let(:go) { FactoryGirl.create :group_order, order: order, ordergroup: user.ordergroup }
let(:goa) { FactoryGirl.create :group_order_article, group_order: go, order_article: order.order_articles.first }
it 'has zero quantity by default' do expect(goa.quantity).to eq(0) end
it 'has zero tolerance by default' do expect(goa.tolerance).to eq(0) end
it 'has zero result by default' do expect(goa.result).to eq(0) end
it 'is not ordered by default' do expect(GroupOrderArticle.ordered.where(:id => goa.id).exists?).to be_false end
it 'has zero total price by default' do expect(goa.total_price).to eq(0) end
describe do
let(:article) { FactoryGirl.create :article, supplier: order.supplier, unit_quantity: 1 }
let(:oa) { order.order_articles.create(:article => article) }
let(:goa) { FactoryGirl.create :group_order_article, group_order: go, order_article: oa }
it 'can be ordered by piece' do
goa.update_quantities(1, 0)
expect(goa.quantity).to eq(1)
expect(goa.tolerance).to eq(0)
end
it 'can be ordered in larger amounts' do
quantity, tolerance = rand(13..99), rand(0..99)
goa.update_quantities(quantity, tolerance)
expect(goa.quantity).to eq(quantity)
expect(goa.tolerance).to eq(tolerance)
end
it 'has a proper total price' do
quantity = rand(1..99)
goa.update_quantities(quantity, 0)
expect(goa.total_price).to eq(quantity * goa.order_article.price.fc_price)
end
it 'can unorder a product' do
goa.update_quantities(rand(1..99), rand(0..99))
goa.update_quantities(0, 0)
expect(goa.quantity).to eq(0)
expect(goa.tolerance).to eq(0)
end
end
end

View file

@ -0,0 +1,25 @@
require 'spec_helper'
describe GroupOrder do
let(:user) { FactoryGirl.create :user, groups: [FactoryGirl.create(:ordergroup)] }
let(:order) { FactoryGirl.create :order }
# the following two tests are currently disabled - https://github.com/foodcoops/foodsoft/issues/158
#it 'needs an order' do
# expect(FactoryGirl.build(:group_order, ordergroup: user.ordergroup)).to be_invalid
#end
#it 'needs an ordergroup' do
# expect(FactoryGirl.build(:group_order, order: order)).to be_invalid
#end
describe do
let(:go) { FactoryGirl.create :group_order, order: order, ordergroup: user.ordergroup }
it 'has zero price initially' do
expect(go.price).to eq(0)
end
end
end

47
spec/models/order_spec.rb Normal file
View file

@ -0,0 +1,47 @@
require 'spec_helper'
describe Order do
it 'needs a supplier' do
expect(FactoryGirl.build(:order, supplier: nil)).to be_invalid
end
it 'needs order articles' do
supplier = FactoryGirl.create :supplier, article_count: 0
expect(FactoryGirl.build(:order, supplier: supplier)).to be_invalid
end
it 'can be created' do
expect(FactoryGirl.build(:order, article_count: 1)).to be_valid
end
describe 'with articles' do
let(:order) { FactoryGirl.create :order }
it 'is open by default' do expect(order).to be_open end
it 'is not finished by default' do expect(order).to_not be_finished end
it 'is not closed by default' do expect(order).to_not be_closed end
it 'has valid order articles' do
order.order_articles.all.each {|oa| expect(oa).to be_valid }
end
it 'can be finished' do
# TODO randomise user
order.finish!(User.first)
expect(order).to_not be_open
expect(order).to be_finished
expect(order).to_not be_closed
end
it 'can be closed' do
# TODO randomise user
order.finish!(User.first)
order.close!(User.first)
expect(order).to_not be_open
expect(order).to be_closed
end
end
end

View file

@ -0,0 +1,16 @@
require 'spec_helper'
describe Supplier do
let(:supplier) { FactoryGirl.create :supplier }
it 'has a unique name' do
supplier2 = FactoryGirl.build :supplier, name: supplier.name
expect(supplier2).to be_invalid
end
it 'has valid articles' do
supplier = FactoryGirl.create :supplier, article_count: true
supplier.articles.all.each {|a| expect(a).to be_valid }
end
end

59
spec/models/user_spec.rb Normal file
View file

@ -0,0 +1,59 @@
require 'spec_helper'
describe User do
it 'is correctly created' do
user = FactoryGirl.create :user,
nick: 'johnnydoe', first_name: 'Johnny', last_name: 'DoeBar',
email: 'johnnydoe@foodcoop.test', phone: '+1234567890'
expect(user.nick).to eq('johnnydoe')
expect(user.first_name).to eq('Johnny')
expect(user.last_name).to eq('DoeBar')
expect(user.name).to eq('Johnny DoeBar')
expect(user.email).to eq('johnnydoe@foodcoop.test')
expect(user.phone).to eq('+1234567890')
end
describe 'does not have the role' do
let(:user) { FactoryGirl.create :user }
it 'admin' do expect(user.role_admin?).to be_false end
it 'finance' do expect(user.role_finance?).to be_false end
it 'article_meta' do expect(user.role_article_meta?).to be_false end
it 'suppliers' do expect(user.role_suppliers?).to be_false end
it 'orders' do expect(user.role_orders?).to be_false end
end
describe do
let(:user) { FactoryGirl.create :user, password: 'blahblah' }
it 'can authenticate with correct password' do
expect(User.authenticate(user.nick, 'blahblah')).to be_true
end
it 'can not authenticate with incorrect password' do
expect(User.authenticate(user.nick, 'foobar')).to be_nil
end
it 'can not set a password without matching confirmation' do
user.password = 'abcdefghij'
user.password_confirmation = 'foobarxyz'
expect(user).to be_invalid
end
it 'can set a password with matching confirmation' do
user.password = 'abcdefghij'
user.password_confirmation = 'abcdefghij'
expect(user).to be_valid
end
it 'has a unique nick' do
expect(FactoryGirl.build(:user, nick: user.nick, email: "x-#{user.email}")).to be_invalid
end
it 'has a unique email' do
expect(FactoryGirl.build(:user, email: "#{user.email}")).to be_invalid
end
end
describe 'admin' do
let(:user) { FactoryGirl.create :admin }
it 'default admin role' do expect(user.role_admin?).to be_true end
end
end

67
spec/spec_helper.rb Normal file
View file

@ -0,0 +1,67 @@
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require 'support/coverage' # needs to be first
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'capybara/rails'
require 'capybara/rspec'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
RSpec.configure do |config|
# ## Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
#config.use_transactional_fixtures = true
# We use capybara with selenium, and need database_cleaner
config.before(:each) do
DatabaseCleaner.strategy = (example.metadata[:js] ? :truncation : :transaction)
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
config.include SessionHelper
end
module Faker
class Unit
class << self
def unit
['kg', '1L', '100ml', 'piece', 'bunch', '500g'].sample
end
end
end
end
# include default foodsoft scope in urls, so that *_path works
ActionDispatch::Integration::Runner.class_eval do
undef default_url_options
def default_url_options(options={})
{foodcoop: FoodsoftConfig.scope}.merge(options)
end
end

14
spec/support/coverage.rb Normal file
View file

@ -0,0 +1,14 @@
# optional test coverage
# needs to be loaded first, e.g. add a require at top of spec_helper
if ENV['COVERAGE']
require 'simplecov'
SimpleCov.start do
add_filter '/spec/'
add_filter '/test/'
add_group 'Models', '/app/models/'
add_group 'Controllers', '/app/controllers/'
add_group 'Helpers', '/app/helpers/'
add_group 'Documents', '/app/documents/'
add_group 'Libraries', '/lib/'
end
end

View file

@ -0,0 +1,17 @@
module SessionHelper
def login(user=nil, password=nil)
visit login_path
user = FactoryGirl.create :user if user.nil?
if user.instance_of? ::User
nick, password = user.nick, user.password
else
nick = user
end
fill_in 'nick', :with => nick
fill_in 'password', :with => password
find('input[type=submit]').click
end
end