Compare commits

..

66 Commits

Author SHA1 Message Date
Matt-Yorkley
49de11567b Report environment correctly in Bugsnag JS 2020-03-31 17:16:13 +01:00
Matt-Yorkley
3af0365c6b Rename partial to bugsnag_js for clarity 2020-03-31 17:16:13 +01:00
Matt-Yorkley
be92b0049b Move conditional inside partial and use default key as fallback 2020-03-31 17:16:13 +01:00
Matt-Yorkley
a1c94d0d9f Add bugsnag js script to admin layout above all.js 2020-03-31 17:16:13 +01:00
Maikel Linke
f6bb8a9a04 Add Bugsnag JS logging 2020-03-31 17:16:13 +01:00
Maikel
d254df7ccc Merge pull request #5073 from Matt-Yorkley/mobile-checkout
[Mobile UX] Order cycle section updates
2020-03-27 15:34:19 +11:00
Pau Pérez Fabregat
8caf10f634 Merge pull request #5079 from openfoodfoundation/dependabot/bundler/unicorn-5.5.4
Bump unicorn from 5.5.3 to 5.5.4
2020-03-26 17:32:17 +01:00
Matt-Yorkley
2966dd9536 Update all locales with the latest Transifex translations 2020-03-26 14:25:34 +01:00
Matt-Yorkley
21e1c0ed0b Merge pull request #5025 from openfoodfoundation/transifex
Transifex
2020-03-26 14:22:38 +01:00
Matt-Yorkley
48b99d02b9 Merge pull request #5060 from Matt-Yorkley/weight-calculator
Fix weight calculator
2020-03-26 14:19:21 +01:00
Pau Pérez Fabregat
f17a2eeaea Merge pull request #5062 from luisramos0/prop_bug
Fix broken new property button in properties page (regression from removing spree_backend)
2020-03-26 11:35:47 +01:00
Pau Pérez Fabregat
18419d0276 Merge pull request #5043 from luisramos0/fix_cookies
Fix cookies policy helper spec in rails 4
2020-03-26 11:23:49 +01:00
Pau Pérez Fabregat
bd19d8b0bd Merge pull request #5042 from luisramos0/api_base
Make explicit the namespace of the BaseController for api controllers
2020-03-26 11:21:27 +01:00
Maikel Linke
4bcd665379 Handle all line items without unit_value in weight calculation 2020-03-26 17:13:29 +11:00
Matt-Yorkley
e63dbcfa89 Fix some SCSS linting warnings 2020-03-25 23:12:23 +01:00
Matt-Yorkley
c3283adcf5 Show full-width ordercycle subheader on tablet and below 2020-03-25 23:12:23 +01:00
Matt-Yorkley
b2ed69831b Adjust style contexts 2020-03-25 23:12:23 +01:00
Matt-Yorkley
7daba62f43 Update colours for different order cycle sidebar cases 2020-03-25 23:12:23 +01:00
Matt-Yorkley
a08020490d Define new colour and use variable where already in use 2020-03-25 23:12:23 +01:00
Matt-Yorkley
eb4d970bc7 Adjust positioning for order cycle sidebar 2020-03-25 23:12:23 +01:00
Matt-Yorkley
7a3549209f Use 4 columns on checkout sidebar 2020-03-25 23:12:23 +01:00
Matt-Yorkley
52ebd1b402 Remove order cycle popovers; these styles are no longer used 2020-03-25 23:12:08 +01:00
Matt-Yorkley
a3a26f704f Extract re-used box-shadow style 2020-03-25 23:07:39 +01:00
Matt-Yorkley
cff8f6dd96 Add box-shadow to distributor header for cart, checkout, and order confirmation pages 2020-03-25 23:07:39 +01:00
Matt-Yorkley
81537d92cf Extract styles for distributor header
These styles are used in shop, cart, checkout, order confirmation. Not just shop.
2020-03-25 23:07:39 +01:00
Matt-Yorkley
91e88bd028 Allow conditional use of order cycle sidebar
We need to re-use the "shopping_shared/header" partial in multiple places, but we don't always want the (nested) order cycle sidebar inside it.
2020-03-25 23:07:39 +01:00
Matt-Yorkley
f5e254a105 Remove quick fix for hiding oc selector 2020-03-25 23:07:39 +01:00
Sigmund Petersen
b41b5d0395 Update Slack invitation link 2020-03-25 20:38:45 +01:00
dependabot-preview[bot]
296d2e5edb Bump unicorn from 5.5.3 to 5.5.4
Bumps [unicorn](https://yhbt.net/unicorn/) from 5.5.3 to 5.5.4.

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-25 19:17:31 +00:00
Luis Ramos
ac0a62e962 Merge pull request #5050 from Matt-Yorkley/bullet_tweaks
Performance tweaks 2
2020-03-25 18:32:49 +00:00
Luis Ramos
2c5db8935b Merge pull request #5022 from Matt-Yorkley/performance_tweaks
Performance tweaks
2020-03-25 15:42:07 +00:00
Luis Ramos
24c8f38111 Restructure spec to avoid variable names with numbers 2020-03-25 15:48:57 +01:00
Luis Ramos
b801bffcd9 Merge pull request #5030 from Matt-Yorkley/reports-loading
Improve reports performance
2020-03-25 12:54:34 +00:00
Luis Ramos
434b68b019 Merge pull request #5048 from Matt-Yorkley/3-0-user-spec
Ensure perform_deliveries is correctly set in user email spec
2020-03-25 11:52:43 +00:00
Luis Ramos
9af4bb9757 Use create instead of build so that we test with callbacks 2020-03-25 11:22:40 +00:00
Matt-Yorkley
d847560d7c Fix rubocop issues 2020-03-25 10:15:03 +01:00
Pau Pérez Fabregat
87fae15434 Merge pull request #4909 from luisramos0/line_items_spec
Adapt line_items_spec to work in the rails 4 branch as well
2020-03-25 10:05:20 +01:00
Matt-Yorkley
e27f7a4301 Ensure perform_deliveries is correctly set when testing user confirmation emails 2020-03-25 08:42:21 +01:00
Luis Ramos
bddfa95eb5 Fix broken new property button in properties page 2020-03-24 21:50:49 +00:00
Matt-Yorkley
ef0fb18fda Fix calculations for weight when variant.unit_value is zero 2020-03-24 22:05:55 +01:00
Matt-Yorkley
87ee4bbebc Add spec for current problematic behaviour 2020-03-24 20:09:54 +01:00
Transifex-Openfoodnetwork
f5567e556b Updating translations for config/locales/pt_BR.yml 2020-03-25 02:22:31 +11:00
Matt-Yorkley
54c3c73ed2 Fix duplicate key in hash 2020-03-24 12:46:21 +01:00
Luis Ramos
8dfdc9bc15 Merge pull request #5056 from openfoodfoundation/dependabot/bundler/rubocop-rails-2.5.0
Bump rubocop-rails from 2.4.2 to 2.5.0
2020-03-24 11:22:21 +00:00
Matt-Yorkley
36aa52736a Refactor order filtering logic 2020-03-24 09:36:59 +01:00
Matt-Yorkley
ac38b2735c Eager-load data in OrdersController 2020-03-23 22:38:57 +01:00
Matt-Yorkley
8b93c5ab56 Invert conditionals for better readability 2020-03-23 22:38:57 +01:00
Matt-Yorkley
434f98fb46 Fix insane N+1 in Package
The #ships_with? method was being called ~800 times when loading the admin order edit page (with Aus production data), and triggering a new query each time it was called.
2020-03-23 22:38:57 +01:00
Matt-Yorkley
c82c54873c Pluck :id when querying active distributors for serializer data 2020-03-23 22:38:55 +01:00
dependabot-preview[bot]
de180d32bf Bump rubocop-rails from 2.4.2 to 2.5.0
Bumps [rubocop-rails](https://github.com/rubocop-hq/rubocop-rails) from 2.4.2 to 2.5.0.
- [Release notes](https://github.com/rubocop-hq/rubocop-rails/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop-rails/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop-rails/compare/v2.4.2...v2.5.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-23 20:37:57 +00:00
Matt-Yorkley
5b481c19cc Eager-load country in Producers controller 2020-03-23 19:33:15 +01:00
Matt-Yorkley
7110f9e6ee Eager-load data used in EnterpriseGroupsController
Cuts page load time by ~75%
2020-03-23 19:33:13 +01:00
Transifex-Openfoodnetwork
63d748b2a4 Updating translations for config/locales/pt_BR.yml 2020-03-24 03:32:23 +11:00
Transifex-Openfoodnetwork
310906c7da Updating translations for config/locales/en_NZ.yml 2020-03-23 15:49:19 +11:00
Transifex-Openfoodnetwork
b81843921b Updating translations for config/locales/en_CA.yml 2020-03-23 08:57:54 +11:00
Matt-Yorkley
dd0e135a4d Add test coverage for Permissions::Order with search_params 2020-03-22 11:45:40 +01:00
Luis Ramos
0f2c5d379a Add test locales to I18n.available_locales before the test and reset them afterwards 2020-03-22 10:32:16 +00:00
Luis Ramos
a29f263041 Make explicit the namespace of the BaseController for api controllers 2020-03-22 09:55:07 +00:00
Matt-Yorkley
0b878dd0a2 Use named scope for finding line_items in a set of orders 2020-03-21 09:45:35 +01:00
Matt-Yorkley
45c204017f Improve reports performance
Add the scoping from the search filters for reports into the logic of building sets like `editable_line_items` before combining them into the query to reduce the number of `line_item` ids in the IN clause.
2020-03-21 09:45:33 +01:00
Transifex-Openfoodnetwork
fa98a8ea17 Updating translations for config/locales/en_NZ.yml 2020-03-21 15:19:06 +11:00
Transifex-Openfoodnetwork
7582df2771 Updating translations for config/locales/en_CA.yml 2020-03-21 00:37:37 +11:00
Transifex-Openfoodnetwork
c788f1ae57 Updating translations for config/locales/it.yml 2020-03-20 19:32:35 +11:00
Matt-Yorkley
7baa875a91 Fix big N+1 issues in enterprises#edit for superadmin
The page is usable now as superadmin. Roughly 10x faster...
2020-03-19 23:41:47 +01:00
Matt-Yorkley
3de887e1d8 Remove some N+1s relating to address (found with bullet gem) 2020-03-19 23:41:47 +01:00
Luis Ramos
1382bb3c6b For some reason in rails 4/spree 2.1 setting the line item as adjustable on the adjustment is not enough to populate line_item.adjustments. Here we make this assignment explicit fixing the spec in rails 4 2020-03-03 15:04:51 +00:00
75 changed files with 598 additions and 230 deletions

View File

@@ -499,7 +499,7 @@ GEM
parallel (1.19.1)
paranoia (1.3.4)
activerecord (~> 3.1)
parser (2.7.0.4)
parser (2.7.0.5)
ast (~> 2.4.0)
paypal-sdk-core (0.2.10)
multi_json (~> 1.0)
@@ -612,7 +612,8 @@ GEM
rexml
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 1.7)
rubocop-rails (2.4.2)
rubocop-rails (2.5.0)
activesupport
rack (>= 1.1)
rubocop (>= 0.72.0)
ruby-progressbar (1.10.1)
@@ -671,7 +672,7 @@ GEM
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
unicode-display_width (1.6.1)
unicorn (5.5.3)
unicorn (5.5.4)
kgio (~> 2.6)
raindrops (~> 0.7)
unicorn-rails (2.2.1)

View File

@@ -35,7 +35,7 @@ We use [BrowserStack](https://www.browserstack.com/) as a manual testing tool. B
Copyright (c) 2012 - 2020 Open Food Foundation, released under the AGPL licence.
[survey]: https://docs.google.com/a/eaterprises.com.au/forms/d/1zxR5vSiU9CigJ9cEaC8-eJLgYid8CR8er7PPH9Mc-30/edit#
[slack-invite]: https://join.slack.com/t/openfoodnetwork/shared_invite/enQtNzY3NDEwNzM2MDM0LWFmNGRhNDUwYzNmNWNkYmFkMzgxNDg1OTg1ODNjNWY4Y2FhNDIwNmE4ZWI0OThiMGNmZjFkODczNGZiYTJmNWI
[slack-invite]: https://join.slack.com/t/openfoodnetwork/shared_invite/zt-9sjkjdlu-r02kUMP1zbrTgUhZhYPF~A
[contributor-guide]: https://ofn-user-guide.gitbook.io/ofn-contributor-guide/who-are-we
[ofn-install]: https://github.com/openfoodfoundation/ofn-install
[super-admin-guide]: https://ofn-user-guide.gitbook.io/ofn-super-admin-guide

View File

@@ -1,77 +1,13 @@
@import "typography";
.darkswarm navigation {
display: block;
background: $white;
distributor.details {
box-sizing: border-box;
display: block;
min-height: 150px;
padding: 30px 0 20px 0;
position: relative;
select {
width: 200px;
}
img {
display: block;
height: 100px;
width: 100px;
margin-right: 12px;
}
location {
@include headingFont;
}
@media all and (max-width: 768px) {
location, location + small {
display: block;
}
}
#distributor_title h3 {
margin-top: 0;
padding-top: 0.45em;
@media all and (max-width: 768px) {
margin-bottom: 8px;
}
}
}
}
ordercycle {
float: right;
background: $teal-400;
color: $white;
background: $grey-050;
color: $grey-800;
width: 100%;
border-radius: 0.5em 0.5em 0 0;
position: absolute;
right: 1em;
padding: 1em;
margin-top: 3em;
height: 7.6em;
&.requires-selection {
background-color: $red-700;
.order-cycle-select {
border: 1px solid $red-500;
.select-label {
background-color: rgba($red-500, 0.5);
}
select {
background-color: $white;
background-image: url('/assets/black-caret.svg');
color: $grey-500;
font-style: italic;
}
}
}
margin-top: 1em;
padding: 1em 1.25em 0;
p {
max-width: 400px;
@@ -97,14 +33,10 @@ ordercycle {
}
}
@media all and (max-width: 768px) {
@media all and (max-width: 480px) {
padding: 0.5em 1em 0.75em;
}
form.custom {
text-align: center;
}
.order-cycle-select {
border: 1px solid $teal-300;
display: inline-block;
@@ -164,9 +96,44 @@ ordercycle {
closing {
@include headingFont;
color: $white;
color: $grey-800;
font-size: 1.25rem;
display: block;
padding: 0.5em 0;
span {
@media all and (max-width: 768px) {
font-size: 0.875em;
}
}
}
}
shop ordercycle {
background: $teal-400;
color: $white;
&.requires-selection {
background-color: $red-700;
.order-cycle-select {
border: 1px solid $red-500;
.select-label {
background-color: rgba($red-500, 0.5);
}
select {
background-color: $white;
background-image: url('/assets/black-caret.svg');
color: $grey-500;
font-style: italic;
}
}
}
closing {
color: $white;
padding: 0 0 12px;
@media all and (max-width: 1024px) {
@@ -181,11 +148,25 @@ ordercycle {
float: none;
padding: 0 0 10px;
}
}
span {
@media all and (max-width: 768px) {
font-size: 0.875em;
}
form.custom {
text-align: center;
}
}
shop navigation ordercycle {
margin-top: 3em;
padding: 1em;
height: 7.6em;
position: absolute;
right: 1em;
}
.sub-header {
form {
p {
margin-bottom: 0.75em;
}
}
}

View File

@@ -1,31 +1,6 @@
@import "mixins";
@import "branding";
// .darkswarm
// product
ordercycle {
.joyride-tip-guide {
background-color: $clr-brick;
.joyride-nub.right {
border-color: $clr-brick !important;
border-top-color: transparent !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
}
p {
margin: 0;
font-weight: 700;
}
@media all and (max-width: 768px) {
z-index: 10;
}
}
}
// Pop over
// Foundation overrides
.joyride-tip-guide.price_breakdown {

View File

@@ -27,7 +27,7 @@
}
products .filter-box {
background: #f7f7f7;
background: $grey-050;
}
.filter-box {

View File

@@ -1,5 +1,7 @@
$ofn-brand: #f27052;
$distributor-header-shadow: 0 1px 0 rgba(0, 0, 0, 0.05), 0 8px 6px -6px rgba(0, 0, 0, 0.2);
// e.g. australia, uk, norway specific color
$ofn-grey: #808184;
@@ -39,6 +41,8 @@ $light-grey-transparency: rgba(0, 0, 0, .1);
$black: #000;
$white: #fff;
$grey-050: #f7f7f7;
$grey-400: #bbb;
$grey-500: #999;
$grey-600: #777;

View File

@@ -44,7 +44,7 @@ checkout {
h5 {
margin: 0;
padding: 0.65em;
background: #f7f7f7;
background: $grey-050;
.label {
font-size: 1em;

View File

@@ -0,0 +1,52 @@
@import 'typography';
section {
:not(shop) navigation {
box-shadow: $distributor-header-shadow;
}
}
.darkswarm navigation {
display: block;
background: $white;
position: relative;
z-index: 2;
.details {
box-sizing: border-box;
display: block;
min-height: 150px;
padding: 30px 0 0;
position: relative;
select {
width: 200px;
}
img {
display: block;
height: 100px;
width: 100px;
margin-right: 12px;
}
location {
@include headingFont;
}
@media all and (max-width: 768px) {
location, location + small {
display: block;
}
}
#distributor_title h3 {
margin-top: 0;
padding-top: 0.45em;
@media all and (max-width: 768px) {
margin-bottom: 8px;
}
}
}
}

View File

@@ -7,7 +7,7 @@
.tab-buttons {
color: $dark-grey;
box-shadow: 0 1px 0 rgba(0,0,0,0.05), 0 8px 6px -6px rgba(0, 0, 0, 0.2);
box-shadow: $distributor-header-shadow;
.columns {
display: flex;

View File

@@ -32,6 +32,12 @@ module Admin
end
end
def edit
@object = Enterprise.where(permalink: params[:id]).
includes(users: [:ship_address, :bill_address]).first
super
end
def welcome
render layout: "spree/layouts/bare_admin"
end
@@ -172,12 +178,14 @@ module Admin
end
def load_methods_and_fees
enterprise_payment_methods = @enterprise.payment_methods.to_a
enterprise_shipping_methods = @enterprise.shipping_methods.to_a
# rubocop:disable Style/TernaryParentheses
@payment_methods = Spree::PaymentMethod.managed_by(spree_current_user).sort_by! do |pm|
[(@enterprise.payment_methods.include? pm) ? 0 : 1, pm.name]
[(enterprise_payment_methods.include? pm) ? 0 : 1, pm.name]
end
@shipping_methods = Spree::ShippingMethod.managed_by(spree_current_user).sort_by! do |sm|
[(@enterprise.shipping_methods.include? sm) ? 0 : 1, sm.name]
[(enterprise_shipping_methods.include? sm) ? 0 : 1, sm.name]
end
# rubocop:enable Style/TernaryParentheses

View File

@@ -1,5 +1,5 @@
module Api
class CustomersController < BaseController
class CustomersController < Api::BaseController
skip_authorization_check only: :index
def index

View File

@@ -1,5 +1,5 @@
module Api
class EnterpriseAttachmentController < BaseController
class EnterpriseAttachmentController < Api::BaseController
class MissingImplementationError < StandardError; end
class UnknownEnterpriseAuthorizationActionError < StandardError; end

View File

@@ -1,5 +1,5 @@
module Api
class EnterpriseFeesController < BaseController
class EnterpriseFeesController < Api::BaseController
respond_to :json
def destroy

View File

@@ -1,5 +1,5 @@
module Api
class LogosController < EnterpriseAttachmentController
class LogosController < Api::EnterpriseAttachmentController
private
def attachment_name

View File

@@ -1,5 +1,5 @@
module Api
class OrderCyclesController < BaseController
class OrderCyclesController < Api::BaseController
include EnterprisesHelper
respond_to :json

View File

@@ -1,5 +1,5 @@
module Api
class OrdersController < BaseController
class OrdersController < Api::BaseController
def show
authorize! :read, order
render json: order, serializer: Api::OrderDetailedSerializer, current_order: order

View File

@@ -1,5 +1,5 @@
module Api
class ProductImagesController < BaseController
class ProductImagesController < Api::BaseController
respond_to :json
def update_product_image

View File

@@ -1,5 +1,5 @@
module Api
class PromoImagesController < EnterpriseAttachmentController
class PromoImagesController < Api::EnterpriseAttachmentController
private
def attachment_name

View File

@@ -8,7 +8,7 @@ class ProducersController < BaseController
.activated
.visible
.is_primary_producer
.includes(address: :state)
.includes(address: [:state, :country])
.includes(:properties)
.includes(supplied_products: :properties)
.all

View File

@@ -8,7 +8,7 @@ class ShopsController < BaseController
.activated
.visible
.is_distributor
.includes(address: :state)
.includes(address: [:state, :country])
.includes(:properties)
.includes(supplied_products: :properties)
.all

View File

@@ -109,7 +109,10 @@ module Spree
private
def load_order
@order = Order.find_by_number!(params[:id], include: :adjustments) if params[:id]
if params[:id]
@order = Order.includes(:adjustments, :shipments, line_items: :adjustments).
find_by_number!(params[:id])
end
authorize! action, @order
end
@@ -128,7 +131,7 @@ module Spree
def load_distribution_choices
@shops = Enterprise.is_distributor.managed_by(spree_current_user).by_name
ocs = OrderCycle.managed_by(spree_current_user)
ocs = OrderCycle.includes(:suppliers, :distributors).managed_by(spree_current_user)
@order_cycles = ocs.soonest_closing +
ocs.soonest_opening +
ocs.closed +

View File

@@ -3,10 +3,10 @@ require 'open_food_network/enterprise_injection_data'
module InjectionHelper
include SerializerHelper
def inject_enterprises(enterprises = Enterprise.activated.includes(address: :state).all)
def inject_enterprises(enterprises = nil)
inject_json_ams(
"enterprises",
enterprises,
enterprises || default_enterprise_query,
Api::EnterpriseSerializer,
enterprise_injection_data
)
@@ -17,7 +17,10 @@ module InjectionHelper
inject_json_ams(
"groups",
EnterpriseGroup.on_front_page.by_position.select(select_only).includes(address: :state).all,
EnterpriseGroup.on_front_page.by_position.select(select_only).
includes(enterprises: [:shipping_methods, { address: [:state, :country] }],
address: :state).
all,
Api::GroupListSerializer
)
end
@@ -35,13 +38,21 @@ module InjectionHelper
inject_json_ams(
"enterprises",
Enterprise.activated.visible.select(select_only).includes(address: :state).all,
Enterprise.activated.visible.select(select_only).includes(address: [:state, :country]).all,
Api::EnterpriseShopfrontListSerializer
)
end
def inject_enterprise_and_relatives
inject_json_ams "enterprises", current_distributor.relatives_including_self.activated.includes(address: :state).all, Api::EnterpriseSerializer, enterprise_injection_data
enterprises_and_relatives = current_distributor.
relatives_including_self.
activated.
includes(address: [:state, :country]).
all
inject_json_ams "enterprises",
enterprises_and_relatives,
Api::EnterpriseSerializer, enterprise_injection_data
end
def inject_group_enterprises
@@ -138,6 +149,10 @@ module InjectionHelper
private
def default_enterprise_query
Enterprise.activated.includes(address: [:state, :country]).all
end
def enterprise_injection_data
@enterprise_injection_data ||= OpenFoodNetwork::EnterpriseInjectionData.new
{ data: @enterprise_injection_data }

View File

@@ -5,5 +5,21 @@ module Spree
def variant_options(v, _options = {})
v.options_text
end
# Overriden to eager-load :states
def available_countries
checkout_zone = Zone.find_by_name(Spree::Config[:checkout_zone])
countries = if checkout_zone && checkout_zone.kind == 'country'
checkout_zone.country_list
else
Country.includes(:states).all
end
countries.collect do |country|
country.name = Spree.t(country.iso, scope: 'country_names', default: country.name)
country
end.sort { |a, b| a.name <=> b.name }
end
end
end

View File

@@ -54,6 +54,8 @@ module Calculator
# Customer ends up getting 350mL (line_item.final_weight_volume) of wine
# that represent 2.8 (quantity_implied_in_final_weight_volume) glasses of wine
def quantity_implied_in_final_weight_volume(line_item)
return line_item.quantity if line_item.variant.unit_value.to_f.zero?
(1.0 * line_item.final_weight_volume / line_item.variant.unit_value).round(3)
end

View File

@@ -36,6 +36,10 @@ Spree::LineItem.class_eval do
end
}
scope :in_orders, lambda { |orders|
where(order_id: orders)
}
# Find line items that are from order sorted by variant name and unit value
scope :sorted_by_name_and_unit_value, -> {
joins(variant: :product).

View File

@@ -24,8 +24,10 @@ module Stock
#
# @return [Array<Spree::ShippingMethod>]
def shipping_methods
super.delete_if do |shipping_method|
!ships_with?(order.distributor, shipping_method)
available_shipping_methods = super.to_a
available_shipping_methods.keep_if do |shipping_method|
ships_with?(order.distributor.shipping_methods.to_a, shipping_method)
end
end
@@ -33,11 +35,11 @@ module Stock
# Checks whether the given distributor provides the specified shipping method
#
# @param distributor [Spree::Enterprise]
# @param shipping_methods [Array<Spree::ShippingMethod>]
# @param shipping_method [Spree::ShippingMethod]
# @return [Boolean]
def ships_with?(distributor, shipping_method)
distributor.shipping_methods.include?(shipping_method)
def ships_with?(shipping_methods, shipping_method)
shipping_methods.include?(shipping_method)
end
end
end

View File

@@ -107,7 +107,7 @@ module Api
end
def active
data.active_distributors.andand.include? enterprise
data.active_distributor_ids.andand.include? enterprise.id
end
# Map svg icons.

View File

@@ -9,7 +9,7 @@ module Api
end
def active
options[:data].active_distributors.andand.include? object
options[:data].active_distributor_ids.andand.include? object.id
end
end
end

View File

@@ -2,24 +2,28 @@ require 'open_food_network/permissions'
module Permissions
class Order
def initialize(user)
def initialize(user, search_params = nil)
@user = user
@permissions = OpenFoodNetwork::Permissions.new(@user)
@search_params = search_params
end
# Find orders that the user can see
def visible_orders
Spree::Order.
orders = Spree::Order.
with_line_items_variants_and_products_outer.
where(visible_orders_where_values)
filtered_orders(orders)
end
# Any orders that the user can edit
def editable_orders
Spree::Order.where(
managed_orders_where_values.
or(coordinated_orders_where_values)
)
orders = Spree::Order.
where(managed_orders_where_values.
or(coordinated_orders_where_values))
filtered_orders(orders)
end
def visible_line_items
@@ -35,6 +39,18 @@ module Permissions
private
attr_reader :search_params
def filtered_orders(orders)
return orders unless filter_orders?
orders.complete.not_state(:canceled).search(search_params).result
end
def filter_orders?
search_params.present?
end
def visible_orders_where_values
# Grouping keeps the 2 where clauses from produced_orders_where_values inside parentheses
# This way it makes the OR work between the 3 types of orders:

View File

@@ -7,7 +7,6 @@
.darkswarm.footer-pad
- content_for :order_cycle_form do
%closing
= t :checkout_now
%p
@@ -15,16 +14,23 @@
%strong
= pickup_time current_order_cycle
= render partial: "shopping_shared/header", locals: { hide_oc_selector: true }
- content_for :ordercycle_sidebar do
.show-for-large-up.large-4.columns
= render partial: "shopping_shared/order_cycles"
= render partial: "shopping_shared/header"
.sub-header.show-for-medium-down
= render partial: "shopping_shared/order_cycles"
%accordion{"close-others" => "false"}
%checkout.row{"ng-controller" => "CheckoutCtrl"}
.small-12.medium-8.large-9.columns
.small-12.medium-8.columns
- unless spree_current_user
= render partial: "checkout/authentication"
%div{"ng-show" => "enabled", "ng-controller" => "AccordionCtrl"}
= render partial: "checkout/form"
.small-12.medium-4.large-3.columns
.small-12.medium-4.columns
= render partial: "checkout/summary"

View File

@@ -38,6 +38,10 @@
- if oc_select_options.count > 1
%option{value: "", disabled: "", selected: ""}= t :shopping_oc_select
- content_for :ordercycle_sidebar do
.show-for-large-up.large-4.columns
= render partial: "shopping_shared/order_cycles"
= render partial: "shopping_shared/header"
= render partial: "shopping_shared/tabs"

View File

@@ -0,0 +1,10 @@
- bugsnag_js_key = ENV['BUGSNAG_JS_KEY'] || ENV['BUGSNAG_API_KEY']
- if bugsnag_js_key.present?
%script{src: "//d2wy8f7a9ursnm.cloudfront.net/v6/bugsnag.min.js"}
:javascript
window.bugsnagClient = bugsnag({
apiKey: "#{bugsnag_js_key}",
beforeSend: function (report) {
report.app.releaseStage = "#{Rails.env}"
}
});

View File

@@ -37,6 +37,7 @@
#footer
%loading
= render "layouts/bugsnag_js"
%script{:src => "https://js.stripe.com/v3/", :type => "text/javascript"}
%script{src: "//maps.googleapis.com/maps/api/js?libraries=places,geometry#{ ENV['GOOGLE_MAPS_API_KEY'] ? '&key=' + ENV['GOOGLE_MAPS_API_KEY'] : ''} "}
= javascript_include_tag "darkswarm/all"

View File

@@ -10,6 +10,4 @@
= distributor.name
%location= distributor.address.city
- unless defined? hide_oc_selector
.show-for-large-up.large-4.columns
= render partial: "shopping_shared/order_cycles"
= yield :ordercycle_sidebar

View File

@@ -1,2 +1,2 @@
$("#new_property").html('<%= escape_javascript(render :template => "spree/admin/properties/new", :formats => [:html], :handlers => [:erb]) %>');
$("#new_property").html('<%= escape_javascript(render :template => "spree/admin/properties/new", :formats => [:html], :handlers => [:haml]) %>');
$("#new_property_link").parent().hide();

View File

@@ -12,6 +12,7 @@
%link{:href => "//fonts.googleapis.com/css?family=Open+Sans:400italic,600italic,400,600&subset=latin,cyrillic,greek,vietnamese", :rel => "stylesheet", :type => "text/css"}
= stylesheet_link_tag 'admin/all'
= render "layouts/bugsnag_js"
= javascript_include_tag 'admin/all'
= render "spree/admin/shared/translations"

View File

@@ -16,8 +16,15 @@
- else
= @order.distributor.next_collection_at
- content_for :ordercycle_sidebar do
.show-for-large-up.large-4.columns
= render partial: "shopping_shared/order_cycles"
= render partial: "shopping_shared/header"
.sub-header.show-for-medium-down
= render partial: "shopping_shared/order_cycles"
%fieldset.footer-pad
- if @order.line_items.empty?
%div.row{"data-hook" => "empty_cart"}

View File

@@ -37,6 +37,9 @@ SMTP_PASSWORD: 'f00d'
# MAILS_FROM: hello@example.com
# MAIL_BCC: manager@example.com
# Javascript error reporting via Bugsnag.
#BUGSNAG_JS_KEY: ""
# SingleSignOn login for Discourse
#
# DISCOURSE_SSO_SECRET should be a random string. It must be the same as provided to your Discourse instance.

View File

@@ -246,6 +246,8 @@ ar:
notes: ملاحظات
error: خطأ
processing_payment: "معالجة الدفع..."
no_pending_payments: "لا توجد دفعات معلقة"
invalid_payment_state: "حالة الدفع غير صالحة"
filter_results: تصفية النتائج
quantity: الكمية
pick_up: النقل
@@ -1483,6 +1485,7 @@ ar:
shopping_oc_closed_description: "يرجى الانتظار حتى تفتح الدورة التالية (أو اتصل بنا مباشرة لمعرفة ما إذا كان يمكننا قبول أي طلبات متأخرة)"
shopping_oc_last_closed: "آخر دورة تم إغلاق %{distance_of_time} منذ"
shopping_oc_next_open: "تفتح الدورة التالية في %{distance_of_time}"
shopping_oc_select: "اختيار..."
shopping_tabs_home: "الصفحة الرئيسية"
shopping_tabs_shop: "المتجر"
shopping_tabs_about: "حول"
@@ -1864,6 +1867,7 @@ ar:
headline: "تم الانتهاء !"
thanks: "شكرًا لملء تفاصيل %{enterprise}."
login: "يمكنك تغيير أو تحديث شركتك في أي مرحلة من خلال تسجيل الدخول إلى شبكة الغذاء المفتوح والذهاب إلى المسؤول."
action: "انتقل إلى واجهة الشركة"
back: "عودة"
continue: "استمر"
action_or: "أو"
@@ -2278,6 +2282,7 @@ ar:
enterprise_register_success_notice: "تهانينا! اكتمل التسجيل لـ %{enterprise}!"
enterprise_bulk_update_success_notice: "تم تحديث المؤسسات بنجاح"
enterprise_bulk_update_error: 'فشل التحديث'
enterprise_shop_show_error: "المتجر الذي تبحث عنه غير موجود أو غير نشط . يرجى التحقق من المحلات التجارية الأخرى."
order_cycles_create_notice: 'تم إنشاء دورة الطلب الخاصة بك.'
order_cycles_update_notice: 'تم تحديث دورة الطلب.'
order_cycles_bulk_update_notice: 'تم تحديث دورات الطلب.'
@@ -2603,6 +2608,34 @@ ar:
few: "حزم"
many: "حزم"
other: "حزم"
bottle:
zero: "زجاجات"
one: "زجاجة"
two: "زجاجات"
few: "زجاجات"
many: "زجاجات"
other: "زجاجات"
item:
zero: "العناصر"
one: "بند"
two: "العناصر"
few: "العناصر"
many: "العناصر"
other: "المواد"
dozen:
zero: "العشرات"
one: "دزينة"
two: "العشرات"
few: "العشرات"
many: "العشرات"
other: "العشرات"
unit:
zero: "الوحدات"
one: "وحدة"
two: "الوحدات"
few: "الوحدات"
many: "الوحدات"
other: "الوحدات"
producers:
signup:
start_free_profile: "ابدأ بملف تعريف مجاني ، وتوسع عندما تكون جاهزًا!"
@@ -2956,7 +2989,8 @@ ar:
tax_invoice: "فاتورة ضريبية"
code: "الشفرة"
from: "من "
to: "إلى"
to: "فاتورة الى"
shipping: "الشحن"
form:
distribution_fields:
title: "توزيع"

View File

@@ -1425,7 +1425,7 @@ ca:
email_confirm_customer_greeting: "Hola %{name},"
email_confirm_customer_intro_html: "Gràcies per comprar a <strong> %{distributor}</strong>."
email_confirm_customer_number_html: "Confirmació de la comanda <strong> # %{number} </strong>"
email_confirm_customer_details_html: "Aquests són els detalls de la teva comanda de <strong> %{distributor} </ strong>:"
email_confirm_customer_details_html: "Aquests són els detalls de la teva comanda de<strong>%{distributor}</strong>:"
email_confirm_customer_signoff: "Salutacions cordials,"
email_confirm_shop_greeting: "Hola %{name},"
email_confirm_shop_order_html: "Que bé! Tens una nova comanda per <strong> %{distributor} </ strong>."
@@ -3015,7 +3015,6 @@ ca:
tax_invoice: "FACTURA D'IMPOSTOS"
code: "Codi"
from: "De"
to: "Per a"
form:
distribution_fields:
title: "Distribució"

View File

@@ -2927,7 +2927,6 @@ de_DE:
tax_invoice: "Steuerrechnung"
code: "Code"
from: "Von"
to: "Zu"
form:
distribution_fields:
title: "Verteilung"

View File

@@ -2927,7 +2927,6 @@ en_AU:
tax_invoice: "TAX INVOICE"
code: "Code"
from: "From"
to: "To"
form:
distribution_fields:
title: "Distribution"

View File

@@ -2856,7 +2856,6 @@ en_BE:
tax_invoice: "TAX INVOICE"
code: "Code"
from: "From"
to: "To"
form:
distribution_fields:
title: "Distribution"

View File

@@ -3018,7 +3018,8 @@ en_CA:
tax_invoice: "Order Number"
code: "Code"
from: "From"
to: "To"
to: "Bill to"
shipping: "Shipping"
form:
distribution_fields:
title: "Distribution"

View File

@@ -2872,7 +2872,6 @@ en_DE:
tax_invoice: "TAX INVOICE"
code: "Code"
from: "From"
to: "To"
form:
distribution_fields:
title: "Distribution"

View File

@@ -3019,7 +3019,6 @@ en_FR:
tax_invoice: "TAX INVOICE"
code: "Code"
from: "From"
to: "To"
form:
distribution_fields:
title: "Distribution"

View File

@@ -3025,7 +3025,6 @@ en_GB:
tax_invoice: "TAX INVOICE"
code: "Code"
from: "From"
to: "To"
form:
distribution_fields:
title: "Distribution"

View File

@@ -246,6 +246,8 @@ en_NZ:
notes: Notes
error: Error
processing_payment: "Processing payment..."
no_pending_payments: "No pending payments"
invalid_payment_state: "Invalid payment state"
filter_results: Filter Results
quantity: Quantity
pick_up: Pick up
@@ -1484,6 +1486,7 @@ en_NZ:
shopping_oc_closed_description: "Please wait until the next cycle opens (or contact us directly to see if we can accept any late orders)"
shopping_oc_last_closed: "The last cycle closed %{distance_of_time} ago"
shopping_oc_next_open: "The next cycle opens in %{distance_of_time}"
shopping_oc_select: "Select..."
shopping_tabs_home: "Home"
shopping_tabs_shop: "Shop"
shopping_tabs_about: "About"
@@ -1857,6 +1860,7 @@ en_NZ:
headline: "Finished!"
thanks: "Thanks for filling out the details for %{enterprise}."
login: "You can change or update your enterprise at any stage by logging into Open Food Network and going to Admin."
action: "Go to Enterprise Dashboard"
back: "Back"
continue: "Continue"
action_or: "OR"
@@ -2273,6 +2277,7 @@ en_NZ:
enterprise_register_success_notice: "Congratulations! Registration for %{enterprise} is complete!"
enterprise_bulk_update_success_notice: "Enterprises updated successfully"
enterprise_bulk_update_error: 'Update failed'
enterprise_shop_show_error: "The shop you are looking for doesn't exist or is inactive on OFN. Please check other shops."
order_cycles_create_notice: 'Your order cycle has been created.'
order_cycles_update_notice: 'Your order cycle has been updated.'
order_cycles_bulk_update_notice: 'Order cycles have been updated.'
@@ -3014,7 +3019,8 @@ en_NZ:
tax_invoice: "TAX INVOICE"
code: "Code"
from: "From"
to: "To"
to: "Bill to"
shipping: "Shipping"
form:
distribution_fields:
title: "Distribution"

View File

@@ -50,6 +50,8 @@ en_US:
shipping_method_ids: "Shipping Methods"
payment_method_ids: "Payment Methods"
errors:
messages:
inclusion: "is not included in the list"
models:
subscription_validator:
attributes:
@@ -116,7 +118,9 @@ en_US:
email_welcome: "Welcome"
email_registered: "is now part of"
email_userguide_html: "The User Guide with detailed support for setting up your Producer or Hub is here: %{link}"
userguide: "Open Food Network User Guide"
email_admin_html: "You can manage your account by logging into the %{link} or by clicking on the cog in the top right hand side of the homepage, and selecting Administration."
admin_panel: "Admin Panel"
email_community_html: "We also have an online forum for community discussion related to OFN software and the unique challenges of running a food enterprise. You are encouraged to join in. We are constantly evolving and your input into this forum will shape what happens next. %{link}"
join_community: "Join the community"
invite_manager:
@@ -242,6 +246,8 @@ en_US:
notes: Notes
error: Error
processing_payment: "Processing payment..."
no_pending_payments: "No pending payments"
invalid_payment_state: "Invalid payment state"
filter_results: Filter Results
quantity: Quantity
pick_up: Pick up
@@ -434,9 +440,12 @@ en_US:
infinity: "Infinity"
to_order_tip: "Items made to order do not have a set stock level, such as loaves of bread made fresh to order."
back_to_products_list: "Back to products list"
editing_product: "Editing Product"
tabs:
product_details: "Product Details"
group_buy_options: "Group Buy Options"
images: "Images"
variants: "Variants"
product_properties: "Product Properties"
product_import:
title: Product Import
@@ -539,6 +548,7 @@ en_US:
title: Inventory
description: Use this page to manage inventories for your enterprises. Any product details set here will override those set on the 'Products' page
enable_reset?: Enable Stock Reset?
default_stock: "Default stock"
inherit?: Inherit?
add: Add
hide: Hide
@@ -693,6 +703,10 @@ en_US:
enable_subscriptions_false: "Disabled"
enable_subscriptions_true: "Enabled"
shopfront_message: "Shopfront Message"
shopfront_message_placeholder: >
An optional message to welcome customers and explain how to shop with
you. If text is entered here it will be displayed in a home tab when
customers first arrive at your shopfront.
shopfront_message_link_tooltip: "Insert / edit link"
shopfront_message_link_prompt: "Please enter a URL to insert"
shopfront_closed_message: "Shopfront Closed Message"
@@ -830,20 +844,32 @@ en_US:
new:
create: "Create"
cancel: "Cancel"
back_to_list: "Back To List"
edit:
advanced_settings: "Advanced Settings"
save: "Save"
save_and_next: "Save and Next"
next: "Next"
cancel: "Cancel"
back_to_list: "Back To List"
save_and_back_to_list: "Save and Back to List"
choose_products_from: "Choose Products From:"
incoming:
save: "Save"
save_and_next: "Save and Next"
next: "Next"
cancel: "Cancel"
back_to_list: "Back To List"
outgoing:
previous: "Previous"
save: "Save"
save_and_back_to_list: "Save and Back to List"
cancel: "Cancel"
back_to_list: "Back To List"
wizard_progress:
edit: "1. General Settings"
incoming: "2. Incoming Products"
outgoing: "3. Outgoing Products"
exchange_form:
pickup_time_tip: When orders from this OC will be ready for the customer
pickup_instructions_placeholder: "Pick-up instructions"
@@ -1081,10 +1107,13 @@ en_US:
destroy_attachment_does_not_exist: "Logo does not exist"
enterprise_promo_image:
destroy_attachment_does_not_exist: "Promo image does not exist"
orders:
failed_to_update: "Failed to update order"
checkout:
already_ordered:
cart: "cart"
message_html: "You have an order for this order cycle already. Check the %{cart} to see the items you ordered before. You can also cancel items as long as the order cycle is open."
failed: "The checkout failed. Please let us know so that we can process your order."
shops:
hubs:
show_closed_shops: "Show closed shops"
@@ -1255,6 +1284,7 @@ en_US:
saving_credit_card: Saving credit card...
card_has_been_removed: "Your card has been removed (number: %{number})"
card_could_not_be_removed: Sorry, the card could not be removed
invalid_credit_card: "Invalid credit card"
ie_warning_headline: "Your browser is out of date :-("
ie_warning_text: "For the best Open Food Network experience, we strongly recommend upgrading your browser:"
ie_warning_chrome: Download Chrome
@@ -1456,6 +1486,7 @@ en_US:
shopping_oc_closed_description: "Please wait until the next cycle opens (or contact us directly to see if we can accept any late orders)"
shopping_oc_last_closed: "The last cycle closed %{distance_of_time} ago"
shopping_oc_next_open: "The next cycle opens in %{distance_of_time}"
shopping_oc_select: "Select..."
shopping_tabs_home: "Home"
shopping_tabs_shop: "Shop"
shopping_tabs_about: "About"
@@ -1829,6 +1860,7 @@ en_US:
headline: "Finished!"
thanks: "Thanks for filling out the details for %{enterprise}."
login: "You can change or update your enterprise at any stage by logging into Open Food Network and going to Admin."
action: "Go to Enterprise Dashboard"
back: "Back"
continue: "Continue"
action_or: "OR"
@@ -1914,6 +1946,7 @@ en_US:
tax_category: "Tax Category"
calculator: "Calculator"
calculator_values: "Calculator values"
calculator_settings_warning: "If you are changing the calculator type, you must save first before you can edit the calculator settings"
flat_percent_per_item: "Flat Percent (per item)"
flat_rate_per_item: "Flat Rate (per item)"
flat_rate_per_order: "Flat Rate (per order)"
@@ -2244,6 +2277,7 @@ en_US:
enterprise_register_success_notice: "Congratulations! Registration for %{enterprise} is complete!"
enterprise_bulk_update_success_notice: "Enterprises updated successfully"
enterprise_bulk_update_error: 'Update failed'
enterprise_shop_show_error: "The shop you are looking for doesn't exist or is inactive on OFN. Please check other shops."
order_cycles_create_notice: 'Your order cycle has been created.'
order_cycles_update_notice: 'Your order cycle has been updated.'
order_cycles_bulk_update_notice: 'Order cycles have been updated.'
@@ -2395,6 +2429,12 @@ en_US:
severity: Severity
description: Description
resolve: Resolve
exchange_products:
load_more_variants: "Load More Variants"
load_all_variants: "Load All Variants"
select_all_variants: "Select All %{total_number_of_variants} Variants"
variants_loaded: "%{num_of_variants_loaded} of %{total_number_of_variants} Variants Loaded"
loading_variants: "Loading Variants"
tag_rules:
shipping_method_tagged_top: "Shipping methods tagged"
shipping_method_tagged_bottom: "are:"
@@ -2477,6 +2517,7 @@ en_US:
customer_placeholder: "customer@example.org"
valid_email_error: "Please enter a valid email address"
subscriptions:
error_saving: "Error saving subscription"
new:
please_select_a_shop: "Please select a shop"
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
@@ -2552,6 +2593,76 @@ en_US:
signup_or_login: "Start By signing up (or logging in)"
have_an_account: "Already have an account?"
action_login: "Log in now."
inflections:
each:
one: "each"
other: "each"
bunch:
one: "bunch"
other: "bunches"
pack:
one: "pack"
other: "packs"
box:
one: "box"
other: "boxes"
bottle:
one: "bottle"
other: "bottles"
jar:
one: "jar"
other: "jars"
head:
one: "head"
other: "heads"
bag:
one: "bag"
other: "bags"
loaf:
one: "loaf"
other: "loaves"
single:
one: "single"
other: "singles"
tub:
one: "tub"
other: "tubs"
packet:
one: "packet"
other: "packets"
item:
one: "item"
other: "items"
dozen:
one: "dozen"
other: "dozens"
unit:
one: "unit"
other: "units"
serve:
one: "serve"
other: "serves"
tray:
one: "tray"
other: "trays"
piece:
one: "piece"
other: "pieces"
pot:
one: "pot"
other: "pots"
bundle:
one: "bundle"
other: "bundles"
flask:
one: "flask"
other: "flasks"
basket:
one: "basket"
other: "baskets"
sack:
one: "sack"
other: "sacks"
producers:
signup:
start_free_profile: "Start with a free profile, and expand when you're ready!"
@@ -2869,7 +2980,6 @@ en_US:
tax_invoice: "TAX INVOICE"
code: "Code"
from: "From"
to: "To"
form:
distribution_fields:
title: "Distribution"

View File

@@ -2870,7 +2870,6 @@ en_ZA:
tax_invoice: "TAX INVOICE"
code: "Code"
from: "From"
to: "To"
form:
distribution_fields:
title: "Distribution"

View File

@@ -2877,7 +2877,6 @@ es:
tax_invoice: "FACTURA DE IMPUESTOS"
code: "Código"
from: "De"
to: "A"
form:
distribution_fields:
title: "Distribución"

View File

@@ -3049,7 +3049,6 @@ fr:
tax_invoice: "FACTURE"
code: "Code"
from: "De"
to: "A"
form:
distribution_fields:
title: "Distribution"

View File

@@ -2949,7 +2949,6 @@ fr_BE:
tax_invoice: "FACTURE"
code: "Code"
from: "De"
to: "A"
form:
distribution_fields:
title: "Distribution"

View File

@@ -3029,7 +3029,6 @@ fr_CA:
tax_invoice: "FACTURE"
code: "Code"
from: "De"
to: "A"
form:
distribution_fields:
title: "Distribution"

View File

@@ -1394,7 +1394,7 @@ it:
order_delivery_address: Indirizzo di consegna
order_delivery_time: Tempo di consegna
order_special_instructions: "Tue note:"
order_pickup_time: Pronto per la raccolta
order_pickup_time: Pronto per il ritiro
order_pickup_instructions: Istruzioni per la raccolta
order_produce: Produrre
order_total_price: Totale
@@ -1463,7 +1463,7 @@ it:
email_shipping_delivery_time: "Consegna il"
email_shipping_delivery_address: "Indirizzo di consegna"
email_shipping_collection_details: Dettagli della raccolta
email_shipping_collection_time: "Pronto per la raccolta:"
email_shipping_collection_time: "Pronto per il ritiro:"
email_shipping_collection_instructions: "Istruzioni per la raccolta:"
email_special_instructions: "Tue note:"
email_signup_greeting: Ciao!
@@ -3023,7 +3023,6 @@ it:
tax_invoice: "FATTURA DELLE TASSE"
code: "Codice"
from: "Da"
to: "A"
form:
distribution_fields:
title: "Distribuzione"

View File

@@ -3018,7 +3018,6 @@ nb:
tax_invoice: "AVGIFTSFAKTURA"
code: "Kode"
from: "Fra"
to: "Til"
form:
distribution_fields:
title: "Distribusjon"

View File

@@ -2865,7 +2865,6 @@ nl_BE:
tax_invoice: "FACTUUR"
code: "Code"
from: "Van"
to: "tot"
form:
distribution_fields:
title: "Distributie"

View File

@@ -2811,7 +2811,6 @@ pt:
tax_invoice: "FACTURA FISCAL"
code: "Código"
from: "De"
to: "Para"
form:
distribution_fields:
title: "Distribuição"

View File

@@ -175,7 +175,7 @@ pt_BR:
home: "OFB"
title: Open Food Brasil
welcome_to: 'Bem-vindo a'
site_meta_description: "A gente começa pela base. Com agricultores e produtores preparados para contar suas histórias com orgulho e verdade. Com distribuidores prontos para conectar pessoas com produtos de forma justa e honesta. Com os compradores que acreditam que melhores decisões de compras semanais podem..."
site_meta_description: "A nossa proposta é conectar agricultoras/es, produtoras/es e consumidoras/es que estão próximos entre si. Buscamos, assim, potencializar a circulação e a comercialização de produtos agroecológicos, orgânicos e artesanais em circuitos curtos, bem como criar novas formas de relação, orientadas pela troca, diálogo e confiança."
search_by_name: Procurar por nome ou localidade
producers_join: Produtores nacionais estão convidados a se unirem à Open Food Brasil.
charges_sales_tax: Cobra imposto sobre bens e serviços?
@@ -583,7 +583,7 @@ pt_BR:
actions_delete: "Deletar selecionado"
loading: "Carregando pedidos"
no_results: "Nenhum pedido encontrado. "
group_buy_unit_size: "Tamanho de unidade para compras de Grupo"
group_buy_unit_size: "Tamanho da Unidade para Grupo de Compras"
total_qtt_ordered: "Quantidade total do pedido"
max_qtt_ordered: "Quantidade máxima do pedido"
current_fulfilled_units: "Unidades completadas no momento"
@@ -598,7 +598,7 @@ pt_BR:
title: Iniciativas
new_enterprise: Nova iniciativa
producer?: "Produtor?"
package: Embalagem
package: Tipo de Perfil
status: Status
manage: Administrar
form:
@@ -806,7 +806,7 @@ pt_BR:
manage: Administrar
manage_link: Configurações
producer?: "Produtor?"
package: "Embalagem"
package: "Tipo de Perfil"
status: "Status"
new_form:
owner: Proprietário
@@ -1333,28 +1333,28 @@ pt_BR:
cookies_policy_link: "política de cookies"
cookies_accept_button: "Aceitar Cookies"
home_shop: Compre Agora
brandstory_headline: "Alimentos, com liberdade"
brandstory_intro: "Às vezes, a melhor maneira de consertar o sistema é construir um novo..."
brandstory_part1: "Começamos do início. Com agricultores e produtores preparados para contar com orgulho suas verdadeiras histórias. Com distribuidores prontos para conectar pessoas com produtos de forma justa e honesta. Com consumidores que acreditam que melhores decisões de compras podem mudar seriamente o mundo."
brandstory_part2: "Então precisamos de uma forma para tornar isto real. Uma maneira para empoderar todos os que produzem, vendem e compram alimentos. Uma maneira de contar história e lidar com a logística. Uma maneira de transformar suas compras em mudanças positivas para a sociedade."
brandstory_part3: "Assim construímos um mercado de alimentos mais justo e transparente, por isso criamos relacionamentos reais. Nosso código é aberto, por isso é de todos. Nos multiplicamos por diversas regiões e países, com pessoas criando seus próprios mercados pelo mundo."
brandstory_part4: "É acessível a todos, em qualquer lugar do mundo."
brandstory_part5_strong: "Somos a Open Food Brasil."
brandstory_part6: "Todos amamos comida. Agora a gente também pode amar nosso maneira de consumir. "
brandstory_headline: "Comida de verdade, com autonomia "
brandstory_intro: "Comer é um ato político! Por trás de todo alimento há pessoas, processos e histórias. "
brandstory_part1: "A nossa proposta é conectar agricultoras/es, produtoras/es e consumidoras/es que estão próximos entre si. Buscamos, assim, potencializar a circulação e a comercialização de produtos agroecológicos, orgânicos e artesanais em circuitos curtos, bem como criar novas formas de relação, orientadas pela troca, diálogo e confiança."
brandstory_part2: "Para tornar essa ideia real, trouxemos a plataforma Open Food Network para o Brasil. Nosso código (a receita do site) é aberto e seu desenvolvimento é orientado globalmente pelas/os interessadas/os e baseado em uma cultura de autonomia e transparência."
brandstory_part3: "Uma maneira de incentivar a colaboração entre quem produz, vende e compra. Uma maneira de contar histórias e lidar com a logística. Uma maneira de transformar seu consumo de alimentos em mudanças positivas para a sociedade."
brandstory_part4: "Colabore com essa (des)construção!"
brandstory_part5_strong: "Open Food Brasil"
brandstory_part6: ""
learn_body: "Explore modelos, histórias e recursos para te dar suporte para desenvolver seu próprio negócio ou organização justa de alimentos. Encontre treinamento, eventos e outras oportunidades para aprender com quem faz parte do seu setor. "
learn_cta: "Inspire-se"
connect_body: "Procure em nossa lista de produtores, distribuidores e cooperativas para encontrar um comércio justo perto de você. Registre seu negócio ou organização na Open Food Brasil para que os consumidores possam te encontrar. Junte-se à comunidade para trocar experiências e resolver problemas."
connect_cta: "Explore"
system_headline: "Compras - é assim que funciona:"
system_headline: "Como comprar:"
system_step1: "1. Busca"
system_step1_text: "Dentre os diversos mercados independentes, escolha o de sua preferência. Procure por região, tipo de alimentos, alimentos locais e sazonais e escolha o método de recebimento que pode ser receber em casa ou retirar no local. "
system_step2: "2. Compra"
system_step2_text: "Conheça as histórias por trás da sua comida e as pessoas que as produzem! Transforme suas compras com alimentos locais acessíveis."
system_step2_text: "Conheça as pessoas e as histórias por trás da sua comida. Transforme sua relação com o alimento!"
system_step3: "3. Retirada / Entrega"
system_step3_text: "Você escolhe a melhor forma de receber o seu alimentar, aguarde pela sua entrega, ou visite seus produtores ou centrais para uma conexão mais pessoal com seus alimentos."
system_step3_text: "Escolha a forma de recebimento do seu pedido: você pode receber em casa ou retirar no local, assim pode encontrar e conhecer as pessoas envolvidas e estreitar sua relação com as/os agricultoras/es ou as/os mediadoras/es da circulação de produtos. "
cta_headline: "Compras que fazem do mundo um lugar melhor."
cta_label: "Estou pronto"
stats_headline: "Estamos criando um novo sistema alimentar"
stats_headline: "Estamos trabalhando para relocalizar os sistemas agroalimentares"
stats_producers: "produtores de alimentos"
stats_shops: "lojas de alimentos"
stats_shoppers: "consumidores de alimentos"
@@ -1901,7 +1901,7 @@ pt_BR:
successfully_updated: '%{resource} foi atualizado com sucesso!'
running_balance: "Balanço corrente"
outstanding_balance: "Saldo devedor"
admin_enterprise_relationships: "Permissões corporativas"
admin_enterprise_relationships: "Permissões da Iniciativa"
admin_enterprise_relationships_everything: "Tudo"
admin_enterprise_relationships_permits: "permite"
admin_enterprise_relationships_seach_placeholder: "Buscar"
@@ -2133,7 +2133,7 @@ pt_BR:
report_header_producer: Produtor
report_header_producer_suburb: Subúrbio do produtor
report_header_unit: Unidade
report_header_group_buy_unit_quantity: Quantidade de unidade de compra em grupo
report_header_group_buy_unit_quantity: Quantidade da Unidade para Grupo de Compras
report_header_cost: Custo
report_header_shipping_cost: ' Custo de envio'
report_header_curr_cost_per_unit: Custo unitário atual
@@ -2229,7 +2229,7 @@ pt_BR:
adrdress: "Endereço"
contact: "Contato"
social: "Social"
business_details: "Detalhes do negócio"
business_details: "Detalhes da iniciativa"
properties: "Propriedades"
shipping: "Envio"
shipping_methods: "Métodos de envio"
@@ -2271,7 +2271,7 @@ pt_BR:
mas não possuem métodos de envio e pagamento válidos. Até que você configure
eles, os consumidores não poderão fazer compras nessas centrais.
enterprise_fees_update_notice: As tarifas da sua iniciativa foram atualizadas.
enterprise_register_package_error: "Por favor selecione um pacote"
enterprise_register_package_error: "Por favor selecione um tipo de perfil"
enterprise_register_error: "Não foi possível completar o registro para %{enterprise}"
enterprise_register_success_notice: "Parabéns! O registro para %{enterprise} está completo!"
enterprise_bulk_update_success_notice: "Iniciativas atualizadas com sucesso"
@@ -2360,7 +2360,7 @@ pt_BR:
hub_shop_text3: >
Se você também quer vender seus próprios produtos, você precisará mudar
essa iniciativa para ser um produtor.
choose_package: Por favor escolha um pacote
choose_package: Por favor escolha um tipo de perfil
choose_package_text1: >
Sua iniciativa não será totalmente ativada até que um tipo de perfil
seja selecionado a partir das opções à esquerda.
@@ -3023,7 +3023,8 @@ pt_BR:
tax_invoice: "NOTA FISCAL"
code: "Código"
from: "De"
to: "Para"
to: "Informações de cobrança"
shipping: "Entrega"
form:
distribution_fields:
title: "Distribuição"
@@ -3140,7 +3141,7 @@ pt_BR:
primary_taxon_form:
product_category: Categoria de Produto
group_buy_form:
group_buy: "Compra de grupo?"
group_buy: "Grupo de Compras?"
bulk_unit_size: Tamanho da unidade em massa
display_as:
display_as: Mostrar como

View File

@@ -1972,7 +1972,6 @@ sv:
tax_invoice: "FAKTURA"
code: "Kod"
from: "Från"
to: "Till"
form:
distribution_fields:
title: "Distribution"

View File

@@ -3010,7 +3010,6 @@ tr:
tax_invoice: "VERGİ FATURASI"
code: "Kod"
from: "İtibaren"
to: "Şu vakte kadar"
form:
distribution_fields:
title: "Dağıtım"

View File

@@ -33,6 +33,14 @@ module Web
end
describe "language from locale" do
# keeps global state unchanged
around do |example|
original_available_locales = I18n.available_locales
I18n.available_locales = ['en', 'en_GB', '']
example.run
I18n.available_locales = original_available_locales
end
scenario "when locale is the language" do
I18n.locale = "en"
expect(helper.locale_language).to eq "en"

View File

@@ -128,7 +128,7 @@ module OpenFoodNetwork
def order_permissions
return @order_permissions unless @order_permissions.nil?
@order_permissions = ::Permissions::Order.new(@user)
@order_permissions = ::Permissions::Order.new(@user, @params[:q])
end
def report_line_items

View File

@@ -1,7 +1,8 @@
module OpenFoodNetwork
class EnterpriseInjectionData
def active_distributors
@active_distributors ||= Enterprise.distributors_with_active_order_cycles.ready_for_checkout
def active_distributor_ids
@active_distributor_ids ||=
Enterprise.distributors_with_active_order_cycles.ready_for_checkout.pluck(:id)
end
def earliest_closing_times

View File

@@ -5,7 +5,7 @@ module OpenFoodNetwork
@user = user
@render_table = render_table
@permissions = ::Permissions::Order.new(user)
@permissions = ::Permissions::Order.new(user, @params[:q])
end
def header

View File

@@ -83,7 +83,7 @@ module OpenFoodNetwork
def order_permissions
return @order_permissions unless @order_permissions.nil?
@order_permissions = ::Permissions::Order.new(@user)
@order_permissions = ::Permissions::Order.new(@user, options[:q])
end
def report_line_items

View File

@@ -128,7 +128,7 @@ module OpenFoodNetwork
def order_permissions
return @order_permissions unless @order_permissions.nil?
@order_permissions = ::Permissions::Order.new(@user)
@order_permissions = ::Permissions::Order.new(@user, @params[:q])
end
def is_temperature_controlled?(line_item)

View File

@@ -12,9 +12,7 @@ module OpenFoodNetwork
end
def list(line_item_includes = nil)
line_items = @order_permissions.
visible_line_items.
merge(Spree::LineItem.where(order_id: orders.result))
line_items = @order_permissions.visible_line_items.in_orders(orders.result)
if @params[:supplier_id_in].present?
line_items = line_items.supplied_by_any(@params[:supplier_id_in])

View File

@@ -7,7 +7,7 @@ describe ShopsController, type: :controller do
let!(:distributor) { create(:distributor_enterprise) }
before do
allow(Enterprise).to receive_message_chain(:distributors_with_active_order_cycles, :ready_for_checkout) { [distributor] }
allow(OpenFoodNetwork::EnterpriseInjectionData).to receive(:active_distributor_ids) { [distributor.id] }
end
it 'renders distributed product properties' do

View File

@@ -0,0 +1,27 @@
# frozen_string_literal: true
require "spec_helper"
feature '
As an admin
I want to manage product properties
' do
include AuthenticationWorkflow
scenario "creating and editing a property" do
login_to_admin_section
visit spree.admin_properties_path
click_link 'New Property'
fill_in 'property_name', with: 'New property!'
fill_in 'property_presentation', with: 'New property presentation!'
click_button 'Create'
expect(page).to have_content 'New property!'
page.find('td.actions a.icon-edit').click
expect(page).to have_field 'property_name', with: 'New property!'
fill_in 'property_name', with: 'New changed property!'
click_button 'Update'
expect(page).to have_content 'New changed property!'
end
end

View File

@@ -19,8 +19,8 @@ describe Calculator::Weight do
end
describe "line item with variant_unit weight and variant unit_value" do
let(:variant) { build(:variant, unit_value: 10_000) }
let(:line_item) { build(:line_item, variant: variant, quantity: 2) }
let(:variant) { create(:variant, unit_value: 10_000) }
let(:line_item) { create(:line_item, variant: variant, quantity: 2) }
before { subject.set_preference(:per_kg, 5) }
@@ -46,11 +46,11 @@ describe Calculator::Weight do
end
it "computes shipping cost for an object with an order" do
variant1 = build(:variant, unit_value: 10_000)
variant2 = build(:variant, unit_value: 20_000)
variant1 = create(:variant, unit_value: 10_000)
variant2 = create(:variant, unit_value: 20_000)
line_item1 = build(:line_item, variant: variant1, quantity: 1)
line_item2 = build(:line_item, variant: variant2, quantity: 2)
line_item1 = create(:line_item, variant: variant1, quantity: 1)
line_item2 = create(:line_item, variant: variant2, quantity: 2)
order = double(:order, line_items: [line_item1, line_item2])
object_with_order = double(:object_with_order, order: order)
@@ -65,7 +65,7 @@ describe Calculator::Weight do
let(:calculator) { described_class.new(preferred_per_kg: 6) }
let(:line_item) do
build(:line_item, variant: variant, quantity: 2).tap do |object|
create(:line_item, variant: variant, quantity: 2).tap do |object|
object.send(:calculate_final_weight_volume)
end
end
@@ -141,7 +141,7 @@ describe Calculator::Weight do
end
context "when the product uses item unit" do
let!(:product_attributes) { { variant_unit: "items", variant_unit_scale: nil, variant_unit: "pc", display_as: "pc" } }
let!(:product_attributes) { { variant_unit: "items", variant_unit_scale: nil, variant_unit_name: "pc", display_as: "pc" } }
let!(:variant_attributes) { { unit_value: 3.0, weight: 2.5, display_as: "pc" } }
it "is correct" do
@@ -151,4 +151,53 @@ describe Calculator::Weight do
end
end
end
context "when variant_unit is 'items'" do
let(:product) {
create(:product, variant_unit: 'items', variant_unit_scale: nil, variant_unit_name: "bunch")
}
let(:line_item) { create(:line_item, variant: variant, quantity: 1) }
before { subject.set_preference(:per_kg, 5) }
context "when unit_value is zero variant.weight is present" do
let(:variant) { create(:variant, product: product, unit_value: 0, weight: 10.0) }
it "uses the variant weight" do
expect(subject.compute(line_item)).to eq 50.0
end
end
context "when unit_value is zero variant.weight is nil" do
let(:variant) { create(:variant, product: product, unit_value: 0, weight: nil) }
it "uses zero weight" do
expect(subject.compute(line_item)).to eq 0
end
end
context "when unit_value is nil and variant.weight is present" do
let(:variant) {
create(:variant, product: product, unit_description: "bunches", unit_value: nil, weight: 10.0)
}
it "uses the variant weight" do
line_item.final_weight_volume = 1
expect(subject.compute(line_item)).to eq 50.0
end
end
context "when unit_value is nil and variant.weight is nil" do
let(:variant) {
create(:variant, product: product, unit_description: "bunches", unit_value: nil, weight: nil)
}
it "uses zero weight" do
line_item.final_weight_volume = 1
expect(subject.compute(line_item)).to eq 0
end
end
end
end

View File

@@ -40,10 +40,13 @@ module Spree
describe "finding line items with and without tax" do
let(:tax_rate) { create(:tax_rate, calculator: Spree::Calculator::DefaultTax.new) }
let!(:adjustment1) { create(:adjustment, adjustable: li1, originator: tax_rate, label: "TR", amount: 123, included_tax: 10.00) }
let!(:adjustment2) { create(:adjustment, adjustable: li1, originator: tax_rate, label: "TR", amount: 123, included_tax: 10.00) }
let!(:adjustment1) { create(:adjustment, originator: tax_rate, label: "TR", amount: 123, included_tax: 10.00) }
before { li1; li2 }
before do
li1
li2
li1.adjustments << adjustment1
end
it "finds line items with tax" do
expect(LineItem.with_tax).to eq([li1])

View File

@@ -76,9 +76,11 @@ describe Spree.user_class do
it "should send a confirmation email" do
setup_email
expect do
create(:user, email: 'new_user@example.com', confirmation_sent_at: nil, confirmed_at: nil)
end.to send_confirmation_instructions
performing_deliveries do
expect do
create(:user, email: 'new_user@example.com', confirmation_sent_at: nil, confirmed_at: nil)
end.to send_confirmation_instructions
end
sent_mail = ActionMailer::Base.deliveries.last
expect(sent_mail.to).to eq ['new_user@example.com']

View File

@@ -50,7 +50,7 @@ describe Api::CachedEnterpriseSerializer do
context 'when the enterprise is not an active distributor' do
let(:enterprise_injection_data) do
instance_double(OpenFoodNetwork::EnterpriseInjectionData, active_distributors: [])
instance_double(OpenFoodNetwork::EnterpriseInjectionData, active_distributor_ids: [])
end
it 'does not duplicate properties' do
@@ -69,7 +69,7 @@ describe Api::CachedEnterpriseSerializer do
context 'when the enterprise is an active distributor' do
let(:enterprise_injection_data) do
instance_double(OpenFoodNetwork::EnterpriseInjectionData, active_distributors: [shop])
instance_double(OpenFoodNetwork::EnterpriseInjectionData, active_distributor_ids: [shop.id])
end
it 'does not duplicate properties' do

View File

@@ -5,14 +5,21 @@ module Permissions
let(:user) { double(:user) }
let(:permissions) { Permissions::Order.new(user) }
let!(:basic_permissions) { OpenFoodNetwork::Permissions.new(user) }
let(:distributor) { create(:distributor_enterprise) }
let(:coordinator) { create(:distributor_enterprise) }
let(:order_cycle) { create(:simple_order_cycle, coordinator: coordinator, distributors: [distributor]) }
let(:order_completed) { create(:completed_order_with_totals, order_cycle: order_cycle, distributor: distributor ) }
let(:order_cancelled) { create(:order, order_cycle: order_cycle, distributor: distributor, state: 'canceled' ) }
let(:order_cart) { create(:order, order_cycle: order_cycle, distributor: distributor, state: 'cart' ) }
let(:order_from_last_year) {
create(:completed_order_with_totals, order_cycle: order_cycle, distributor: distributor,
completed_at: Time.zone.now - 1.year)
}
before { allow(OpenFoodNetwork::Permissions).to receive(:new) { basic_permissions } }
describe "finding orders that are visible in reports" do
let(:distributor) { create(:distributor_enterprise) }
let(:coordinator) { create(:distributor_enterprise) }
let(:random_enterprise) { create(:distributor_enterprise) }
let(:order_cycle) { create(:simple_order_cycle, coordinator: coordinator, distributors: [distributor]) }
let(:order) { create(:order, order_cycle: order_cycle, distributor: distributor ) }
let!(:line_item) { create(:line_item, order: order) }
let!(:producer) { create(:supplier_enterprise) }
@@ -64,6 +71,18 @@ module Permissions
expect(permissions.visible_orders).to_not include order
end
end
context "with search params" do
let(:search_params) { { completed_at_gt: Time.zone.now.yesterday.strftime('%Y-%m-%d') } }
let(:permissions) { Permissions::Order.new(user, search_params) }
it "only returns completed, non-cancelled orders within search filter range" do
expect(permissions.visible_orders).to include order_completed
expect(permissions.visible_orders).to_not include order_cancelled
expect(permissions.visible_orders).to_not include order_cart
expect(permissions.visible_orders).to_not include order_from_last_year
end
end
end
context "as an enterprise that is a distributor in the order cycle, but not the distributor of the order" do
@@ -78,10 +97,7 @@ module Permissions
end
describe "finding line items that are visible in reports" do
let(:distributor) { create(:distributor_enterprise) }
let(:coordinator) { create(:distributor_enterprise) }
let(:random_enterprise) { create(:distributor_enterprise) }
let(:order_cycle) { create(:simple_order_cycle, coordinator: coordinator, distributors: [distributor]) }
let(:order) { create(:order, order_cycle: order_cycle, distributor: distributor ) }
let!(:line_item1) { create(:line_item, order: order) }
let!(:line_item2) { create(:line_item, order: order) }
@@ -137,6 +153,27 @@ module Permissions
expect(permissions.visible_line_items).to_not include line_item1, line_item2
end
end
context "with search params" do
let!(:line_item3) { create(:line_item, order: order_completed) }
let!(:line_item4) { create(:line_item, order: order_cancelled) }
let!(:line_item5) { create(:line_item, order: order_cart) }
let!(:line_item6) { create(:line_item, order: order_from_last_year) }
let(:search_params) { { completed_at_gt: Time.zone.now.yesterday.strftime('%Y-%m-%d') } }
let(:permissions) { Permissions::Order.new(user, search_params) }
before do
allow(user).to receive(:has_spree_role?) { "admin" }
end
it "only returns line items from completed, non-cancelled orders within search filter range" do
expect(permissions.visible_line_items).to include order_completed.line_items.first
expect(permissions.visible_line_items).to_not include order_cancelled.line_items.first
expect(permissions.visible_line_items).to_not include order_cart.line_items.first
expect(permissions.visible_line_items).to_not include order_from_last_year.line_items.first
end
end
end
end
end