Compare commits

..

15 commits

Author SHA1 Message Date
27b4177a4c add demo bnn
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-02-24 16:49:41 +01:00
bdeb47edec add articles for nkn
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-24 15:53:24 +01:00
FGU
1c6413a67e wip on demo day seeds
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-24 15:34:55 +01:00
Philipp Rothmann
f4f61f02db this merge breaks alot
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-23 18:21:40 +01:00
44f5d13920 update article category implemented
adapt tests

add translations

adapt test

fix bug
2023-02-23 13:29:29 +01:00
f62dfc918b include foodsoft-article-import
Some checks failed
continuous-integration/drone/push Build is failing
use filetypes for manual uploading bnn, odin, foodsoft file

use opts in .parse

adapt specs to include file format

add specs for odin, bnn, foodsoft files

adapt localize input to remove ',' separator and replace with '.'

remove depr foodsoftfile.rb and spreadsheet.rb

remove todo
2023-02-22 16:59:50 +01:00
Philipp Rothmann
a355399f8e fix: give docker user storge directory permissions for fileupload 2023-02-22 16:59:50 +01:00
Philipp Rothmann
8cf500dc42 fix: set RAILS_SERVE_STATIC_FILES for deployment 2023-02-22 16:59:50 +01:00
Philipp Rothmann
7694d0bdcf fix: assets precompile by using terser
importmaps broke precompiliation with uglifier
see: https://github.com/rails/importmap-rails/issues/5
2023-02-22 16:59:50 +01:00
Philipp Rothmann
3c17b3abea fix(messages): migrate message bodys to richtext 2023-02-22 16:59:50 +01:00
Philipp Rothmann
9ce8524b49 feat(messages): add html formatting to messages
This commit allows users to use the trix editor to send
messages with basic formatting and attachements.

* add active storage
* add actiontext
* add richtext field to messages
* add imageprocessing for message attachements
* add html email layout and adjust translations to use html urls
2023-02-22 16:59:50 +01:00
Philipp Rothmann
ad62cbd086 feat(finance): show sum of ordergroup balances 2023-02-22 16:59:50 +01:00
Philipp Rothmann
a2c8c6e0e0 add: drone ci
fix: ci

fix: .drone docker rails version

add .drone caching

fix drone ci
2023-02-22 16:59:50 +01:00
91a38bc73b move BigDecimal.new to BigDecimal() 2023-02-17 13:16:28 +01:00
782194cd08 change .search to .ransack for updated ransack gem 2023-02-17 13:16:19 +01:00
44 changed files with 398 additions and 718 deletions

View file

@ -79,7 +79,7 @@ steps:
- name: deployment - name: deployment
image: git.local-it.org/philipp/stack-ssh-deply:latest image: git.local-it.org/philipp/stack-ssh-deply:latest
settings: settings:
stack: "foodsoft_${DRONE_BRANCH}" stack: "foodsoft_${DRONE_COMMIT:0:8}"
compose: "deployment/compose.yml" compose: "deployment/compose.yml"
deploy_key: deploy_key:
from_secret: drone_deploy_key from_secret: drone_deploy_key
@ -96,23 +96,23 @@ steps:
- proxy - proxy
environment: environment:
IMAGE: git.local-it.org/foodsoft/foodsoft:${DRONE_COMMIT:0:8} IMAGE: git.local-it.org/foodsoft/foodsoft:${DRONE_COMMIT:0:8}
STACK_NAME: "foodsoft_${DRONE_BRANCH}" STACK_NAME: "foodsoft_${DRONE_COMMIT:0:8}"
DOMAIN: "foodsoft.dev.local-it.cloud" DOMAIN: "${DRONE_COMMIT:0:8}.foodsoft.dev.local-it.cloud"
LETS_ENCRYPT_ENV: production LETS_ENCRYPT_ENV: production
FOODCOOP_MULTI_INSTALL: true FOODCOOP_MULTI_INSTALL: true
FOODCOOP_NAME: Einkaufskooperative Foobar FOODCOOP_NAME: example
FOODCOOP_CITY: Berlin FOODCOOP_CITY: XXX
FOODCOOP_COUNTRY: Deutschland FOODCOOP_COUNTRY: XXX
FOODCOOP_EMAIL: foodsoft@local-it.org FOODCOOP_EMAIL: info@example.org
FOODCOOP_PHONE: 123456789 FOODCOOP_PHONE: XXX
FOODCOOP_STREET: Einkaufsstraße 5 FOODCOOP_STREET: XXX
FOODCOOP_ZIP_CODE: 12345 FOODCOOP_ZIP_CODE: XXX
FOODCOOP_HOMEPAGE: https://foodsoft.local-it.org FOODCOOP_HOMEPAGE: https://order.example.org
FOODCOOP_HELP_URL: https://git.local-it.org/foodsoft/foodsoft FOODCOOP_HELP_URL: https://order.example.org
FOODCOOP_TIME_ZONE: Berlin FOODCOOP_TIME_ZONE: Berlin
FOODCOOP_USE_NICK: true FOODCOOP_USE_NICK: true
FOODCOOP_LANGUAGE: de FOODCOOP_LANGUAGE: de
FOODCOOP_FOOTER: '<a href="https://foodsoft.local-it.org/">Foodsoft</a> hosted by <a href="https://local-it.org">local-it e,V,</a>.' FOODCOOP_FOOTER: '<a href="https://example.org/">example</a> hosted by <a href="https://yourhoster.org">Your Tech Co-op</a>.'
USE_APPLE_POINTS: false USE_APPLE_POINTS: false
STOP_ORDERING_UNDER: 75 STOP_ORDERING_UNDER: 75
MINIMUM_BALANCE: 0 MINIMUM_BALANCE: 0
@ -120,15 +120,15 @@ steps:
MYSQL_HOST: db MYSQL_HOST: db
MYSQL_PORT: 3306 MYSQL_PORT: 3306
MYSQL_USER: foodsoft MYSQL_USER: foodsoft
EMAIL_SENDER: demo@local-it.org EMAIL_SENDER: noreply@example.org
EMAIL_ERROR: flip@yksflip.de EMAIL_ERROR: systems@example.org
SMTP_ADDRESS: mail.local-it.org SMTP_ADDRESS: mail.example.com
SMTP_AUTHENTICATION: login SMTP_AUTHENTICATION: plain
SMTP_DOMAIN: mail.local-it.org SMTP_DOMAIN: mail.example.com
SMTP_ENABLE_STARTTLS_AUTO: true SMTP_ENABLE_STARTTLS_AUTO: true
SMTP_PORT: 587 SMTP_PORT: 587
SMTP_USER_NAME: demo@local-it.org SMTP_USER_NAME: foodsoft
EMAIL_REPLY_DOMAIN: EMAIL_REPLY_DOMAIN: example.org
SMTP_SERVER_HOST: 0.0.0.0 SMTP_SERVER_HOST: 0.0.0.0
SMTP_SERVER_PORT: 2525 SMTP_SERVER_PORT: 2525
SECRET_DB_PASSWORD_VERSION: v1 SECRET_DB_PASSWORD_VERSION: v1

View file

@ -23,7 +23,7 @@ gem 'bootsnap', require: false
gem 'mysql2' gem 'mysql2'
gem 'prawn' gem 'prawn'
gem 'prawn-table' gem 'prawn-table'
gem 'haml', '~> 5.0' gem 'haml'
gem 'haml-rails' gem 'haml-rails'
gem 'kaminari' gem 'kaminari'
gem 'simple_form' gem 'simple_form'

View file

@ -242,8 +242,9 @@ GEM
rails (>= 4.0.0) rails (>= 4.0.0)
globalid (1.0.0) globalid (1.0.0)
activesupport (>= 5.0) activesupport (>= 5.0)
haml (5.2.2) haml (6.1.1)
temple (>= 0.8.0) temple (>= 0.8.2)
thor
tilt tilt
haml-rails (2.1.0) haml-rails (2.1.0)
actionpack (>= 5.1) actionpack (>= 5.1)
@ -639,7 +640,7 @@ DEPENDENCIES
foodsoft_polls! foodsoft_polls!
foodsoft_wiki! foodsoft_wiki!
gaffe gaffe
haml (~> 5.0) haml
haml-rails haml-rails
hashie (~> 3.4.6) hashie (~> 3.4.6)
i18n-js (~> 3.0.0.rc8) i18n-js (~> 3.0.0.rc8)

161
README.md
View file

