Merge branch 'master' of github.com:foodcoops/foodsoft
This commit is contained in:
commit
c597d70596
42 changed files with 2825 additions and 73 deletions
14
.travis.yml
Normal file
14
.travis.yml
Normal 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
|
26
Gemfile
26
Gemfile
|
@ -54,10 +54,6 @@ group :development do
|
|||
gem 'binding_of_caller'
|
||||
# gem "rails-i18n-debug"
|
||||
|
||||
# Re-enable rails benchmarker/profiler
|
||||
gem 'ruby-prof'
|
||||
gem 'test-unit'
|
||||
|
||||
# Get infos when not using proper eager loading
|
||||
gem 'bullet'
|
||||
|
||||
|
@ -70,4 +66,24 @@ group :development do
|
|||
#gem 'common_deploy', require: false, path: '../../common_deploy' # pending foodcoops/foodsoft#34, git: 'git://github.com/fsmanuel/common_deploy.git'
|
||||
# Avoid having content-length warnings
|
||||
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
|
||||
|
|
67
Gemfile.lock
67
Gemfile.lock
|
@ -62,6 +62,14 @@ GEM
|
|||
net-ssh-gateway (>= 1.1.0)
|
||||
capistrano-ext (1.2.1)
|
||||
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)
|
||||
client_side_validations (3.1.4)
|
||||
coderay (1.0.8)
|
||||
|
@ -74,6 +82,8 @@ GEM
|
|||
coffee-script-source (1.3.3)
|
||||
commonjs (0.2.6)
|
||||
daemons (1.1.9)
|
||||
database_cleaner (0.7.1)
|
||||
diff-lcs (1.2.4)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.0.3)
|
||||
exception_notification (2.6.1)
|
||||
|
@ -81,6 +91,14 @@ GEM
|
|||
execjs (1.4.0)
|
||||
multi_json (~> 1.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-rails (0.3.5)
|
||||
actionpack (>= 3.1, < 4.1)
|
||||
|
@ -92,9 +110,13 @@ GEM
|
|||
highline (1.6.19)
|
||||
hike (1.2.3)
|
||||
i18n (0.6.1)
|
||||
i18n-spec (0.4.0)
|
||||
iso
|
||||
inherited_resources (1.3.1)
|
||||
has_scope (~> 0.5.0)
|
||||
responders (~> 0.6)
|
||||
iso (0.2.0)
|
||||
i18n
|
||||
journey (1.0.4)
|
||||
jquery-rails (2.1.3)
|
||||
railties (>= 3.1.0, < 5.0)
|
||||
|
@ -128,8 +150,9 @@ GEM
|
|||
activesupport (~> 3.1)
|
||||
polyamorous (~> 0.5.0)
|
||||
mime-types (1.21)
|
||||
mini_portile (0.5.1)
|
||||
mono_logger (1.1.0)
|
||||
multi_json (1.7.6)
|
||||
multi_json (1.7.9)
|
||||
mysql2 (0.3.11)
|
||||
net-scp (1.1.1)
|
||||
net-ssh (>= 2.6.5)
|
||||
|
@ -138,6 +161,8 @@ GEM
|
|||
net-ssh (2.6.7)
|
||||
net-ssh-gateway (1.2.0)
|
||||
net-ssh (>= 2.6.5)
|
||||
nokogiri (1.6.0)
|
||||
mini_portile (~> 0.5.0)
|
||||
pdf-reader (1.2.0)
|
||||
Ascii85 (~> 1.0.0)
|
||||
hashery (~> 2.0)
|
||||
|
@ -180,7 +205,7 @@ GEM
|
|||
rdoc (3.12.2)
|
||||
json (~> 1.4)
|
||||
redis (3.0.4)
|
||||
redis-namespace (1.3.0)
|
||||
redis-namespace (1.3.1)
|
||||
redis (~> 3.0.0)
|
||||
responders (0.9.3)
|
||||
railties (~> 3.1)
|
||||
|
@ -190,8 +215,20 @@ GEM
|
|||
redis-namespace (~> 1.2)
|
||||
sinatra (>= 0.9.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)
|
||||
rubyzip (0.9.9)
|
||||
sass (3.2.1)
|
||||
sass-rails (3.2.5)
|
||||
railties (~> 3.2.0)
|
||||
|
@ -200,6 +237,11 @@ GEM
|
|||
select2-rails (3.4.2)
|
||||
sass-rails
|
||||
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)
|
||||
activesupport (>= 2.3.2)
|
||||
simple-navigation-bootstrap (0.0.4)
|
||||
|
@ -207,6 +249,10 @@ GEM
|
|||
simple_form (2.1.0)
|
||||
actionpack (~> 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)
|
||||
rack (~> 1.4)
|
||||
rack-protection (~> 1.3)
|
||||
|
@ -220,7 +266,6 @@ GEM
|
|||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
sqlite3 (1.3.6)
|
||||
test-unit (2.5.3)
|
||||
therubyracer (0.10.2)
|
||||
libv8 (~> 3.3.10)
|
||||
thin (1.5.1)
|
||||
|
@ -245,12 +290,15 @@ GEM
|
|||
uniform_notifier (1.1.1)
|
||||
vegas (0.1.11)
|
||||
rack (>= 1.0.0)
|
||||
websocket (1.0.7)
|
||||
whenever (0.8.1)
|
||||
activesupport (>= 2.3.4)
|
||||
chronic (>= 0.6.3)
|
||||
wikicloth (0.8.0)
|
||||
builder
|
||||
expression_parser
|
||||
xpath (2.0.0)
|
||||
nokogiri (~> 1.3)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
@ -264,11 +312,16 @@ DEPENDENCIES
|
|||
bullet
|
||||
capistrano (= 2.13.5)
|
||||
capistrano-ext
|
||||
capybara (~> 2.1.0)
|
||||
client_side_validations
|
||||
coffee-rails (~> 3.2.1)
|
||||
daemons
|
||||
database_cleaner
|
||||
exception_notification
|
||||
factory_girl_rails (~> 4.0)
|
||||
faker
|
||||
haml-rails
|
||||
i18n-spec
|
||||
inherited_resources
|
||||
jquery-rails
|
||||
kaminari
|
||||
|
@ -281,14 +334,18 @@ DEPENDENCIES
|
|||
rails (~> 3.2.9)
|
||||
rails-settings-cached (= 0.2.4)
|
||||
resque
|
||||
rspec-core
|
||||
rspec-expectations
|
||||
rspec-rails
|
||||
ruby-prof
|
||||
sass-rails (~> 3.2.3)
|
||||
select2-rails
|
||||
selenium-webdriver (~> 2.35.1)
|
||||
simple-navigation
|
||||
simple-navigation-bootstrap
|
||||
simple_form
|
||||
simplecov
|
||||
sqlite3
|
||||
test-unit
|
||||
therubyracer
|
||||
thin
|
||||
twitter-bootstrap-rails
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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)
|
||||
[![Dependency Status](https://gemnasium.com/foodcoops/foodsoft.png)](https://gemnasium.com/foodcoops/foodsoft)
|
||||
|
||||
|
|
|
@ -20,11 +20,17 @@ class OrderFax < OrderPdf
|
|||
move_down 5
|
||||
text "#{contact[:zip_code]} #{contact[:city]}", size: 9, align: :right
|
||||
move_down 5
|
||||
text "#{I18n.t('simple_form.labels.supplier.customer_number')}: #{@order.supplier.try(:customer_number)}", size: 9, align: :right
|
||||
move_down 5
|
||||
text "#{I18n.t('simple_form.labels.supplier.phone')}: #{contact[:phone]}", size: 9, align: :right
|
||||
move_down 5
|
||||
text "#{I18n.t('simple_form.labels.supplier.email')}: #{contact[:email]}", 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
|
||||
end
|
||||
unless contact[:phone].blank?
|
||||
text "#{I18n.t('simple_form.labels.supplier.phone')}: #{contact[:phone]}", size: 9, align: :right
|
||||
move_down 5
|
||||
end
|
||||
unless contact[:email].blank?
|
||||
text "#{I18n.t('simple_form.labels.supplier.email')}: #{contact[:email]}", size: 9, align: :right
|
||||
end
|
||||
end
|
||||
|
||||
# Recipient
|
||||
|
@ -32,8 +38,10 @@ class OrderFax < OrderPdf
|
|||
text @order.name
|
||||
move_down 5
|
||||
text @order.supplier.try(:address).to_s
|
||||
move_down 5
|
||||
text "#{I18n.t('simple_form.labels.supplier.fax')}: #{@order.supplier.try(:fax)}"
|
||||
unless @order.supplier.try(:fax).blank?
|
||||
move_down 5
|
||||
text "#{I18n.t('simple_form.labels.supplier.fax')}: #{@order.supplier[:fax]}"
|
||||
end
|
||||
end
|
||||
|
||||
move_down 5
|
||||
|
@ -42,25 +50,37 @@ class OrderFax < OrderPdf
|
|||
move_down 10
|
||||
text "#{I18n.t('simple_form.labels.delivery.delivered_on')}:"
|
||||
move_down 10
|
||||
text "#{I18n.t('simple_form.labels.supplier.contact_person')}: #{@order.supplier.try(:contact_person)}"
|
||||
move_down 10
|
||||
unless @order.supplier.try(:contact_person).blank?
|
||||
text "#{I18n.t('simple_form.labels.supplier.contact_person')}: #{@order.supplier[:contact_person]}"
|
||||
move_down 10
|
||||
end
|
||||
|
||||
# Articles
|
||||
total = 0
|
||||
data = [I18n.t('documents.order_fax.rows')]
|
||||
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.units_to_order,
|
||||
a.article.name,
|
||||
a.price.unit_quantity,
|
||||
a.article.unit,
|
||||
a.price.price]
|
||||
number_to_currency(a.price.price),
|
||||
number_to_currency(subtotal)]
|
||||
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.header = true
|
||||
table.cells.border_width = 1
|
||||
table.cells.border_color = '666666'
|
||||
|
||||
table.row(0).border_bottom_width = 2
|
||||
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
|
||||
#font_size: 8,
|
||||
#vertical_padding: 3,
|
||||
|
|
|
@ -13,11 +13,9 @@ class Supplier < ActiveRecord::Base
|
|||
:delivery_days, :order_howto, :note, :shared_supplier_id, :min_order_quantity
|
||||
|
||||
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_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
|
||||
|
||||
scope :undeleted, -> { where(deleted_at: nil) }
|
||||
|
|
|
@ -3,7 +3,7 @@ class Workgroup < Group
|
|||
|
||||
has_many :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
|
||||
validate :last_admin_on_earth, :on => :update
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
.well.well-small
|
||||
%h3= t('.notes_and_journal')
|
||||
#note
|
||||
- unless @order.note.empty?
|
||||
- unless @order.note.blank?
|
||||
= simple_format @order.note
|
||||
- else
|
||||
%p= t('.comment_on_transaction')
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
%thead
|
||||
%tr
|
||||
%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
|
||||
%tbody
|
||||
|
@ -17,4 +17,4 @@
|
|||
%td
|
||||
= link_to t('.new_transaction'), new_finance_ordergroup_transaction_path(ordergroup), class: 'btn btn-mini'
|
||||
= link_to t('.account_statement'), finance_ordergroup_transactions_path(ordergroup), class: 'btn btn-mini'
|
||||
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
%pre
|
||||
* #{t '.help.list_item_1'}
|
||||
%pre
|
||||
** #{t '.help_list_item_2'}
|
||||
** #{t '.help.list_item_2'}
|
||||
%tr
|
||||
%td= t '.help.ordered_list'
|
||||
%td
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
= f.input :date
|
||||
= f.input :note
|
||||
= f.submit
|
||||
= link_to t('ui.cancel'), stock_takings_path
|
||||
= link_to t('ui.or_cancel'), stock_takings_path
|
||||
|
|
|
@ -14,4 +14,4 @@
|
|||
= render :partial => 'stock_change', :collection => @stock_taking.stock_changes
|
||||
.form-actions
|
||||
= f.submit class: 'btn'
|
||||
= link_to t('ui.cancel'), stock_takings_path
|
||||
= link_to t('ui.or_cancel'), stock_takings_path
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
- title "Lager (#{StockArticle.available.count})"
|
||||
- title t('.title', article_count: StockArticle.available.count)
|
||||
- content_for :javascript do
|
||||
:javascript
|
||||
$(function() {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
- content_for :sidebar do
|
||||
.well.well-small
|
||||
%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('.all_tasks'), tasks_path
|
||||
%li= link_to t('.archive'), archive_tasks_path
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
- title "Meine Aufgaben"
|
||||
- title t('.title')
|
||||
= render 'nav'
|
||||
|
||||
- unless @unaccepted_tasks.empty?
|
||||
|
|
|
@ -505,6 +505,7 @@ de:
|
|||
- Gebinde
|
||||
- Einheit
|
||||
- Preis/Einheit
|
||||
total: Gesamtpreis
|
||||
order_matrix:
|
||||
filename: Bestellung %{name}-%{date} - Sortiermatrix
|
||||
heading: Artikelübersicht
|
||||
|
@ -719,6 +720,7 @@ de:
|
|||
ordergroups:
|
||||
account_balance: Kontostand
|
||||
account_statement: Kontoauszug
|
||||
contact: Kontakt
|
||||
name: Name
|
||||
new_transaction: Neue Transaktion
|
||||
update:
|
||||
|
@ -1602,6 +1604,7 @@ de:
|
|||
contact_person: Kontaktperson
|
||||
contact_phone: Telefon
|
||||
ignore_apple_restriction: Bestellstop bei zu wenig Äpfeln ignorieren
|
||||
name: Name
|
||||
page:
|
||||
body: Inhalt
|
||||
parent_id: Oberseite
|
||||
|
@ -1669,6 +1672,7 @@ de:
|
|||
language:
|
||||
de: Deutsch
|
||||
en: English
|
||||
fr: Französisch
|
||||
nl: Niederländisch
|
||||
required:
|
||||
mark: ! '*'
|
||||
|
@ -1742,6 +1746,7 @@ de:
|
|||
show_stock_takings: Inventurübersicht
|
||||
stock_count: ! 'Artikelanzahl:'
|
||||
stock_worth: ! 'Aktueller Lagerwert:'
|
||||
title: Lager (%{article_count})
|
||||
toggle_unavailable: Nicht verfügbare Artikel zeigen/verstecken
|
||||
view_options: Ansichtsoptionen
|
||||
new:
|
||||
|
@ -1833,6 +1838,7 @@ de:
|
|||
group_tasks: Gruppenaufgaben
|
||||
my_tasks: Meine Aufgaben
|
||||
new_task: Neue Aufgabe erstellen
|
||||
pages: Seiten
|
||||
new:
|
||||
title: Neue Aufgabe erstellen
|
||||
repeated: Aufgabe wird wöchentlich wiederholt
|
||||
|
|
|
@ -493,7 +493,7 @@ en:
|
|||
- Article
|
||||
- Amount
|
||||
- Price
|
||||
- Unit Quantity
|
||||
- Unit quantity
|
||||
- Unit
|
||||
- Sum
|
||||
sum: Sum
|
||||
|
@ -504,20 +504,24 @@ en:
|
|||
- Order Number
|
||||
- Amount
|
||||
- Name
|
||||
- Barrel
|
||||
- Unit quantity
|
||||
- Unit
|
||||
- Price/Unit
|
||||
- Subtotal
|
||||
total: Total
|
||||
order_matrix:
|
||||
filename: Order %{name}-%{date} - sorting matrix
|
||||
heading: Article overview
|
||||
rows:
|
||||
- Article
|
||||
- Unit
|
||||
- Barrel
|
||||
- Unit quantity
|
||||
- FC-Price
|
||||
- Amount
|
||||
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:
|
||||
format: ! '%{attribute} %{message}'
|
||||
general: A problem has occured.
|
||||
|
@ -721,6 +725,7 @@ en:
|
|||
ordergroups:
|
||||
account_balance: Account balance
|
||||
account_statement: Account statement
|
||||
contact: Contact
|
||||
name: Name
|
||||
new_transaction: New transaction
|
||||
update:
|
||||
|
@ -1604,6 +1609,7 @@ en:
|
|||
contact_person: Contact person
|
||||
contact_phone: Phone
|
||||
ignore_apple_restriction: Ignore order stop by apple points restriction
|
||||
name: Name
|
||||
page:
|
||||
body: Body
|
||||
parent_id: Parent page
|
||||
|
@ -1671,6 +1677,7 @@ en:
|
|||
language:
|
||||
de: German
|
||||
en: English
|
||||
fr: French
|
||||
nl: Dutch
|
||||
required:
|
||||
mark: ! '*'
|
||||
|
@ -1744,6 +1751,7 @@ en:
|
|||
show_stock_takings: Inventory overview
|
||||
stock_count: ! 'Number of articles:'
|
||||
stock_worth: ! 'Current stock value:'
|
||||
title: Stock (%{article_count})
|
||||
toggle_unavailable: Show/hide unavailable articles
|
||||
view_options: View options
|
||||
new:
|
||||
|
@ -1835,6 +1843,7 @@ en:
|
|||
group_tasks: Group tasks
|
||||
my_tasks: My tasks
|
||||
new_task: Create new task
|
||||
pages: Pages
|
||||
new:
|
||||
title: Create new tasks
|
||||
repeated: Task is repeated weekly
|
||||
|
|
1919
config/locales/fr.yml
Normal file
1919
config/locales/fr.yml
Normal file
File diff suppressed because it is too large
Load diff
|
@ -479,48 +479,60 @@ nl:
|
|||
notice:
|
||||
documents:
|
||||
order_by_articles:
|
||||
filename:
|
||||
rows:
|
||||
title:
|
||||
filename: Bestelling %{name}-%{date} - Artikellijst
|
||||
rows:
|
||||
- Huishouden
|
||||
- Hoeveelheid
|
||||
- Prijs
|
||||
title: ! 'Artikellijst van bestelling: %{name}, gesloten op %{date}'
|
||||
order_by_groups:
|
||||
filename:
|
||||
rows:
|
||||
sum:
|
||||
title:
|
||||
filename: Bestelling %{name}-%{date} - Huishoudenslijst
|
||||
rows:
|
||||
- Artikel
|
||||
- Hoeveelheid
|
||||
- Prijs
|
||||
- Gr.Eenh.
|
||||
- Eenheid
|
||||
- Som
|
||||
sum: Som
|
||||
title: ! 'Huishoudenslijst van bestelling: %{name}, gesloten op %{date}'
|
||||
order_fax:
|
||||
filename:
|
||||
rows:
|
||||
filename: Bestelling %{name}-%{date} - Fax
|
||||
rows: ! '[]'
|
||||
total: Totaal
|
||||
order_matrix:
|
||||
filename:
|
||||
heading:
|
||||
filename: Bestelling %{name}-%{date} - Sorteermatrix
|
||||
heading: Artikeloverzicht
|
||||
rows:
|
||||
title:
|
||||
total:
|
||||
title: ! 'Sorteermatrix van bestelling: %{name}, gesloten op %{date}'
|
||||
total:
|
||||
one: In totaal éen artikel
|
||||
other: In totaal %{count} artikelen
|
||||
errors:
|
||||
format:
|
||||
general:
|
||||
general: Er is een probleem opgetreden.
|
||||
general_again:
|
||||
general_msg:
|
||||
general_msg: ! 'Er is een probleem opgetreden: %{msg}'
|
||||
messages:
|
||||
accepted:
|
||||
blank:
|
||||
accepted: moet geaccepteerd worden
|
||||
blank: moet ingevuld worden
|
||||
confirmation:
|
||||
empty:
|
||||
equal_to:
|
||||
empty: moet ingevuld worden
|
||||
equal_to: moet precies %{count} zijn
|
||||
even:
|
||||
exclusion:
|
||||
greater_than:
|
||||
exclusion: moet even zijn
|
||||
greater_than: moet groter dan %{count} zijn
|
||||
greater_than_or_equal_to:
|
||||
inclusion:
|
||||
invalid:
|
||||
less_than:
|
||||
less_than_or_equal_to:
|
||||
not_a_number:
|
||||
not_an_integer:
|
||||
odd:
|
||||
less_than: moet kleiner dan %{count} zijn
|
||||
less_than_or_equal_to: moet groter of gelijk aan %{count} zijn
|
||||
not_a_number: is geen getal
|
||||
not_an_integer: moet een geheel getal zijn
|
||||
odd: moet oneven zijn
|
||||
record_invalid:
|
||||
taken:
|
||||
taken_with_deleted:
|
||||
taken: is al in gebruik
|
||||
taken_with_deleted: is al in gebruik (verwijderde groep)
|
||||
too_long:
|
||||
too_short:
|
||||
wrong_length:
|
||||
|
@ -697,6 +709,7 @@ nl:
|
|||
ordergroups:
|
||||
account_balance: Tegoed
|
||||
account_statement:
|
||||
contact:
|
||||
name: Naam
|
||||
new_transaction: Nieuwe transactie
|
||||
update:
|
||||
|
@ -1493,6 +1506,7 @@ nl:
|
|||
contact_person: Contactpersoon
|
||||
contact_phone: Telefoon
|
||||
ignore_apple_restriction:
|
||||
name:
|
||||
page:
|
||||
body:
|
||||
parent_id:
|
||||
|
@ -1560,6 +1574,7 @@ nl:
|
|||
language:
|
||||
de: Duits
|
||||
en: Engels
|
||||
fr: Frans
|
||||
nl: Nederlands
|
||||
required:
|
||||
mark: ! '*'
|
||||
|
@ -1633,6 +1648,7 @@ nl:
|
|||
show_stock_takings:
|
||||
stock_count:
|
||||
stock_worth:
|
||||
title:
|
||||
toggle_unavailable:
|
||||
view_options:
|
||||
new:
|
||||
|
@ -1724,6 +1740,7 @@ nl:
|
|||
group_tasks:
|
||||
my_tasks:
|
||||
new_task:
|
||||
pages:
|
||||
new:
|
||||
title:
|
||||
repeated:
|
||||
|
@ -1764,9 +1781,9 @@ nl:
|
|||
history:
|
||||
marks:
|
||||
close: ! '×'
|
||||
success:
|
||||
success: <i class="icon icon-ok"></i>
|
||||
or_cancel: of annuleren
|
||||
please_wait:
|
||||
please_wait: Een moment alstublieft...
|
||||
save: Opslaan
|
||||
show: Tonen
|
||||
views:
|
||||
|
|
|
@ -38,6 +38,15 @@ namespace :foodsoft do
|
|||
puts yellow "All done! Your foodcoft should be running smoothly."
|
||||
start_server
|
||||
end
|
||||
|
||||
namespace :setup do
|
||||
desc "Initialize stock configuration"
|
||||
task :stock_config do
|
||||
setup_app_config
|
||||
setup_development
|
||||
setup_secret_token
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def setup_bundler
|
||||
|
|
3
lib/tasks/rspec.rake
Normal file
3
lib/tasks/rspec.rake
Normal file
|
@ -0,0 +1,3 @@
|
|||
require 'rspec/core/rake_task'
|
||||
RSpec::Core::RakeTask.new(:spec)
|
||||
task :default => :spec
|
|
@ -55,12 +55,16 @@ fi
|
|||
sed -i "s|^\\(\\s*gem\\s\\+'sqlite3'\\)|#\1|" Gemfile
|
||||
sed -i "s|^\\(\\s*sqlite3\\b\)|#\1|" Gemfile.lock
|
||||
# make sure postgresql db is present, as it is the default heroku db
|
||||
echo $'\ngem "pg"' >>Gemfile
|
||||
echo $'\ngem "localeapp"' >>Gemfile
|
||||
echo "
|
||||
gem 'pg'" >>Gemfile
|
||||
# always use unicorn
|
||||
echo $'\ngem "unicorn"' >>Gemfile
|
||||
echo "
|
||||
gem 'unicorn'" >>Gemfile
|
||||
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
|
||||
sed -i 's|^\(config/\*.yml\)|#\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']
|
||||
end
|
||||
EOF
|
||||
echo "
|
||||
gem 'localeapp'" >>Gemfile
|
||||
# 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
|
||||
# update Gemfile.lock after Gemfile updates (required by heroku)
|
||||
bundle install --quiet
|
||||
# TODO add more extensive database seed
|
||||
|
||||
# and push = deploy
|
||||
|
|
20
spec/factories/article.rb
Normal file
20
spec/factories/article.rb
Normal 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
|
10
spec/factories/group_order.rb
Normal file
10
spec/factories/group_order.rb
Normal 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
|
9
spec/factories/group_order_article.rb
Normal file
9
spec/factories/group_order_article.rb
Normal 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
31
spec/factories/order.rb
Normal 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
|
21
spec/factories/supplier.rb
Normal file
21
spec/factories/supplier.rb
Normal 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
36
spec/factories/user.rb
Normal 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
12
spec/i18n_spec.rb
Normal 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
|
55
spec/integration/balancing_spec.rb
Normal file
55
spec/integration/balancing_spec.rb
Normal 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
|
57
spec/integration/product_distribution_example_spec.rb
Normal file
57
spec/integration/product_distribution_example_spec.rb
Normal 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
|
21
spec/integration/session_spec.rb
Normal file
21
spec/integration/session_spec.rb
Normal 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
|
63
spec/integration/supplier_spec.rb
Normal file
63
spec/integration/supplier_spec.rb
Normal 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
|
47
spec/models/article_spec.rb
Normal file
47
spec/models/article_spec.rb
Normal 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
|
48
spec/models/group_order_article_spec.rb
Normal file
48
spec/models/group_order_article_spec.rb
Normal 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
|
25
spec/models/group_order_spec.rb
Normal file
25
spec/models/group_order_spec.rb
Normal 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
47
spec/models/order_spec.rb
Normal 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
|
16
spec/models/supplier_spec.rb
Normal file
16
spec/models/supplier_spec.rb
Normal 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
59
spec/models/user_spec.rb
Normal 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
67
spec/spec_helper.rb
Normal 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
14
spec/support/coverage.rb
Normal 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
|
17
spec/support/session_helper.rb
Normal file
17
spec/support/session_helper.rb
Normal 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
|
Loading…
Reference in a new issue