@ -1,124 +1,65 @@
Foodsoft Foodsoft
========= =========
[![Build Status](https://github.com/foodcoops/foodsoft/workflows/Ruby/badge.svg)](https://github.com/foodcoops/foodsoft/actions)
[![Coverage Status](https://coveralls.io/repos/foodcoops/foodsoft/badge.svg?branch=master)](https://coveralls.io/r/foodcoops/foodsoft?branch=master)
[![Docs Status](https://inch-ci.org/github/foodcoops/foodsoft.svg?branch=master)](http://inch-ci.org/github/foodcoops/foodsoft)
[![Code Climate](https://codeclimate.com/github/foodcoops/foodsoft.svg)](https://codeclimate.com/github/foodcoops/foodsoft)
[![Docker Status](https://img.shields.io/docker/cloud/build/foodcoops/foodsoft.svg)](https://hub.docker.com/r/foodcoops/foodsoft)
[![Documentation](https://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/foodcoops/foodsoft)
[Website](https://foodsoft.local-it.org) Web-based software to manage a non-profit food coop (product catalog, ordering, accounting, job scheduling).
[Prototypefund](https://prototypefund.de/project/weiterentwicklung-von-foodsoft/)
A food cooperative is a group of people that buy food from suppliers of their own choosing. A collective do-it-yourself supermarket. Members order their products online and collect them on a specified day. And all put in a bit of work to make that possible. Foodsoft facilitates the process.
If you're a food coop considering to use foodsoft, please have a look at the [wiki page for foodcoops](https://github.com/foodcoops/foodsoft/wiki/For-foodcoops). When you'd like to experiment with or develop foodsoft, you can read [how to set it up](https://github.com/foodcoops/foodsoft/blob/master/doc/SETUP_DEVELOPMENT.md) on your own computer.
More information about using this software and contributing can be found on the [wiki](https://github.com/foodcoops/foodsoft/wiki).
Foodsoft ist ein Tool für [Lebensmittelkooperativen](https://de.wikipedia.org/wiki/Lebensmittelkooperative), welches selbstorganisierte gemeinsame Bestellungen in Großmengen von regionalen und ökologischen Produkten vereinfacht und transparent gestaltet. Developing
----------
Foodsoft wurde ursprünglich entwickelt und betrieben von [foodcoops.net](https://foodcoops.net/) Get foodsoft [running locally](doc/SETUP_DEVELOPMENT.md),
then visit our [Developing Guidelines](https://github.com/foodcoops/foodsoft/wiki/Developing-Guidelines)
page on the wiki.
Get a foodsoft dev-environment running in the browser with Gitpod
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/foodcoops/foodsoft)
Follow these [instructions](doc/SETUP_DEVELOPMENT_GITPOD.md) to complete setup from within the Gitpod workspace.
Deploying
---------
Setup foodsoft to [run in production](doc/SETUP_PRODUCTION.md), or join an existing
[hosting platform](https://foodcoops.net/foodsoft-hosting/).
#### Zielgruppe License
-------
Unsere Zielgruppen sind Bürger:innen, Gruppen und Vereine, die eine Einkauskooperative aufbauen wollen und eine Software, die die Bestellung, Verteilung und Abrechnung erleichtert, benötigen. Foodsoft is licensed under the [AGPL](https://www.gnu.org/licenses/agpl-3.0.html)
license (version 3 or later). Practically this means that you are free to use,
adapt and redistribute the software, as long as you publish any changes you
make to the code.
#### Vorhaben For private use, there are no restrictions, but if you give others access to
Foodsoft (like running it open to the internet), you must also make your
changes available under the same license. This can be as easy as
[forking](https://github.com/foodcoops/foodsoft/fork) the project on Github and
pushing your changes. You are not required to integrate your changes back into
the main Foodsoft version (but if you're up for it that would be very welcome).
* ✅ Technische Schuld reduzieren To make it a little easier, configuration files are exempt, so you can just
* ✅ Ruby on Rails Upgrade install and configure Foodsoft without having to publish your changes. These
* ✅ Artikel Import verbessern files are marked as public domain in the file header.
(Großhandelschnitstelle)
* ✅ Userexperience Verbessern
#### Was ist eine Einkaufskooperative?
![Wie funktioniert eine Einkauskooperative?](./doc/foodcoop-explained.jpg)
State of this Fork
------------------
#### Increase Test Coverage
1. integration and model tests
* [x] fork
* [x] upstream [#966](https://github.com/foodcoops/foodsoft/pull/966)
1. Controller tests
* [x] [fork](https://git.local-it.org/Foodsoft/foodsoft/src/branch/8_increase_test_coverage_controllers)
* [ ] upstream [#970](https://github.com/foodcoops/foodsoft/pull/970)
#### Upgrade
1. Migrate to RSwag API Tests
* [x] [fork](https://git.local-it.org/Foodsoft/foodsoft/src/branch/28_introduce_rswag)
* [x] upstream [#969](https://github.com/foodcoops/foodsoft/pull/969)
1. Rails v7
* [x] [fork](https://git.local-it.org/Foodsoft/foodsoft/src/branch/9_rails_v_7)
* [x] upstream [#979](https://github.com/foodcoops/foodsoft/pull/979)
disussion [#956](https://github.com/foodcoops/foodsoft/issues/956)
1. Javascript Importmap
* [x] [fork](https://git.local-it.org/Foodsoft/foodsoft/src/branch/9_rails_v_7_js_importmap)
* [x] upstream
#### Article Order Import/Export
Updating Articles from large resellers and exporting orders is now much easier!
1. adds bnn fileformat that is used from large german resellers e.g. naturkost nord
* [x] [fork](https://git.local-it.org/Foodsoft/foodsoft/src/branch/11_bnn_import_article_update)
[gem](https://git.local-it.org/Foodsoft/foodsoft_article_import)
* [ ] upstream
1. Import category field
* [x] [fork](https://git.local-it.org/Foodsoft/foodsoft/src/branch/56_add_update_of_article_category_to_file_import)
* [ ] upstream
1. Export order as a custom csv file
* [x] [fork](https://git.local-it.org/Foodsoft/foodsoft/src/branch/12_generate_custom_csv_file)
* [ ] upstream
1. Naturkostnord Plugin
* [ ] [fork](https://git.local-it.org/Foodsoft/foodsoft/src/branch/12_nkn_file_plugin)
* [ ] upstream
#### Improve User Experience
1. Richtext editor for messages. Also allows sending attachements.
* [x] [fork](https://git.local-it.org/Foodsoft/foodsoft/src/branch/16_html_message_templates)
* [x] upstream
1. Show the sum of all order group balances
* [x] [fork](https://git.local-it.org/Foodsoft/foodsoft/src/branch/47_finance_ordergroup_sums)
* [x] upstream
1. UI improvements for group order view
* [x] [fork](https://git.local-it.org/Foodsoft/foodsoft/src/branch/uxui_group_order)
* [ ] upstream
1. Favorites
* [ ] [fork](https://git.local-it.org/Foodsoft/foodsoft/src/branch/20_favourites)
* [ ] upstream
1. Show the per kilo / litre price
* [x] [fork](https://git.local-it.org/Foodsoft/foodsoft/src/branch/11_include_kilo_litre_price)
* [ ] upstream
#### Other
1. Fix broken plugin mechanism
* [x] [fork](https://git.local-it.org/Foodsoft/foodsoft/src/branch/downgrade-haml)
* [x] upstream
#### Screenshots
![rswag](./doc/screenshots/rswag.png)
---
![bnn upload](./doc/screenshots/bnn_upload.png)
---
![message formatting](./doc/screenshots/message_formatting.png)
---
![balance sum](./doc/screenshots/balance_sum.png)
---
![custom csv export](./doc/screenshots/custom_csv_export.png)
csv export
---
![order](./doc/screenshots/order.png)
If you have any remaining questions, please
[open an issue](https://github.com/foodcoops/foodsoft/issues/new) or open a new
topic at the [forum](https://forum.foodcoops.net).
Please see [LICENSE](LICENSE.md) for the full and authoritative text. Some
bundled third-party components have [other licenses](vendor/README.md).
Thanks to [Icons8](http://icons8.com/) for letting us use their icons.

View file

@ -179,13 +179,17 @@ function updateBalance() {
var balance = groupBalance - total; var balance = groupBalance - total;
$('#new_balance').html(I18n.l("currency", balance)); $('#new_balance').html(I18n.l("currency", balance));
$('#total_balance').val(I18n.l("currency", balance)); $('#total_balance').val(I18n.l("currency", balance));
// determine bgcolor and submit button state according to balance
var bgcolor = '';
if (balance < minimumBalance) { if (balance < minimumBalance) {
bgcolor = '#FF0000';
$('#submit_button').attr('disabled', 'disabled') $('#submit_button').attr('disabled', 'disabled')
$('#balance-alert').css('display', 'block')
} else { } else {
$('#submit_button').removeAttr('disabled') $('#submit_button').removeAttr('disabled')
$('#balance-alert').css('display', 'none') }
// update bgcolor
for (i in itemTotal) {
$('#td_price_' + i).css('background-color', bgcolor);
} }
} }

View file

@ -230,7 +230,7 @@ table {
margin: .5em 0; margin: .5em 0;
input:disabled { input:disabled {
background-color: gray; } background-color: red; }
} }
} }
} }
@ -241,9 +241,6 @@ table {
tr.order-article:hover .article-info { tr.order-article:hover .article-info {
display: none; display: none;
} }
tr.order-article:focus .article-info {
display: none;
}
} }
#order-footer { #order-footer {
@ -278,13 +275,10 @@ tr.order-article .article-info {
display: none; display: none;
} }
tr.order-article:focus .article-info { tr.order-article:hover .article-info {
display: block; display: block;
} }
tr.order-article:focus {
background-color: #E9E9E9;
}
// ********* Articles // ********* Articles

View file

@ -1,23 +1,11 @@
.missing-many td { .list .missing-many td, .list .missing-many:hover td {
background-color: #ffc590aa; background-color: #ebbebe;
} }
.missing-many:hover td, .missing-many:focus td { .list .missing-few td, .list .missing-few:hover td {
background-color: #ffc590; background-color: #ffee75;
} }
.missing-few td { .list .missing-none td, .list .missing-none:hover td {
background-color: #fcf488aa; background-color: #E4EED6;
}
.missing-few:hover td, .missing-few:focus td {
background-color: #fcf488;
}
.missing-none td {
background-color: #d0f6ffaa;
}
.missing-none:hover td, .missing-none:focus td {
background-color: #d0f6ff;
} }

View file

@ -49,7 +49,7 @@ class OrdersController < ApplicationController
send_order_pdf @order, params[:document] send_order_pdf @order, params[:document]
end end
format.csv do format.csv do
send_data OrderCsv.new(@order, options= {custom_csv: params[:custom_csv]}).to_csv, filename: @order.name + '.csv', type: 'text/csv' send_data OrderCsv.new(@order).to_csv, filename: @order.name + '.csv', type: 'text/csv'
end end
format.text do format.text do
send_data OrderTxt.new(@order).to_txt, filename: @order.name + '.txt', type: 'text/plain' send_data OrderTxt.new(@order).to_txt, filename: @order.name + '.txt', type: 'text/plain'
@ -57,19 +57,6 @@ class OrdersController < ApplicationController
end end
end end
def custom_csv
@order = Order.find(params[:id])
@view = (params[:view] || 'default').gsub(/[^-_a-zA-Z0-9]/, '')
@partial = case @view
when 'default' then 'articles'
when 'groups' then 'shared/articles_by/groups'
when 'articles' then 'shared/articles_by/articles'
else 'articles'
end
render :layout => false
end
# Page to create a new order. # Page to create a new order.
def new def new
if params[:order_id] if params[:order_id]

View file

@ -53,12 +53,4 @@ module GroupOrdersHelper
return 'missing-many' return 'missing-many'
end end
end end
def price_per_base_unit(article:, price:)
quantity_unit = QuantityUnit.parse(article.unit)
return nil unless quantity_unit.present?
scaled_price, base_unit = quantity_unit.scale_price_to_base_unit(price)
"#{number_to_currency(scaled_price)}/#{base_unit}"
end
end end

View file

@ -155,16 +155,4 @@ module OrdersHelper
link_to t('orders.index.action_receive'), receive_order_path(order), class: "btn#{' btn-success' unless order.received?} #{options[:class]}" link_to t('orders.index.action_receive'), receive_order_path(order), class: "btn#{' btn-success' unless order.received?} #{options[:class]}"
end end
end end
def custom_csv_collection
[
OrderArticle.human_attribute_name(:units_to_order),
Article.human_attribute_name(:order_number),
Article.human_attribute_name(:name),
Article.human_attribute_name(:unit),
Article.human_attribute_name(:unit_quantity_short),
ArticlePrice.human_attribute_name(:price),
OrderArticle.human_attribute_name(:total_price)
]
end
end end

View file

@ -2,8 +2,6 @@ require 'csv'
class OrderCsv < RenderCsv class OrderCsv < RenderCsv
def header def header
params = @options[:custom_csv]
arr = if params.nil?
[ [
OrderArticle.human_attribute_name(:units_to_order), OrderArticle.human_attribute_name(:units_to_order),
Article.human_attribute_name(:order_number), Article.human_attribute_name(:order_number),
@ -13,49 +11,19 @@ class OrderCsv < RenderCsv
ArticlePrice.human_attribute_name(:price), ArticlePrice.human_attribute_name(:price),
OrderArticle.human_attribute_name(:total_price) OrderArticle.human_attribute_name(:total_price)
] ]
else
[
params[:first],
params[:second],
params[:third],
params[:fourth],
params[:fifth],
params[:sixth],
params[:seventh]
]
end
end end
def data def data
@object.order_articles.ordered.includes([:article, :article_price]).all.map do |oa| @object.order_articles.ordered.includes([:article, :article_price]).all.map do |oa|
yield [ yield [
match_params(oa, header[0]), oa.units_to_order,
match_params(oa, header[1]), oa.article.order_number,
match_params(oa, header[2]), oa.article.name,
match_params(oa, header[3]), oa.article.unit,
match_params(oa, header[4]), oa.price.unit_quantity > 1 ? oa.price.unit_quantity : nil,
match_params(oa, header[5]), number_to_currency(oa.price.price * oa.price.unit_quantity),
match_params(oa, header[6]) number_to_currency(oa.total_price)
] ]
end end
end end
def match_params(object, attribute)
case attribute
when OrderArticle.human_attribute_name(:units_to_order)
object.units_to_order
when Article.human_attribute_name(:order_number)
object.article.order_number
when Article.human_attribute_name(:name)
object.article.name
when Article.human_attribute_name(:unit)
object.article.unit
when Article.human_attribute_name(:unit_quantity_short)
object.price.unit_quantity > 1 ? object.price.unit_quantity : nil
when ArticlePrice.human_attribute_name(:price)
number_to_currency(object.price.price * object.price.unit_quantity)
when OrderArticle.human_attribute_name(:total_price)
number_to_currency(object.total_price)
end
end
end end

View file

@ -1,59 +0,0 @@
class QuantityUnit
def initialize(quantity, unit)
@quantity = quantity
@unit = unit
end
def self.parse(number_with_unit)
# remove whitespace
number_with_unit = number_with_unit.gsub(/\s+/, '')
# to lowercase
number_with_unit = number_with_unit.downcase
# remove numerical part
number = number_with_unit.gsub(/[^0-9.,]/, '')
# remove unit part
unit = number_with_unit.gsub(/[^a-zA-Z]/, '')
# convert comma to dot
number = number.gsub(',', '.')
# convert to float
number = number.to_f
return nil unless unit.in?(%w[g kg l ml])
QuantityUnit.new(number, unit)
end
def scale_price_to_base_unit(price)
return nil unless price.is_a?(Numeric)
factor = if @unit == 'kg' || @unit == 'l'
1
elsif @unit == 'g' || @unit == 'ml'
1000
end
scaled_price = price / @quantity * factor
scaled_price.round(2)
base_unit = if @unit == 'kg' || @unit == 'g'
'kg'
elsif @unit == 'l' || @unit == 'ml'
'L'
end
[scaled_price, base_unit]
end
def to_s
"#{@quantity} #{@unit}"
end
def quantity
@quantity
end
def unit
@unit
end
end

View file

@ -20,7 +20,6 @@ class RenderCsv
end end
data { |d| csv << d } data { |d| csv << d }
end end
ret << I18n.t('.orders.articles.prices_sum') << ";" << "#{number_to_currency(@object.sum(:gross))}/#{number_to_currency(@object.sum(:net))}" if @options[:custom_csv]
ret.encode(@options[:encoding], invalid: :replace, undef: :replace) ret.encode(@options[:encoding], invalid: :replace, undef: :replace)
end end

View file

@ -81,7 +81,7 @@ class Supplier < ApplicationRecord
all_order_numbers = [] all_order_numbers = []
updated_article_pairs, outlisted_articles, new_articles = [], [], [] updated_article_pairs, outlisted_articles, new_articles = [], [], []
custom_codes_path = File.join(Rails.root, "config", "custom_codes.yml") custom_codes_path = File.join(Rails.root, "config", "custom_codes.yml")
opts = options.except(:convert_units, :outlist_absent, :update_category) opts = options.except(:convert_units, :outlist_absent)
custom_codes_file_path = custom_codes_path if File.exist?(custom_codes_path) custom_codes_file_path = custom_codes_path if File.exist?(custom_codes_path)
FoodsoftArticleImport.parse(file, custom_file_path: custom_codes_file_path, type: type, **opts) do |new_attrs, status, line| FoodsoftArticleImport.parse(file, custom_file_path: custom_codes_file_path, type: type, **opts) do |new_attrs, status, line|
article = articles.undeleted.where(order_number: new_attrs[:order_number]).first article = articles.undeleted.where(order_number: new_attrs[:order_number]).first

View file

@ -1,15 +0,0 @@
%h4= t '.title'
%hr
%table.table-condensed
%thead
%th= t '.package_fill_level'
%tbody
%tr{class: "missing-none"}
%td= t '.missing_none'
%tr{class: "missing-few"}
%td= t '.missing_few'
%tr{class: "missing-many"}
%td= t '.missing_many'
%hr
%b= t('.tolerance') + ':'
= t '.tolerance_explained'

View file

@ -22,41 +22,54 @@
- title t('.title'), false - title t('.title'), false
.alert.alert-error#balance-alert{style: ('display:none')}
=t 'group_orders.errors.balance_alert'
.row-fluid .row-fluid
.span2 .well.pull-left
.well = close_button :alert
= render 'switch_order', current_order: @order %h2= @order.name
.well %dl.dl-horizontal
= render 'explanations' - unless @order.note.blank?
.well.span9 %dt= heading_helper Order, :note
%h2.span9= t '.sub_title', order_name: @order.name %dd= @order.note
.span3 %dt= heading_helper Order, :created_by
%table.table-condensed %dd= show_user_link(@order.created_by)
-if @order.ends %dt= heading_helper Order, :ends
%tr %dd= format_time(@order.ends)
%td= heading_helper(Order, :ends) + ': ' %dt= heading_helper Order, :pickup
%td= format_time(@order.ends) %dd= format_date(@order.pickup)
- unless @order.stockit? or @order.supplier.min_order_quantity.blank? - unless @order.stockit? or @order.supplier.min_order_quantity.blank?
%tr %dt= heading_helper Supplier, :min_order_quantity, short: true
%td= heading_helper(Supplier, :min_order_quantity) %dd= @order.supplier.min_order_quantity
%td= number_to_currency(@order.supplier.min_order_quantity) %dt= t '.sum_amount'
%tr %dd= number_to_currency @order.sum
%td= t('group_orders.form.sum_amount') + ':' - unless @group_order.new_record?
%td= number_to_currency(@order.sum) %dt= heading_helper GroupOrder, :updated_by
%hr %dd
.form-search.pull-right = show_user(@group_order.updated_by)
(#{format_time(@group_order.updated_on)})
%dt= heading_helper Ordergroup, :account_balance
%dd= number_to_currency(@ordering_data[:account_balance])
- unless FoodsoftConfig[:charge_members_manually]
%dt= heading_helper Ordergroup, :available_funds
%dd= number_to_currency(@ordering_data[:available_funds])
.well.pull-right
= close_button :alert
= render 'switch_order', current_order: @order
.row-fluid
.well.clear
.form-search
.input-append .input-append
= text_field_tag :article, params[:article], placeholder: t('.search_article'), class: 'search-query delayed-search resettable' = text_field_tag :article, params[:article], placeholder: t('.search_article'), class: 'search-query delayed-search resettable'
%button.add-on.btn.reset-search{:type => :button, :title => t('.reset_article_search')} %button.add-on.btn.reset-search{:type => :button, :title => t('.reset_article_search')}
%i.icon.icon-remove %i.icon.icon-remove
= form_for @group_order do |f| = form_for @group_order do |f|
= f.hidden_field :lock_version = f.hidden_field :lock_version
= f.hidden_field :order_id = f.hidden_field :order_id
= f.hidden_field :updated_by_user_id = f.hidden_field :updated_by_user_id
= f.hidden_field :ordergroup_id = f.hidden_field :ordergroup_id
%table.table %table.table.table-hover
%thead %thead
%tr %tr
%th= heading_helper Article, :name %th= heading_helper Article, :name
@ -64,7 +77,6 @@
%th{style: 'width:120px'}= heading_helper StockArticle, :supplier %th{style: 'width:120px'}= heading_helper StockArticle, :supplier
%th{style: "width:13px;"} %th{style: "width:13px;"}
%th{style: "width:4.5em;"}= t '.price' %th{style: "width:4.5em;"}= t '.price'
%th{style: "width:4.5em;"}= t '.price_per_base_unit'
%th{style: "width:4.5em;"}= heading_helper Article, :unit %th{style: "width:4.5em;"}= heading_helper Article, :unit
- unless @order.stockit? - unless @order.stockit?
%th{style: "width:70px;"}= heading_helper OrderArticle, :missing_units, short: true %th{style: "width:70px;"}= heading_helper OrderArticle, :missing_units, short: true
@ -82,13 +94,12 @@
%i.icon-tag %i.icon-tag
%td{colspan: "9"} %td{colspan: "9"}
- order_articles.each do |order_article| - order_articles.each do |order_article|
%tr{class: "#{cycle('even', 'odd', name: 'articles')} order-article #{get_missing_units_css_class(@ordering_data[:order_articles][order_article.id][:missing_units])}", valign: "top", tabindex: "0"} %tr{class: "#{cycle('even', 'odd', name: 'articles')} order-article #{get_missing_units_css_class(@ordering_data[:order_articles][order_article.id][:missing_units])}", valign: "top"}
%td.name= order_article.article.name %td.name= order_article.article.name
- if @order.stockit? - if @order.stockit?
%td= truncate order_article.article.supplier.name, length: 15 %td= truncate order_article.article.supplier.name, length: 15
%td= h order_article.article.origin %td= h order_article.article.origin
%td= number_to_currency(@ordering_data[:order_articles][order_article.id][:price]) %td= number_to_currency(@ordering_data[:order_articles][order_article.id][:price])
%td= price_per_base_unit(article: order_article.article, price: @ordering_data[:order_articles][order_article.id][:price])
%td= order_article.article.unit %td= order_article.article.unit
%td %td
- if @order.stockit? - if @order.stockit?
@ -97,16 +108,15 @@
%span{id: "missing_units_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:missing_units] %span{id: "missing_units_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:missing_units]
%td.quantity %td.quantity
.outer{style: "diyplay: inline-block; float: left; width: 50px;"}
%input{id: "q_#{order_article.id}", name: "group_order[group_order_articles_attributes][#{order_article.id}][quantity]", type: "hidden", value: @ordering_data[:order_articles][order_article.id][:quantity], 'data-min' => (@ordering_data[:order_articles][order_article.id][:quantity] if @order.boxfill?), 'data-max' => (@ordering_data[:order_articles][order_article.id][:quantity]+@ordering_data[:order_articles][order_article.id][:missing_units] if @order.boxfill?)}/ %input{id: "q_#{order_article.id}", name: "group_order[group_order_articles_attributes][#{order_article.id}][quantity]", type: "hidden", value: @ordering_data[:order_articles][order_article.id][:quantity], 'data-min' => (@ordering_data[:order_articles][order_article.id][:quantity] if @order.boxfill?), 'data-max' => (@ordering_data[:order_articles][order_article.id][:quantity]+@ordering_data[:order_articles][order_article.id][:missing_units] if @order.boxfill?)}/
%span.used{id: "q_used_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:used_quantity] %span.used{id: "q_used_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:used_quantity]
+ +
%span.unused{id: "q_unused_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:quantity] - @ordering_data[:order_articles][order_article.id][:used_quantity] %span.unused{id: "q_unused_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:quantity] - @ordering_data[:order_articles][order_article.id][:used_quantity]
.btn-group .btn-group
%a.btn.btn-ordering{'data-decrease_quantity' => order_article.id}
%i.icon-minus
%a.btn.btn-ordering{'data-increase_quantity' => order_article.id} %a.btn.btn-ordering{'data-increase_quantity' => order_article.id}
%i.icon-plus %i.icon-plus
%a.btn.btn-ordering{'data-decrease_quantity' => order_article.id}
%i.icon-minus
%td.tolerance{style: ('display:none' if @order.stockit?)} %td.tolerance{style: ('display:none' if @order.stockit?)}
%input{id: "t_#{order_article.id}", name: "group_order[group_order_articles_attributes][#{order_article.id}][tolerance]", type: "hidden", value: @ordering_data[:order_articles][order_article.id][:tolerance], 'data-min' => (@ordering_data[:order_articles][order_article.id][:tolerance] if @order.boxfill?)}/ %input{id: "t_#{order_article.id}", name: "group_order[group_order_articles_attributes][#{order_article.id}][tolerance]", type: "hidden", value: @ordering_data[:order_articles][order_article.id][:tolerance], 'data-min' => (@ordering_data[:order_articles][order_article.id][:tolerance] if @order.boxfill?)}/
@ -115,10 +125,10 @@
+ +
%span.unused{id: "t_unused_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:tolerance] - @ordering_data[:order_articles][order_article.id][:used_tolerance] %span.unused{id: "t_unused_#{order_article.id}"}= @ordering_data[:order_articles][order_article.id][:tolerance] - @ordering_data[:order_articles][order_article.id][:used_tolerance]
.btn-group .btn-group
%a.btn.btn-ordering{'data-decrease_tolerance' => order_article.id}
%i.icon-minus
%a.btn.btn-ordering{'data-increase_tolerance' => order_article.id} %a.btn.btn-ordering{'data-increase_tolerance' => order_article.id}
%i.icon-plus %i.icon-plus
%a.btn.btn-ordering{'data-decrease_tolerance' => order_article.id}
%i.icon-minus
%td{id: "td_price_#{order_article.id}", style: "text-align:right; padding-right:10px; width:4em"} %td{id: "td_price_#{order_article.id}", style: "text-align:right; padding-right:10px; width:4em"}
%span{id: "price_#{order_article.id}_display"}= number_to_currency(@ordering_data[:order_articles][order_article.id][:total_price]) %span{id: "price_#{order_article.id}_display"}= number_to_currency(@ordering_data[:order_articles][order_article.id][:total_price])
@ -144,7 +154,25 @@
#order-footer #order-footer
#info-box #info-box
#total-sum #total-sum
= render 'total_sum' %table
%tr
%td= t('.total_sum_amount') + ':'
%td.currency
%span#total_price= number_to_currency(@group_order.price)
%tr
- if FoodsoftConfig[:charge_members_manually]
- old_balance = @ordering_data[:account_balance]
%td= heading_helper(Ordergroup, :account_balance) + ':'
%td.currency= number_to_currency(@ordering_data[:account_balance])
- else
- old_balance = @ordering_data[:available_funds]
%td= heading_helper(Ordergroup, :available_funds) + ':'
%td.currency= number_to_currency(@ordering_data[:available_funds])
%tr
%td= t('.new_funds') + ':'
%td.currency
%strong
%span#new_balance= number_to_currency(old_balance - @group_order.price)
#order-button #order-button
= submit_tag( t('.action_save'), id: 'submit_button', class: 'btn btn-primary' ) = submit_tag( t('.action_save'), id: 'submit_button', class: 'btn btn-primary' )
#{link_to t('ui.or_cancel'), group_orders_path} #{link_to t('ui.or_cancel'), group_orders_path}

View file

@ -1,10 +1,9 @@
- orders = Order.open.started - orders = Order.open.started.reject{ |order| order == current_order }
- unless orders.empty? - unless orders.empty?
%ul.nav.nav-pills.nav-stacked %h2= t '.title'
.nav-header= t '.title' %ul.unstyled
%li= link_to t('ui.overview'), :group_orders
- orders.each do |order| - orders.each do |order|
.btn-small.pull-right %li
=link_to_ordering(order, style: (order == current_order ? 'color: white' : '' ), 'data-confirm_switch_order' => true){ t 'ui.edit' } = link_to_ordering(order, 'data-confirm_switch_order' => true)
%li( class="#{ order == current_order ? 'active' : ''}") - if order.ends
=link_to_ordering(order, show: true, 'data-confirm_switch_order' => true) = t '.remaining', remaining: time_ago_in_words(order.ends)

View file

@ -1,19 +0,0 @@
%table
%tr
%td= t('group_orders.form.total_sum_amount') + ':'
%td.currency
%span#total_price= number_to_currency(@group_order.price)
%tr
- if FoodsoftConfig[:charge_members_manually]
- old_balance = @ordering_data[:account_balance]
%td= heading_helper(Ordergroup, :account_balance) + ':'
%td.currency= number_to_currency(@ordering_data[:account_balance])
- else
- old_balance = @ordering_data[:available_funds]
%td= heading_helper(Ordergroup, :available_funds) + ':'
%td.currency= number_to_currency(@ordering_data[:available_funds])
%tr
%td= t('group_orders.form.new_funds') + ':'
%td.currency
%strong
%span#new_balance= number_to_currency(old_balance - @group_order.price)

View file

@ -18,13 +18,10 @@
%th= heading_helper Ordergroup, :available_funds %th= heading_helper Ordergroup, :available_funds
%th.numeric= number_to_currency(@ordergroup.get_available_funds) %th.numeric= number_to_currency(@ordergroup.get_available_funds)
.row-fluid
.span9
= render :partial => "shared/open_orders", :locals => {:ordergroup => @ordergroup} = render :partial => "shared/open_orders", :locals => {:ordergroup => @ordergroup}
// finished orders // finished orders
- unless @finished_not_closed_orders_including_group_order.empty? - unless @finished_not_closed_orders_including_group_order.empty?
.row-fluid
.span9
%section %section
%h2= t '.finished_orders.title' %h2= t '.finished_orders.title'
= render partial: 'orders', locals: {orders: @finished_not_closed_orders_including_group_order, pagination: false} = render partial: 'orders', locals: {orders: @finished_not_closed_orders_including_group_order, pagination: false}
@ -35,8 +32,6 @@
// closed orders // closed orders
- unless @closed_orders_including_group_order.empty? - unless @closed_orders_including_group_order.empty?
.row-fluid
.span9
%section %section
%h2= t '.closed_orders.title' %h2= t '.closed_orders.title'
= render partial: 'orders', locals: {orders: @closed_orders_including_group_order, pagination: false} = render partial: 'orders', locals: {orders: @closed_orders_including_group_order, pagination: false}

View file

@ -7,52 +7,44 @@
- title t('.title', order: @order.name) - title t('.title', order: @order.name)
.row-fluid .row-fluid
.well.pull-left
.well.span2 // Order summary
= render 'switch_order', current_order: @order
.well.span9
%h2= t '.articles.title'
%dl.dl-horizontal %dl.dl-horizontal
// Name
%dt= heading_helper Order, :name %dt= heading_helper Order, :name
%dd= @order.name %dd= @order.name
// Order Ends %dt= heading_helper Order, :note
%dd= @order.note
%dt= heading_helper Order, :ends %dt= heading_helper Order, :ends
%dd= format_time(@order.ends) %dd= format_time(@order.ends)
// Pickup
- unless @order.pickup.blank?
%dt= heading_helper Order, :pickup %dt= heading_helper Order, :pickup
%dd= format_date(@order.pickup) %dd= format_date(@order.pickup)
// Min Order Quantity %dt= heading_helper GroupOrder, :price
- unless @order.stockit? or @order.supplier.min_order_quantity.blank?
%dt= heading_helper Supplier, :min_order_quantity, short: true
%dd= @order.supplier.min_order_quantity
// Group Order Sum Amount
%dt= t 'group_orders.form.sum_amount'
%dd= number_to_currency @order.sum
// Created By
%dt= heading_helper Order, :created_by
%dd= show_user_link(@order.created_by)
// Updated By
- unless @group_order.new_record?
%dt= heading_helper GroupOrder, :updated_by
%dd %dd
= show_user(@group_order.updated_by) - if @group_order
(#{format_time(@group_order.updated_on)}) = number_to_currency(@group_order.price)
// Closed By - else
= t '.not_ordered'
- if @group_order && @group_order.transport
%dt= heading_helper GroupOrder, :transport
%dd= number_to_currency(@group_order.transport)
%dt= heading_helper GroupOrder, :total
%dd= number_to_currency(@group_order.total)
- if @order.closed? - if @order.closed?
%dt= heading_helper Order, :closed_by %dt= heading_helper Order, :closed_by
%dd= show_user_link @order.updated_by %dd= show_user_link @order.updated_by
// Note %p= link_to t('.comment'), "#comments"
- unless @order.note.blank?
%dt= heading_helper Order, :note .well.pull-right
%dd= @order.note = close_button :alert
= render 'switch_order', current_order: @order
// Article box // Article box
%section %section
%h2= t '.articles.title'
.column_content#result .column_content#result
- if @group_order - if @group_order
%p= link_to t('.articles.show_hide'), '#', 'data-toggle-this' => 'tr.ignored' %p.pull-right= link_to t('.articles.show_hide'), '#', 'data-toggle-this' => 'tr.ignored'
%p= link_to(t('.articles.edit_order'), edit_group_order_path(@group_order, order_id: @order.id), class: 'btn btn-primary') if @order.open?
%table.table.table-hover %table.table.table-hover
%thead %thead
%tr %tr
@ -105,15 +97,15 @@
%th= number_to_currency(@group_order.total) %th= number_to_currency(@group_order.total)
%br/ %br/
= link_to_top = link_to_top
%p.pull-right= link_to(t('.articles.edit_order'), edit_group_order_path(@group_order, order_id: @order.id), class: 'btn btn-primary') if @order.open?
- else - else
- if @order.open? - if @order.open?
= t '.articles.not_ordered_msg' = t '.articles.not_ordered_msg'
= link_to t('.articles.order_now'), action: "order", id: @order = link_to t('.articles.order_now'), action: "order", id: @order
- else - else
= t '.articles.order_closed_msg' = t '.articles.order_closed_msg'
// Comments box // Comments box
%hr %section
%h2= t '.comments.title' %h2= t '.comments.title'
#comments #comments
= render 'shared/comments', comments: @order.comments = render 'shared/comments', comments: @order.comments

View file

@ -1,15 +0,0 @@
= simple_form_for :custom_csv,format: :csv, :url => order_path(@order, view: @view, format: :csv), method: :get do |f|
.modal-header
= close_button :modal
.h3=I18n.t('.orders.custom_csv.description')
.modal-body
= f.input :first, as: :select, collection: custom_csv_collection, label: "1. " + I18n.t('.orders.custom_csv.column')
= f.input :second, as: :select, collection: custom_csv_collection, required: false, label: "2. " + I18n.t('.orders.custom_csv.column')
= f.input :third, as: :select, collection: custom_csv_collection, required: false, label: "3. " + I18n.t('.orders.custom_csv.column')
= f.input :fourth, as: :select, collection: custom_csv_collection, required: false, label: "4. " + I18n.t('.orders.custom_csv.column')
= f.input :fifth, as: :select, collection: custom_csv_collection, required: false, label: "5. " + I18n.t('.orders.custom_csv.column')
= f.input :sixth, as: :select, collection: custom_csv_collection, required: false, label: "6. " + I18n.t('.orders.custom_csv.column')
= f.input :seventh, as: :select, collection: custom_csv_collection, required: false, label: "7. " + I18n.t('.orders.custom_csv.column')
.modal-footer
= link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'}
= f.submit class: 'btn btn-primary'

View file

@ -1,3 +0,0 @@
$('#modalContainer').html('#{j(render("custom_csv_form"))}');
$('#modalContainer').modal();
$('#modalContainer').submit(function() {$('#modalContainer').modal('hide');});

View file

@ -9,7 +9,6 @@
%thead %thead
%tr %tr
%th= heading_helper Order, :name %th= heading_helper Order, :name
%th
%th= heading_helper Order, :pickup %th= heading_helper Order, :pickup
%th= heading_helper Order, :ends %th= heading_helper Order, :ends
%th= t '.who_ordered' %th= t '.who_ordered'
@ -18,23 +17,21 @@
- total = 0 - total = 0
- orders.each do |order| - orders.each do |order|
%tr %tr
%td %td= link_to_ordering(order)
= link_to_ordering(order, show: true)
%td
.btn-small= link_to_ordering(order){ t 'ui.edit' }
%td= format_date(order.pickup) unless order.pickup.nil? %td= format_date(order.pickup) unless order.pickup.nil?
%td= format_time(order.ends) unless order.ends.nil? %td= format_time(order.ends) unless order.ends.nil?
- if group_order = order.group_order(ordergroup) - if group_order = order.group_order(ordergroup)
- total += group_order.price - total += group_order.price
%td= "#{show_user group_order.updated_by} (#{format_time(group_order.updated_on)})" %td= "#{show_user group_order.updated_by} (#{format_time(group_order.updated_on)})"
%td.numeric %td.numeric
= link_to_ordering(order, show: true) do
= number_to_currency(group_order.price) = number_to_currency(group_order.price)
- else - else
%td{:colspan => 2} %td{:colspan => 2}
- if total > 0 - if total > 0
%tfooter %tfooter
%tr %tr
%th(colspan="4") %th(colspan="3")
%th= t('.total_sum') + ':' %th= t('.total_sum') + ':'
%th.numeric= number_to_currency(total) %th.numeric= number_to_currency(total)
- else - else

View file

@ -10,4 +10,3 @@
- unless order.stockit? - unless order.stockit?
%li= link_to t('.fax_txt'), order_path(order, format: :txt), {title: t('.download_file')} %li= link_to t('.fax_txt'), order_path(order, format: :txt), {title: t('.download_file')}
%li= link_to t('.fax_csv'), order_path(order, format: :csv), {title: t('.download_file')} %li= link_to t('.fax_csv'), order_path(order, format: :csv), {title: t('.download_file')}
%li= link_to t('.custom_csv'), custom_csv_order_path(order), remote: true

View file

@ -1046,33 +1046,17 @@ de:
error_stale: In der Zwischenzeit hat jemand anderes auch bestellt, daher konnte die Bestellung nicht aktualisiert werden. error_stale: In der Zwischenzeit hat jemand anderes auch bestellt, daher konnte die Bestellung nicht aktualisiert werden.
notice: Die Bestellung wurde gespeichert. notice: Die Bestellung wurde gespeichert.
errors: errors:
balance_alert: Kontostand im Minus
closed: Diese Bestellung ist bereits abgeschlossen. closed: Diese Bestellung ist bereits abgeschlossen.
no_member: Du bist kein Mitglieder einer Bestellgruppe. no_member: Du bist kein Mitglieder einer Bestellgruppe.
notfound: Fehlerhafte URL, das ist nicht Deine Bestellung. notfound: Fehlerhafte URL, das ist nicht Deine Bestellung.
explanations:
package_fill_level: |
Gebindefüllstand
missing_none: |
Voll
missing_few: |
Wenig fehlt
missing_many: |
Viel fehlt
title: Erklärungen
tolerance_explained: |
Zusätzliche Menge die du bestellen würdest, damit das Gebinde voll wird.
tolerance: Toleranz
form: form:
action_save: Bestellung speichern action_save: Bestellung speichern
new_funds: Neuer Kontostand new_funds: Neuer Kontostand
price: Preis price: Preis
price_per_base_unit: Grundpreis
reset_article_search: Suche zurücksetzen reset_article_search: Suche zurücksetzen
search_article: Artikel suchen... search_article: Artikel suchen...
sum_amount: Gesamtbestellmenge bisher sum_amount: Gesamtbestellmenge bisher
title: Bestellen title: Bestellen
sub_title: Bestellung für %{order_name} aufgeben
total_sum_amount: Gesamtbetrag total_sum_amount: Gesamtbetrag
total_tolerance: Gesamt-Toleranz total_tolerance: Gesamt-Toleranz
units: Gebinde units: Gebinde
@ -1116,6 +1100,7 @@ de:
sum: Summe sum: Summe
title: Dein Bestellergebnis für %{order} title: Dein Bestellergebnis für %{order}
switch_order: switch_order:
remaining: "noch %{remaining}"
title: Laufende Bestellungen title: Laufende Bestellungen
update: update:
error_general: Die Bestellung konnte nicht aktualisiert werden, da ein Fehler auftrat. error_general: Die Bestellung konnte nicht aktualisiert werden, da ein Fehler auftrat.
@ -1480,9 +1465,6 @@ de:
units_ordered: Bestellte Einheiten units_ordered: Bestellte Einheiten
create: create:
notice: Die Bestellung wurde erstellt. notice: Die Bestellung wurde erstellt.
custom_csv:
description: Wähle die Attribute und deren Reihenfolge für die zu erzeugende CSV Datei
column: Spalte
edit: edit:
title: 'Bestellung bearbeiten: %{name}' title: 'Bestellung bearbeiten: %{name}'
edit_amount: edit_amount:

View file

@ -1048,33 +1048,17 @@ en:
error_stale: Someone else has ordered in the meantime, couldn't update the order. error_stale: Someone else has ordered in the meantime, couldn't update the order.
notice: The order was saved. notice: The order was saved.
errors: errors:
balance_alert: Negative account balance
closed: This order is already closed. closed: This order is already closed.
no_member: You are not a member of an ordergroup. no_member: You are not a member of an ordergroup.
notfound: Incorrect URL, this is not your order. notfound: Incorrect URL, this is not your order.
explanations:
title: Explanations
tolerance: Tolerance
package_fill_level: |
Package Fill Level
missing_none: |
No more missing
missing_few: |
Few missing
missing_many: |
Many missing
tolerance_explained: |
Additional amount you would buy to fill a wholesale package
form: form:
action_save: Save order action_save: Save order
new_funds: New account balance new_funds: New account balance
price: Price price: Price
price_per_base_unit: Base price
reset_article_search: Reset search reset_article_search: Reset search
search_article: Search for articles... search_article: Search for articles...
sum_amount: Current amount sum_amount: Current amount
title: Orders title: Orders
sub_title: Place order for %{order_name}
total_sum_amount: Total amount total_sum_amount: Total amount
total_tolerance: Total tolerance total_tolerance: Total tolerance
units: Units units: Units
@ -1118,6 +1102,7 @@ en:
sum: Sum sum: Sum
title: Your order result for %{order} title: Your order result for %{order}
switch_order: switch_order:
remaining: "%{remaining} remaining"
title: Current orders title: Current orders
update: update:
error_general: The order couldnt be updated due to a bug. error_general: The order couldnt be updated due to a bug.
@ -1490,9 +1475,6 @@ en:
units_ordered: Units ordered units_ordered: Units ordered
create: create:
notice: The order was created. notice: The order was created.
custom_csv:
description: Please choose the order as well as the attributes for the csv file
column: column
edit: edit:
title: 'Edit order: %{name}' title: 'Edit order: %{name}'
edit_amount: edit_amount:
@ -1646,7 +1628,6 @@ en:
who_ordered: Who ordered? who_ordered: Who ordered?
order_download_button: order_download_button:
article_pdf: Article PDF article_pdf: Article PDF
custom_csv: Custom CSV
download_file: Download file download_file: Download file
fax_csv: Fax CSV fax_csv: Fax CSV
fax_pdf: Fax PDF fax_pdf: Fax PDF

View file

@ -930,7 +930,6 @@ es:
action_save: Guardar pedido action_save: Guardar pedido
new_funds: Nuevo balance de cuenta new_funds: Nuevo balance de cuenta
price: Precio price: Precio
price_per_base_unit: Precio de base
reset_article_search: Reinicia la búsqueda reset_article_search: Reinicia la búsqueda
search_article: Busca artículos... search_article: Busca artículos...
sum_amount: Cantidad actual sum_amount: Cantidad actual
@ -1262,9 +1261,6 @@ es:
units_ordered: Unidades pedidas units_ordered: Unidades pedidas
create: create:
notice: Se ha creado el pedido notice: Se ha creado el pedido
custom_csv:
description: Por favor elija el orden de los atributos así como los atributos para el archivo csv
column: columna
edit: edit:
title: 'Edita pedido: %{name}' title: 'Edita pedido: %{name}'
edit_amount: edit_amount:

View file

@ -678,7 +678,6 @@ fr:
action_save: Enregistrer ta commande action_save: Enregistrer ta commande
new_funds: Nouveau solde new_funds: Nouveau solde
price: Prix price: Prix
price_per_base_unit: Prix de base
reset_article_search: Réinitialiser la recherche reset_article_search: Réinitialiser la recherche
search_article: Rechercher des produits... search_article: Rechercher des produits...
sum_amount: Quantité déjà commandée sum_amount: Quantité déjà commandée
@ -1012,9 +1011,6 @@ fr:
units_ordered: Unités commandées units_ordered: Unités commandées
create: create:
notice: La commande a bien été définie. notice: La commande a bien été définie.
custom_csv:
description: Veuillez choisir l'ordre des attributs ainsi que les attributs pour le fichier csv
column: colonne
edit: edit:
title: 'Modifier la commande: %{name}' title: 'Modifier la commande: %{name}'
edit_amount: edit_amount:

View file

@ -1018,7 +1018,6 @@ nl:
error_stale: In de tussentijd heeft iemand anders ook bestelt, daarom kon de bestelling niet bijgewerkt worden. error_stale: In de tussentijd heeft iemand anders ook bestelt, daarom kon de bestelling niet bijgewerkt worden.
notice: Bestelling opgeslagen. notice: Bestelling opgeslagen.
errors: errors:
balance_alert: Accountsaldo in het rood
closed: Deze bestelling is al gesloten. closed: Deze bestelling is al gesloten.
no_member: Je bent geen lid van dit huishouden. no_member: Je bent geen lid van dit huishouden.
notfound: Foute URL, dit is niet jouw bestelling. notfound: Foute URL, dit is niet jouw bestelling.
@ -1026,12 +1025,10 @@ nl:
action_save: Bestelling opslaan action_save: Bestelling opslaan
new_funds: Nieuw tegoed new_funds: Nieuw tegoed
price: Prijs price: Prijs
price_per_base_unit: Basisprjis
reset_article_search: Alles tonen reset_article_search: Alles tonen
search_article: Artikelen zoeken... search_article: Artikelen zoeken...
sum_amount: Huidig totaalbedrag sum_amount: Huidig totaalbedrag
title: Bestellen title: Bestellen
sub_title: Plaats bestelling voor %{order_name}
total_sum_amount: Totalbedrag total_sum_amount: Totalbedrag
total_tolerance: Totale tolerantie total_tolerance: Totale tolerantie
units: Eenheden units: Eenheden
@ -1075,6 +1072,7 @@ nl:
sum: Som sum: Som
title: Jouw bestelling voor %{order} title: Jouw bestelling voor %{order}
switch_order: switch_order:
remaining: "nog %{remaining}"
title: Lopende bestellingen title: Lopende bestellingen
update: update:
error_general: Er is een probleem opgetreden, de bestelling kon niet bijgewerkt worden. error_general: Er is een probleem opgetreden, de bestelling kon niet bijgewerkt worden.
@ -1442,9 +1440,6 @@ nl:
units_ordered: Bestelde eenheden units_ordered: Bestelde eenheden
create: create:
notice: De bestelling is aangemaakt. notice: De bestelling is aangemaakt.
custom_csv:
description: Kies de volgorde van de attributen en de attributen voor het csv-bestand
column: kolom
edit: edit:
title: 'Bestelling aanpassen: %{name}' title: 'Bestelling aanpassen: %{name}'
edit_amount: edit_amount:

View file

@ -47,7 +47,6 @@ Rails.application.routes.draw do
get :receive get :receive
post :receive post :receive
get :custom_csv
get :receive_on_order_article_create get :receive_on_order_article_create
get :receive_on_order_article_update get :receive_on_order_article_update
end end

View file

@ -1,4 +1,4 @@
# default seed is minimal # default seed is minimal
require Rails.root.join('db/seeds/demo-seeds.rb') require Rails.root.join('db/seeds/minimal.seeds.rb')
# to generate new seeds, use the seed_dumper gem # to generate new seeds, use the seed_dumper gem

View file

@ -39,9 +39,6 @@ nkn_supplier = Supplier.create!(
) )
chocolate_category = ArticleCategory.create!(name: "Schokolade") chocolate_category = ArticleCategory.create!(name: "Schokolade")
obst_category = ArticleCategory.create!(name: "Obst, Gemüse, Sprossen, Pilze")
nudeln_category = ArticleCategory.create!(name: "Nudeln, Trockenfrüchte, Müsli")
reis_category = ArticleCategory.create!(name: "Getreide, Ölsaaten. Nußkerne")
Article.create!( Article.create!(
name: "Vollmilch-Schokolade", name: "Vollmilch-Schokolade",
@ -98,7 +95,7 @@ seed_order(supplier_id: chocolate_supplier.id, starts: 0.days.ago, ends: 7.days.
apple = Article.create!( apple = Article.create!(
name: "Äpfel Elstar", name: "Äpfel Elstar",
supplier_id: nkn_supplier.id, supplier_id: nkn_supplier.id,
article_category_id: obst_category.id, article_category_id: supplier_category.id,
manufacturer: "Obsthof Bruno Brugger", manufacturer: "Obsthof Bruno Brugger",
origin: "D", price: 3.49, tax: 7.0, origin: "D", price: 3.49, tax: 7.0,
unit: "1kg", unit_quantity: 10, unit: "1kg", unit_quantity: 10,
@ -108,7 +105,7 @@ apple = Article.create!(
brokkoli = Article.create!( brokkoli = Article.create!(
name: "Brokkoli", name: "Brokkoli",
supplier_id: nkn_supplier.id, supplier_id: nkn_supplier.id,
article_category_id: obst_category.id, article_category_id: supplier_category.id,
manufacturer: "Fattoria degli Orsi", manufacturer: "Fattoria degli Orsi",
origin: "IT", price: 2.89, tax: 7.0, origin: "IT", price: 2.89, tax: 7.0,
unit: "400g", unit_quantity: 6, unit: "400g", unit_quantity: 6,
@ -118,17 +115,17 @@ brokkoli = Article.create!(
tomatoes = Article.create!( tomatoes = Article.create!(
name: "Tomaten", name: "Tomaten",
supplier_id: nkn_supplier.id, supplier_id: nkn_supplier.id,
article_category_id: obst_category.id, article_category_id: supplier_category.id,
manufacturer: "Terra di Puglia", manufacturer: "Terra di Puglia",
origin: "IT", price: 2.89, tax: 7.0, origin: "IT", price: 2.89, tax: 7.0,
unit: "500g", unit_quantity: 20, unit: "500g", unit_quantity: 20,
note: "pomodori italiani, demeter", note: "pomodori italianio, demeter",
availability: true, order_number: "7") availability: true, order_number: "7")
rice = Article.create!( rice = Article.create!(
name: "Reis", name: "Reis",
supplier_id: nkn_supplier.id, supplier_id: nkn_supplier.id,
article_category_id: reis_category.id, article_category_id: supplier_category.id,
manufacturer: "Finck", manufacturer: "Finck",
origin: "D", price: 3.29, tax: 7.0, origin: "D", price: 3.29, tax: 7.0,
unit: "3kg", unit_quantity: 10, unit: "3kg", unit_quantity: 10,
@ -138,7 +135,7 @@ rice = Article.create!(
spaghetti = Article.create!( spaghetti = Article.create!(
name: "Spaghetti", name: "Spaghetti",
supplier_id: nkn_supplier.id, supplier_id: nkn_supplier.id,
article_category_id: nudeln_category.id, article_category_id: supplier_category.id,
manufacturer: "Pastificio Zanellini spa", manufacturer: "Pastificio Zanellini spa",
origin: "D", price: 2.89, tax: 7.0, origin: "D", price: 2.89, tax: 7.0,
unit: "500g", unit_quantity: 4, unit: "500g", unit_quantity: 4,

View file

@ -1,7 +1,7 @@
BNN;3;0;Naturkost Nord, Hamburg;T;Angebot Nr. 0922;EUR;20220905;20221001;20220825;837;1 BNN;3;0;Naturkost Nord, Hamburg;T;Angebot Nr. 0922;EUR;20220905;20221001;20220825;837;1
5;;;;4280001958081;4280001958203;Žpfel Elstar;erntefrisch und knackig;;;obb;;D;C%;DE-™KO-001;120;0301;10;55;;1;10 x1kg;10;1kg;1;N;;;;1,41;;;;1;;;4,49;2,89;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;1;; 5;;;;4280001958081;4280001958203;Žpfel Elstar;erntefrisch und knackig;;;obb;;D;C%;DE-™KO-001;120;0301;10;55;;1;10 x1Kg;10;1Kg;1;N;;;;1,41;;;;1;;;4,49;2,89;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;1;;
6;;;;4280001958081;4280001958203;Brokkoli;gesund und lecker;;;fig;;IT;C%;DE-™KO-001;120;03;10;55;;1;6 x400g;6;400g;1;N;;;;1,41;;;;1;;;4,49;2,99;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;2,5;; 6;;;;4280001958081;4280001958203;Brokkoli;aus der Erde;;;VIB;;IT;C%;DE-™KO-001;120;03;10;55;;1;4 x400g;4;400g;1;N;;;;1,41;;;;1;;;4,49;3,20;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;2,5;;
7;;;;4280001958081;4280001958203;Tomaten;pomodori italiani, demeter;;;TDP;;IT;C%;DE-™KO-001;120;03;10;55;;1;20 x500g;20;500g;1;N;;;;1,41;;;;1;;;4,49;3,19;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;2;; 7;;;;4280001958081;4280001958203;Tomaten;Datteltomaten, demeter;;;TDP;;IT;C%;DE-™KO-001;120;03;10;55;;1;20 x500g;20;500g;1;N;;;;1,41;;;;1;;;4,49;3,00;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;2;;
8;;;;4280001958081;4280001958203;Reis;Reis im Vorratssack, demeter;;;FIN;;D;C%;DE-™KO-001;120;05;10;55;;1;12 x3k;12;3kg;1;N;;;;1,41;;;;1;;;4,49;3,49;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;0,3;; 8;;;;4280001958081;4280001958203;Reis;Reispfannen geeignet;;;FIN;;D;C%;DE-™KO-001;120;05;10;55;;1;12 x300g;12;300g;1;N;;;;1,41;;;;1;;;4,49;3,00;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;3,333333;;
9;;;;4280001958081;4280001958203;Spaghetti;100% italienisches Hartweizengrieá;;;ZLN;;D;C%;DE-™KO-001;120;06;10;55;;1;4 x500g;4;500g;1;N;;;;1,41;;;;1;;;4,49;2,99;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;2;; 9;;;;4280001958081;4280001958203;Spaghetti;Vollkorn;;;ZLN;;D;C%;DE-™KO-001;120;06;10;55;;1;4 x500g;4;500g;1;N;;;;1,41;;;;1;;;4,49;3,00;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;2;;
10;;;;4280001958081;4280001958203;Kartoffeln;vorwiegend festkochend;;;rsh;;D;C%;DE-™KO-001;120;0311;10;55;;1;6 x5Kg;6;5Kg;1;N;;;;1,41;;;;1;;;4,49;3,00;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;0.2;; 10;;;;4280001958081;4280001958203;Kartoffeln;vorwiegend festkochend;;;rsh;;D;C%;DE-™KO-001;120;0311;10;55;;1;6 x5Kg;6;5Kg;1;N;;;;1,41;;;;1;;;4,49;3,00;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;0.2;;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

View file

@ -8,10 +8,7 @@ feature ArticlesController do
before { login user } before { login user }
describe ':index', js: true do describe ':index', js: true do
before { before { visit supplier_articles_path(supplier_id: supplier.id) }
login user
visit supplier_articles_path(supplier_id: supplier.id)
}
it 'can visit supplier articles path' do it 'can visit supplier articles path' do
expect(page).to have_content(supplier.name) expect(page).to have_content(supplier.name)

View file

@ -1,22 +0,0 @@
require_relative '../spec_helper'
describe QuantityUnit do
it "parses a string correctly" do
qu = QuantityUnit.parse("1.5 k g"); expect([qu.quantity, qu.unit]).to eq([1.5, "kg"])
qu = QuantityUnit.parse(" 1,5 kg"); expect([qu.quantity, qu.unit]).to eq([1.5, "kg"])
qu = QuantityUnit.parse("1500 g"); expect([qu.quantity, qu.unit]).to eq([1500, "g"])
qu = QuantityUnit.parse("1.5L "); expect([qu.quantity, qu.unit]).to eq([1.5, "l"])
qu = QuantityUnit.parse("2400mL"); expect([qu.quantity, qu.unit]).to eq([2400, "ml"])
end
it "scales prices correctly" do
qu = QuantityUnit.new(1.5, "kg")
expect(qu.scale_price_to_base_unit(12.34)).to eq([8.23, "kg"])
qu = QuantityUnit.new(1500, "g")
expect(qu.scale_price_to_base_unit(12.34)).to eq([8.23, "kg"])
qu = QuantityUnit.new(1.5, "l")
expect(qu.scale_price_to_base_unit(12.34)).to eq([8.23, "L"])
qu = QuantityUnit.new(2400, "ml")
expect(qu.scale_price_to_base_unit(12.34)).to eq([5.14, "L"])
end
end