From ed37604bc283ffa1c8000f372c21ca1cb4b953b9 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Sat, 18 Jun 2016 09:09:43 +0100 Subject: [PATCH 01/71] Update from address in notification emails --- app/mailers/producer_mailer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/mailers/producer_mailer.rb b/app/mailers/producer_mailer.rb index 30fad48f58..bdaf25123d 100644 --- a/app/mailers/producer_mailer.rb +++ b/app/mailers/producer_mailer.rb @@ -14,7 +14,7 @@ class ProducerMailer < Spree::BaseMailer if has_orders? order_cycle, producer mail(to: @producer.email, - from: from_address, + from: @coordinator.email, subject: subject, reply_to: @coordinator.email, cc: @coordinator.email) From f37f89dd07b6132704b040be8f30d981c62f8b13 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Mon, 20 Jun 2016 15:13:49 +0100 Subject: [PATCH 02/71] Adding Community forum to ContentConfig --- app/controllers/admin/contents_controller.rb | 4 ++-- app/models/content_configuration.rb | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/controllers/admin/contents_controller.rb b/app/controllers/admin/contents_controller.rb index 87c86997d9..c8d04efebb 100644 --- a/app/controllers/admin/contents_controller.rb +++ b/app/controllers/admin/contents_controller.rb @@ -6,9 +6,9 @@ module Admin {name: 'Producer signup page', preferences: [:producer_signup_pricing_table_html, :producer_signup_case_studies_html, :producer_signup_detail_html]}, {name: 'Hub signup page', preferences: [:hub_signup_pricing_table_html, :hub_signup_case_studies_html, :hub_signup_detail_html]}, {name: 'Group signup page', preferences: [:group_signup_pricing_table_html, :group_signup_case_studies_html, :group_signup_detail_html]}, - {name: 'Footer', preferences: [:footer_logo, + {name: 'Footer and External Links', preferences: [:footer_logo, :footer_facebook_url, :footer_twitter_url, :footer_instagram_url, :footer_linkedin_url, :footer_googleplus_url, :footer_pinterest_url, - :footer_email, :footer_links_md, :footer_about_url, :footer_tos_url]}] + :footer_email, :community_forum_url, :footer_links_md, :footer_about_url, :footer_tos_url]}] end def update diff --git a/app/models/content_configuration.rb b/app/models/content_configuration.rb index e20279f5ee..fc35a2b0ba 100644 --- a/app/models/content_configuration.rb +++ b/app/models/content_configuration.rb @@ -34,6 +34,8 @@ class ContentConfiguration < Spree::Preferences::FileConfiguration # Footer preference :footer_logo, :file has_attached_file :footer_logo, default_url: "/assets/ofn-logo-footer.png" + + #Other preference :footer_facebook_url, :string, default: "https://www.facebook.com/OpenFoodNet" preference :footer_twitter_url, :string, default: "https://twitter.com/OpenFoodNet" preference :footer_instagram_url, :string, default: "" @@ -41,6 +43,7 @@ class ContentConfiguration < Spree::Preferences::FileConfiguration preference :footer_googleplus_url, :string, default: "" preference :footer_pinterest_url, :string, default: "" preference :footer_email, :string, default: "hello@openfoodnetwork.org" + preference :community_forum_url, :string, default: "http://community.openfoodnetwork.org" preference :footer_links_md, :text, default: <<-EOS [Newsletter sign-up](/) From 98548e15c55485ea509769288edccc4c731017dc Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Mon, 20 Jun 2016 15:18:25 +0100 Subject: [PATCH 03/71] I18n of enterprise emails --- app/views/enterprise_mailer/welcome.html.haml | 2 +- .../spree/user_mailer/signup_confirmation.html.haml | 4 +--- config/locales/en.yml | 9 +++++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/views/enterprise_mailer/welcome.html.haml b/app/views/enterprise_mailer/welcome.html.haml index 97b350de45..a5d6f20823 100644 --- a/app/views/enterprise_mailer/welcome.html.haml +++ b/app/views/enterprise_mailer/welcome.html.haml @@ -13,7 +13,7 @@ = t :email_admin_html, link: link_to('Admin Panel', spree.admin_url) %p - = t :email_community_html, link: link_to('Join the community.', 'http://community.openfoodnetwork.org/') + = t :email_community_html, link: link_to(t(:join_the_community), #{ ContentConfig.community_forum_url }) %p = t :email_help diff --git a/app/views/spree/user_mailer/signup_confirmation.html.haml b/app/views/spree/user_mailer/signup_confirmation.html.haml index e45b99a000..fe55de9a40 100644 --- a/app/views/spree/user_mailer/signup_confirmation.html.haml +++ b/app/views/spree/user_mailer/signup_confirmation.html.haml @@ -21,9 +21,7 @@ %p.lead = t :email_signup_text %p - = t :email_signup_help_html - %a{:href => "mailto:hello@openfoodnetwork.org", :target => "_blank"} - hello@openfoodnetwork.org + = t :email_signup_help_html, email: mail_to(ContentConfig.footer_email, ContentConfig.footer_email) = render 'shared/mailers/signoff' diff --git a/config/locales/en.yml b/config/locales/en.yml index 7fd49fc2fe..71e2a5df2a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -237,7 +237,7 @@ en: address: Address address2: Address (contd.) city: City - state: State + state: County postcode: Postcode country: Country unauthorized: Unauthorized @@ -400,6 +400,7 @@ en: 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." 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" email_help: "If you have any difficulties, check out our FAQs, browse the forum or post a 'Support' topic and someone will help you out!" email_confirmation_greeting: "Hi, %{contact}!" email_confirmation_profile_created: "A profile for %{name} has been successfully created! @@ -447,7 +448,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using email_signup_text: "Thanks for joining the network. If you are a customer, we look forward to introducing you to many fantastic farmers, wonderful food hubs and delicious food! If you are a producer or food enterprise, we are excited to have you as a part of the network." - email_signup_help_html: "We welcome all your questions and feedback; you can use the Send Feedback button on the site or email us at" + email_signup_help_html: "We welcome all your questions and feedback; you can use the Send Feedback button on the site or email us at %{email}" producer_mail_greeting: "Dear" producer_mail_text_before: "We now have all the consumer orders for the next food drop." @@ -820,8 +821,8 @@ Please follow the instructions there to make your enterprise visible on the Open registration_detail_postcode: "Postcode:" registration_detail_postcode_placeholder: "e.g. 3070" registration_detail_postcode_error: "Postcode required" - registration_detail_state: "State:" - registration_detail_state_error: "State required" + registration_detail_state: "County:" + registration_detail_state_error: "County required" registration_detail_country: "Country:" registration_detail_country_error: "Please select a country" fees: "Fees" From 99d22649a2307b2a5a0ab21d57fd06e42f97d2ef Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Mon, 20 Jun 2016 15:21:34 +0100 Subject: [PATCH 04/71] Undoing this change, shouldn't be on this branch --- app/mailers/producer_mailer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/mailers/producer_mailer.rb b/app/mailers/producer_mailer.rb index bdaf25123d..30fad48f58 100644 --- a/app/mailers/producer_mailer.rb +++ b/app/mailers/producer_mailer.rb @@ -14,7 +14,7 @@ class ProducerMailer < Spree::BaseMailer if has_orders? order_cycle, producer mail(to: @producer.email, - from: @coordinator.email, + from: from_address, subject: subject, reply_to: @coordinator.email, cc: @coordinator.email) From 5b22e19ec9e29e100826b1bddad14907d6a09a1c Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Mon, 20 Jun 2016 15:24:24 +0100 Subject: [PATCH 05/71] Undoing locale changes accidentally committed --- config/locales/en.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 71e2a5df2a..44aa36e58f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -237,7 +237,7 @@ en: address: Address address2: Address (contd.) city: City - state: County + state: State postcode: Postcode country: Country unauthorized: Unauthorized @@ -821,8 +821,8 @@ Please follow the instructions there to make your enterprise visible on the Open registration_detail_postcode: "Postcode:" registration_detail_postcode_placeholder: "e.g. 3070" registration_detail_postcode_error: "Postcode required" - registration_detail_state: "County:" - registration_detail_state_error: "County required" + registration_detail_state: "State:" + registration_detail_state_error: "State required" registration_detail_country: "Country:" registration_detail_country_error: "Please select a country" fees: "Fees" From 02d8f524261e731778a7f3a09ad8c30e8d3b1cd4 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Mon, 20 Jun 2016 17:02:10 +0100 Subject: [PATCH 06/71] Fixing syntax --- app/views/enterprise_mailer/welcome.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/enterprise_mailer/welcome.html.haml b/app/views/enterprise_mailer/welcome.html.haml index a5d6f20823..5f55b51709 100644 --- a/app/views/enterprise_mailer/welcome.html.haml +++ b/app/views/enterprise_mailer/welcome.html.haml @@ -13,7 +13,7 @@ = t :email_admin_html, link: link_to('Admin Panel', spree.admin_url) %p - = t :email_community_html, link: link_to(t(:join_the_community), #{ ContentConfig.community_forum_url }) + = t :email_community_html, link: link_to("t(:join_the_community)", "#{ ContentConfig.community_forum_url }") %p = t :email_help From fa52712e359a176eec233b4dc1db124821201106 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Mon, 20 Jun 2016 18:32:32 +0100 Subject: [PATCH 07/71] More syntax fixes --- app/views/enterprise_mailer/welcome.html.haml | 2 +- app/views/spree/user_mailer/signup_confirmation.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/enterprise_mailer/welcome.html.haml b/app/views/enterprise_mailer/welcome.html.haml index 5f55b51709..655606340d 100644 --- a/app/views/enterprise_mailer/welcome.html.haml +++ b/app/views/enterprise_mailer/welcome.html.haml @@ -13,7 +13,7 @@ = t :email_admin_html, link: link_to('Admin Panel', spree.admin_url) %p - = t :email_community_html, link: link_to("t(:join_the_community)", "#{ ContentConfig.community_forum_url }") + = t :email_community_html, link: link_to(t(:join_the_community)}, "#{ ContentConfig.community_forum_url }") %p = t :email_help diff --git a/app/views/spree/user_mailer/signup_confirmation.html.haml b/app/views/spree/user_mailer/signup_confirmation.html.haml index fe55de9a40..7b5c8587dc 100644 --- a/app/views/spree/user_mailer/signup_confirmation.html.haml +++ b/app/views/spree/user_mailer/signup_confirmation.html.haml @@ -21,7 +21,7 @@ %p.lead = t :email_signup_text %p - = t :email_signup_help_html, email: mail_to(ContentConfig.footer_email, ContentConfig.footer_email) + = t :email_signup_help_html, email: mail_to("#{ContentConfig.footer_email}", "#{ContentConfig.footer_email}") = render 'shared/mailers/signoff' From e7adacc5411284e1103c99ce335c1f6abb788c5a Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Mon, 20 Jun 2016 18:34:54 +0100 Subject: [PATCH 08/71] Typo --- app/views/enterprise_mailer/welcome.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/enterprise_mailer/welcome.html.haml b/app/views/enterprise_mailer/welcome.html.haml index 655606340d..79fae6542b 100644 --- a/app/views/enterprise_mailer/welcome.html.haml +++ b/app/views/enterprise_mailer/welcome.html.haml @@ -13,7 +13,7 @@ = t :email_admin_html, link: link_to('Admin Panel', spree.admin_url) %p - = t :email_community_html, link: link_to(t(:join_the_community)}, "#{ ContentConfig.community_forum_url }") + = t :email_community_html, link: link_to(t(:join_the_community), "#{ ContentConfig.community_forum_url }") %p = t :email_help From e253590c1c279a972ec024ae0b636b73b91aa133 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Tue, 21 Jun 2016 17:07:42 +0100 Subject: [PATCH 09/71] code cleanup --- app/views/spree/user_mailer/signup_confirmation.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/user_mailer/signup_confirmation.html.haml b/app/views/spree/user_mailer/signup_confirmation.html.haml index 7b5c8587dc..9586110772 100644 --- a/app/views/spree/user_mailer/signup_confirmation.html.haml +++ b/app/views/spree/user_mailer/signup_confirmation.html.haml @@ -21,7 +21,7 @@ %p.lead = t :email_signup_text %p - = t :email_signup_help_html, email: mail_to("#{ContentConfig.footer_email}", "#{ContentConfig.footer_email}") + = t :email_signup_help_html, email: mail_to "#{ContentConfig.footer_email}" = render 'shared/mailers/signoff' From 9c29e56fc310878f223940828903524da96a5b86 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Tue, 21 Jun 2016 17:44:45 +0100 Subject: [PATCH 10/71] More typo --- app/views/spree/user_mailer/signup_confirmation.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/user_mailer/signup_confirmation.html.haml b/app/views/spree/user_mailer/signup_confirmation.html.haml index 9586110772..5598156346 100644 --- a/app/views/spree/user_mailer/signup_confirmation.html.haml +++ b/app/views/spree/user_mailer/signup_confirmation.html.haml @@ -21,7 +21,7 @@ %p.lead = t :email_signup_text %p - = t :email_signup_help_html, email: mail_to "#{ContentConfig.footer_email}" + = t :email_signup_help_html, email: mail_to("#{ContentConfig.footer_email}") = render 'shared/mailers/signoff' From 37ace7773417da56b89335102108210420f5a697 Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Wed, 13 Jul 2016 10:55:17 +1000 Subject: [PATCH 11/71] Add bill_address_id and ship_address_id to customers --- ..._bill_address_and_ship_address_to_customer.rb | 12 ++++++++++++ db/schema.rb | 16 +++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 db/migrate/20160713003535_add_bill_address_and_ship_address_to_customer.rb diff --git a/db/migrate/20160713003535_add_bill_address_and_ship_address_to_customer.rb b/db/migrate/20160713003535_add_bill_address_and_ship_address_to_customer.rb new file mode 100644 index 0000000000..306276bcc0 --- /dev/null +++ b/db/migrate/20160713003535_add_bill_address_and_ship_address_to_customer.rb @@ -0,0 +1,12 @@ +class AddBillAddressAndShipAddressToCustomer < ActiveRecord::Migration + def change + add_column :customers, :bill_address_id, :integer + add_column :customers, :ship_address_id, :integer + + add_index :customers, :bill_address_id + add_index :customers, :ship_address_id + + add_foreign_key :customers, :spree_addresses, column: :bill_address_id + add_foreign_key :customers, :spree_addresses, column: :ship_address_id + end +end diff --git a/db/schema.rb b/db/schema.rb index d0403533fd..a5bd420a1a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20160707023818) do +ActiveRecord::Schema.define(:version => 20160713003535) do create_table "account_invoices", :force => true do |t| t.integer "user_id", :null => false @@ -79,16 +79,20 @@ ActiveRecord::Schema.define(:version => 20160707023818) do add_index "coordinator_fees", ["order_cycle_id"], :name => "index_coordinator_fees_on_order_cycle_id" create_table "customers", :force => true do |t| - t.string "email", :null => false - t.integer "enterprise_id", :null => false + t.string "email", :null => false + t.integer "enterprise_id", :null => false t.string "code" t.integer "user_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "bill_address_id" + t.integer "ship_address_id" end + add_index "customers", ["bill_address_id"], :name => "index_customers_on_bill_address_id" add_index "customers", ["email"], :name => "index_customers_on_email" add_index "customers", ["enterprise_id", "code"], :name => "index_customers_on_enterprise_id_and_code", :unique => true + add_index "customers", ["ship_address_id"], :name => "index_customers_on_ship_address_id" add_index "customers", ["user_id"], :name => "index_customers_on_user_id" create_table "delayed_jobs", :force => true do |t| @@ -1111,6 +1115,8 @@ ActiveRecord::Schema.define(:version => 20160707023818) do add_foreign_key "coordinator_fees", "order_cycles", name: "coordinator_fees_order_cycle_id_fk" add_foreign_key "customers", "enterprises", name: "customers_enterprise_id_fk" + add_foreign_key "customers", "spree_addresses", name: "customers_bill_address_id_fk", column: "bill_address_id" + add_foreign_key "customers", "spree_addresses", name: "customers_ship_address_id_fk", column: "ship_address_id" add_foreign_key "customers", "spree_users", name: "customers_user_id_fk", column: "user_id" add_foreign_key "distributors_payment_methods", "enterprises", name: "distributors_payment_methods_distributor_id_fk", column: "distributor_id" From b08a642377f54112dae3b9bad7b731fc5449337e Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Wed, 13 Jul 2016 11:25:23 +1000 Subject: [PATCH 12/71] Add billing_address and shipping_address to Customer --- app/models/customer.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/models/customer.rb b/app/models/customer.rb index c208c619ba..b7de44a0ef 100644 --- a/app/models/customer.rb +++ b/app/models/customer.rb @@ -6,6 +6,12 @@ class Customer < ActiveRecord::Base has_many :orders, class_name: Spree::Order before_destroy :check_for_orders + belongs_to :bill_address, foreign_key: :bill_address_id, class_name: Spree::Address + alias_attribute :billing_address, :bill_address + + belongs_to :ship_address, foreign_key: :ship_address_id, class_name: Spree::Address + alias_attribute :shipping_address, :ship_address + before_validation :downcase_email before_validation :empty_code From ca0c3a028d08a8fea55b76c79665bd9726c6bb5f Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Wed, 13 Jul 2016 11:36:22 +1000 Subject: [PATCH 13/71] Add name to customers --- db/migrate/20160713013358_add_name_to_customer.rb | 5 +++++ db/schema.rb | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20160713013358_add_name_to_customer.rb diff --git a/db/migrate/20160713013358_add_name_to_customer.rb b/db/migrate/20160713013358_add_name_to_customer.rb new file mode 100644 index 0000000000..832816657e --- /dev/null +++ b/db/migrate/20160713013358_add_name_to_customer.rb @@ -0,0 +1,5 @@ +class AddNameToCustomer < ActiveRecord::Migration + def change + add_column :customers, :name, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index a5bd420a1a..9a825e299c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20160713003535) do +ActiveRecord::Schema.define(:version => 20160713013358) do create_table "account_invoices", :force => true do |t| t.integer "user_id", :null => false @@ -87,6 +87,7 @@ ActiveRecord::Schema.define(:version => 20160713003535) do t.datetime "updated_at", :null => false t.integer "bill_address_id" t.integer "ship_address_id" + t.string "name" end add_index "customers", ["bill_address_id"], :name => "index_customers_on_bill_address_id" From add39f74018c0ac11d1ba1dd4e6930256ee7b4d8 Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Fri, 15 Jul 2016 15:40:44 +1000 Subject: [PATCH 14/71] Enterprise user can update customer's name --- app/serializers/api/admin/customer_serializer.rb | 2 +- app/views/admin/customers/index.html.haml | 8 +++++++- .../column_preference_defaults.rb | 1 + spec/features/admin/customers_spec.rb | 16 ++++++++++++---- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/app/serializers/api/admin/customer_serializer.rb b/app/serializers/api/admin/customer_serializer.rb index 4634625c11..deec9933fc 100644 --- a/app/serializers/api/admin/customer_serializer.rb +++ b/app/serializers/api/admin/customer_serializer.rb @@ -1,5 +1,5 @@ class Api::Admin::CustomerSerializer < ActiveModel::Serializer - attributes :id, :email, :enterprise_id, :user_id, :code, :tags, :tag_list + attributes :id, :email, :enterprise_id, :user_id, :code, :tags, :tag_list, :name def tag_list object.tag_list.join(",") diff --git a/app/views/admin/customers/index.html.haml b/app/views/admin/customers/index.html.haml index 98e8b3c414..f10214179b 100644 --- a/app/views/admin/customers/index.html.haml +++ b/app/views/admin/customers/index.html.haml @@ -37,6 +37,7 @@ %img.spinner{ src: "/assets/spinning-circles.svg" } %h1 =t :loading_customers + .row{ :class => "sixteen columns alpha", 'ng-show' => '!RequestMonitor.loading && filteredCustomers.length == 0'} %h1#no_results =t :no_customers_found @@ -48,8 +49,9 @@ %table.index#customers %col.email{ width: "20%", 'ng-show' => 'columns.email.visible' } + %col.name{ width: "20%", 'ng-show' => 'columns.code.visible' } %col.code{ width: "20%", 'ng-show' => 'columns.code.visible' } - %col.tags{ width: "50%", 'ng-show' => 'columns.tags.visible' } + %col.tags{ width: "30%", 'ng-show' => 'columns.tags.visible' } %col.actions{ width: "10%"} %thead %tr{ ng: { controller: "ColumnsCtrl" } } @@ -57,6 +59,8 @@ -# %input{ :type => "checkbox", :name => 'toggle_bulk', 'ng-click' => 'toggleAllCheckboxes()', 'ng-checked' => "allBoxesChecked()" } %th.email{ 'ng-show' => 'columns.email.visible' } %a{ :href => '', 'ng-click' => "predicate = 'customer.email'; reverse = !reverse" } Email + %th.name{ 'ng-show' => 'columns.name.visible' } + %a{ :href => '', 'ng-click' => "predicate = 'customer.name'; reverse = !reverse" } Name %th.code{ 'ng-show' => 'columns.code.visible' } %a{ :href => '', 'ng-click' => "predicate = 'customer.code'; reverse = !reverse" } Code %th.tags{ 'ng-show' => 'columns.tags.visible' } Tags @@ -67,6 +71,8 @@ -# %td.bulk -# %input{ :type => "checkbox", :name => 'bulk', 'ng-model' => 'customer.checked' } %td.email{ 'ng-show' => 'columns.email.visible', "ng-bind" => '::customer.email' } + %td.name{ 'ng-show' => 'columns.name.visible'} + %input{ type: 'text', name: 'name', ng: { model: 'customer.name' }, 'obj-for-update' => 'customer', 'attr-for-update' => 'name'} %td.code{ 'ng-show' => 'columns.code.visible' } %input{ type: 'text', name: 'code', ng: {model: 'customer.code', change: 'checkForDuplicateCodes()'}, "obj-for-update" => "customer", "attr-for-update" => "code" } %i.icon-warning-sign{ ng: {if: 'duplicate'} } diff --git a/lib/open_food_network/column_preference_defaults.rb b/lib/open_food_network/column_preference_defaults.rb index 09dc197832..a6d7397b84 100644 --- a/lib/open_food_network/column_preference_defaults.rb +++ b/lib/open_food_network/column_preference_defaults.rb @@ -28,6 +28,7 @@ module OpenFoodNetwork node = 'admin.customers.index' { email: { name: I18n.t("admin.email"), visible: true }, + name: { name: I18n.t("admin.name"), visible: true }, code: { name: I18n.t("#{node}.code"), visible: true }, tags: { name: I18n.t("admin.tags"), visible: true } } diff --git a/spec/features/admin/customers_spec.rb b/spec/features/admin/customers_spec.rb index 89893860df..9e341ba61f 100644 --- a/spec/features/admin/customers_spec.rb +++ b/spec/features/admin/customers_spec.rb @@ -80,8 +80,10 @@ feature 'Customers' do within "tr#c_#{customer1.id}" do fill_in "code", with: "new-customer-code" expect(page).to have_css "input[name=code].update-pending" - end - within "tr#c_#{customer1.id}" do + + fill_in "name", with: "customer abc" + expect(page).to have_css "input[name=name].update-pending" + find(:css, "tags-input .tags input").set "awesome\n" expect(page).to have_css ".tag_watcher.update-pending" end @@ -89,18 +91,22 @@ feature 'Customers' do # Every says it updated expect(page).to have_css "input[name=code].update-success" + expect(page).to have_css "input[name=name].update-success" expect(page).to have_css ".tag_watcher.update-success" # And it actually did expect(customer1.reload.code).to eq "new-customer-code" + expect(customer1.reload.name).to eq "customer abc" expect(customer1.tag_list).to eq ["awesome"] # Clearing attributes within "tr#c_#{customer1.id}" do fill_in "code", with: "" expect(page).to have_css "input[name=code].update-pending" - end - within "tr#c_#{customer1.id}" do + + fill_in "name", with: "" + expect(page).to have_css "input[name=name].update-pending" + find("tags-input li.tag-item a.remove-button").trigger('click') expect(page).to have_css ".tag_watcher.update-pending" end @@ -108,10 +114,12 @@ feature 'Customers' do # Every says it updated expect(page).to have_css "input[name=code].update-success" + expect(page).to have_css "input[name=name].update-success" expect(page).to have_css ".tag_watcher.update-success" # And it actually did expect(customer1.reload.code).to be nil + expect(customer1.reload.name).to eq '' expect(customer1.tag_list).to eq [] end From 7f203f549186527254b9800ccb5f343825e4155d Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Wed, 20 Jul 2016 15:37:59 +1000 Subject: [PATCH 15/71] Show billing address and shipping address on customers index page --- .../services/switch_class.js.coffee | 2 +- .../api/admin/customer_serializer.rb | 10 +++++++++- app/views/admin/customers/index.html.haml | 20 ++++++++++++------- config/locales/en.yml | 2 ++ .../column_preference_defaults.rb | 10 ++++++---- spec/factories.rb | 1 + .../admin/customer_serializer_spec.rb | 3 +++ 7 files changed, 35 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/admin/index_utils/services/switch_class.js.coffee b/app/assets/javascripts/admin/index_utils/services/switch_class.js.coffee index c2a3419e2c..0be1f2ec40 100644 --- a/app/assets/javascripts/admin/index_utils/services/switch_class.js.coffee +++ b/app/assets/javascripts/admin/index_utils/services/switch_class.js.coffee @@ -1,5 +1,5 @@ angular.module("admin.indexUtils").factory "switchClass", ($timeout) -> - return (element,classToAdd,removeClasses,timeout) -> + return (element, classToAdd, removeClasses, timeout) -> $timeout.cancel element.timeout if element.timeout element.removeClass className for className in removeClasses element.addClass classToAdd diff --git a/app/serializers/api/admin/customer_serializer.rb b/app/serializers/api/admin/customer_serializer.rb index deec9933fc..93f66676d1 100644 --- a/app/serializers/api/admin/customer_serializer.rb +++ b/app/serializers/api/admin/customer_serializer.rb @@ -1,5 +1,5 @@ class Api::Admin::CustomerSerializer < ActiveModel::Serializer - attributes :id, :email, :enterprise_id, :user_id, :code, :tags, :tag_list, :name + attributes :id, :email, :enterprise_id, :user_id, :code, :tags, :tag_list, :name, :bill_address, :ship_address def tag_list object.tag_list.join(",") @@ -11,4 +11,12 @@ class Api::Admin::CustomerSerializer < ActiveModel::Serializer tag_rule_map || { text: tag, rules: nil } end end + + def ship_address + object.ship_address.andand.address1 + end + + def bill_address + object.bill_address.andand.address1 + end end diff --git a/app/views/admin/customers/index.html.haml b/app/views/admin/customers/index.html.haml index f10214179b..0d4c85d339 100644 --- a/app/views/admin/customers/index.html.haml +++ b/app/views/admin/customers/index.html.haml @@ -49,21 +49,25 @@ %table.index#customers %col.email{ width: "20%", 'ng-show' => 'columns.email.visible' } - %col.name{ width: "20%", 'ng-show' => 'columns.code.visible' } - %col.code{ width: "20%", 'ng-show' => 'columns.code.visible' } - %col.tags{ width: "30%", 'ng-show' => 'columns.tags.visible' } + %col.name{ width: "20%", 'ng-show' => 'columns.name.visible' } + %col.code{ width: "10%", 'ng-show' => 'columns.code.visible' } + %col.tags{ width: "20%", 'ng-show' => 'columns.tags.visible' } + %col.bill_address{ width: "10%", 'ng-show' => 'columns.bill_address.visible' } + %col.ship_address{ width: "10%", 'ng-show' => 'columns.ship_address.visible' } %col.actions{ width: "10%"} %thead %tr{ ng: { controller: "ColumnsCtrl" } } -# %th.bulk -# %input{ :type => "checkbox", :name => 'toggle_bulk', 'ng-click' => 'toggleAllCheckboxes()', 'ng-checked' => "allBoxesChecked()" } %th.email{ 'ng-show' => 'columns.email.visible' } - %a{ :href => '', 'ng-click' => "predicate = 'customer.email'; reverse = !reverse" } Email + %a{ :href => '', 'ng-click' => "predicate = 'customer.email'; reverse = !reverse" }=t('admin.email') %th.name{ 'ng-show' => 'columns.name.visible' } - %a{ :href => '', 'ng-click' => "predicate = 'customer.name'; reverse = !reverse" } Name + %a{ :href => '', 'ng-click' => "predicate = 'customer.name'; reverse = !reverse" }=t('admin.name') %th.code{ 'ng-show' => 'columns.code.visible' } - %a{ :href => '', 'ng-click' => "predicate = 'customer.code'; reverse = !reverse" } Code - %th.tags{ 'ng-show' => 'columns.tags.visible' } Tags + %a{ :href => '', 'ng-click' => "predicate = 'customer.code'; reverse = !reverse" }=t('admin.customers.index.code') + %th.tags{ 'ng-show' => 'columns.tags.visible' }=t('admin.tags') + %th.bill_address{ 'ng-show' => 'columns.bill_address.visible' }=t('admin.customers.index.bill_address') + %th.ship_address{ 'ng-show' => 'columns.ship_address.visible' }=t('admin.customers.index.ship_address') %th.actions Ask?  %input{ :type => 'checkbox', 'ng-model' => "confirmDelete" } @@ -80,6 +84,8 @@ %td.tags{ 'ng-show' => 'columns.tags.visible' } .tag_watcher{ 'obj-for-update' => "customer", "attr-for-update" => "tag_list"} %tags_with_translation{ object: 'customer', 'find-tags' => 'findTags(query)' } + %td.bill_address{ 'ng-show' => 'columns.bill_address.visible', "ng-bind" => '::customer.bill_address | limitTo: 15' } + %td.ship_address{ 'ng-show' => 'columns.ship_address.visible', "ng-bind" => '::customer.ship_address | limitTo: 15' } %td.actions %a{ 'ng-click' => "deleteCustomer(customer)", :class => "delete-customer icon-trash no-text" } diff --git a/config/locales/en.yml b/config/locales/en.yml index 386f44ae8b..bff650be2b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -118,6 +118,8 @@ en: add_a_new_customer_for: Add a new customer for %{shop_name} code: Code duplicate_code: "This code is used already." + bill_address: "Billing Address" + ship_address: "Shipping Address" products: bulk_edit: diff --git a/lib/open_food_network/column_preference_defaults.rb b/lib/open_food_network/column_preference_defaults.rb index a6d7397b84..41eef63c09 100644 --- a/lib/open_food_network/column_preference_defaults.rb +++ b/lib/open_food_network/column_preference_defaults.rb @@ -27,10 +27,12 @@ module OpenFoodNetwork def customers_index_columns node = 'admin.customers.index' { - email: { name: I18n.t("admin.email"), visible: true }, - name: { name: I18n.t("admin.name"), visible: true }, - code: { name: I18n.t("#{node}.code"), visible: true }, - tags: { name: I18n.t("admin.tags"), visible: true } + email: { name: I18n.t("admin.email"), visible: true }, + name: { name: I18n.t("admin.name"), visible: true }, + code: { name: I18n.t("#{node}.code"), visible: true }, + tags: { name: I18n.t("admin.tags"), visible: true }, + bill_address: { name: I18n.t("#{node}.bill_address"), visible: true }, + ship_address: { name: I18n.t("#{node}.ship_address"), visible: true } } end diff --git a/spec/factories.rb b/spec/factories.rb index 3b0c548923..9875d22652 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -270,6 +270,7 @@ FactoryGirl.define do enterprise code { SecureRandom.base64(150) } user + bill_address { create(:address) } end factory :billable_period do diff --git a/spec/serializers/admin/customer_serializer_spec.rb b/spec/serializers/admin/customer_serializer_spec.rb index b8e43f5fcc..ad4b75db49 100644 --- a/spec/serializers/admin/customer_serializer_spec.rb +++ b/spec/serializers/admin/customer_serializer_spec.rb @@ -11,5 +11,8 @@ describe Api::Admin::CustomerSerializer do expect(tags.length).to eq 3 expect(tags[0]).to eq({ "text" => 'one', "rules" => nil }) expect(tags[1]).to eq({ "text" => 'two', "rules" => 1 }) + + expect(result['bill_address']).to eq customer.bill_address.address1 + expect(result['ship_address']).to be nil end end From 225bed9990a6f9c29a06d201e82482c89887c5cb Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Wed, 27 Jul 2016 14:16:14 +1000 Subject: [PATCH 16/71] Add a simple edit address dialog --- .../directives/edit_address_dialog.js.coffee | 11 +++++++++++ .../directives/new_customer_dialog.js.coffee | 2 +- .../templates/admin/edit_address_dialog.html.haml | 5 +++++ app/views/admin/customers/index.html.haml | 3 ++- 4 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee create mode 100644 app/assets/javascripts/templates/admin/edit_address_dialog.html.haml diff --git a/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee b/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee new file mode 100644 index 0000000000..817a4db62c --- /dev/null +++ b/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee @@ -0,0 +1,11 @@ +angular.module("admin.customers").directive 'editAddressDialog', ($compile, $templateCache, DialogDefaults, CurrentShop, Customers) -> + restrict: 'A' + scope: true + link: (scope, element, attr) -> + template = $compile($templateCache.get('admin/edit_address_dialog.html'))(scope) + template.dialog(DialogDefaults) + + console.log('xie') + + element.bind 'click', (e) -> + template.dialog('open') diff --git a/app/assets/javascripts/admin/customers/directives/new_customer_dialog.js.coffee b/app/assets/javascripts/admin/customers/directives/new_customer_dialog.js.coffee index f2dae5836b..60a19838d6 100644 --- a/app/assets/javascripts/admin/customers/directives/new_customer_dialog.js.coffee +++ b/app/assets/javascripts/admin/customers/directives/new_customer_dialog.js.coffee @@ -1,4 +1,4 @@ -angular.module("admin.customers").directive 'newCustomerDialog', ($compile, $injector, $templateCache, DialogDefaults, CurrentShop, Customers) -> +angular.module("admin.customers").directive 'newCustomerDialog', ($compile, $templateCache, DialogDefaults, CurrentShop, Customers) -> restrict: 'A' scope: true link: (scope, element, attr) -> diff --git a/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml b/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml new file mode 100644 index 0000000000..6b7fe8bb67 --- /dev/null +++ b/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml @@ -0,0 +1,5 @@ +#edit-address-dialog + h2 'Edit Address' + #countries + = 1+1 + diff --git a/app/views/admin/customers/index.html.haml b/app/views/admin/customers/index.html.haml index 0d4c85d339..1b713f518b 100644 --- a/app/views/admin/customers/index.html.haml +++ b/app/views/admin/customers/index.html.haml @@ -84,7 +84,8 @@ %td.tags{ 'ng-show' => 'columns.tags.visible' } .tag_watcher{ 'obj-for-update' => "customer", "attr-for-update" => "tag_list"} %tags_with_translation{ object: 'customer', 'find-tags' => 'findTags(query)' } - %td.bill_address{ 'ng-show' => 'columns.bill_address.visible', "ng-bind" => '::customer.bill_address | limitTo: 15' } + %td.bill_address{ 'ng-show' => 'columns.bill_address.visible' } + %a{ href: '#', "ng-bind" => '::customer.bill_address | limitTo: 15', 'edit-address-dialog' => true } %td.ship_address{ 'ng-show' => 'columns.ship_address.visible', "ng-bind" => '::customer.ship_address | limitTo: 15' } %td.actions %a{ 'ng-click' => "deleteCustomer(customer)", :class => "delete-customer icon-trash no-text" } From 8234956a614f81eeefdc53ab9346fdcdc731ec8a Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Wed, 27 Jul 2016 14:38:28 +1000 Subject: [PATCH 17/71] Inject available countries on admin customers page --- .../customers/controllers/customers_controller.js.coffee | 3 ++- app/helpers/admin/injection_helper.rb | 4 ++++ app/views/admin/customers/index.html.haml | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee b/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee index 2721c92961..769cec1c18 100644 --- a/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee +++ b/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee @@ -1,5 +1,6 @@ -angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filter, Customers, TagRuleResource, CurrentShop, RequestMonitor, Columns, pendingChanges, shops) -> +angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filter, Customers, TagRuleResource, CurrentShop, RequestMonitor, Columns, pendingChanges, shops, availableCountries) -> $scope.shops = shops + $scope.availableCountries = availableCountries $scope.RequestMonitor = RequestMonitor $scope.submitAll = pendingChanges.submitAll $scope.add = Customers.add diff --git a/app/helpers/admin/injection_helper.rb b/app/helpers/admin/injection_helper.rb index 67105b6b34..b528eb84a4 100644 --- a/app/helpers/admin/injection_helper.rb +++ b/app/helpers/admin/injection_helper.rb @@ -39,6 +39,10 @@ module Admin admin_inject_json_ams_array ngModule, "shops", @shops, Api::Admin::IdNameSerializer end + def admin_inject_available_countries(ngModule='admin.customers') + admin_inject_json_ams_array ngModule, 'availableCountries', available_countries, Api::CountrySerializer + end + def admin_inject_hubs(opts={module: 'ofn.admin'}) admin_inject_json_ams_array opts[:module], "hubs", @hubs, Api::Admin::IdNameSerializer end diff --git a/app/views/admin/customers/index.html.haml b/app/views/admin/customers/index.html.haml index 1b713f518b..9fb243e0f8 100644 --- a/app/views/admin/customers/index.html.haml +++ b/app/views/admin/customers/index.html.haml @@ -12,6 +12,7 @@ = admin_inject_column_preferences module: 'admin.customers' = admin_inject_shops += admin_inject_available_countries %div{ ng: { controller: 'customersCtrl' } } .row.filters From d16014294533e8fc42b684c73a1c6456e911d72c Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Wed, 27 Jul 2016 14:58:42 +1000 Subject: [PATCH 18/71] Make bill address and ship address as nested attributes --- app/models/customer.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/customer.rb b/app/models/customer.rb index b7de44a0ef..efa8b5e096 100644 --- a/app/models/customer.rb +++ b/app/models/customer.rb @@ -8,9 +8,11 @@ class Customer < ActiveRecord::Base belongs_to :bill_address, foreign_key: :bill_address_id, class_name: Spree::Address alias_attribute :billing_address, :bill_address + accepts_nested_attributes_for :bill_address belongs_to :ship_address, foreign_key: :ship_address_id, class_name: Spree::Address alias_attribute :shipping_address, :ship_address + accepts_nested_attributes_for :ship_address before_validation :downcase_email before_validation :empty_code From 34d5df69a51d1aba9e71c5a6d762513ddf4c45a1 Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Wed, 27 Jul 2016 15:16:50 +1000 Subject: [PATCH 19/71] Fix failed customers controller spec --- .../controllers/customers_controller_spec.js.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee b/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee index 5f190b9382..f97ff35d36 100644 --- a/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee +++ b/spec/javascripts/unit/admin/customers/controllers/customers_controller_spec.js.coffee @@ -15,11 +15,15 @@ describe "CustomersCtrl", -> { name: "Shop 3", id: 3 } ] + availableCountries = [ + {id: 109, name: "Australia", states: [{id: 55, name: "ACT", abbr: "ACT"}]} + ] + inject ($controller, $rootScope, _CustomerResource_, $httpBackend) -> scope = $rootScope http = $httpBackend - $controller 'customersCtrl', {$scope: scope, CustomerResource: _CustomerResource_, shops: shops} + $controller 'customersCtrl', {$scope: scope, CustomerResource: _CustomerResource_, shops: shops, availableCountries: availableCountries} jasmine.addMatchers toDeepEqual: (util, customEqualityTesters) -> compare: (actual, expected) -> From 69addf056b9396c7ef30e80bfb4089889d6a2f89 Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Fri, 5 Aug 2016 13:23:16 +1000 Subject: [PATCH 20/71] Edit customer address form --- .../directives/edit_address_dialog.js.coffee | 6 ++- .../admin/edit_address_dialog.html.haml | 52 +++++++++++++++++-- app/models/customer.rb | 6 +++ 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee b/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee index 817a4db62c..e1d4180561 100644 --- a/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee +++ b/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee @@ -2,10 +2,12 @@ angular.module("admin.customers").directive 'editAddressDialog', ($compile, $tem restrict: 'A' scope: true link: (scope, element, attr) -> + scope.$watch 'country', (newVal) -> + if newVal + scope.states = newVal.states + template = $compile($templateCache.get('admin/edit_address_dialog.html'))(scope) template.dialog(DialogDefaults) - console.log('xie') - element.bind 'click', (e) -> template.dialog('open') diff --git a/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml b/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml index 6b7fe8bb67..908588f610 100644 --- a/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml +++ b/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml @@ -1,5 +1,51 @@ #edit-address-dialog - h2 'Edit Address' - #countries - = 1+1 + %h2 Edit Shipping Address + %form{ name: 'edit_address_form', novalidate: true, ng: { submit: 'editAddress()'}} + .row + Required fields are denoted with an asterisk ( + %span.required * + ) + %table.no-borders + %tr + %td + Address1 + %span.required * + %td + %input{ type: 'text', name: 'address1', required: true, ng: { model: 'address1'} } + %tr + %td + Address2: + %td + %input{ type: 'text', name: 'address2', ng: { model: 'address2'} } + %tr + %td + Phone: + %td + %input{ type: 'text', name: 'phone', required: true, ng: { model: 'phone'} } + %tr + %td + City: + %td + %input{ type: 'text', name: 'city', required: true, ng: { model: 'city'} } + %tr + %td + Zipcode: + %td + %input{ type: 'text', name: 'zipcode', required: true, ng: { model: 'zipcode'} } + %tr + %td + Country: + %td + %select{name: 'country', required: true, ng: {model: 'country', options: 'country as country.name for country in availableCountries track by country.id'}} + %option{value: ''} Select Country + %tr + %td + State: + %td + %select{name: 'state', required: true, ng: {model: 'state', options: 'state as state.name for state in states track by state.id'}} + %option{value: ''} Select State + + .text-center + %input.button.red.icon-plus{ type: 'submit', value: 'Update Address'} + diff --git a/app/models/customer.rb b/app/models/customer.rb index efa8b5e096..3003acb848 100644 --- a/app/models/customer.rb +++ b/app/models/customer.rb @@ -16,6 +16,7 @@ class Customer < ActiveRecord::Base before_validation :downcase_email before_validation :empty_code + before_validation :set_unused_address_fields validates :code, uniqueness: { scope: :enterprise_id, allow_nil: true } validates :email, presence: true, uniqueness: { scope: :enterprise_id, message: I18n.t('validation_msg_is_associated_with_an_exising_customer') } @@ -35,6 +36,11 @@ class Customer < ActiveRecord::Base self.code = nil if code.blank? end + def set_unused_address_fields + bill_address.firstname = bill_address.lastname = 'unused' if bill_address.present? + ship_address.firstname = ship_address.lastname = 'unused' if ship_address.present? + end + def associate_user self.user = user || Spree::User.find_by_email(email) end From 5b40c745f34f7a190b487fb9762cd00709d4b498 Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Fri, 5 Aug 2016 16:48:55 +1000 Subject: [PATCH 21/71] Add address serializer to customer serializer --- app/serializers/api/admin/customer_serializer.rb | 13 ++++--------- app/views/admin/customers/index.html.haml | 4 ++-- spec/serializers/admin/customer_serializer_spec.rb | 3 ++- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/app/serializers/api/admin/customer_serializer.rb b/app/serializers/api/admin/customer_serializer.rb index 93f66676d1..1c9d19306d 100644 --- a/app/serializers/api/admin/customer_serializer.rb +++ b/app/serializers/api/admin/customer_serializer.rb @@ -1,5 +1,8 @@ class Api::Admin::CustomerSerializer < ActiveModel::Serializer - attributes :id, :email, :enterprise_id, :user_id, :code, :tags, :tag_list, :name, :bill_address, :ship_address + attributes :id, :email, :enterprise_id, :user_id, :code, :tags, :tag_list, :name + + has_one :ship_address, serializer: Api::AddressSerializer + has_one :bill_address, serializer: Api::AddressSerializer def tag_list object.tag_list.join(",") @@ -11,12 +14,4 @@ class Api::Admin::CustomerSerializer < ActiveModel::Serializer tag_rule_map || { text: tag, rules: nil } end end - - def ship_address - object.ship_address.andand.address1 - end - - def bill_address - object.bill_address.andand.address1 - end end diff --git a/app/views/admin/customers/index.html.haml b/app/views/admin/customers/index.html.haml index 9fb243e0f8..9adf8812cb 100644 --- a/app/views/admin/customers/index.html.haml +++ b/app/views/admin/customers/index.html.haml @@ -86,8 +86,8 @@ .tag_watcher{ 'obj-for-update' => "customer", "attr-for-update" => "tag_list"} %tags_with_translation{ object: 'customer', 'find-tags' => 'findTags(query)' } %td.bill_address{ 'ng-show' => 'columns.bill_address.visible' } - %a{ href: '#', "ng-bind" => '::customer.bill_address | limitTo: 15', 'edit-address-dialog' => true } - %td.ship_address{ 'ng-show' => 'columns.ship_address.visible', "ng-bind" => '::customer.ship_address | limitTo: 15' } + %a{ href: '#', "ng-bind" => '::customer.bill_address.address1 | limitTo: 15', 'edit-address-dialog' => true } + %td.ship_address{ 'ng-show' => 'columns.ship_address.visible', "ng-bind" => '::customer.ship_address.address1 | limitTo: 15' } %td.actions %a{ 'ng-click' => "deleteCustomer(customer)", :class => "delete-customer icon-trash no-text" } diff --git a/spec/serializers/admin/customer_serializer_spec.rb b/spec/serializers/admin/customer_serializer_spec.rb index ad4b75db49..5694b1004f 100644 --- a/spec/serializers/admin/customer_serializer_spec.rb +++ b/spec/serializers/admin/customer_serializer_spec.rb @@ -12,7 +12,8 @@ describe Api::Admin::CustomerSerializer do expect(tags[0]).to eq({ "text" => 'one', "rules" => nil }) expect(tags[1]).to eq({ "text" => 'two', "rules" => 1 }) - expect(result['bill_address']).to eq customer.bill_address.address1 + expect(result['bill_address']['id']).to eq customer.bill_address.id + expect(result['bill_address']['address1']).to eq customer.bill_address.address1 expect(result['ship_address']).to be nil end end From 45e3f8ab3a09b549bf09cf2ae31367b950057b7f Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Fri, 5 Aug 2016 20:04:41 +1000 Subject: [PATCH 22/71] Fill the from with model --- .../directives/edit_address_dialog.js.coffee | 14 +++++++++++--- .../admin/edit_address_dialog.html.haml | 16 ++++++++-------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee b/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee index e1d4180561..f80cd7c0ee 100644 --- a/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee +++ b/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee @@ -1,13 +1,21 @@ -angular.module("admin.customers").directive 'editAddressDialog', ($compile, $templateCache, DialogDefaults, CurrentShop, Customers) -> +angular.module("admin.customers").directive 'editAddressDialog', ($compile, $templateCache, $filter, DialogDefaults, Customers) -> restrict: 'A' scope: true link: (scope, element, attr) -> - scope.$watch 'country', (newVal) -> + scope.$watch 'address.country_id', (newVal) -> if newVal - scope.states = newVal.states + scope.states = scope.filter_states(newVal) + + scope.updateAddress = -> + console.log(scope.edit_address_form) template = $compile($templateCache.get('admin/edit_address_dialog.html'))(scope) template.dialog(DialogDefaults) element.bind 'click', (e) -> + scope.address = scope.customer.bill_address template.dialog('open') + scope.$apply() + + scope.filter_states = (countryID) -> + $filter('filter')(scope.availableCountries, {id: countryID})[0].states diff --git a/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml b/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml index 908588f610..e6de7fb134 100644 --- a/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml +++ b/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml @@ -1,6 +1,6 @@ #edit-address-dialog %h2 Edit Shipping Address - %form{ name: 'edit_address_form', novalidate: true, ng: { submit: 'editAddress()'}} + %form{ name: 'edit_address_form', novalidate: true, ng: { submit: 'updateAddress()'}} .row Required fields are denoted with an asterisk ( %span.required * @@ -11,38 +11,38 @@ Address1 %span.required * %td - %input{ type: 'text', name: 'address1', required: true, ng: { model: 'address1'} } + %input{ type: 'text', name: 'address1', required: true, ng: { model: 'address.address1'} } %tr %td Address2: %td - %input{ type: 'text', name: 'address2', ng: { model: 'address2'} } + %input{ type: 'text', name: 'address2', ng: { model: 'address.address2'} } %tr %td Phone: %td - %input{ type: 'text', name: 'phone', required: true, ng: { model: 'phone'} } + %input{ type: 'text', name: 'phone', required: true, ng: { model: 'address.phone'} } %tr %td City: %td - %input{ type: 'text', name: 'city', required: true, ng: { model: 'city'} } + %input{ type: 'text', name: 'city', required: true, ng: { model: 'address.city'} } %tr %td Zipcode: %td - %input{ type: 'text', name: 'zipcode', required: true, ng: { model: 'zipcode'} } + %input{ type: 'text', name: 'zipcode', required: true, ng: { model: 'address.zipcode'} } %tr %td Country: %td - %select{name: 'country', required: true, ng: {model: 'country', options: 'country as country.name for country in availableCountries track by country.id'}} + %select{name: 'country', required: true, ng: {model: 'address.country_id', options: 'country.id as country.name for country in availableCountries'}} %option{value: ''} Select Country %tr %td State: %td - %select{name: 'state', required: true, ng: {model: 'state', options: 'state as state.name for state in states track by state.id'}} + %select{name: 'state', required: true, ng: {model: 'address.state_id', options: 'state.id as state.name for state in states'}} %option{value: ''} Select State .text-center From 81d9ec71d95e86b8f49bff61131a696db5ae14a1 Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Wed, 10 Aug 2016 14:49:58 +1000 Subject: [PATCH 23/71] Front-end updating address function --- .../directives/edit_address_dialog.js.coffee | 13 +++++++++++-- .../customers/services/customer_resource.js.coffee | 4 ++++ .../admin/customers/services/customers.js.coffee | 8 ++++++++ .../templates/admin/edit_address_dialog.html.haml | 2 +- app/assets/stylesheets/admin/validation.css.scss | 5 +++++ app/views/admin/customers/index.html.haml | 5 +++-- 6 files changed, 32 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee b/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee index f80cd7c0ee..1758c752b3 100644 --- a/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee +++ b/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee @@ -7,13 +7,22 @@ angular.module("admin.customers").directive 'editAddressDialog', ($compile, $tem scope.states = scope.filter_states(newVal) scope.updateAddress = -> - console.log(scope.edit_address_form) + scope.edit_address_form.$setPristine() + + Customers.update(scope.address, scope.customer, scope.current_address).$promise.then (data) -> + scope.customer = data + template.dialog('close') template = $compile($templateCache.get('admin/edit_address_dialog.html'))(scope) template.dialog(DialogDefaults) element.bind 'click', (e) -> - scope.address = scope.customer.bill_address + if e.target.id == 'bill-address-link' + scope.current_address = 'bill_address' + else + scope.current_address = 'ship_address' + scope.address = scope.customer[scope.current_address] + template.dialog('open') scope.$apply() diff --git a/app/assets/javascripts/admin/customers/services/customer_resource.js.coffee b/app/assets/javascripts/admin/customers/services/customer_resource.js.coffee index 5b6c1ab205..3904d0333d 100644 --- a/app/assets/javascripts/admin/customers/services/customer_resource.js.coffee +++ b/app/assets/javascripts/admin/customers/services/customer_resource.js.coffee @@ -14,4 +14,8 @@ angular.module("admin.customers").factory 'CustomerResource', ($resource) -> method: 'DELETE' params: id: '@id' + 'update': + method: 'PUT' + params: + id: '@id' }) diff --git a/app/assets/javascripts/admin/customers/services/customers.js.coffee b/app/assets/javascripts/admin/customers/services/customers.js.coffee index cd4c9bbb44..90833cd5a1 100644 --- a/app/assets/javascripts/admin/customers/services/customers.js.coffee +++ b/app/assets/javascripts/admin/customers/services/customers.js.coffee @@ -25,3 +25,11 @@ angular.module("admin.customers").factory "Customers", ($q, InfoDialog, RequestM request = CustomerResource.index(params, (data) => @customers = data) RequestMonitor.load(request.$promise) request.$promise + + update: (address, customer, current_address) -> + params = + id: customer.id + customer: + "#{current_address}_attributes": address + CustomerResource.update params + diff --git a/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml b/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml index e6de7fb134..786cbbd0e2 100644 --- a/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml +++ b/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml @@ -1,5 +1,5 @@ #edit-address-dialog - %h2 Edit Shipping Address + %h2 {{ current_address === 'bill_address' ? 'Edit Billing Address' : 'Edit Shipping Address'}} %form{ name: 'edit_address_form', novalidate: true, ng: { submit: 'updateAddress()'}} .row Required fields are denoted with an asterisk ( diff --git a/app/assets/stylesheets/admin/validation.css.scss b/app/assets/stylesheets/admin/validation.css.scss index c97335a6c4..f8fa261fdb 100644 --- a/app/assets/stylesheets/admin/validation.css.scss +++ b/app/assets/stylesheets/admin/validation.css.scss @@ -5,3 +5,8 @@ input.ng-invalid { border: solid 1px red; } } + +select.ng-invalid { + border: solid 1px red; +} + diff --git a/app/views/admin/customers/index.html.haml b/app/views/admin/customers/index.html.haml index 9adf8812cb..d6156fd22d 100644 --- a/app/views/admin/customers/index.html.haml +++ b/app/views/admin/customers/index.html.haml @@ -86,8 +86,9 @@ .tag_watcher{ 'obj-for-update' => "customer", "attr-for-update" => "tag_list"} %tags_with_translation{ object: 'customer', 'find-tags' => 'findTags(query)' } %td.bill_address{ 'ng-show' => 'columns.bill_address.visible' } - %a{ href: '#', "ng-bind" => '::customer.bill_address.address1 | limitTo: 15', 'edit-address-dialog' => true } - %td.ship_address{ 'ng-show' => 'columns.ship_address.visible', "ng-bind" => '::customer.ship_address.address1 | limitTo: 15' } + %a{ id: 'bill-address-link', href: '#', "ng-bind" => "customer.bill_address ? customer.bill_address.address1 : 'Edit' | limitTo: 15", 'edit-address-dialog' => true } + %td.ship_address{ 'ng-show' => 'columns.ship_address.visible' } + %a{ id: 'ship-address-link', href: '#', "ng-bind" => "customer.ship_address ? customer.ship_address.address1 : 'Edit' | limitTo: 15", 'edit-address-dialog' => true } %td.actions %a{ 'ng-click' => "deleteCustomer(customer)", :class => "delete-customer icon-trash no-text" } From 22ccbd5556edf160eaaa2f506a3d2412e5ba73f5 Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Fri, 12 Aug 2016 10:49:53 +1000 Subject: [PATCH 24/71] Required fields validation --- .../directives/edit_address_dialog.js.coffee | 11 ++++++++--- .../admin/edit_address_dialog.html.haml | 19 +++++++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee b/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee index 1758c752b3..31da6fa153 100644 --- a/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee +++ b/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee @@ -2,16 +2,21 @@ angular.module("admin.customers").directive 'editAddressDialog', ($compile, $tem restrict: 'A' scope: true link: (scope, element, attr) -> + scope.errors = [] + scope.$watch 'address.country_id', (newVal) -> if newVal scope.states = scope.filter_states(newVal) scope.updateAddress = -> scope.edit_address_form.$setPristine() + if scope.edit_address_form.$valid + Customers.update(scope.address, scope.customer, scope.current_address).$promise.then (data) -> + scope.customer = data + template.dialog('close') + else + scope.errors.push("Sorry! Please input all of the required fields!") - Customers.update(scope.address, scope.customer, scope.current_address).$promise.then (data) -> - scope.customer = data - template.dialog('close') template = $compile($templateCache.get('admin/edit_address_dialog.html'))(scope) template.dialog(DialogDefaults) diff --git a/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml b/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml index 786cbbd0e2..357a8184d9 100644 --- a/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml +++ b/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml @@ -5,6 +5,8 @@ Required fields are denoted with an asterisk ( %span.required * ) + .error{ ng: { repeat: "error in errors", bind: "error" } } + %table.no-borders %tr %td @@ -14,33 +16,38 @@ %input{ type: 'text', name: 'address1', required: true, ng: { model: 'address.address1'} } %tr %td - Address2: + Address2 %td %input{ type: 'text', name: 'address2', ng: { model: 'address.address2'} } %tr %td - Phone: + Phone + %span.required * %td %input{ type: 'text', name: 'phone', required: true, ng: { model: 'address.phone'} } %tr %td - City: + City + %span.required * %td %input{ type: 'text', name: 'city', required: true, ng: { model: 'address.city'} } %tr %td - Zipcode: + Zipcode + %span.required * %td %input{ type: 'text', name: 'zipcode', required: true, ng: { model: 'address.zipcode'} } %tr %td - Country: + Country + %span.required * %td %select{name: 'country', required: true, ng: {model: 'address.country_id', options: 'country.id as country.name for country in availableCountries'}} %option{value: ''} Select Country %tr %td - State: + State + %span.required * %td %select{name: 'state', required: true, ng: {model: 'address.state_id', options: 'state.id as state.name for state in states'}} %option{value: ''} Select State From bdb2b5cce8c4dbad53ef38571c262b5054d12017 Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Fri, 12 Aug 2016 11:15:43 +1000 Subject: [PATCH 25/71] Style and i18n the edit address page --- .../admin/edit_address_dialog.html.haml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml b/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml index 357a8184d9..05010a8708 100644 --- a/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml +++ b/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml @@ -9,44 +9,44 @@ %table.no-borders %tr - %td - Address1 + %td{style: 'width: 30%'} + = t('spree.street_address') %span.required * %td %input{ type: 'text', name: 'address1', required: true, ng: { model: 'address.address1'} } %tr %td - Address2 + = t('spree.street_address_1') %td %input{ type: 'text', name: 'address2', ng: { model: 'address.address2'} } %tr %td - Phone + = t('spree.phone') %span.required * %td %input{ type: 'text', name: 'phone', required: true, ng: { model: 'address.phone'} } %tr %td - City + = t('spree.city') %span.required * %td %input{ type: 'text', name: 'city', required: true, ng: { model: 'address.city'} } %tr %td - Zipcode + = t('spree.zipcode') %span.required * %td %input{ type: 'text', name: 'zipcode', required: true, ng: { model: 'address.zipcode'} } %tr %td - Country + = t('spree.country') %span.required * %td %select{name: 'country', required: true, ng: {model: 'address.country_id', options: 'country.id as country.name for country in availableCountries'}} %option{value: ''} Select Country %tr %td - State + = t('spree.state') %span.required * %td %select{name: 'state', required: true, ng: {model: 'address.state_id', options: 'state.id as state.name for state in states'}} From 95c152420ca79b4f4ea8575fcd3ca3eaa2121dac Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Fri, 12 Aug 2016 11:55:22 +1000 Subject: [PATCH 26/71] Test customer model updating shipping address --- spec/models/customer_spec.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/spec/models/customer_spec.rb b/spec/models/customer_spec.rb index 32e380f4d3..37134e9574 100644 --- a/spec/models/customer_spec.rb +++ b/spec/models/customer_spec.rb @@ -18,6 +18,26 @@ describe Customer, type: :model do end end + describe 'update shipping address' do + let(:customer) { create(:customer) } + + it 'updates the shipping address' do + expect(customer.shipping_address).to be_nil + + ship_address = {zipcode: "3127", + city: "Melbourne", + state_id: 1, + phone: "455500146", + address1: "U 3/32 Florence Road Surrey Hills2", + country_id: 1} + customer.update_attributes!(ship_address_attributes: ship_address) + + expect(customer.ship_address.city).to eq 'Melbourne' + expect(customer.ship_address.firstname).to eq 'unused' + expect(customer.ship_address.lastname).to eq 'unused' + end + end + describe 'creation callbacks' do let!(:user1) { create(:user) } let!(:user2) { create(:user) } From 98f3e15d8745fcc430f3dae150536be808722d68 Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Fri, 12 Aug 2016 14:12:09 +1000 Subject: [PATCH 27/71] Updating customer address feature tests --- spec/features/admin/customers_spec.rb | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/spec/features/admin/customers_spec.rb b/spec/features/admin/customers_spec.rb index 9e341ba61f..080d192f77 100644 --- a/spec/features/admin/customers_spec.rb +++ b/spec/features/admin/customers_spec.rb @@ -150,6 +150,52 @@ feature 'Customers' do expect(customer2.reload.code).to be nil end + describe 'updating a customer addresses' do + before do + select2_select managed_distributor2.name, from: "shop_id" + end + + it 'updates the existing billing address' do + expect(page).to have_content 'BILLING ADDRESS' + + first('#bill-address-link').click + + expect(page).to have_content 'Edit Billing Address' + fill_in 'address1', with: "New Address1" + click_button 'Update Address' + + expect(page).to have_link 'New Address1' + + RackRequestBlocker.wait_for_requests_complete + + expect(customer4.reload.bill_address.address1).to eq 'New Address1' + end + + it 'creates a new shipping address' do + expect(page).to have_content 'SHIPPING ADDRESS' + + first('#ship-address-link').click + expect(page).to have_content 'Edit Shipping Address' + + fill_in 'address1', with: "New Address1" + fill_in 'phone', with: "12345678" + fill_in 'city', with: "Melbourne" + fill_in 'zipcode', with: "3000" + + select 'Australia', from: 'country' + select 'Victoria', from: 'state' + click_button 'Update Address' + + RackRequestBlocker.wait_for_requests_complete + + ship_address = customer4.reload.ship_address + + expect(ship_address.address1).to eq 'New Address1' + expect(ship_address.phone).to eq '12345678' + expect(ship_address.city).to eq 'Melbourne' + end + end + describe "creating a new customer" do context "when no shop has been selected" do it "asks the user to select a shop" do From ed1f05e674ca3099a79be8771aa6cbdef229c718 Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Fri, 12 Aug 2016 16:31:49 +1000 Subject: [PATCH 28/71] Show successful message --- .../customers/directives/edit_address_dialog.js.coffee | 3 ++- spec/features/admin/customers_spec.rb | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee b/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee index 31da6fa153..c81f187ef3 100644 --- a/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee +++ b/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee @@ -1,4 +1,4 @@ -angular.module("admin.customers").directive 'editAddressDialog', ($compile, $templateCache, $filter, DialogDefaults, Customers) -> +angular.module("admin.customers").directive 'editAddressDialog', ($compile, $templateCache, $filter, DialogDefaults, Customers, StatusMessage) -> restrict: 'A' scope: true link: (scope, element, attr) -> @@ -14,6 +14,7 @@ angular.module("admin.customers").directive 'editAddressDialog', ($compile, $tem Customers.update(scope.address, scope.customer, scope.current_address).$promise.then (data) -> scope.customer = data template.dialog('close') + StatusMessage.display('success', "Address updated successfully.") else scope.errors.push("Sorry! Please input all of the required fields!") diff --git a/spec/features/admin/customers_spec.rb b/spec/features/admin/customers_spec.rb index 080d192f77..07352ad151 100644 --- a/spec/features/admin/customers_spec.rb +++ b/spec/features/admin/customers_spec.rb @@ -164,10 +164,9 @@ feature 'Customers' do fill_in 'address1', with: "New Address1" click_button 'Update Address' + expect(page).to have_content 'Address updated successfully.' expect(page).to have_link 'New Address1' - RackRequestBlocker.wait_for_requests_complete - expect(customer4.reload.bill_address.address1).to eq 'New Address1' end @@ -186,7 +185,8 @@ feature 'Customers' do select 'Victoria', from: 'state' click_button 'Update Address' - RackRequestBlocker.wait_for_requests_complete + expect(page).to have_content 'Address updated successfully.' + expect(page).to have_link 'New Address1' ship_address = customer4.reload.ship_address From c34e9c046bea0162788df332a7f61933d23e5b27 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 17 Aug 2016 16:44:27 +1000 Subject: [PATCH 29/71] Remove quotes around url --- app/views/enterprise_mailer/welcome.html.haml | 2 +- app/views/spree/user_mailer/signup_confirmation.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/enterprise_mailer/welcome.html.haml b/app/views/enterprise_mailer/welcome.html.haml index 79fae6542b..33db02ed98 100644 --- a/app/views/enterprise_mailer/welcome.html.haml +++ b/app/views/enterprise_mailer/welcome.html.haml @@ -13,7 +13,7 @@ = t :email_admin_html, link: link_to('Admin Panel', spree.admin_url) %p - = t :email_community_html, link: link_to(t(:join_the_community), "#{ ContentConfig.community_forum_url }") + = t :email_community_html, link: link_to(t(:join_the_community), ContentConfig.community_forum_url) %p = t :email_help diff --git a/app/views/spree/user_mailer/signup_confirmation.html.haml b/app/views/spree/user_mailer/signup_confirmation.html.haml index 5598156346..273d497c5d 100644 --- a/app/views/spree/user_mailer/signup_confirmation.html.haml +++ b/app/views/spree/user_mailer/signup_confirmation.html.haml @@ -21,7 +21,7 @@ %p.lead = t :email_signup_text %p - = t :email_signup_help_html, email: mail_to("#{ContentConfig.footer_email}") + = t :email_signup_help_html, email: mail_to(ContentConfig.footer_email) = render 'shared/mailers/signoff' From e5d7b545c93cf9584e94673d7e90a00ba39844f7 Mon Sep 17 00:00:00 2001 From: Bing Xie Date: Wed, 24 Aug 2016 10:43:50 +1000 Subject: [PATCH 30/71] I18n and refactoring --- .../directives/edit_address_dialog.js.coffee | 12 ++++++------ .../admin/customers/services/customers.js.coffee | 4 ++-- .../templates/admin/edit_address_dialog.html.haml | 11 +++++++---- app/views/admin/customers/index.html.haml | 4 ++-- config/locales/en.yml | 8 ++++++++ 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee b/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee index c81f187ef3..5fb55eaeba 100644 --- a/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee +++ b/app/assets/javascripts/admin/customers/directives/edit_address_dialog.js.coffee @@ -11,12 +11,12 @@ angular.module("admin.customers").directive 'editAddressDialog', ($compile, $tem scope.updateAddress = -> scope.edit_address_form.$setPristine() if scope.edit_address_form.$valid - Customers.update(scope.address, scope.customer, scope.current_address).$promise.then (data) -> + Customers.update(scope.address, scope.customer, scope.addressType).$promise.then (data) -> scope.customer = data template.dialog('close') - StatusMessage.display('success', "Address updated successfully.") + StatusMessage.display('success', t('admin.customers.index.update_address_success')) else - scope.errors.push("Sorry! Please input all of the required fields!") + scope.errors.push(t('admin.customers.index.update_address_error')) template = $compile($templateCache.get('admin/edit_address_dialog.html'))(scope) @@ -24,10 +24,10 @@ angular.module("admin.customers").directive 'editAddressDialog', ($compile, $tem element.bind 'click', (e) -> if e.target.id == 'bill-address-link' - scope.current_address = 'bill_address' + scope.addressType = 'bill_address' else - scope.current_address = 'ship_address' - scope.address = scope.customer[scope.current_address] + scope.addressType = 'ship_address' + scope.address = scope.customer[scope.addressType] template.dialog('open') scope.$apply() diff --git a/app/assets/javascripts/admin/customers/services/customers.js.coffee b/app/assets/javascripts/admin/customers/services/customers.js.coffee index 90833cd5a1..f4c6f6f3cd 100644 --- a/app/assets/javascripts/admin/customers/services/customers.js.coffee +++ b/app/assets/javascripts/admin/customers/services/customers.js.coffee @@ -26,10 +26,10 @@ angular.module("admin.customers").factory "Customers", ($q, InfoDialog, RequestM RequestMonitor.load(request.$promise) request.$promise - update: (address, customer, current_address) -> + update: (address, customer, addressType) -> params = id: customer.id customer: - "#{current_address}_attributes": address + "#{addressType}_attributes": address CustomerResource.update params diff --git a/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml b/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml index 05010a8708..351a267bd3 100644 --- a/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml +++ b/app/assets/javascripts/templates/admin/edit_address_dialog.html.haml @@ -1,8 +1,9 @@ #edit-address-dialog - %h2 {{ current_address === 'bill_address' ? 'Edit Billing Address' : 'Edit Shipping Address'}} + %h2 {{ addressType === 'bill_address' ? "#{t('admin.customers.index.edit_bill_address')}" : "#{t('admin.customers.index.edit_ship_address')}" }} %form{ name: 'edit_address_form', novalidate: true, ng: { submit: 'updateAddress()'}} .row - Required fields are denoted with an asterisk ( + = t('admin.customers.index.required_fileds') + ( %span.required * ) .error{ ng: { repeat: "error in errors", bind: "error" } } @@ -43,14 +44,16 @@ %span.required * %td %select{name: 'country', required: true, ng: {model: 'address.country_id', options: 'country.id as country.name for country in availableCountries'}} - %option{value: ''} Select Country + %option{value: ''} + = t('admin.customers.index.select_country') %tr %td = t('spree.state') %span.required * %td %select{name: 'state', required: true, ng: {model: 'address.state_id', options: 'state.id as state.name for state in states'}} - %option{value: ''} Select State + %option{value: ''} + = t('admin.customers.index.select_state') .text-center %input.button.red.icon-plus{ type: 'submit', value: 'Update Address'} diff --git a/app/views/admin/customers/index.html.haml b/app/views/admin/customers/index.html.haml index d6156fd22d..7e08c2e4b3 100644 --- a/app/views/admin/customers/index.html.haml +++ b/app/views/admin/customers/index.html.haml @@ -86,9 +86,9 @@ .tag_watcher{ 'obj-for-update' => "customer", "attr-for-update" => "tag_list"} %tags_with_translation{ object: 'customer', 'find-tags' => 'findTags(query)' } %td.bill_address{ 'ng-show' => 'columns.bill_address.visible' } - %a{ id: 'bill-address-link', href: '#', "ng-bind" => "customer.bill_address ? customer.bill_address.address1 : 'Edit' | limitTo: 15", 'edit-address-dialog' => true } + %a{ id: 'bill-address-link', href: '#', "ng-bind" => "customer.bill_address ? customer.bill_address.address1 : '#{t('admin.customers.index.edit')}' | limitTo: 15", 'edit-address-dialog' => true } %td.ship_address{ 'ng-show' => 'columns.ship_address.visible' } - %a{ id: 'ship-address-link', href: '#', "ng-bind" => "customer.ship_address ? customer.ship_address.address1 : 'Edit' | limitTo: 15", 'edit-address-dialog' => true } + %a{ id: 'ship-address-link', href: '#', "ng-bind" => "customer.ship_address ? customer.ship_address.address1 : '#{t('admin.customers.index.edit')}' | limitTo: 15", 'edit-address-dialog' => true } %td.actions %a{ 'ng-click' => "deleteCustomer(customer)", :class => "delete-customer icon-trash no-text" } diff --git a/config/locales/en.yml b/config/locales/en.yml index bff650be2b..b74f62ed8c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -120,6 +120,14 @@ en: duplicate_code: "This code is used already." bill_address: "Billing Address" ship_address: "Shipping Address" + update_address_success: 'Address updated successfully.' + update_address_error: 'Sorry! Please input all of the required fields!' + edit_bill_address: 'Edit Billing Address' + edit_ship_address: 'Edit Shipping Address' + required_fileds: 'Required fields are denoted with an asterisk ' + select_country: 'Select Country' + select_state: 'Select State' + edit: 'Edit' products: bulk_edit: From 0dc12d8791849001cedf862b95e3b019a77e4df5 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 10 Aug 2016 10:45:22 +1000 Subject: [PATCH 31/71] Parameterise add_product_to_cart spec helper method --- spec/features/consumer/shopping/cart_spec.rb | 2 +- spec/features/consumer/shopping/checkout_auth_spec.rb | 2 +- spec/features/consumer/shopping/checkout_spec.rb | 2 +- spec/support/request/shop_workflow.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/features/consumer/shopping/cart_spec.rb b/spec/features/consumer/shopping/cart_spec.rb index ed573d0460..2bae14214c 100644 --- a/spec/features/consumer/shopping/cart_spec.rb +++ b/spec/features/consumer/shopping/cart_spec.rb @@ -19,7 +19,7 @@ feature "full-page cart", js: true do before do add_enterprise_fee enterprise_fee set_order order - add_product_to_cart + add_product_to_cart order, product visit spree.cart_path end diff --git a/spec/features/consumer/shopping/checkout_auth_spec.rb b/spec/features/consumer/shopping/checkout_auth_spec.rb index 0b0683def0..e23e4c15a8 100644 --- a/spec/features/consumer/shopping/checkout_auth_spec.rb +++ b/spec/features/consumer/shopping/checkout_auth_spec.rb @@ -18,7 +18,7 @@ feature "As a consumer I want to check out my cart", js: true do before do set_order order - add_product_to_cart + add_product_to_cart order, product end it "does not not render the login form when logged in" do diff --git a/spec/features/consumer/shopping/checkout_spec.rb b/spec/features/consumer/shopping/checkout_spec.rb index 10147b21a4..6055cb47d1 100644 --- a/spec/features/consumer/shopping/checkout_spec.rb +++ b/spec/features/consumer/shopping/checkout_spec.rb @@ -23,7 +23,7 @@ feature "As a consumer I want to check out my cart", js: true do add_enterprise_fee enterprise_fee set_order order - add_product_to_cart + add_product_to_cart order, product end describe "with shipping and payment methods" do diff --git a/spec/support/request/shop_workflow.rb b/spec/support/request/shop_workflow.rb index 01c24bee05..5dc07961d8 100644 --- a/spec/support/request/shop_workflow.rb +++ b/spec/support/request/shop_workflow.rb @@ -16,7 +16,7 @@ module ShopWorkflow ApplicationController.any_instance.stub(:session).and_return({order_id: order.id, access_token: order.token}) end - def add_product_to_cart + def add_product_to_cart(order, product) populator = Spree::OrderPopulator.new(order, order.currency) populator.populate(variants: {product.variants.first.id => 1}) From 7b2f65a965169f8536206527be1d58ec64167e79 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 10 Aug 2016 10:57:46 +1000 Subject: [PATCH 32/71] Refactor spec so we can have different products in the cart --- spec/features/consumer/shopping/cart_spec.rb | 24 ++++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/spec/features/consumer/shopping/cart_spec.rb b/spec/features/consumer/shopping/cart_spec.rb index 2bae14214c..ab2b5e5a7c 100644 --- a/spec/features/consumer/shopping/cart_spec.rb +++ b/spec/features/consumer/shopping/cart_spec.rb @@ -10,20 +10,23 @@ feature "full-page cart", js: true do let!(:zone) { create(:zone_with_member) } let(:distributor) { create(:distributor_enterprise, with_payment_and_shipping: true, charges_sales_tax: true) } let(:supplier) { create(:supplier_enterprise) } - let!(:order_cycle) { create(:simple_order_cycle, suppliers: [supplier], distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product.variants.first]) } - let(:enterprise_fee) { create(:enterprise_fee, amount: 11.00, tax_category: product.tax_category) } - let(:product) { create(:taxed_product, supplier: supplier, zone: zone, price: 110.00, tax_rate_amount: 0.1) } - let(:variant) { product.variants.first } + let!(:order_cycle) { create(:simple_order_cycle, suppliers: [supplier], distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product_tax.variants.first, product_fee.variants.first]) } + let(:enterprise_fee) { create(:enterprise_fee, amount: 11.00, tax_category: product_tax.tax_category) } + let(:product_tax) { create(:taxed_product, supplier: supplier, zone: zone, price: 110.00, tax_rate_amount: 0.1) } + let(:product_fee) { create(:simple_product, supplier: supplier, price: 0.86) } let(:order) { create(:order, order_cycle: order_cycle, distributor: distributor) } before do add_enterprise_fee enterprise_fee set_order order - add_product_to_cart order, product - visit spree.cart_path end describe "tax" do + before do + add_product_to_cart order, product_tax + visit spree.cart_path + end + it "shows the total tax for the order, including product tax and tax on fees" do page.should have_selector '.tax-total', text: '11.00' # 10 + 1 end @@ -31,12 +34,15 @@ feature "full-page cart", js: true do describe "updating quantities with insufficient stock available" do let(:li) { order.line_items(true).last } + let(:variant) { product_tax.variants.first } before do - variant.update_attributes! on_hand: 2 + add_product_to_cart order, product_tax end it "prevents me from entering an invalid value" do + # Given we have 2 on hand, and we've loaded the page after that fact + variant.update_attributes! on_hand: 2 visit spree.cart_path accept_alert 'Insufficient stock available, only 2 remaining' do @@ -47,6 +53,10 @@ feature "full-page cart", js: true do end it "shows the quantities saved, not those submitted" do + # Given we load the page with 3 on hand, then the number available drops to 2 + visit spree.cart_path + variant.update_attributes! on_hand: 2 + fill_in "order_line_items_attributes_0_quantity", with: '4' click_button 'Update' From b0eebc2e455dd0fd9910eff0f0b9bb817a747f65 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 10 Aug 2016 12:17:10 +1000 Subject: [PATCH 33/71] Round FlatPercentItemTotal calcs per-item before summing full quantity --- .../flat_percent_item_total_decorator.rb | 18 +++++++++++++++ spec/features/consumer/shopping/cart_spec.rb | 23 +++++++++++++++++-- .../flat_percent_item_total_spec.rb | 15 ++++++++++++ spec/support/request/shop_workflow.rb | 4 ++-- 4 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 app/models/spree/calculator/flat_percent_item_total_decorator.rb create mode 100644 spec/models/spree/calculator/flat_percent_item_total_spec.rb diff --git a/app/models/spree/calculator/flat_percent_item_total_decorator.rb b/app/models/spree/calculator/flat_percent_item_total_decorator.rb new file mode 100644 index 0000000000..3df011fcaf --- /dev/null +++ b/app/models/spree/calculator/flat_percent_item_total_decorator.rb @@ -0,0 +1,18 @@ +Spree::Calculator::FlatPercentItemTotal.class_eval do + # Spree's calculator sums all amounts, and then calculates a percentage on them. + # In the cart, we display line item individual amounts rounded, so to have consistent + # calculations we do the same internally. Here, we round adjustments at the individual + # item level first, then multiply by the item quantity. + + + def compute(object) + line_items_for(object).sum do |li| + unless li.price.present? && li.quantity.present? + raise ArgumentError, "object must respond to #price and #quantity" + end + + value = (li.price * BigDecimal(self.preferred_flat_percent.to_s) / 100.0).round(2) + value * li.quantity + end + end +end diff --git a/spec/features/consumer/shopping/cart_spec.rb b/spec/features/consumer/shopping/cart_spec.rb index ab2b5e5a7c..ac34d9246b 100644 --- a/spec/features/consumer/shopping/cart_spec.rb +++ b/spec/features/consumer/shopping/cart_spec.rb @@ -13,16 +13,35 @@ feature "full-page cart", js: true do let!(:order_cycle) { create(:simple_order_cycle, suppliers: [supplier], distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product_tax.variants.first, product_fee.variants.first]) } let(:enterprise_fee) { create(:enterprise_fee, amount: 11.00, tax_category: product_tax.tax_category) } let(:product_tax) { create(:taxed_product, supplier: supplier, zone: zone, price: 110.00, tax_rate_amount: 0.1) } - let(:product_fee) { create(:simple_product, supplier: supplier, price: 0.86) } + let(:product_fee) { create(:simple_product, supplier: supplier, price: 0.86, on_hand: 100) } let(:order) { create(:order, order_cycle: order_cycle, distributor: distributor) } before do - add_enterprise_fee enterprise_fee set_order order end + describe "fees" do + let(:percentage_fee) { create(:enterprise_fee, calculator: Spree::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 20)) } + + before do + add_enterprise_fee percentage_fee + add_product_to_cart order, product_fee, quantity: 8 + visit spree.cart_path + end + + it "rounds fee calculations correctly" do + # $0.86 + 20% = $1.032 + # Fractional cents should be immediately rounded down and not carried through + expect(page).to have_selector '.cart-item-price', text: '$1.03' + expect(page).to have_selector '.cart-item-total', text: '$8.24' + expect(page).to have_selector '.order-total.item-total', text: '$8.24' + expect(page).to have_selector '.order-total.grand-total', text: '$8.24' + end + end + describe "tax" do before do + add_enterprise_fee enterprise_fee add_product_to_cart order, product_tax visit spree.cart_path end diff --git a/spec/models/spree/calculator/flat_percent_item_total_spec.rb b/spec/models/spree/calculator/flat_percent_item_total_spec.rb new file mode 100644 index 0000000000..b4b5e21d62 --- /dev/null +++ b/spec/models/spree/calculator/flat_percent_item_total_spec.rb @@ -0,0 +1,15 @@ +module Spree + describe Calculator::FlatPercentItemTotal do + let(:calculator) { Calculator::FlatPercentItemTotal.new preferred_flat_percent: 20 } + + it "calculates for a simple line item" do + line_item = LineItem.new price: 50, quantity: 2 + expect(calculator.compute(line_item)).to eq 20 + end + + it "rounds fractional cents before summing" do + line_item = LineItem.new price: 0.86, quantity: 8 + expect(calculator.compute(line_item)).to eq 1.36 + end + end +end diff --git a/spec/support/request/shop_workflow.rb b/spec/support/request/shop_workflow.rb index 5dc07961d8..3fc7ac53a6 100644 --- a/spec/support/request/shop_workflow.rb +++ b/spec/support/request/shop_workflow.rb @@ -16,9 +16,9 @@ module ShopWorkflow ApplicationController.any_instance.stub(:session).and_return({order_id: order.id, access_token: order.token}) end - def add_product_to_cart(order, product) + def add_product_to_cart(order, product, quantity: 1) populator = Spree::OrderPopulator.new(order, order.currency) - populator.populate(variants: {product.variants.first.id => 1}) + populator.populate(variants: {product.variants.first.id => quantity}) # Recalculate fee totals order.update_distribution_charge! From 5b964ef502219c3d59a13f74a1c0190fb8f32ff5 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 10 Aug 2016 12:35:30 +1000 Subject: [PATCH 34/71] Provide price to calculator to meet new requirements of FlatPercentItemTotal --- lib/open_food_network/enterprise_fee_calculator.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/open_food_network/enterprise_fee_calculator.rb b/lib/open_food_network/enterprise_fee_calculator.rb index 7222abad1c..e72f643ff2 100644 --- a/lib/open_food_network/enterprise_fee_calculator.rb +++ b/lib/open_food_network/enterprise_fee_calculator.rb @@ -104,8 +104,7 @@ module OpenFoodNetwork def calculate_fee_for(variant, enterprise_fee) # Spree's Calculator interface accepts Orders or LineItems, # so we meet that interface with a struct. - # Amount is faked, this is a method on LineItem - line_item = OpenStruct.new variant: variant, quantity: 1, amount: variant.price + line_item = OpenStruct.new variant: variant, quantity: 1, price: variant.price, amount: variant.price enterprise_fee.compute_amount(line_item) end From fa30e28335d2fa291d59db8ccb12ffb3e4e27dad Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 10 Aug 2016 12:42:38 +1000 Subject: [PATCH 35/71] Update spec: Our pricing calculations are now consistent between the frontend and backend carts --- .../consumer/shopping/variant_overrides_spec.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/features/consumer/shopping/variant_overrides_spec.rb b/spec/features/consumer/shopping/variant_overrides_spec.rb index ecb0c4efe8..e6be127791 100644 --- a/spec/features/consumer/shopping/variant_overrides_spec.rb +++ b/spec/features/consumer/shopping/variant_overrides_spec.rb @@ -91,17 +91,17 @@ feature "shopping with variant overrides defined", js: true, retry: 3 do page.should have_field "order[line_items_attributes][0][quantity]", with: '2' page.should have_selector "tr.line-item.variant-#{v1.id} .cart-item-total", text: '$122.22' - page.should have_selector "#edit-cart .item-total", text: '$122.21' - page.should have_selector "#edit-cart .grand-total", text: '$122.21' + page.should have_selector "#edit-cart .item-total", text: '$122.22' + page.should have_selector "#edit-cart .grand-total", text: '$122.22' end it "shows the correct prices in the checkout" do fill_in "variants[#{v1.id}]", with: "2" click_checkout - page.should have_selector 'form.edit_order .cart-total', text: '$122.21' + page.should have_selector 'form.edit_order .cart-total', text: '$122.22' page.should have_selector 'form.edit_order .shipping', text: '$0.00' - page.should have_selector 'form.edit_order .total', text: '$122.21' + page.should have_selector 'form.edit_order .total', text: '$122.22' end end @@ -115,7 +115,7 @@ feature "shopping with variant overrides defined", js: true, retry: 3 do o = Spree::Order.complete.last o.line_items.first.price.should == 55.55 - o.total.should == 122.21 + o.total.should == 122.22 end it "subtracts stock from the override" do From 701c047a0ae93231135ed1733cc6b9f2b7e1aa3c Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 19 Aug 2016 16:48:32 +1000 Subject: [PATCH 36/71] Move our customisations of FlatPercentItemTotal calculator to a new calc: FlatPercentPerItem --- .../flat_percent_per_item.rb} | 14 ++++++++++++-- config/application.rb | 2 ++ config/locales/en.yml | 1 + spec/features/consumer/shopping/cart_spec.rb | 2 +- .../calculator/flat_percent_per_item_spec.rb | 13 +++++++++++++ .../calculator/flat_percent_item_total_spec.rb | 15 --------------- 6 files changed, 29 insertions(+), 18 deletions(-) rename app/models/{spree/calculator/flat_percent_item_total_decorator.rb => calculator/flat_percent_per_item.rb} (61%) create mode 100644 spec/models/calculator/flat_percent_per_item_spec.rb delete mode 100644 spec/models/spree/calculator/flat_percent_item_total_spec.rb diff --git a/app/models/spree/calculator/flat_percent_item_total_decorator.rb b/app/models/calculator/flat_percent_per_item.rb similarity index 61% rename from app/models/spree/calculator/flat_percent_item_total_decorator.rb rename to app/models/calculator/flat_percent_per_item.rb index 3df011fcaf..17089b2f2c 100644 --- a/app/models/spree/calculator/flat_percent_item_total_decorator.rb +++ b/app/models/calculator/flat_percent_per_item.rb @@ -1,9 +1,19 @@ -Spree::Calculator::FlatPercentItemTotal.class_eval do - # Spree's calculator sums all amounts, and then calculates a percentage on them. +require_dependency 'spree/calculator' + +class Calculator::FlatPercentPerItem < Spree::Calculator + # Spree's FlatPercentItemTotal calculator sums all amounts, and then calculates a percentage + # on them. # In the cart, we display line item individual amounts rounded, so to have consistent # calculations we do the same internally. Here, we round adjustments at the individual # item level first, then multiply by the item quantity. + preference :flat_percent, :decimal, :default => 0 + + attr_accessible :preferred_flat_percent + + def self.description + I18n.t(:flat_percent_per_item) + end def compute(object) line_items_for(object).sum do |li| diff --git a/config/application.rb b/config/application.rb index 9abd0a3b9b..b3041e9b30 100644 --- a/config/application.rb +++ b/config/application.rb @@ -29,12 +29,14 @@ module Openfoodnetwork app.config.spree.calculators.shipping_methods << OpenFoodNetwork::Calculator::Weight app.config.spree.calculators.enterprise_fees = [Spree::Calculator::FlatPercentItemTotal, + Calculator::FlatPercentPerItem, Spree::Calculator::FlatRate, Spree::Calculator::FlexiRate, Spree::Calculator::PerItem, Spree::Calculator::PriceSack, OpenFoodNetwork::Calculator::Weight] app.config.spree.calculators.payment_methods = [Spree::Calculator::FlatPercentItemTotal, + Calculator::FlatPercentPerItem, Spree::Calculator::FlatRate, Spree::Calculator::FlexiRate, Spree::Calculator::PerItem, diff --git a/config/locales/en.yml b/config/locales/en.yml index 4827f6609a..1d8707a7b9 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -911,6 +911,7 @@ Please follow the instructions there to make your enterprise visible on the Open tax_category: "Tax Category" calculator: "Calculator" calculator_values: "Calculator values" + flat_percent_per_item: "Flat Percent (per item)" new_order_cycles: "New Order Cycles" select_a_coordinator_for_your_order_cycle: "Select a coordinator for your order cycle" edit_order_cycle: "Edit Order Cycle" diff --git a/spec/features/consumer/shopping/cart_spec.rb b/spec/features/consumer/shopping/cart_spec.rb index ac34d9246b..b604769502 100644 --- a/spec/features/consumer/shopping/cart_spec.rb +++ b/spec/features/consumer/shopping/cart_spec.rb @@ -21,7 +21,7 @@ feature "full-page cart", js: true do end describe "fees" do - let(:percentage_fee) { create(:enterprise_fee, calculator: Spree::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 20)) } + let(:percentage_fee) { create(:enterprise_fee, calculator: Calculator::FlatPercentPerItem.new(preferred_flat_percent: 20)) } before do add_enterprise_fee percentage_fee diff --git a/spec/models/calculator/flat_percent_per_item_spec.rb b/spec/models/calculator/flat_percent_per_item_spec.rb new file mode 100644 index 0000000000..aaeff2a328 --- /dev/null +++ b/spec/models/calculator/flat_percent_per_item_spec.rb @@ -0,0 +1,13 @@ +describe Calculator::FlatPercentPerItem do + let(:calculator) { Calculator::FlatPercentPerItem.new preferred_flat_percent: 20 } + + it "calculates for a simple line item" do + line_item = Spree::LineItem.new price: 50, quantity: 2 + expect(calculator.compute(line_item)).to eq 20 + end + + it "rounds fractional cents before summing" do + line_item = Spree::LineItem.new price: 0.86, quantity: 8 + expect(calculator.compute(line_item)).to eq 1.36 + end +end diff --git a/spec/models/spree/calculator/flat_percent_item_total_spec.rb b/spec/models/spree/calculator/flat_percent_item_total_spec.rb deleted file mode 100644 index b4b5e21d62..0000000000 --- a/spec/models/spree/calculator/flat_percent_item_total_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Spree - describe Calculator::FlatPercentItemTotal do - let(:calculator) { Calculator::FlatPercentItemTotal.new preferred_flat_percent: 20 } - - it "calculates for a simple line item" do - line_item = LineItem.new price: 50, quantity: 2 - expect(calculator.compute(line_item)).to eq 20 - end - - it "rounds fractional cents before summing" do - line_item = LineItem.new price: 0.86, quantity: 8 - expect(calculator.compute(line_item)).to eq 1.36 - end - end -end From 10b076562f8ace7d11a1bb504eef5f5337428ef9 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 19 Aug 2016 17:06:46 +1000 Subject: [PATCH 37/71] Make all calculators use FlatPercentPerItem instead of FlatPercentItemTotal --- ...wap_calculator_to_flat_percent_per_item.rb | 29 +++++++++++++++++++ db/schema.rb | 4 +-- 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20160819065331_swap_calculator_to_flat_percent_per_item.rb diff --git a/db/migrate/20160819065331_swap_calculator_to_flat_percent_per_item.rb b/db/migrate/20160819065331_swap_calculator_to_flat_percent_per_item.rb new file mode 100644 index 0000000000..eb8e206e8f --- /dev/null +++ b/db/migrate/20160819065331_swap_calculator_to_flat_percent_per_item.rb @@ -0,0 +1,29 @@ +class SwapCalculatorToFlatPercentPerItem < ActiveRecord::Migration + class Spree::Calculator < ActiveRecord::Base + end + + def up + Spree::Calculator.where(calculable_type: "EnterpriseFee", type: 'Spree::Calculator::FlatPercentItemTotal').each do |c| + swap_calculator_type c, 'Calculator::FlatPercentPerItem' + end + end + + def down + Spree::Calculator.where(calculable_type: "EnterpriseFee", type: 'Spree::Calculator::FlatPercentPerItem').each do |c| + swap_calculator_type c, 'Calculator::FlatPercentItemTotal' + end + end + + + private + + def swap_calculator_type(calculator, to_class) + value = calculator.preferred_flat_percent + + calculator.type = to_class + calculator.save + + calculator = Spree::Calculator.find calculator.id + calculator.preferred_flat_percent = value + end +end diff --git a/db/schema.rb b/db/schema.rb index 9a825e299c..48b07e3cdb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20160713013358) do +ActiveRecord::Schema.define(:version => 20160819065331) do create_table "account_invoices", :force => true do |t| t.integer "user_id", :null => false @@ -582,9 +582,9 @@ ActiveRecord::Schema.define(:version => 20160713013358) do t.string "email" t.text "special_instructions" t.integer "distributor_id" + t.integer "order_cycle_id" t.string "currency" t.string "last_ip_address" - t.integer "order_cycle_id" t.integer "cart_id" t.integer "customer_id" end From 308c24caf4a1a2934afcda27e011893763dbb9f6 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 19 Aug 2016 17:42:55 +1000 Subject: [PATCH 38/71] Add FlatPercentPerItem calculator for shipping methods, remove FlatPercentItemTotal for enterprise fees (causes shopfront cart discrepencies). --- config/application.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/application.rb b/config/application.rb index b3041e9b30..d90b450ff8 100644 --- a/config/application.rb +++ b/config/application.rb @@ -27,9 +27,9 @@ module Openfoodnetwork # Register Spree calculators initializer "spree.register.calculators" do |app| app.config.spree.calculators.shipping_methods << OpenFoodNetwork::Calculator::Weight + app.config.spree.calculators.shipping_methods << Calculator::FlatPercentPerItem - app.config.spree.calculators.enterprise_fees = [Spree::Calculator::FlatPercentItemTotal, - Calculator::FlatPercentPerItem, + app.config.spree.calculators.enterprise_fees = [Calculator::FlatPercentPerItem, Spree::Calculator::FlatRate, Spree::Calculator::FlexiRate, Spree::Calculator::PerItem, From 24d0e4fcf8aa70dad95199480ac25ff0090ba1ca Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 19 Aug 2016 17:58:59 +1000 Subject: [PATCH 39/71] Update specs for calculator change --- spec/features/admin/enterprise_fees_spec.rb | 4 ++-- spec/features/consumer/shopping/variant_overrides_spec.rb | 2 +- spec/lib/open_food_network/enterprise_fee_calculator_spec.rb | 2 +- spec/models/enterprise_fee_spec.rb | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/features/admin/enterprise_fees_spec.rb b/spec/features/admin/enterprise_fees_spec.rb index 7025b54766..cd24e8e3a3 100644 --- a/spec/features/admin/enterprise_fees_spec.rb +++ b/spec/features/admin/enterprise_fees_spec.rb @@ -77,13 +77,13 @@ feature %q{ page.should have_select "enterprise_fee_set_collection_attributes_0_fee_type", selected: 'Admin' page.should have_selector "input[value='Greetings!']" page.should have_select 'enterprise_fee_set_collection_attributes_0_tax_category_id', selected: 'Inherit From Product' - page.should have_selector "option[selected]", text: 'Flat Percent' + page.should have_selector "option[selected]", text: 'Flat Percent (per item)' fee.reload fee.enterprise.should == enterprise fee.name.should == 'Greetings!' fee.fee_type.should == 'admin' - fee.calculator_type.should == "Spree::Calculator::FlatPercentItemTotal" + fee.calculator_type.should == "Calculator::FlatPercentPerItem" # Sets tax_category and inherits_tax_category fee.tax_category.should == nil diff --git a/spec/features/consumer/shopping/variant_overrides_spec.rb b/spec/features/consumer/shopping/variant_overrides_spec.rb index e6be127791..f4ee8e6275 100644 --- a/spec/features/consumer/shopping/variant_overrides_spec.rb +++ b/spec/features/consumer/shopping/variant_overrides_spec.rb @@ -28,7 +28,7 @@ feature "shopping with variant overrides defined", js: true, retry: 3 do let!(:vo4) { create(:variant_override, hub: hub, variant: v4, count_on_hand: 3, default_stock: nil, resettable: false) } let!(:vo5) { create(:variant_override, hub: hub, variant: v5, count_on_hand: 0, default_stock: nil, resettable: false) } let!(:vo6) { create(:variant_override, hub: hub, variant: v6, count_on_hand: 6, default_stock: nil, resettable: false) } - let(:ef) { create(:enterprise_fee, enterprise: hub, fee_type: 'packing', calculator: Spree::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10)) } + let(:ef) { create(:enterprise_fee, enterprise: hub, fee_type: 'packing', calculator: Calculator::FlatPercentPerItem.new(preferred_flat_percent: 10)) } before do outgoing_exchange.variants = [v1, v2, v3, v4, v5, v6] diff --git a/spec/lib/open_food_network/enterprise_fee_calculator_spec.rb b/spec/lib/open_food_network/enterprise_fee_calculator_spec.rb index a31295ac9d..0fb42f3052 100644 --- a/spec/lib/open_food_network/enterprise_fee_calculator_spec.rb +++ b/spec/lib/open_food_network/enterprise_fee_calculator_spec.rb @@ -66,7 +66,7 @@ module OpenFoodNetwork end describe "summing percentage fees for the variant" do - let!(:enterprise_fee1) { create(:enterprise_fee, amount: 20, fee_type: "admin", calculator: Spree::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 20)) } + let!(:enterprise_fee1) { create(:enterprise_fee, amount: 20, fee_type: "admin", calculator: ::Calculator::FlatPercentPerItem.new(preferred_flat_percent: 20)) } let!(:exchange) { create(:exchange, order_cycle: order_cycle, sender: coordinator, receiver: distributor, incoming: false, enterprise_fees: [enterprise_fee1], variants: [product1.master]) } diff --git a/spec/models/enterprise_fee_spec.rb b/spec/models/enterprise_fee_spec.rb index 7fac566f4b..e0df4ce5d0 100644 --- a/spec/models/enterprise_fee_spec.rb +++ b/spec/models/enterprise_fee_spec.rb @@ -75,7 +75,7 @@ describe EnterpriseFee do it "returns fees with any other calculator" do ef1 = create(:enterprise_fee, calculator: Spree::Calculator::DefaultTax.new) - ef2 = create(:enterprise_fee, calculator: Spree::Calculator::FlatPercentItemTotal.new) + ef2 = create(:enterprise_fee, calculator: Calculator::FlatPercentPerItem.new) ef3 = create(:enterprise_fee, calculator: Spree::Calculator::PerItem.new) ef4 = create(:enterprise_fee, calculator: Spree::Calculator::PriceSack.new) @@ -93,7 +93,7 @@ describe EnterpriseFee do it "does not return fees with any other calculator" do ef1 = create(:enterprise_fee, calculator: Spree::Calculator::DefaultTax.new) - ef2 = create(:enterprise_fee, calculator: Spree::Calculator::FlatPercentItemTotal.new) + ef2 = create(:enterprise_fee, calculator: Calculator::FlatPercentPerItem.new) ef3 = create(:enterprise_fee, calculator: Spree::Calculator::PerItem.new) ef4 = create(:enterprise_fee, calculator: Spree::Calculator::PriceSack.new) From 509564819aec6a54a697353997040447a2103588 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 26 Aug 2016 10:26:50 +1000 Subject: [PATCH 40/71] Remove FlatPercentPerItem calculator for shipping methods and payment methods to reduce confusion --- config/application.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/config/application.rb b/config/application.rb index d90b450ff8..f9d6151e10 100644 --- a/config/application.rb +++ b/config/application.rb @@ -27,7 +27,6 @@ module Openfoodnetwork # Register Spree calculators initializer "spree.register.calculators" do |app| app.config.spree.calculators.shipping_methods << OpenFoodNetwork::Calculator::Weight - app.config.spree.calculators.shipping_methods << Calculator::FlatPercentPerItem app.config.spree.calculators.enterprise_fees = [Calculator::FlatPercentPerItem, Spree::Calculator::FlatRate, @@ -36,7 +35,6 @@ module Openfoodnetwork Spree::Calculator::PriceSack, OpenFoodNetwork::Calculator::Weight] app.config.spree.calculators.payment_methods = [Spree::Calculator::FlatPercentItemTotal, - Calculator::FlatPercentPerItem, Spree::Calculator::FlatRate, Spree::Calculator::FlexiRate, Spree::Calculator::PerItem, From 4529ced3f2a75e0111469d33da7f19aca93df76f Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 10 Aug 2016 15:34:47 +1000 Subject: [PATCH 41/71] Find properties of items sold by a shop --- app/models/spree/property_decorator.rb | 7 +++++ spec/models/spree/property_spec.rb | 39 ++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/app/models/spree/property_decorator.rb b/app/models/spree/property_decorator.rb index f6eaefc75f..ede97bcc2d 100644 --- a/app/models/spree/property_decorator.rb +++ b/app/models/spree/property_decorator.rb @@ -6,6 +6,13 @@ module Spree where('spree_product_properties.product_id IN (?)', enterprise.supplied_product_ids) } + scope :sold_by, ->(shop) { + joins(products: {variants: {exchanges: :order_cycle}}). + merge(Exchange.outgoing). + merge(Exchange.to_enterprise(shop)). + merge(OrderCycle.active) + } + after_save :refresh_products_cache # When a Property is destroyed, dependent-destroy will destroy all ProductProperties, diff --git a/spec/models/spree/property_spec.rb b/spec/models/spree/property_spec.rb index 6867b9de1f..f291c4a7af 100644 --- a/spec/models/spree/property_spec.rb +++ b/spec/models/spree/property_spec.rb @@ -30,6 +30,45 @@ module Spree expect(Spree::Property.applied_by(producer).to_a.count).to eq 1 end end + + describe ".sold_by" do + let!(:shop) { create(:distributor_enterprise) } + let!(:shop_other) { create(:distributor_enterprise) } + let!(:product) { create(:simple_product) } + let!(:product_other_ex) { create(:simple_product) } + let!(:product_no_oc) { create(:simple_product) } + let!(:product_closed_oc) { create(:simple_product) } + let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first]) } + let!(:oc_closed) { create(:closed_order_cycle, distributors: [shop], variants: [product_closed_oc.variants.first]) } + let!(:exchange_other_shop) { create(:exchange, order_cycle: oc, sender: oc.coordinator, receiver: shop_other, variants: [product_other_ex.variants.first]) } + let(:property) { product.properties.last } + let(:property_other_ex) { product_other_ex.properties.last } + let(:property_no_oc) { product_no_oc.properties.last } + let(:property_closed_oc) { product_closed_oc.properties.last } + + before do + product.set_property 'Organic', 'NASAA 12345' + product_other_ex.set_property 'Biodynamic', 'ASDF 12345' + product_no_oc.set_property 'Shiny', 'Very' + product_closed_oc.set_property 'Spiffy', 'Ooh yeah' + end + + it "returns the property" do + expect(Property.sold_by(shop)).to eq [property] + end + + it "doesn't return the property from another exchange" do + expect(Property.sold_by(shop)).not_to include property_other_ex + end + + it "doesn't return the property with no order cycle" do + expect(Property.sold_by(shop)).not_to include property_no_oc + end + + it "doesn't return the property from a closed order cycle" do + expect(Property.sold_by(shop)).not_to include property_closed_oc + end + end end describe "callbacks" do From aa6e7cba307fe6a115bb8be8b8a83a5af6cde2a6 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 19 Aug 2016 09:48:12 +1000 Subject: [PATCH 42/71] Do not return duplicates with Spree::Property.sold_by --- app/models/spree/property_decorator.rb | 3 ++- spec/models/spree/property_spec.rb | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/models/spree/property_decorator.rb b/app/models/spree/property_decorator.rb index ede97bcc2d..58657ad3b1 100644 --- a/app/models/spree/property_decorator.rb +++ b/app/models/spree/property_decorator.rb @@ -10,7 +10,8 @@ module Spree joins(products: {variants: {exchanges: :order_cycle}}). merge(Exchange.outgoing). merge(Exchange.to_enterprise(shop)). - merge(OrderCycle.active) + merge(OrderCycle.active). + select('DISTINCT spree_properties.*') } after_save :refresh_products_cache diff --git a/spec/models/spree/property_spec.rb b/spec/models/spree/property_spec.rb index f291c4a7af..6e6ed2d780 100644 --- a/spec/models/spree/property_spec.rb +++ b/spec/models/spree/property_spec.rb @@ -68,6 +68,19 @@ module Spree it "doesn't return the property from a closed order cycle" do expect(Property.sold_by(shop)).not_to include property_closed_oc end + + context "with another product in the order cycle" do + let!(:product2) { create(:simple_product) } + let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first, product2.variants.first]) } + + before do + product2.set_property 'Organic', 'NASAA 12345' + end + + it "doesn't return duplicates" do + expect(Property.sold_by(shop).to_a.count).to eq 1 + end + end end end From c70993ce755d1d36e182cc1ef6cf8e1c8f895ea0 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 19 Aug 2016 10:17:41 +1000 Subject: [PATCH 43/71] Find producer properties of items sold by a shop --- app/models/producer_property.rb | 9 ++++ app/models/spree/property_decorator.rb | 3 ++ spec/models/producer_property_spec.rb | 64 ++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/app/models/producer_property.rb b/app/models/producer_property.rb index 5b9fdd6d1c..bf1f083936 100644 --- a/app/models/producer_property.rb +++ b/app/models/producer_property.rb @@ -8,6 +8,15 @@ class ProducerProperty < ActiveRecord::Base after_destroy :refresh_products_cache_from_destroy + scope :sold_by, ->(shop) { + joins(producer: {supplied_products: {variants: {exchanges: :order_cycle}}}). + merge(Exchange.outgoing). + merge(Exchange.to_enterprise(shop)). + merge(OrderCycle.active). + select('DISTINCT producer_properties.*') + } + + def property_name property.name if property end diff --git a/app/models/spree/property_decorator.rb b/app/models/spree/property_decorator.rb index 58657ad3b1..50e450a03b 100644 --- a/app/models/spree/property_decorator.rb +++ b/app/models/spree/property_decorator.rb @@ -1,5 +1,7 @@ module Spree Property.class_eval do + has_many :producer_properties + scope :applied_by, ->(enterprise) { select('DISTINCT spree_properties.*'). joins(:product_properties). @@ -14,6 +16,7 @@ module Spree select('DISTINCT spree_properties.*') } + after_save :refresh_products_cache # When a Property is destroyed, dependent-destroy will destroy all ProductProperties, diff --git a/spec/models/producer_property_spec.rb b/spec/models/producer_property_spec.rb index eaa7f0de0c..2d0009ce12 100644 --- a/spec/models/producer_property_spec.rb +++ b/spec/models/producer_property_spec.rb @@ -1,14 +1,70 @@ require 'spec_helper' describe ProducerProperty do - describe "products caching" do - let(:producer) { create(:supplier_enterprise) } - let(:pp) { producer.producer_properties.first } + let(:producer) { create(:supplier_enterprise) } + let(:pp) { producer.producer_properties.first } + + before do + producer.set_producer_property 'Organic Certified', 'NASAA 54321' + end + + describe ".sold_by" do + let!(:shop) { create(:distributor_enterprise) } + let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first]) } + let(:product) { create(:simple_product, supplier: producer) } + let(:producer_other) { create(:supplier_enterprise) } + let(:product_other) { create(:simple_product, supplier: producer_other) } + let(:pp_other) { producer_other.producer_properties.first } before do - producer.set_producer_property 'Organic Certified', 'NASAA 54321' + producer_other.set_producer_property 'Spiffy', 'Ya' end + describe "with an associated producer property" do + it "returns the producer property" do + expect(ProducerProperty.sold_by(shop)).to eq [pp] + end + end + + describe "with a producer property for a producer not carried by that shop" do + let!(:exchange) { create(:exchange, order_cycle: oc, incoming: true, sender: producer_other, receiver: oc.coordinator) } + + it "doesn't return the producer property" do + expect(ProducerProperty.sold_by(shop)).not_to include pp_other + end + end + + describe "with a producer property for a product in a different shop" do + let(:shop_other) { create(:distributor_enterprise) } + let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first]) } + let!(:exchange) { create(:exchange, order_cycle: oc, incoming: false, sender: oc.coordinator, receiver: shop_other, variants: [product_other.variants.first]) } + + it "doesn't return the producer property" do + expect(ProducerProperty.sold_by(shop)).not_to include pp_other + end + end + + describe "with a producer property for a product in a closed order cycle" do + before do + oc.update_attributes! orders_close_at: 1.week.ago + end + + it "doesn't return the producer property" do + expect(ProducerProperty.sold_by(shop)).not_to include pp + end + end + + describe "with a duplicate producer property" do + let(:product2) { create(:simple_product, supplier: producer) } + let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first, product2.variants.first]) } + + it "doesn't return duplicates" do + expect(ProducerProperty.sold_by(shop).to_a.count).to eq 1 + end + end + end + + describe "products caching" do it "refreshes the products cache on change" do expect(OpenFoodNetwork::ProductsCache).to receive(:producer_property_changed).with(pp) pp.value = 123 From 7b5e8fa603b98ce41f493dc4642523d0bb48335b Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 19 Aug 2016 11:30:20 +1000 Subject: [PATCH 44/71] Rename API field properties to supplied_properties --- .../darkswarm/filters/properties.js.coffee | 12 ++++-------- .../darkswarm/filters/properties_of.js.coffee | 2 +- .../templates/partials/enterprise_details.html.haml | 2 +- app/serializers/api/enterprise_serializer.rb | 4 ++-- app/views/producers/_fat.html.haml | 2 +- 5 files changed, 9 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/darkswarm/filters/properties.js.coffee b/app/assets/javascripts/darkswarm/filters/properties.js.coffee index 51b02e6634..dab89a4c08 100644 --- a/app/assets/javascripts/darkswarm/filters/properties.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/properties.js.coffee @@ -1,5 +1,5 @@ -Darkswarm.filter 'properties', ()-> - # Filter anything that responds to object.properties +Darkswarm.filter 'properties', -> + # Filter anything that responds to object.supplied_properties (objects, ids) -> objects ||= [] ids ?= [] @@ -7,10 +7,6 @@ Darkswarm.filter 'properties', ()-> # No properties selected, pass all objects through. objects else - objects.filter (obj)-> - properties = obj.properties - # Combine object properties with supplied properties, if they exist. - # properties = properties.concat obj.supplied_properties if obj.supplied_properties - # Match property array. - properties.some (property)-> + objects.filter (obj) -> + obj.supplied_properties.some (property) -> property.id in ids diff --git a/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee b/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee index 4ab8c94bfd..a40e1ff9c3 100644 --- a/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee @@ -2,6 +2,6 @@ Darkswarm.filter 'propertiesOf', -> (objects)-> properties = {} for object in objects - for property in object.properties + for property in object.supplied_properties properties[property.id] = property properties diff --git a/app/assets/javascripts/templates/partials/enterprise_details.html.haml b/app/assets/javascripts/templates/partials/enterprise_details.html.haml index 46a37050e2..c454312f18 100644 --- a/app/assets/javascripts/templates/partials/enterprise_details.html.haml +++ b/app/assets/javascripts/templates/partials/enterprise_details.html.haml @@ -10,7 +10,7 @@ %span.filter-shopfront.property-selectors.pad-top %ul.inline-block - %li{"ng-repeat" => "property in enterprise.properties"} + %li{"ng-repeat" => "property in enterprise.supplied_properties"} %a.button.tiny{"ng-bind" => "property.presentation"} .about-container.pad-top diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index d30c2d8677..a742b91d63 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -21,7 +21,7 @@ end class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer attributes :orders_close_at, :active - has_many :properties, serializer: Api::PropertySerializer + has_many :supplied_properties, serializer: Api::PropertySerializer def orders_close_at options[:data].earliest_closing_times[object.id] @@ -31,7 +31,7 @@ class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer options[:data].active_distributors.andand.include? object end - def properties + def supplied_properties # This results in 3 queries per enterprise product_properties = Spree::Property.applied_by(object) producer_properties = object.properties diff --git a/app/views/producers/_fat.html.haml b/app/views/producers/_fat.html.haml index 28ed0c985f..8d68a2b84f 100644 --- a/app/views/producers/_fat.html.haml +++ b/app/views/producers/_fat.html.haml @@ -21,7 +21,7 @@ %render-svg{path: "{{taxon.icon}}"} %span{"ng-bind" => "::taxon.name"} %div - %span.fat-properties{"ng-repeat" => "property in producer.properties"} + %span.fat-properties{"ng-repeat" => "property in producer.supplied_properties"} %span{"ng-bind" => "property.presentation"} %div.show-for-medium-up{"ng-if" => "producer.supplied_taxons.length==0"} From 58e0b95cf6aa10aaa4f1e71cca2be8da78f8213e Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 19 Aug 2016 12:06:19 +1000 Subject: [PATCH 45/71] Show property badges on shops --- app/serializers/api/enterprise_serializer.rb | 10 ++++++++ app/views/home/_fat.html.haml | 10 +++++--- spec/features/consumer/shops_spec.rb | 26 +++++++++++++++++++- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index a742b91d63..f68c8be679 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -22,6 +22,7 @@ end class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer attributes :orders_close_at, :active has_many :supplied_properties, serializer: Api::PropertySerializer + has_many :distributed_properties, serializer: Api::PropertySerializer def orders_close_at options[:data].earliest_closing_times[object.id] @@ -38,6 +39,15 @@ class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer OpenFoodNetwork::PropertyMerge.merge product_properties, producer_properties end + + def distributed_properties + # This results in 3 queries per enterprise + product_properties = Spree::Property.sold_by(object) + ids = ProducerProperty.sold_by(object).pluck(:property_id) + producer_properties = Spree::Property.where(id: ids) + + OpenFoodNetwork::PropertyMerge.merge product_properties, producer_properties + end end class Api::CachedEnterpriseSerializer < ActiveModel::Serializer diff --git a/app/views/home/_fat.html.haml b/app/views/home/_fat.html.haml index 4e90771cc1..d5703f84d8 100644 --- a/app/views/home/_fat.html.haml +++ b/app/views/home/_fat.html.haml @@ -4,9 +4,13 @@ %label = t :hubs_buy .trans-sentence - %span.fat-taxons{"ng-repeat" => "taxon in hub.taxons"} - %render-svg{path: "{{taxon.icon}}"} - %span{"ng-bind" => "::taxon.name"} + %div + %span.fat-taxons{"ng-repeat" => "taxon in hub.taxons"} + %render-svg{path: "{{taxon.icon}}"} + %span{"ng-bind" => "::taxon.name"} + %div + %span.fat-properties{"ng-repeat" => "property in hub.distributed_properties"} + %span{"ng-bind" => "property.presentation"} %div.show-for-medium-up{"ng-if" => "::hub.taxons.length==0"}   .columns.small-12.medium-3.large-2.fat diff --git a/spec/features/consumer/shops_spec.rb b/spec/features/consumer/shops_spec.rb index adbbf05f9a..2a65a73aef 100644 --- a/spec/features/consumer/shops_spec.rb +++ b/spec/features/consumer/shops_spec.rb @@ -56,12 +56,36 @@ feature 'Shops', js: true do expect(page).to have_current_path enterprise_shop_path(distributor) end + describe "property badges" do + let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product.variants.first]) } + let(:product) { create(:simple_product, supplier: producer) } + + before do + product.set_property 'Local', 'XYZ 123' + end + + it "shows property badges" do + # Given a shop with a product with a property + # And the product's producer has a producer property + + # When I go to the shops path + visit shops_path + + # And I open the shop + expand_active_table_node distributor.name + + # Then I should see both properties + expect(page).to have_content 'Local' # Product property + expect(page).to have_content 'Organic' # Producer property + end + end + describe "hub producer modal" do let!(:product) { create(:simple_product, supplier: producer, taxons: [taxon]) } let!(:taxon) { create(:taxon, name: 'Fruit') } let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product.variants.first]) } - it "should show hub producer modals" do + it "shows hub producer modals" do expand_active_table_node distributor.name expect(page).to have_content producer.name open_enterprise_modal producer From 08465a531d62c48c1b7f27b9330646db3ebf0722 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 19 Aug 2016 15:11:30 +1000 Subject: [PATCH 46/71] Make properties and propertiesOf filters compatible with both products and enterprises --- .../darkswarm/filters/properties.js.coffee | 3 ++- .../darkswarm/filters/properties_of.js.coffee | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/darkswarm/filters/properties.js.coffee b/app/assets/javascripts/darkswarm/filters/properties.js.coffee index dab89a4c08..1453cac053 100644 --- a/app/assets/javascripts/darkswarm/filters/properties.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/properties.js.coffee @@ -8,5 +8,6 @@ Darkswarm.filter 'properties', -> objects else objects.filter (obj) -> - obj.supplied_properties.some (property) -> + properties = obj.supplied_properties || obj.properties + properties.some (property) -> property.id in ids diff --git a/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee b/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee index a40e1ff9c3..ea73db7f3a 100644 --- a/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee @@ -1,7 +1,12 @@ Darkswarm.filter 'propertiesOf', -> - (objects)-> + (objects) -> properties = {} for object in objects - for property in object.supplied_properties - properties[property.id] = property + if object.supplied_properties? + for property in object.supplied_properties + properties[property.id] = property + else + for property of object.properties + properties[property.id] = property + properties From 1059c170d1288c6ec5cee89ea894091a6fa2ab2a Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Wed, 31 Aug 2016 11:31:59 +1000 Subject: [PATCH 47/71] Adding require_relative of Gateway decorator in attempt to fix inheritance for Gateway::PayPalExpress --- app/models/spree/gateway/pay_pal_express_decorator.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/spree/gateway/pay_pal_express_decorator.rb b/app/models/spree/gateway/pay_pal_express_decorator.rb index dc8239a107..f83151e617 100644 --- a/app/models/spree/gateway/pay_pal_express_decorator.rb +++ b/app/models/spree/gateway/pay_pal_express_decorator.rb @@ -1,3 +1,5 @@ +require_relative '../gateway_decorator' + module Spree class Gateway::PayPalExpress < Gateway # Something odd is happening with class inheritance here, this class (defined in spree_paypal_express gem) From b2e14711acc43ef80928416289da4296a341b319 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Wed, 31 Aug 2016 12:43:22 +1000 Subject: [PATCH 48/71] Gateway providers inherit from decorated Gateway and PaymentMethod classes in production Achieved by requiring payment method and gateway decorators in Spree initializer --- .../gateway/pay_pal_express_decorator.rb | 9 ----- app/models/spree/gateway_decorator.rb | 13 -------- app/models/spree/payment_method_decorator.rb | 33 ++++++++----------- config/initializers/spree.rb | 3 ++ 4 files changed, 16 insertions(+), 42 deletions(-) delete mode 100644 app/models/spree/gateway/pay_pal_express_decorator.rb diff --git a/app/models/spree/gateway/pay_pal_express_decorator.rb b/app/models/spree/gateway/pay_pal_express_decorator.rb deleted file mode 100644 index f83151e617..0000000000 --- a/app/models/spree/gateway/pay_pal_express_decorator.rb +++ /dev/null @@ -1,9 +0,0 @@ -require_relative '../gateway_decorator' - -module Spree - class Gateway::PayPalExpress < Gateway - # Something odd is happening with class inheritance here, this class (defined in spree_paypal_express gem) - # doesn't seem to pick up attr_accessible from the Gateway class, so we redefine the attrs we need here - attr_accessible :tag_list - end -end diff --git a/app/models/spree/gateway_decorator.rb b/app/models/spree/gateway_decorator.rb index 9125ef1d2d..bc4312961e 100644 --- a/app/models/spree/gateway_decorator.rb +++ b/app/models/spree/gateway_decorator.rb @@ -1,18 +1,5 @@ Spree::Gateway.class_eval do - acts_as_taggable - - # Due to class load order, when config.cache_classes is enabled (ie. staging and production - # environments), this association isn't inherited from PaymentMethod. As a result, creating - # payment methods using payment gateways results in: - # undefined method `association_class' for nil:NilClass - # To avoid that, we redefine this association here. - - has_and_belongs_to_many :distributors, join_table: 'distributors_payment_methods', :class_name => 'Enterprise', foreign_key: 'payment_method_id', association_foreign_key: 'distributor_id' - - # Default to live preference :server, :string, :default => 'live' preference :test_mode, :boolean, :default => false - - attr_accessible :tag_list end diff --git a/app/models/spree/payment_method_decorator.rb b/app/models/spree/payment_method_decorator.rb index 77e22c591f..4a718dfc16 100644 --- a/app/models/spree/payment_method_decorator.rb +++ b/app/models/spree/payment_method_decorator.rb @@ -1,7 +1,6 @@ Spree::PaymentMethod.class_eval do acts_as_taggable - # See gateway_decorator.rb when modifying this association has_and_belongs_to_many :distributors, join_table: 'distributors_payment_methods', :class_name => 'Enterprise', association_foreign_key: 'distributor_id' attr_accessible :distributor_ids, :tag_list @@ -45,26 +44,20 @@ Spree::PaymentMethod.class_eval do def has_distributor?(distributor) self.distributors.include?(distributor) end -end -# Ensure that all derived classes also allow distributor_ids -Spree::Gateway.providers.each do |p| - p.attr_accessible :distributor_ids - p.instance_eval do - def clean_name - case name - when "Spree::PaymentMethod::Check" - "Cash/EFT/etc. (payments for which automatic validation is not required)" - when "Spree::Gateway::Migs" - "MasterCard Internet Gateway Service (MIGS)" - when "Spree::Gateway::Pin" - "Pin Payments" - when "Spree::Gateway::PayPalExpress" - "PayPal Express" - else - i = name.rindex('::') + 2 - name[i..-1] - end + def self.clean_name + case name + when "Spree::PaymentMethod::Check" + "Cash/EFT/etc. (payments for which automatic validation is not required)" + when "Spree::Gateway::Migs" + "MasterCard Internet Gateway Service (MIGS)" + when "Spree::Gateway::Pin" + "Pin Payments" + when "Spree::Gateway::PayPalExpress" + "PayPal Express" + else + i = name.rindex('::') + 2 + name[i..-1] end end end diff --git a/config/initializers/spree.rb b/config/initializers/spree.rb index 92ba3db249..30182ef63a 100644 --- a/config/initializers/spree.rb +++ b/config/initializers/spree.rb @@ -9,6 +9,9 @@ require 'spree/product_filters' +require "#{Rails.root}/app/models/spree/payment_method_decorator" +require "#{Rails.root}/app/models/spree/gateway_decorator" + Spree.config do |config| config.shipping_instructions = true config.address_requires_state = true From be51a55f163efadc52081f174680a0ee3692d51e Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 2 Sep 2016 13:45:49 +1000 Subject: [PATCH 49/71] Only display shopfront trial message on dashboard page. Fixes #1120 --- .../stylesheets/admin/components/trial_progess_bar.sass | 3 ++- .../layouts/admin/add_trial_progress_bar.html.haml.deface | 5 ----- .../admin/overview/single_enterprise_dashboard.html.haml | 2 ++ 3 files changed, 4 insertions(+), 6 deletions(-) delete mode 100644 app/overrides/spree/layouts/admin/add_trial_progress_bar.html.haml.deface diff --git a/app/assets/stylesheets/admin/components/trial_progess_bar.sass b/app/assets/stylesheets/admin/components/trial_progess_bar.sass index 37ef4642d9..cb6a648273 100644 --- a/app/assets/stylesheets/admin/components/trial_progess_bar.sass +++ b/app/assets/stylesheets/admin/components/trial_progess_bar.sass @@ -1,7 +1,8 @@ #trial_progress_bar position: fixed + left: 0px bottom: 0px - width: 100% + width: 100vw padding: 8px 10px font-weight: bold background-color: #5498da diff --git a/app/overrides/spree/layouts/admin/add_trial_progress_bar.html.haml.deface b/app/overrides/spree/layouts/admin/add_trial_progress_bar.html.haml.deface deleted file mode 100644 index eb9b44ad10..0000000000 --- a/app/overrides/spree/layouts/admin/add_trial_progress_bar.html.haml.deface +++ /dev/null @@ -1,5 +0,0 @@ -/ insert_top "[data-hook='admin_footer_scripts']" - -- enterprise = spree_current_user.enterprises.first if OpenFoodNetwork::Permissions.new(spree_current_user).manages_one_enterprise? - -= render 'spree/admin/shared/trial_progress_bar', enterprise: enterprise \ No newline at end of file diff --git a/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml b/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml index 91c0934e21..6073d6dae2 100644 --- a/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml +++ b/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml @@ -98,3 +98,5 @@ %a.button.bottom{href: main_app.admin_order_cycles_path} = t "manage_order_cycles" %span.icon-arrow-right + += render 'spree/admin/shared/trial_progress_bar', enterprise: @enterprise From da55eb6d2764308eecf7ccf0c0f6a4d9f8485282 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Wed, 7 Sep 2016 11:13:05 +1000 Subject: [PATCH 50/71] Form for changing enterprise type specifies trial length --- app/helpers/admin/business_model_configuration_helper.rb | 4 ++++ app/views/admin/enterprises/_change_type_form.html.haml | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/helpers/admin/business_model_configuration_helper.rb b/app/helpers/admin/business_model_configuration_helper.rb index b1a2f1ac12..de17761924 100644 --- a/app/helpers/admin/business_model_configuration_helper.rb +++ b/app/helpers/admin/business_model_configuration_helper.rb @@ -16,6 +16,10 @@ module Admin private + def free_use? + Spree::Config[:account_invoices_monthly_fixed] == 0 && Spree::Config[:account_invoices_monthly_rate] == 0 + end + def fixed_description fixed_amount = Spree::Money.new(Spree::Config[:account_invoices_monthly_fixed], {currency: Spree::Config[:currency]} ).rounded monthly_bill_includes_fixed? ? "#{fixed_amount}" : "" diff --git a/app/views/admin/enterprises/_change_type_form.html.haml b/app/views/admin/enterprises/_change_type_form.html.haml index 6474af1344..dd86311a9b 100644 --- a/app/views/admin/enterprises/_change_type_form.html.haml +++ b/app/views/admin/enterprises/_change_type_form.html.haml @@ -76,8 +76,12 @@ %span.error{ ng: { show: "(change_type.sells.$error.required || change_type.sells.$error.pattern) && submitted" } } Please choose one of the options above. - if @enterprise.sells == 'unspecified' && @enterprise.shop_trial_start_date.nil? - %input.button.big{ type: 'submit', value: 'Start 30 Day Trial', ng: { click: "submit(change_type)", show: "sells=='own' || sells=='any'" } } - %input.button.big{ type: 'submit', value: 'Select and continue', ng: { click: "submit(change_type)", hide: "sells=='own' || sells=='any'" } } + -if free_use? + %input.button.big{ type: 'submit', value: 'Select and continue', ng: { click: "submit(change_type)" } } + - else + - trial_length = Spree::Config[:shop_trial_length_days] + %input.button.big{ type: 'submit', value: "Start #{trial_length}-Day Shop Trial", ng: { click: "submit(change_type)", show: "sells=='own' || sells=='any'" } } + %input.button.big{ type: 'submit', value: 'Select and continue', ng: { click: "submit(change_type)", hide: "sells=='own' || sells=='any'" } } - elsif @enterprise.sells == 'unspecified' %input.button.big{ type: 'submit', value: 'Select and continue', ng: { click: "submit(change_type)" } } - else From 261a574da92132acfd2ba2a55acdf176a1a29240 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Wed, 7 Sep 2016 11:13:48 +1000 Subject: [PATCH 51/71] Tweaking styling on enterprise change form, and dashboard header row --- .../admin/enterprises/_change_type_form.html.haml | 10 ++++++---- app/views/admin/shared/_user_guide_link.html.haml | 2 +- .../overview/single_enterprise_dashboard.html.haml | 12 ++++++------ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/app/views/admin/enterprises/_change_type_form.html.haml b/app/views/admin/enterprises/_change_type_form.html.haml index dd86311a9b..ac5ca55821 100644 --- a/app/views/admin/enterprises/_change_type_form.html.haml +++ b/app/views/admin/enterprises/_change_type_form.html.haml @@ -50,7 +50,9 @@ -# At the end of your trial, there is a one-off $200 fee to fully activate your account. Then you will be billed for 2% of your actual transactions, capped at $50 a month (so if you don’t sell anything you don’t pay anything, but you never pay more than $50 a month). - else - .shop_profile.option.one-third.column.alpha + .two.columns.alpha +   + .shop_profile.option.six.columns %a.full-width.button.selector{ ng: { click: "sells='none'", class: "{selected: sells=='none'}" } } .top %h3 Profile Only @@ -59,17 +61,17 @@ %p.description People can find and contact you on the Open Food Network. Your enterprise will be visible on the map, and will be searchable in listings. - .full_hub.option.one-third.column + .full_hub.option.six.columns %a.full-width.button.selector{ ng: { click: "sells='any'", class: "{selected: sells=='any'}" } } .top %h3 Hub Shop %p Sell produce from others .bottom %monthly-pricing-description{ joiner: "newline" } - %p.description Your enterprise is the backbone of your local food system. You aggregate produce from other enterprises and can sell it through your shop on the Open Food Network. - + .two.columns.omega +   .row .sixteen.columns.alpha diff --git a/app/views/admin/shared/_user_guide_link.html.haml b/app/views/admin/shared/_user_guide_link.html.haml index bfae6002e7..6081422aba 100644 --- a/app/views/admin/shared/_user_guide_link.html.haml +++ b/app/views/admin/shared/_user_guide_link.html.haml @@ -1 +1 @@ -= button_link_to "User Guide", "http://www.openfoodnetwork.org/platform/user-guide/", :icon => 'icon-external-link', :id => 'user_guide_link', target: '_blank' += button_link_to "User Guide", "http://www.openfoodnetwork.org/platform/user-guide/", :icon => 'icon-external-link', target: '_blank' diff --git a/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml b/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml index 6073d6dae2..76377f32e2 100644 --- a/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml +++ b/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml @@ -1,11 +1,11 @@ - content_for :page_title do - %h1 - = @enterprise.name - %span.small< - = "(#{enterprise_type_name(@enterprise)})" + = @enterprise.name + %span.small< + = "(#{enterprise_type_name(@enterprise)})" - content_for :page_actions do - = render 'admin/shared/user_guide_link' + %li#user_guide_link + = render 'admin/shared/user_guide_link' :javascript function toggleType(){ @@ -17,7 +17,7 @@ } $("#package_selection").slideToggle() } - #package_button + %li#package_button %button#toggle_type{ onClick: 'toggleType()' } = t "change_package" %i.icon-chevron-down From 0760d4cc1f26fd06f60b420293e3671f205d0a07 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Thu, 8 Sep 2016 12:15:36 +1000 Subject: [PATCH 52/71] Fixing property filters on shopfront --- .../javascripts/darkswarm/filters/properties_of.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee b/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee index ea73db7f3a..7eac12bf1e 100644 --- a/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee @@ -6,7 +6,7 @@ Darkswarm.filter 'propertiesOf', -> for property in object.supplied_properties properties[property.id] = property else - for property of object.properties + for property in object.properties properties[property.id] = property properties From 7eeee78c4ecfee6a1db90f137d7bcb8eaa4e78ee Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 26 Aug 2016 11:40:21 +1000 Subject: [PATCH 53/71] WIP: Move hubs partials from home to shops, their rightful home --- app/views/{home => shops}/_fat.html.haml | 0 app/views/{home => shops}/_filters.html.haml | 0 app/views/{home => shops}/_hubs.html.haml | 0 app/views/{home => shops}/_hubs_table.html.haml | 0 app/views/{home => shops}/_skinny.html.haml | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename app/views/{home => shops}/_fat.html.haml (100%) rename app/views/{home => shops}/_filters.html.haml (100%) rename app/views/{home => shops}/_hubs.html.haml (100%) rename app/views/{home => shops}/_hubs_table.html.haml (100%) rename app/views/{home => shops}/_skinny.html.haml (100%) diff --git a/app/views/home/_fat.html.haml b/app/views/shops/_fat.html.haml similarity index 100% rename from app/views/home/_fat.html.haml rename to app/views/shops/_fat.html.haml diff --git a/app/views/home/_filters.html.haml b/app/views/shops/_filters.html.haml similarity index 100% rename from app/views/home/_filters.html.haml rename to app/views/shops/_filters.html.haml diff --git a/app/views/home/_hubs.html.haml b/app/views/shops/_hubs.html.haml similarity index 100% rename from app/views/home/_hubs.html.haml rename to app/views/shops/_hubs.html.haml diff --git a/app/views/home/_hubs_table.html.haml b/app/views/shops/_hubs_table.html.haml similarity index 100% rename from app/views/home/_hubs_table.html.haml rename to app/views/shops/_hubs_table.html.haml diff --git a/app/views/home/_skinny.html.haml b/app/views/shops/_skinny.html.haml similarity index 100% rename from app/views/home/_skinny.html.haml rename to app/views/shops/_skinny.html.haml From 4c4021935299aa8731164c104c7ecf9f5a397b6a Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 26 Aug 2016 11:43:23 +1000 Subject: [PATCH 54/71] Move hubs partials from home to shops, their rightful home --- app/views/groups/show.html.haml | 4 ++-- app/views/shops/_filters.html.haml | 6 +++--- app/views/shops/_hubs.html.haml | 6 +++--- app/views/shops/_hubs_table.html.haml | 4 ++-- app/views/shops/index.html.haml | 4 ++-- spec/features/consumer/shops_spec.rb | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index ef9e281155..49270dcc05 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -98,8 +98,8 @@ "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", "ng-controller" => "GroupEnterpriseNodeCtrl"} .small-12.columns - = render partial: 'home/skinny' - = render partial: 'home/fat' + = render 'shops/skinny' + = render 'shops/fat' = render partial: 'shared/components/enterprise_no_results' diff --git a/app/views/shops/_filters.html.haml b/app/views/shops/_filters.html.haml index bfd13fdf54..c6692e5a84 100644 --- a/app/views/shops/_filters.html.haml +++ b/app/views/shops/_filters.html.haml @@ -1,7 +1,7 @@ .row - = render partial: 'shared/components/filter_controls' + = render 'shared/components/filter_controls' -# .small-12.medium-6.columns   - = render partial: 'shared/components/show_profiles' + = render 'shared/components/show_profiles' .row.animate-show{"ng-show" => "filtersActive"} .small-12.columns @@ -19,4 +19,4 @@ = t :hubs_filter_delivery %shipping-type-selector -= render partial: 'shared/components/filter_box' += render 'shared/components/filter_box' diff --git a/app/views/shops/_hubs.html.haml b/app/views/shops/_hubs.html.haml index e899270efc..6087d2330c 100644 --- a/app/views/shops/_hubs.html.haml +++ b/app/views/shops/_hubs.html.haml @@ -7,14 +7,14 @@ = t :hubs_intro = render "shared/components/enterprise_search" - = render "home/filters" + = render "filters" .row .small-12.columns .name-matches{"ng-show" => "nameMatchesFiltered.length > 0"} %h2 = t :hubs_matches - = render "home/hubs_table", enterprises: "nameMatches" + = render "hubs_table", enterprises: "nameMatches" .distance-matches{"ng-if" => "nameMatchesFiltered.length == 0 || distanceMatchesShown"} %h2{"ng-show" => "nameMatchesFiltered.length > 0 || query.length > 0"} @@ -22,7 +22,7 @@ %span{"ng-show" => "nameMatchesFiltered.length > 0"} {{ nameMatchesFiltered[0].name }}... %span{"ng-hide" => "nameMatchesFiltered.length > 0"} {{ query }}... - = render "home/hubs_table", enterprises: "distanceMatches" + = render "hubs_table", enterprises: "distanceMatches" .show-distance-matches{"ng-show" => "nameMatchesFiltered.length > 0 && !distanceMatchesShown"} %a{href: "", "ng-click" => "showDistanceMatches()"} diff --git a/app/views/shops/_hubs_table.html.haml b/app/views/shops/_hubs_table.html.haml index edf9eb5ec8..3d8bfca7d1 100644 --- a/app/views/shops/_hubs_table.html.haml +++ b/app/views/shops/_hubs_table.html.haml @@ -4,7 +4,7 @@ "ng-controller" => "HubNodeCtrl", id: "{{hub.hash}}"} .small-12.columns - = render 'home/skinny' - = render 'home/fat' + = render 'skinny' + = render 'fat' = render 'shared/components/enterprise_no_results', enterprises: "#{enterprises}Filtered" diff --git a/app/views/shops/index.html.haml b/app/views/shops/index.html.haml index 1b3cf547a8..7e288f4157 100644 --- a/app/views/shops/index.html.haml +++ b/app/views/shops/index.html.haml @@ -10,5 +10,5 @@ %p.text-big = t :shops_text -= render partial: "home/hubs" -= render partial: "shared/footer" += render "hubs" += render "shared/footer" diff --git a/spec/features/consumer/shops_spec.rb b/spec/features/consumer/shops_spec.rb index 2a65a73aef..0d19eddf52 100644 --- a/spec/features/consumer/shops_spec.rb +++ b/spec/features/consumer/shops_spec.rb @@ -47,7 +47,7 @@ feature 'Shops', js: true do it "should show closed shops after clicking the button" do create(:simple_product, distributors: [d1, d2]) visit shops_path - click_link_and_ensure("Show closed shops", -> { page.has_selector? 'hub.inactive' }) + click_link_and_ensure("Show Closed Shops", -> { page.has_selector? 'hub.inactive' }) page.should have_selector 'hub.inactive', text: d2.name end From 38d568276247724bcf1df0a0a4e2fe090ae858bb Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 26 Aug 2016 12:43:21 +1000 Subject: [PATCH 55/71] Add property filters for shops --- app/views/shops/_filters.html.haml | 10 ++++++++- app/views/shops/_hubs_table.html.haml | 2 +- config/locales/en.yml | 1 + spec/features/consumer/shops_spec.rb | 30 +++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/app/views/shops/_filters.html.haml b/app/views/shops/_filters.html.haml index c6692e5a84..08d8b075f0 100644 --- a/app/views/shops/_filters.html.haml +++ b/app/views/shops/_filters.html.haml @@ -3,7 +3,7 @@ -# .small-12.medium-6.columns   = render 'shared/components/show_profiles' -.row.animate-show{"ng-show" => "filtersActive"} +.row.animate-show.filter-row{"ng-show" => "filtersActive"} .small-12.columns .row.filter-box .small-12.large-9.columns @@ -19,4 +19,12 @@ = t :hubs_filter_delivery %shipping-type-selector + .small-12.large-12.columns + %h5.tdhead + .light + = t :hubs_filter_by + = t :hubs_filter_property + .filter-shopfront.property-selectors + %single-line-selectors{ selectors: "filterSelectors", objects: "visibleMatches | filter:filterExpression | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | propertiesOf", "active-selectors" => "activeProperties"} + = render 'shared/components/filter_box' diff --git a/app/views/shops/_hubs_table.html.haml b/app/views/shops/_hubs_table.html.haml index 3d8bfca7d1..2f4d85af0e 100644 --- a/app/views/shops/_hubs_table.html.haml +++ b/app/views/shops/_hubs_table.html.haml @@ -1,5 +1,5 @@ .active_table - %hub.active_table_node.row{"ng-repeat" => "hub in #{enterprises}Filtered = (#{enterprises} | filter:filterExpression | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+distance', '+orders_close_at'])", + %hub.active_table_node.row{"ng-repeat" => "hub in #{enterprises}Filtered = (#{enterprises} | filter:filterExpression | taxons:activeTaxons | properties:activeProperties | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+distance', '+orders_close_at'])", "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", "ng-controller" => "HubNodeCtrl", id: "{{hub.hash}}"} diff --git a/config/locales/en.yml b/config/locales/en.yml index 1d8707a7b9..991c308c2f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -505,6 +505,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using hubs_filter_by: "Filter by" hubs_filter_type: "Type" hubs_filter_delivery: "Delivery" + hubs_filter_property: "Property" hubs_matches: "Did you mean?" hubs_intro: Shop in your local area hubs_distance: Closest to diff --git a/spec/features/consumer/shops_spec.rb b/spec/features/consumer/shops_spec.rb index 0d19eddf52..b744282952 100644 --- a/spec/features/consumer/shops_spec.rb +++ b/spec/features/consumer/shops_spec.rb @@ -56,6 +56,36 @@ feature 'Shops', js: true do expect(page).to have_current_path enterprise_shop_path(distributor) end + describe "filtering by product property" do + let!(:order_cycle) { create(:simple_order_cycle, distributors: [d1, d2], coordinator: create(:distributor_enterprise)) } + let(:p1) { create(:simple_product, supplier: producer) } + let(:p2) { create(:simple_product, supplier: create(:supplier_enterprise)) } + let(:ex_d1) { order_cycle.exchanges.outgoing.where(receiver_id: d1).first } + let(:ex_d2) { order_cycle.exchanges.outgoing.where(receiver_id: d2).first } + + before do + p2.set_property 'Local', 'XYZ 123' + + ex_d1.variants << p1.variants.first + ex_d2.variants << p2.variants.first + end + + it "filters" do + toggle_filters + + toggle_filter 'Organic' + + expect(page).to have_content d1.name + expect(page).not_to have_content d2.name + + toggle_filter 'Organic' + toggle_filter 'Local' + + expect(page).not_to have_content d1.name + expect(page).to have_content d2.name + end + end + describe "property badges" do let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product.variants.first]) } let(:product) { create(:simple_product, supplier: producer) } From 63ef5de0e55b93d0a1efab6a39eff586312d9839 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 26 Aug 2016 14:19:18 +1000 Subject: [PATCH 56/71] Use short syntax for render partial --- app/views/groups/show.html.haml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 49270dcc05..6342e1af70 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -60,8 +60,8 @@ .small-12.columns %h1 = t :groups_producers - = render partial: "shared/components/enterprise_search" - = render partial: "producers/filters" + = render "shared/components/enterprise_search" + = render "producers/filters" .row .small-12.columns @@ -73,10 +73,10 @@ id: "{{producer.hash}}"} .small-12.columns - = render partial: 'producers/skinny' - = render partial: 'producers/fat' + = render "producers/skinny" + = render "producers/fat" - = render partial: 'shared/components/enterprise_no_results' + = render 'shared/components/enterprise_no_results' %tab{heading: t(:groups_hubs), active: "tabs.hubs.active", @@ -87,8 +87,8 @@ %h1 = t :groups_hubs - = render partial: "shared/components/enterprise_search" - = render partial: "hub_filters" + = render "shared/components/enterprise_search" + = render "hub_filters" .row .small-12.columns @@ -101,10 +101,10 @@ = render 'shops/skinny' = render 'shops/fat' - = render partial: 'shared/components/enterprise_no_results' + = render 'shared/components/enterprise_no_results' .small-12.medium-12.large-3.columns - = render partial: 'contact' + = render 'contact' .small-12.columns.pad-top .row.pad-top @@ -122,4 +122,4 @@ %p   -= render partial: "shared/footer" += render "shared/footer" From ed2522f6d2df1d996f850f5d5858771a5a9d9060 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 26 Aug 2016 15:49:43 +1000 Subject: [PATCH 57/71] Explicitly specify supplied or distributed properties for ng filters: properties, propertiesOf --- .../darkswarm/filters/properties.js.coffee | 8 ++++++-- .../darkswarm/filters/properties_of.js.coffee | 12 ++++++------ app/views/groups/show.html.haml | 4 ++-- app/views/producers/_filters.html.haml | 2 +- app/views/producers/index.html.haml | 2 +- app/views/shop/products/_filters.html.haml | 2 +- app/views/shops/_filters.html.haml | 2 +- app/views/shops/_hubs_table.html.haml | 2 +- spec/features/consumer/shops_spec.rb | 6 ++++-- 9 files changed, 23 insertions(+), 17 deletions(-) diff --git a/app/assets/javascripts/darkswarm/filters/properties.js.coffee b/app/assets/javascripts/darkswarm/filters/properties.js.coffee index 1453cac053..fe7ed71fa3 100644 --- a/app/assets/javascripts/darkswarm/filters/properties.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/properties.js.coffee @@ -1,13 +1,17 @@ Darkswarm.filter 'properties', -> # Filter anything that responds to object.supplied_properties - (objects, ids) -> + (objects, ids, source) -> objects ||= [] ids ?= [] + + source ||= 'properties' + return [] unless source in ['properties', 'supplied_properties', 'distributed_properties'] + if ids.length == 0 # No properties selected, pass all objects through. objects else objects.filter (obj) -> - properties = obj.supplied_properties || obj.properties + properties = obj[source] properties.some (property) -> property.id in ids diff --git a/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee b/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee index 7eac12bf1e..f3f4f51b5e 100644 --- a/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee @@ -1,12 +1,12 @@ Darkswarm.filter 'propertiesOf', -> - (objects) -> + (objects, source) -> + source ||= 'properties' + return {} unless source in ['properties', 'supplied_properties', 'distributed_properties'] + properties = {} for object in objects - if object.supplied_properties? - for property in object.supplied_properties - properties[property.id] = property - else - for property in object.properties + if object[source]? + for property in object[source] properties[property.id] = property properties diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 6342e1af70..2f2f0e7a62 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -67,7 +67,7 @@ .small-12.columns .active_table %producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", - "ng-repeat" => "producer in filteredEnterprises = (group_producers | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties)", + "ng-repeat" => "producer in filteredEnterprises = (group_producers | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties:'supplied_properties')", "ng-controller" => "GroupEnterpriseNodeCtrl", "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", id: "{{producer.hash}}"} @@ -94,7 +94,7 @@ .small-12.columns .active_table %hub.active_table_node.row.animate-repeat{id: "{{hub.hash}}", - "ng-repeat" => "hub in filteredEnterprises = (group_hubs | searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+orders_close_at'])", + "ng-repeat" => "hub in filteredEnterprises = (group_hubs | searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | properties:activeProperties:'distributed_properties' | orderBy:['-active', '+orders_close_at'])", "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", "ng-controller" => "GroupEnterpriseNodeCtrl"} .small-12.columns diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 771ed932c9..25f3d45af7 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -18,6 +18,6 @@ = t :producers_filter = t :producers_filter_property .filter-shopfront.property-selectors - %single-line-selectors{ selectors: "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | propertiesOf", "active-selectors" => "activeProperties"} + %single-line-selectors{ selectors: "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | propertiesOf:'supplied_properties'", "active-selectors" => "activeProperties"} = render partial: 'shared/components/filter_box' diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index 04048ef77e..af6c2e4fd1 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -16,7 +16,7 @@ .small-12.columns .active_table %producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", - "ng-repeat" => "producer in filteredEnterprises = (Enterprises.producers | visible | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties)", + "ng-repeat" => "producer in filteredEnterprises = (Enterprises.producers | visible | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties:'supplied_properties')", "ng-controller" => "ProducerNodeCtrl", "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", id: "{{producer.hash}}"} diff --git a/app/views/shop/products/_filters.html.haml b/app/views/shop/products/_filters.html.haml index 7efaba6cc9..10c7c20deb 100644 --- a/app/views/shop/products/_filters.html.haml +++ b/app/views/shop/products/_filters.html.haml @@ -1,5 +1,5 @@ .filter-shopfront.taxon-selectors.text-right - %single-line-selectors{ selectors: "taxonSelectors", objects: "Products.products | products:query | properties: activeProperties | taxonsOf", "active-selectors" => "activeTaxons"} + %single-line-selectors{ selectors: "taxonSelectors", objects: "Products.products | products:query | properties:activeProperties | taxonsOf", "active-selectors" => "activeTaxons"} .filter-shopfront.property-selectors.text-right %single-line-selectors{ selectors: "propertySelectors", objects: "Products.products | products:query | taxons:activeTaxons | propertiesOf", "active-selectors" => "activeProperties"} diff --git a/app/views/shops/_filters.html.haml b/app/views/shops/_filters.html.haml index 08d8b075f0..93d4e5b19f 100644 --- a/app/views/shops/_filters.html.haml +++ b/app/views/shops/_filters.html.haml @@ -25,6 +25,6 @@ = t :hubs_filter_by = t :hubs_filter_property .filter-shopfront.property-selectors - %single-line-selectors{ selectors: "filterSelectors", objects: "visibleMatches | filter:filterExpression | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | propertiesOf", "active-selectors" => "activeProperties"} + %single-line-selectors{ selectors: "filterSelectors", objects: "visibleMatches | filter:filterExpression | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | propertiesOf:'distributed_properties'", "active-selectors" => "activeProperties"} = render 'shared/components/filter_box' diff --git a/app/views/shops/_hubs_table.html.haml b/app/views/shops/_hubs_table.html.haml index 2f4d85af0e..6d5803b477 100644 --- a/app/views/shops/_hubs_table.html.haml +++ b/app/views/shops/_hubs_table.html.haml @@ -1,5 +1,5 @@ .active_table - %hub.active_table_node.row{"ng-repeat" => "hub in #{enterprises}Filtered = (#{enterprises} | filter:filterExpression | taxons:activeTaxons | properties:activeProperties | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+distance', '+orders_close_at'])", + %hub.active_table_node.row{"ng-repeat" => "hub in #{enterprises}Filtered = (#{enterprises} | filter:filterExpression | taxons:activeTaxons | properties:activeProperties:'distributed_properties' | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+distance', '+orders_close_at'])", "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", "ng-controller" => "HubNodeCtrl", id: "{{hub.hash}}"} diff --git a/spec/features/consumer/shops_spec.rb b/spec/features/consumer/shops_spec.rb index b744282952..74fb5b955f 100644 --- a/spec/features/consumer/shops_spec.rb +++ b/spec/features/consumer/shops_spec.rb @@ -58,8 +58,8 @@ feature 'Shops', js: true do describe "filtering by product property" do let!(:order_cycle) { create(:simple_order_cycle, distributors: [d1, d2], coordinator: create(:distributor_enterprise)) } - let(:p1) { create(:simple_product, supplier: producer) } - let(:p2) { create(:simple_product, supplier: create(:supplier_enterprise)) } + let!(:p1) { create(:simple_product, supplier: producer) } + let!(:p2) { create(:simple_product, supplier: create(:supplier_enterprise)) } let(:ex_d1) { order_cycle.exchanges.outgoing.where(receiver_id: d1).first } let(:ex_d2) { order_cycle.exchanges.outgoing.where(receiver_id: d2).first } @@ -68,6 +68,8 @@ feature 'Shops', js: true do ex_d1.variants << p1.variants.first ex_d2.variants << p2.variants.first + + visit shops_path end it "filters" do From 8339d247f86bf70553b4b99e61ff6b844a09b9f4 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 26 Aug 2016 16:22:05 +1000 Subject: [PATCH 58/71] Shops on groups page filter by property --- app/views/groups/_hub_filters.html.haml | 21 ------------- app/views/groups/show.html.haml | 4 +-- app/views/shops/_filters.html.haml | 8 +++-- spec/features/consumer/groups_spec.rb | 39 +++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 25 deletions(-) delete mode 100644 app/views/groups/_hub_filters.html.haml diff --git a/app/views/groups/_hub_filters.html.haml b/app/views/groups/_hub_filters.html.haml deleted file mode 100644 index 71924d5e85..0000000000 --- a/app/views/groups/_hub_filters.html.haml +++ /dev/null @@ -1,21 +0,0 @@ -.row - = render partial: 'shared/components/filter_controls' - = render partial: 'shared/components/show_profiles' - -.row.animate-show{"ng-show" => "filtersActive"} - .small-12.columns - .row.filter-box - .small-12.large-9.columns - %h5.tdhead - .light - = t :hubs_filter_by - = t :hubs_filter_type - %filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-5{"selector-set" => "filterSelectors", objects: "group_hubs | searchEnterprises:query | shipping:shippingTypes | showHubProfiles:show_profiles | taxonsOf", "active-selectors" => "activeTaxons"} - .small-12.large-3.columns - %h5.tdhead - .light - = t :hubs_filter_by - = t :hubs_filter_delivery - %shipping-type-selector - -= render partial: 'shared/components/filter_box' diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 2f2f0e7a62..90b74c0b42 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -88,13 +88,13 @@ = t :groups_hubs = render "shared/components/enterprise_search" - = render "hub_filters" + = render "shops/filters", resource: "group_hubs", property_filters: "| searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles" .row .small-12.columns .active_table %hub.active_table_node.row.animate-repeat{id: "{{hub.hash}}", - "ng-repeat" => "hub in filteredEnterprises = (group_hubs | searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | properties:activeProperties:'distributed_properties' | orderBy:['-active', '+orders_close_at'])", + "ng-repeat" => "hub in filteredEnterprises = (group_hubs | searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | properties:activeProperties:'distributed_properties' | orderBy:['-active', '+orders_close_at'])", "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", "ng-controller" => "GroupEnterpriseNodeCtrl"} .small-12.columns diff --git a/app/views/shops/_filters.html.haml b/app/views/shops/_filters.html.haml index 93d4e5b19f..1094d81b2f 100644 --- a/app/views/shops/_filters.html.haml +++ b/app/views/shops/_filters.html.haml @@ -1,3 +1,6 @@ +- resource ||= "visibleMatches" +- property_filters ||= "| filter:filterExpression | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles" + .row = render 'shared/components/filter_controls' -# .small-12.medium-6.columns   @@ -11,7 +14,8 @@ .light = t :hubs_filter_by = t :hubs_filter_type - %filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-5{ "selector-set" => "filterSelectors", objects: "visibleMatches | visible | taxonsOf", "active-selectors" => "activeTaxons" } + + %filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-5{ "selector-set" => "filterSelectors", objects: "#{resource} | visible | taxonsOf", "active-selectors" => "activeTaxons" } .small-12.large-3.columns %h5.tdhead .light @@ -25,6 +29,6 @@ = t :hubs_filter_by = t :hubs_filter_property .filter-shopfront.property-selectors - %single-line-selectors{ selectors: "filterSelectors", objects: "visibleMatches | filter:filterExpression | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | propertiesOf:'distributed_properties'", "active-selectors" => "activeProperties"} + %single-line-selectors{ selectors: "filterSelectors", objects: "#{resource} #{property_filters} | propertiesOf:'distributed_properties'", "active-selectors" => "activeProperties"} = render 'shared/components/filter_box' diff --git a/spec/features/consumer/groups_spec.rb b/spec/features/consumer/groups_spec.rb index 039322b379..4a5f166d7d 100644 --- a/spec/features/consumer/groups_spec.rb +++ b/spec/features/consumer/groups_spec.rb @@ -54,4 +54,43 @@ feature 'Groups', js: true do end end end + + describe "shops" do + describe "filtering by product property" do + let!(:group) { create(:enterprise_group, enterprises: [d1, d2], on_front_page: true) } + let!(:order_cycle) { create(:simple_order_cycle, distributors: [d1, d2], coordinator: create(:distributor_enterprise)) } + let(:producer) { create(:supplier_enterprise) } + let(:d1) { create(:distributor_enterprise) } + let(:d2) { create(:distributor_enterprise) } + let(:p1) { create(:simple_product, supplier: producer) } + let(:p2) { create(:simple_product, supplier: create(:supplier_enterprise)) } + let(:ex_d1) { order_cycle.exchanges.outgoing.where(receiver_id: d1).first } + let(:ex_d2) { order_cycle.exchanges.outgoing.where(receiver_id: d2).first } + + before do + producer.set_producer_property 'Organic', 'NASAA 12345' + p2.set_property 'Local', 'XYZ 123' + + ex_d1.variants << p1.variants.first + ex_d2.variants << p2.variants.first + + visit group_path(group, anchor: "/hubs") + end + + it "filters" do + toggle_filters + + toggle_filter 'Organic' + + expect(page).to have_content d1.name + expect(page).not_to have_content d2.name + + toggle_filter 'Organic' + toggle_filter 'Local' + + expect(page).not_to have_content d1.name + expect(page).to have_content d2.name + end + end + end end From e00846776e15a4469fcfffcc7fabbef85cb3372d Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 31 Aug 2016 10:11:05 +1000 Subject: [PATCH 59/71] Client-side, always show properties by their presentation, not their name --- app/helpers/injection_helper.rb | 2 +- app/serializers/api/property_serializer.rb | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/helpers/injection_helper.rb b/app/helpers/injection_helper.rb index 6db2e583bc..dad9cf11f9 100644 --- a/app/helpers/injection_helper.rb +++ b/app/helpers/injection_helper.rb @@ -45,7 +45,7 @@ module InjectionHelper end def inject_properties - inject_json_ams "properties", Spree::Property.all, Api::IdNameSerializer + inject_json_ams "properties", Spree::Property.all, Api::PropertySerializer end def inject_currency_config diff --git a/app/serializers/api/property_serializer.rb b/app/serializers/api/property_serializer.rb index 7da4fce990..cdb3f2bae3 100644 --- a/app/serializers/api/property_serializer.rb +++ b/app/serializers/api/property_serializer.rb @@ -1,3 +1,9 @@ class Api::PropertySerializer < ActiveModel::Serializer attributes :id, :name, :presentation + + # Client-side we don't care about the property name. Send the presentation + # since this is what we want to show to the user. + def name + object.presentation + end end From 8ec2ebbf944c7b774aa59258b471a57535669bf4 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 31 Aug 2016 11:32:38 +1000 Subject: [PATCH 60/71] Swap to using multi-line selectors for property filters - z-index issues with single-line-selectors --- app/assets/stylesheets/darkswarm/_shop-filters.css.sass | 2 +- app/views/producers/_filters.html.haml | 2 +- app/views/shops/_filters.html.haml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/_shop-filters.css.sass b/app/assets/stylesheets/darkswarm/_shop-filters.css.sass index 3c4f9a514d..07fea7a0b1 100644 --- a/app/assets/stylesheets/darkswarm/_shop-filters.css.sass +++ b/app/assets/stylesheets/darkswarm/_shop-filters.css.sass @@ -96,7 +96,7 @@ // content. Ensure that the dropdown appears above the content. .filter-row position: relative - z-index: 100 + z-index: 90 .filter-shopfront &.taxon-selectors, &.property-selectors diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 25f3d45af7..3e067d73fb 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -18,6 +18,6 @@ = t :producers_filter = t :producers_filter_property .filter-shopfront.property-selectors - %single-line-selectors{ selectors: "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | propertiesOf:'supplied_properties'", "active-selectors" => "activeProperties"} + %filter-selector{ "selector-set" => "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | propertiesOf:'supplied_properties'", "active-selectors" => "activeProperties"} = render partial: 'shared/components/filter_box' diff --git a/app/views/shops/_filters.html.haml b/app/views/shops/_filters.html.haml index 1094d81b2f..68caa353bb 100644 --- a/app/views/shops/_filters.html.haml +++ b/app/views/shops/_filters.html.haml @@ -29,6 +29,6 @@ = t :hubs_filter_by = t :hubs_filter_property .filter-shopfront.property-selectors - %single-line-selectors{ selectors: "filterSelectors", objects: "#{resource} #{property_filters} | propertiesOf:'distributed_properties'", "active-selectors" => "activeProperties"} + %filter-selector{ "selector-set" => "filterSelectors", objects: "#{resource} #{property_filters} | propertiesOf:'distributed_properties'", "active-selectors" => "activeProperties"} = render 'shared/components/filter_box' From 38c63fc88b910750f9fdfdd93d0552b598ad8cac Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 31 Aug 2016 12:00:55 +1000 Subject: [PATCH 61/71] Available producer filters update when taxon filter changed --- app/views/producers/_filters.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 3e067d73fb..17f260196a 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -18,6 +18,6 @@ = t :producers_filter = t :producers_filter_property .filter-shopfront.property-selectors - %filter-selector{ "selector-set" => "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | propertiesOf:'supplied_properties'", "active-selectors" => "activeProperties"} + %filter-selector{ "selector-set" => "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | taxons:activeTaxons | propertiesOf:'supplied_properties'", "active-selectors" => "activeProperties"} = render partial: 'shared/components/filter_box' From 3a2e0b7effd22791c40f57294a36e035f2571792 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 31 Aug 2016 12:11:20 +1000 Subject: [PATCH 62/71] Fix spacing --- app/views/shops/_filters.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shops/_filters.html.haml b/app/views/shops/_filters.html.haml index 68caa353bb..42e2b2ec28 100644 --- a/app/views/shops/_filters.html.haml +++ b/app/views/shops/_filters.html.haml @@ -1,5 +1,5 @@ - resource ||= "visibleMatches" -- property_filters ||= "| filter:filterExpression | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles" +- property_filters ||= "| filter:filterExpression | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles" .row = render 'shared/components/filter_controls' From c37bf3d07748c87147f67d3f57c9b74c989463fc Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 9 Sep 2016 14:28:05 +1000 Subject: [PATCH 63/71] Rename Property#sold_by and ProducerProperty#sold_by to currently_sold_by --- app/models/producer_property.rb | 2 +- app/models/spree/property_decorator.rb | 2 +- app/serializers/api/enterprise_serializer.rb | 4 ++-- spec/models/producer_property_spec.rb | 12 ++++++------ spec/models/spree/property_spec.rb | 12 ++++++------ 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/models/producer_property.rb b/app/models/producer_property.rb index bf1f083936..7e2dd4ace1 100644 --- a/app/models/producer_property.rb +++ b/app/models/producer_property.rb @@ -8,7 +8,7 @@ class ProducerProperty < ActiveRecord::Base after_destroy :refresh_products_cache_from_destroy - scope :sold_by, ->(shop) { + scope :currently_sold_by, ->(shop) { joins(producer: {supplied_products: {variants: {exchanges: :order_cycle}}}). merge(Exchange.outgoing). merge(Exchange.to_enterprise(shop)). diff --git a/app/models/spree/property_decorator.rb b/app/models/spree/property_decorator.rb index 50e450a03b..c0abfda7e4 100644 --- a/app/models/spree/property_decorator.rb +++ b/app/models/spree/property_decorator.rb @@ -8,7 +8,7 @@ module Spree where('spree_product_properties.product_id IN (?)', enterprise.supplied_product_ids) } - scope :sold_by, ->(shop) { + scope :currently_sold_by, ->(shop) { joins(products: {variants: {exchanges: :order_cycle}}). merge(Exchange.outgoing). merge(Exchange.to_enterprise(shop)). diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index f68c8be679..7cdf3d4adc 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -42,8 +42,8 @@ class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer def distributed_properties # This results in 3 queries per enterprise - product_properties = Spree::Property.sold_by(object) - ids = ProducerProperty.sold_by(object).pluck(:property_id) + product_properties = Spree::Property.currently_sold_by(object) + ids = ProducerProperty.currently_sold_by(object).pluck(:property_id) producer_properties = Spree::Property.where(id: ids) OpenFoodNetwork::PropertyMerge.merge product_properties, producer_properties diff --git a/spec/models/producer_property_spec.rb b/spec/models/producer_property_spec.rb index 2d0009ce12..559e7c7a28 100644 --- a/spec/models/producer_property_spec.rb +++ b/spec/models/producer_property_spec.rb @@ -8,7 +8,7 @@ describe ProducerProperty do producer.set_producer_property 'Organic Certified', 'NASAA 54321' end - describe ".sold_by" do + describe ".currently_sold_by" do let!(:shop) { create(:distributor_enterprise) } let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first]) } let(:product) { create(:simple_product, supplier: producer) } @@ -22,7 +22,7 @@ describe ProducerProperty do describe "with an associated producer property" do it "returns the producer property" do - expect(ProducerProperty.sold_by(shop)).to eq [pp] + expect(ProducerProperty.currently_sold_by(shop)).to eq [pp] end end @@ -30,7 +30,7 @@ describe ProducerProperty do let!(:exchange) { create(:exchange, order_cycle: oc, incoming: true, sender: producer_other, receiver: oc.coordinator) } it "doesn't return the producer property" do - expect(ProducerProperty.sold_by(shop)).not_to include pp_other + expect(ProducerProperty.currently_sold_by(shop)).not_to include pp_other end end @@ -40,7 +40,7 @@ describe ProducerProperty do let!(:exchange) { create(:exchange, order_cycle: oc, incoming: false, sender: oc.coordinator, receiver: shop_other, variants: [product_other.variants.first]) } it "doesn't return the producer property" do - expect(ProducerProperty.sold_by(shop)).not_to include pp_other + expect(ProducerProperty.currently_sold_by(shop)).not_to include pp_other end end @@ -50,7 +50,7 @@ describe ProducerProperty do end it "doesn't return the producer property" do - expect(ProducerProperty.sold_by(shop)).not_to include pp + expect(ProducerProperty.currently_sold_by(shop)).not_to include pp end end @@ -59,7 +59,7 @@ describe ProducerProperty do let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first, product2.variants.first]) } it "doesn't return duplicates" do - expect(ProducerProperty.sold_by(shop).to_a.count).to eq 1 + expect(ProducerProperty.currently_sold_by(shop).to_a.count).to eq 1 end end end diff --git a/spec/models/spree/property_spec.rb b/spec/models/spree/property_spec.rb index 6e6ed2d780..8ba93738cf 100644 --- a/spec/models/spree/property_spec.rb +++ b/spec/models/spree/property_spec.rb @@ -31,7 +31,7 @@ module Spree end end - describe ".sold_by" do + describe ".currently_sold_by" do let!(:shop) { create(:distributor_enterprise) } let!(:shop_other) { create(:distributor_enterprise) } let!(:product) { create(:simple_product) } @@ -54,19 +54,19 @@ module Spree end it "returns the property" do - expect(Property.sold_by(shop)).to eq [property] + expect(Property.currently_sold_by(shop)).to eq [property] end it "doesn't return the property from another exchange" do - expect(Property.sold_by(shop)).not_to include property_other_ex + expect(Property.currently_sold_by(shop)).not_to include property_other_ex end it "doesn't return the property with no order cycle" do - expect(Property.sold_by(shop)).not_to include property_no_oc + expect(Property.currently_sold_by(shop)).not_to include property_no_oc end it "doesn't return the property from a closed order cycle" do - expect(Property.sold_by(shop)).not_to include property_closed_oc + expect(Property.currently_sold_by(shop)).not_to include property_closed_oc end context "with another product in the order cycle" do @@ -78,7 +78,7 @@ module Spree end it "doesn't return duplicates" do - expect(Property.sold_by(shop).to_a.count).to eq 1 + expect(Property.currently_sold_by(shop).to_a.count).to eq 1 end end end From 1bc477f6b1678f4915f297411b68d8c87a46eaa4 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 9 Sep 2016 14:32:33 +1000 Subject: [PATCH 64/71] Add ProducerProperty.ever_sold_by --- app/models/producer_property.rb | 8 ++++++-- spec/models/producer_property_spec.rb | 12 ++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/app/models/producer_property.rb b/app/models/producer_property.rb index 7e2dd4ace1..b0bb1b6e51 100644 --- a/app/models/producer_property.rb +++ b/app/models/producer_property.rb @@ -8,14 +8,18 @@ class ProducerProperty < ActiveRecord::Base after_destroy :refresh_products_cache_from_destroy - scope :currently_sold_by, ->(shop) { + scope :ever_sold_by, ->(shop) { joins(producer: {supplied_products: {variants: {exchanges: :order_cycle}}}). merge(Exchange.outgoing). merge(Exchange.to_enterprise(shop)). - merge(OrderCycle.active). select('DISTINCT producer_properties.*') } + scope :currently_sold_by, ->(shop) { + ever_sold_by(shop). + merge(OrderCycle.active) + } + def property_name property.name if property diff --git a/spec/models/producer_property_spec.rb b/spec/models/producer_property_spec.rb index 559e7c7a28..0de7aae19b 100644 --- a/spec/models/producer_property_spec.rb +++ b/spec/models/producer_property_spec.rb @@ -8,7 +8,7 @@ describe ProducerProperty do producer.set_producer_property 'Organic Certified', 'NASAA 54321' end - describe ".currently_sold_by" do + describe ".currently_sold_by and .ever_sold_by" do let!(:shop) { create(:distributor_enterprise) } let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first]) } let(:product) { create(:simple_product, supplier: producer) } @@ -23,6 +23,7 @@ describe ProducerProperty do describe "with an associated producer property" do it "returns the producer property" do expect(ProducerProperty.currently_sold_by(shop)).to eq [pp] + expect(ProducerProperty.ever_sold_by(shop)).to eq [pp] end end @@ -31,6 +32,7 @@ describe ProducerProperty do it "doesn't return the producer property" do expect(ProducerProperty.currently_sold_by(shop)).not_to include pp_other + expect(ProducerProperty.ever_sold_by(shop)).not_to include pp_other end end @@ -41,6 +43,7 @@ describe ProducerProperty do it "doesn't return the producer property" do expect(ProducerProperty.currently_sold_by(shop)).not_to include pp_other + expect(ProducerProperty.ever_sold_by(shop)).not_to include pp_other end end @@ -49,9 +52,13 @@ describe ProducerProperty do oc.update_attributes! orders_close_at: 1.week.ago end - it "doesn't return the producer property" do + it "doesn't return the producer property for .currently_sold_by" do expect(ProducerProperty.currently_sold_by(shop)).not_to include pp end + + it "returns the producer property for .ever_sold_by" do + expect(ProducerProperty.ever_sold_by(shop)).to include pp + end end describe "with a duplicate producer property" do @@ -60,6 +67,7 @@ describe ProducerProperty do it "doesn't return duplicates" do expect(ProducerProperty.currently_sold_by(shop).to_a.count).to eq 1 + expect(ProducerProperty.ever_sold_by(shop).to_a.count).to eq 1 end end end From f98b25b719bb3fadd65b431345163f5c45887a6e Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 9 Sep 2016 14:38:56 +1000 Subject: [PATCH 65/71] Add Spree::Property.ever_sold_by --- app/models/spree/property_decorator.rb | 8 ++++++-- spec/models/spree/property_spec.rb | 26 +++++++++++++++++++------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/app/models/spree/property_decorator.rb b/app/models/spree/property_decorator.rb index c0abfda7e4..81577cef4e 100644 --- a/app/models/spree/property_decorator.rb +++ b/app/models/spree/property_decorator.rb @@ -8,14 +8,18 @@ module Spree where('spree_product_properties.product_id IN (?)', enterprise.supplied_product_ids) } - scope :currently_sold_by, ->(shop) { + scope :ever_sold_by, ->(shop) { joins(products: {variants: {exchanges: :order_cycle}}). merge(Exchange.outgoing). merge(Exchange.to_enterprise(shop)). - merge(OrderCycle.active). select('DISTINCT spree_properties.*') } + scope :currently_sold_by, ->(shop) { + ever_sold_by(shop). + merge(OrderCycle.active) + } + after_save :refresh_products_cache diff --git a/spec/models/spree/property_spec.rb b/spec/models/spree/property_spec.rb index 8ba93738cf..29046a8782 100644 --- a/spec/models/spree/property_spec.rb +++ b/spec/models/spree/property_spec.rb @@ -31,42 +31,53 @@ module Spree end end - describe ".currently_sold_by" do + describe ".currently_sold_by and .ever_sold_by" do let!(:shop) { create(:distributor_enterprise) } let!(:shop_other) { create(:distributor_enterprise) } let!(:product) { create(:simple_product) } let!(:product_other_ex) { create(:simple_product) } let!(:product_no_oc) { create(:simple_product) } - let!(:product_closed_oc) { create(:simple_product) } let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first]) } - let!(:oc_closed) { create(:closed_order_cycle, distributors: [shop], variants: [product_closed_oc.variants.first]) } let!(:exchange_other_shop) { create(:exchange, order_cycle: oc, sender: oc.coordinator, receiver: shop_other, variants: [product_other_ex.variants.first]) } let(:property) { product.properties.last } let(:property_other_ex) { product_other_ex.properties.last } let(:property_no_oc) { product_no_oc.properties.last } - let(:property_closed_oc) { product_closed_oc.properties.last } before do product.set_property 'Organic', 'NASAA 12345' product_other_ex.set_property 'Biodynamic', 'ASDF 12345' product_no_oc.set_property 'Shiny', 'Very' - product_closed_oc.set_property 'Spiffy', 'Ooh yeah' end it "returns the property" do expect(Property.currently_sold_by(shop)).to eq [property] + expect(Property.ever_sold_by(shop)).to eq [property] end it "doesn't return the property from another exchange" do expect(Property.currently_sold_by(shop)).not_to include property_other_ex + expect(Property.ever_sold_by(shop)).not_to include property_other_ex end it "doesn't return the property with no order cycle" do expect(Property.currently_sold_by(shop)).not_to include property_no_oc + expect(Property.ever_sold_by(shop)).not_to include property_no_oc end - it "doesn't return the property from a closed order cycle" do - expect(Property.currently_sold_by(shop)).not_to include property_closed_oc + describe "closed order cyces" do + let!(:product_closed_oc) { create(:simple_product) } + let!(:oc_closed) { create(:closed_order_cycle, distributors: [shop], variants: [product_closed_oc.variants.first]) } + let(:property_closed_oc) { product_closed_oc.properties.last } + + before { product_closed_oc.set_property 'Spiffy', 'Ooh yeah' } + + it "doesn't return the property for .currently_sold_by" do + expect(Property.currently_sold_by(shop)).not_to include property_closed_oc + end + + it "returns the property for .ever_sold_by" do + expect(Property.ever_sold_by(shop)).to include property_closed_oc + end end context "with another product in the order cycle" do @@ -79,6 +90,7 @@ module Spree it "doesn't return duplicates" do expect(Property.currently_sold_by(shop).to_a.count).to eq 1 + expect(Property.ever_sold_by(shop).to_a.count).to eq 1 end end end From 306bd25dd98f991ccf7fb9f9713d55ba4566a8cb Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 9 Sep 2016 14:45:11 +1000 Subject: [PATCH 66/71] EnterpriseSerialiser shows current properties for open shops and all properties for closed shops --- app/serializers/api/enterprise_serializer.rb | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index 7cdf3d4adc..d3d7159959 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -42,9 +42,17 @@ class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer def distributed_properties # This results in 3 queries per enterprise - product_properties = Spree::Property.currently_sold_by(object) - ids = ProducerProperty.currently_sold_by(object).pluck(:property_id) - producer_properties = Spree::Property.where(id: ids) + + if active + product_properties = Spree::Property.currently_sold_by(object) + producer_property_ids = ProducerProperty.currently_sold_by(object).pluck(:property_id) + + else + product_properties = Spree::Property.ever_sold_by(object) + producer_property_ids = ProducerProperty.ever_sold_by(object).pluck(:property_id) + end + + producer_properties = Spree::Property.where(id: producer_property_ids) OpenFoodNetwork::PropertyMerge.merge product_properties, producer_properties end From db583df19877fd80f1b5c25ad879e9989247b13e Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 16 Sep 2016 10:50:59 +1000 Subject: [PATCH 67/71] Use inner join for Spree::Taxon.distributed_taxons --- app/models/spree/taxon_decorator.rb | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/app/models/spree/taxon_decorator.rb b/app/models/spree/taxon_decorator.rb index a051de98fa..fcc784475c 100644 --- a/app/models/spree/taxon_decorator.rb +++ b/app/models/spree/taxon_decorator.rb @@ -33,20 +33,18 @@ Spree::Taxon.class_eval do # Find all the taxons of distributed products for each enterprise, indexed by enterprise. # Format: {enterprise_id => [taxon_id, ...]} - def self.distributed_taxons - taxons = {} + def self.distributed_taxons(which_taxons=:all) + # TODO: Why can't we merge(Spree::Product.with_order_cycles_inner) here? + taxons = Spree::Taxon. + joins(products: {variants_including_master: {exchanges: :order_cycle}}). + merge(Exchange.outgoing). + select('spree_taxons.*, exchanges.receiver_id AS enterprise_id') - Spree::Taxon. - joins(:products). - merge(Spree::Product.with_order_cycles_outer). - where('o_exchanges.incoming = ?', false). - select('spree_taxons.*, o_exchanges.receiver_id AS enterprise_id'). - each do |t| - taxons[t.enterprise_id.to_i] ||= Set.new - taxons[t.enterprise_id.to_i] << t.id - end - - taxons + taxons.inject({}) do |ts, t| + ts[t.enterprise_id.to_i] ||= Set.new + ts[t.enterprise_id.to_i] << t.id + ts + end end From c0db23af90e9d1a6bed9836b1d7dff6976e5acdf Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 16 Sep 2016 11:13:24 +1000 Subject: [PATCH 68/71] Spree::Taxon.distributed_taxons can be scoped to taxons in open order cycles --- app/models/spree/taxon_decorator.rb | 5 +++++ spec/models/spree/taxon_spec.rb | 17 +++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/app/models/spree/taxon_decorator.rb b/app/models/spree/taxon_decorator.rb index fcc784475c..1878a20e49 100644 --- a/app/models/spree/taxon_decorator.rb +++ b/app/models/spree/taxon_decorator.rb @@ -32,6 +32,9 @@ Spree::Taxon.class_eval do end # Find all the taxons of distributed products for each enterprise, indexed by enterprise. + # May return :all taxons (distributed in open and closed order cycles), + # or :current taxons (distributed in an open order cycle). + # # Format: {enterprise_id => [taxon_id, ...]} def self.distributed_taxons(which_taxons=:all) # TODO: Why can't we merge(Spree::Product.with_order_cycles_inner) here? @@ -40,6 +43,8 @@ Spree::Taxon.class_eval do merge(Exchange.outgoing). select('spree_taxons.*, exchanges.receiver_id AS enterprise_id') + taxons = taxons.merge(OrderCycle.active) if which_taxons == :current + taxons.inject({}) do |ts, t| ts[t.enterprise_id.to_i] ||= Set.new ts[t.enterprise_id.to_i] << t.id diff --git a/spec/models/spree/taxon_spec.rb b/spec/models/spree/taxon_spec.rb index 8fb4b22dc5..873a201013 100644 --- a/spec/models/spree/taxon_spec.rb +++ b/spec/models/spree/taxon_spec.rb @@ -29,13 +29,18 @@ module Spree end end - describe "finding all distributed taxons" do - let!(:oc) { create(:simple_order_cycle, distributors: [e], variants: [p1.master]) } - let!(:s) { create(:supplier_enterprise) } - let!(:p1) { create(:simple_product, supplier: s, taxons: [t1, t2]) } + describe "finding distributed taxons" do + let!(:oc_open) { create(:open_order_cycle, distributors: [e], variants: [p_open.variants.first]) } + let!(:oc_closed) { create(:closed_order_cycle, distributors: [e], variants: [p_closed.variants.first]) } + let!(:p_open) { create(:simple_product, primary_taxon: t1) } + let!(:p_closed) { create(:simple_product, primary_taxon: t2) } - it "finds taxons" do - Taxon.distributed_taxons.should == {e.id => Set.new(p1.taxons.map(&:id))} + it "finds all distributed taxons" do + expect(Taxon.distributed_taxons(:all)).to eq({e.id => Set.new([t1.id, t2.id])}) + end + + it "finds currently distributed taxons" do + expect(Taxon.distributed_taxons(:current)).to eq({e.id => Set.new([t1.id])}) end end end From 3ca42ae055f27d86c28031e33d4d2f95b80902f0 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 16 Sep 2016 11:24:47 +1000 Subject: [PATCH 69/71] Extract ids_to_objs to SerializerHelper --- app/helpers/serializer_helper.rb | 6 ++++++ app/serializers/api/enterprise_serializer.rb | 12 ++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) create mode 100644 app/helpers/serializer_helper.rb diff --git a/app/helpers/serializer_helper.rb b/app/helpers/serializer_helper.rb new file mode 100644 index 0000000000..2e48e3741d --- /dev/null +++ b/app/helpers/serializer_helper.rb @@ -0,0 +1,6 @@ +module SerializerHelper + def ids_to_objs(ids) + return [] if ids.blank? + ids.map { |id| {id: id} } + end +end diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index d3d7159959..fd723a40e8 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -20,6 +20,8 @@ class Api::EnterpriseSerializer < ActiveModel::Serializer end class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer + include SerializerHelper + attributes :orders_close_at, :active has_many :supplied_properties, serializer: Api::PropertySerializer has_many :distributed_properties, serializer: Api::PropertySerializer @@ -59,6 +61,8 @@ class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer end class Api::CachedEnterpriseSerializer < ActiveModel::Serializer + include SerializerHelper + cached #delegate :cache_key, to: :object @@ -161,12 +165,4 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer } icon_fonts[object.category] end - - - private - - def ids_to_objs(ids) - return [] if ids.blank? - ids.map { |id| {id: id} } - end end From e8f96e4818d8388e61d3b76eba233c2418c78301 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 16 Sep 2016 11:28:23 +1000 Subject: [PATCH 70/71] When a shop is open, only show taxon badges for currently open order cycles --- app/serializers/api/enterprise_serializer.rb | 22 ++++++++------ .../enterprise_injection_data.rb | 8 +++-- spec/features/consumer/shops_spec.rb | 29 +++++++++++++++++++ .../serializers/enterprise_serializer_spec.rb | 3 +- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index fd723a40e8..3537bcdd24 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -23,6 +23,7 @@ class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer include SerializerHelper attributes :orders_close_at, :active + attributes :taxons, :supplied_taxons has_many :supplied_properties, serializer: Api::PropertySerializer has_many :distributed_properties, serializer: Api::PropertySerializer @@ -58,6 +59,18 @@ class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer OpenFoodNetwork::PropertyMerge.merge product_properties, producer_properties end + + def taxons + if active + ids_to_objs options[:data].current_distributed_taxons[object.id] + else + ids_to_objs options[:data].all_distributed_taxons[object.id] + end + end + + def supplied_taxons + ids_to_objs options[:data].supplied_taxons[object.id] + end end class Api::CachedEnterpriseSerializer < ActiveModel::Serializer @@ -77,16 +90,7 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer :email_address, :hash, :logo, :promo_image, :path, :pickup, :delivery, :icon, :icon_font, :producer_icon_font, :category, :producers, :hubs - attributes :taxons, :supplied_taxons - has_one :address, serializer: Api::AddressSerializer - def taxons - ids_to_objs options[:data].distributed_taxons[object.id] - end - - def supplied_taxons - ids_to_objs options[:data].supplied_taxons[object.id] - end def pickup services = options[:data].shipping_method_services[object.id] diff --git a/lib/open_food_network/enterprise_injection_data.rb b/lib/open_food_network/enterprise_injection_data.rb index 87516007c6..938c8b3aab 100644 --- a/lib/open_food_network/enterprise_injection_data.rb +++ b/lib/open_food_network/enterprise_injection_data.rb @@ -20,8 +20,12 @@ module OpenFoodNetwork @supplied_taxons ||= Spree::Taxon.supplied_taxons end - def distributed_taxons - @distributed_taxons ||= Spree::Taxon.distributed_taxons + def all_distributed_taxons + @all_distributed_taxons ||= Spree::Taxon.distributed_taxons(:all) + end + + def current_distributed_taxons + @current_distributed_taxons ||= Spree::Taxon.distributed_taxons(:current) end end end diff --git a/spec/features/consumer/shops_spec.rb b/spec/features/consumer/shops_spec.rb index 74fb5b955f..f8f54a197b 100644 --- a/spec/features/consumer/shops_spec.rb +++ b/spec/features/consumer/shops_spec.rb @@ -88,6 +88,35 @@ feature 'Shops', js: true do end end + describe "taxon badges" do + let!(:closed_oc) { create(:closed_order_cycle, distributors: [shop], variants: [p_closed.variants.first]) } + let!(:p_closed) { create(:simple_product, taxons: [taxon_closed]) } + let(:shop) { create(:distributor_enterprise) } + let(:taxon_closed) { create(:taxon, name: 'Closed') } + + describe "open shops" do + let!(:open_oc) { create(:open_order_cycle, distributors: [shop], variants: [p_open.variants.first]) } + let!(:p_open) { create(:simple_product, taxons: [taxon_open]) } + let(:taxon_open) { create(:taxon, name: 'Open') } + + it "shows taxons for open order cycles only" do + visit shops_path + expand_active_table_node shop.name + expect(page).to have_selector '.fat-taxons', text: 'Open' + expect(page).not_to have_selector '.fat-taxons', text: 'Closed' + end + end + + describe "closed shops" do + it "shows taxons for any order cycle" do + visit shops_path + click_link 'Show Closed Shops' + expand_active_table_node shop.name + expect(page).to have_selector '.fat-taxons', text: 'Closed' + end + end + end + describe "property badges" do let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product.variants.first]) } let(:product) { create(:simple_product, supplier: producer) } diff --git a/spec/serializers/enterprise_serializer_spec.rb b/spec/serializers/enterprise_serializer_spec.rb index f5eff4f771..bea2672157 100644 --- a/spec/serializers/enterprise_serializer_spec.rb +++ b/spec/serializers/enterprise_serializer_spec.rb @@ -6,7 +6,8 @@ describe Api::EnterpriseSerializer do let(:taxon) { create(:taxon) } let(:data) { OpenStruct.new(earliest_closing_times: {}, active_distributors: [], - distributed_taxons: {enterprise.id => [123]}, + all_distributed_taxons: {enterprise.id => [123]}, + current_distributed_taxons: {enterprise.id => [123]}, supplied_taxons: {enterprise.id => [456]}, shipping_method_services: {}, relatives: {enterprise.id => {producers: [123], distributors: [456]}}) } From 7d149ed198a18ce602cf3b35eff93f55645df851 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Sun, 18 Sep 2016 17:46:43 +1000 Subject: [PATCH 71/71] Revert shop property filters - causing 10x slowdown This commit reverts commits 7eeee78c4ecfee6a1db90f137d7bcb8eaa4e78ee to e8f96e4818d8388e61d3b76eba233c2418c78301 (inclusive) --- .../darkswarm/filters/properties.js.coffee | 8 +-- .../darkswarm/filters/properties_of.js.coffee | 12 ++-- .../darkswarm/_shop-filters.css.sass | 2 +- app/helpers/injection_helper.rb | 2 +- app/helpers/serializer_helper.rb | 6 -- app/models/producer_property.rb | 8 +-- app/models/spree/property_decorator.rb | 8 +-- app/models/spree/taxon_decorator.rb | 27 ++++---- app/serializers/api/enterprise_serializer.rb | 48 ++++++-------- app/serializers/api/property_serializer.rb | 6 -- app/views/groups/_hub_filters.html.haml | 21 +++++++ app/views/groups/show.html.haml | 28 ++++----- app/views/{shops => home}/_fat.html.haml | 0 app/views/home/_filters.html.haml | 22 +++++++ app/views/{shops => home}/_hubs.html.haml | 6 +- .../{shops => home}/_hubs_table.html.haml | 6 +- app/views/{shops => home}/_skinny.html.haml | 0 app/views/producers/_filters.html.haml | 2 +- app/views/producers/index.html.haml | 2 +- app/views/shop/products/_filters.html.haml | 2 +- app/views/shops/_filters.html.haml | 34 ---------- app/views/shops/index.html.haml | 4 +- config/locales/en.yml | 1 - .../enterprise_injection_data.rb | 8 +-- spec/features/consumer/groups_spec.rb | 39 ------------ spec/features/consumer/shops_spec.rb | 63 +------------------ spec/models/producer_property_spec.rb | 22 +++---- spec/models/spree/property_spec.rb | 34 ++++------ spec/models/spree/taxon_spec.rb | 17 ++--- .../serializers/enterprise_serializer_spec.rb | 3 +- 30 files changed, 142 insertions(+), 299 deletions(-) delete mode 100644 app/helpers/serializer_helper.rb create mode 100644 app/views/groups/_hub_filters.html.haml rename app/views/{shops => home}/_fat.html.haml (100%) create mode 100644 app/views/home/_filters.html.haml rename app/views/{shops => home}/_hubs.html.haml (89%) rename app/views/{shops => home}/_hubs_table.html.haml (67%) rename app/views/{shops => home}/_skinny.html.haml (100%) delete mode 100644 app/views/shops/_filters.html.haml diff --git a/app/assets/javascripts/darkswarm/filters/properties.js.coffee b/app/assets/javascripts/darkswarm/filters/properties.js.coffee index fe7ed71fa3..1453cac053 100644 --- a/app/assets/javascripts/darkswarm/filters/properties.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/properties.js.coffee @@ -1,17 +1,13 @@ Darkswarm.filter 'properties', -> # Filter anything that responds to object.supplied_properties - (objects, ids, source) -> + (objects, ids) -> objects ||= [] ids ?= [] - - source ||= 'properties' - return [] unless source in ['properties', 'supplied_properties', 'distributed_properties'] - if ids.length == 0 # No properties selected, pass all objects through. objects else objects.filter (obj) -> - properties = obj[source] + properties = obj.supplied_properties || obj.properties properties.some (property) -> property.id in ids diff --git a/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee b/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee index f3f4f51b5e..7eac12bf1e 100644 --- a/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/properties_of.js.coffee @@ -1,12 +1,12 @@ Darkswarm.filter 'propertiesOf', -> - (objects, source) -> - source ||= 'properties' - return {} unless source in ['properties', 'supplied_properties', 'distributed_properties'] - + (objects) -> properties = {} for object in objects - if object[source]? - for property in object[source] + if object.supplied_properties? + for property in object.supplied_properties + properties[property.id] = property + else + for property in object.properties properties[property.id] = property properties diff --git a/app/assets/stylesheets/darkswarm/_shop-filters.css.sass b/app/assets/stylesheets/darkswarm/_shop-filters.css.sass index 07fea7a0b1..3c4f9a514d 100644 --- a/app/assets/stylesheets/darkswarm/_shop-filters.css.sass +++ b/app/assets/stylesheets/darkswarm/_shop-filters.css.sass @@ -96,7 +96,7 @@ // content. Ensure that the dropdown appears above the content. .filter-row position: relative - z-index: 90 + z-index: 100 .filter-shopfront &.taxon-selectors, &.property-selectors diff --git a/app/helpers/injection_helper.rb b/app/helpers/injection_helper.rb index dad9cf11f9..6db2e583bc 100644 --- a/app/helpers/injection_helper.rb +++ b/app/helpers/injection_helper.rb @@ -45,7 +45,7 @@ module InjectionHelper end def inject_properties - inject_json_ams "properties", Spree::Property.all, Api::PropertySerializer + inject_json_ams "properties", Spree::Property.all, Api::IdNameSerializer end def inject_currency_config diff --git a/app/helpers/serializer_helper.rb b/app/helpers/serializer_helper.rb deleted file mode 100644 index 2e48e3741d..0000000000 --- a/app/helpers/serializer_helper.rb +++ /dev/null @@ -1,6 +0,0 @@ -module SerializerHelper - def ids_to_objs(ids) - return [] if ids.blank? - ids.map { |id| {id: id} } - end -end diff --git a/app/models/producer_property.rb b/app/models/producer_property.rb index b0bb1b6e51..bf1f083936 100644 --- a/app/models/producer_property.rb +++ b/app/models/producer_property.rb @@ -8,18 +8,14 @@ class ProducerProperty < ActiveRecord::Base after_destroy :refresh_products_cache_from_destroy - scope :ever_sold_by, ->(shop) { + scope :sold_by, ->(shop) { joins(producer: {supplied_products: {variants: {exchanges: :order_cycle}}}). merge(Exchange.outgoing). merge(Exchange.to_enterprise(shop)). + merge(OrderCycle.active). select('DISTINCT producer_properties.*') } - scope :currently_sold_by, ->(shop) { - ever_sold_by(shop). - merge(OrderCycle.active) - } - def property_name property.name if property diff --git a/app/models/spree/property_decorator.rb b/app/models/spree/property_decorator.rb index 81577cef4e..50e450a03b 100644 --- a/app/models/spree/property_decorator.rb +++ b/app/models/spree/property_decorator.rb @@ -8,18 +8,14 @@ module Spree where('spree_product_properties.product_id IN (?)', enterprise.supplied_product_ids) } - scope :ever_sold_by, ->(shop) { + scope :sold_by, ->(shop) { joins(products: {variants: {exchanges: :order_cycle}}). merge(Exchange.outgoing). merge(Exchange.to_enterprise(shop)). + merge(OrderCycle.active). select('DISTINCT spree_properties.*') } - scope :currently_sold_by, ->(shop) { - ever_sold_by(shop). - merge(OrderCycle.active) - } - after_save :refresh_products_cache diff --git a/app/models/spree/taxon_decorator.rb b/app/models/spree/taxon_decorator.rb index 1878a20e49..a051de98fa 100644 --- a/app/models/spree/taxon_decorator.rb +++ b/app/models/spree/taxon_decorator.rb @@ -32,24 +32,21 @@ Spree::Taxon.class_eval do end # Find all the taxons of distributed products for each enterprise, indexed by enterprise. - # May return :all taxons (distributed in open and closed order cycles), - # or :current taxons (distributed in an open order cycle). - # # Format: {enterprise_id => [taxon_id, ...]} - def self.distributed_taxons(which_taxons=:all) - # TODO: Why can't we merge(Spree::Product.with_order_cycles_inner) here? - taxons = Spree::Taxon. - joins(products: {variants_including_master: {exchanges: :order_cycle}}). - merge(Exchange.outgoing). - select('spree_taxons.*, exchanges.receiver_id AS enterprise_id') + def self.distributed_taxons + taxons = {} - taxons = taxons.merge(OrderCycle.active) if which_taxons == :current + Spree::Taxon. + joins(:products). + merge(Spree::Product.with_order_cycles_outer). + where('o_exchanges.incoming = ?', false). + select('spree_taxons.*, o_exchanges.receiver_id AS enterprise_id'). + each do |t| + taxons[t.enterprise_id.to_i] ||= Set.new + taxons[t.enterprise_id.to_i] << t.id + end - taxons.inject({}) do |ts, t| - ts[t.enterprise_id.to_i] ||= Set.new - ts[t.enterprise_id.to_i] << t.id - ts - end + taxons end diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index 3537bcdd24..f68c8be679 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -20,10 +20,7 @@ class Api::EnterpriseSerializer < ActiveModel::Serializer end class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer - include SerializerHelper - attributes :orders_close_at, :active - attributes :taxons, :supplied_taxons has_many :supplied_properties, serializer: Api::PropertySerializer has_many :distributed_properties, serializer: Api::PropertySerializer @@ -45,37 +42,15 @@ class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer def distributed_properties # This results in 3 queries per enterprise - - if active - product_properties = Spree::Property.currently_sold_by(object) - producer_property_ids = ProducerProperty.currently_sold_by(object).pluck(:property_id) - - else - product_properties = Spree::Property.ever_sold_by(object) - producer_property_ids = ProducerProperty.ever_sold_by(object).pluck(:property_id) - end - - producer_properties = Spree::Property.where(id: producer_property_ids) + product_properties = Spree::Property.sold_by(object) + ids = ProducerProperty.sold_by(object).pluck(:property_id) + producer_properties = Spree::Property.where(id: ids) OpenFoodNetwork::PropertyMerge.merge product_properties, producer_properties end - - def taxons - if active - ids_to_objs options[:data].current_distributed_taxons[object.id] - else - ids_to_objs options[:data].all_distributed_taxons[object.id] - end - end - - def supplied_taxons - ids_to_objs options[:data].supplied_taxons[object.id] - end end class Api::CachedEnterpriseSerializer < ActiveModel::Serializer - include SerializerHelper - cached #delegate :cache_key, to: :object @@ -90,7 +65,16 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer :email_address, :hash, :logo, :promo_image, :path, :pickup, :delivery, :icon, :icon_font, :producer_icon_font, :category, :producers, :hubs + attributes :taxons, :supplied_taxons + has_one :address, serializer: Api::AddressSerializer + def taxons + ids_to_objs options[:data].distributed_taxons[object.id] + end + + def supplied_taxons + ids_to_objs options[:data].supplied_taxons[object.id] + end def pickup services = options[:data].shipping_method_services[object.id] @@ -169,4 +153,12 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer } icon_fonts[object.category] end + + + private + + def ids_to_objs(ids) + return [] if ids.blank? + ids.map { |id| {id: id} } + end end diff --git a/app/serializers/api/property_serializer.rb b/app/serializers/api/property_serializer.rb index cdb3f2bae3..7da4fce990 100644 --- a/app/serializers/api/property_serializer.rb +++ b/app/serializers/api/property_serializer.rb @@ -1,9 +1,3 @@ class Api::PropertySerializer < ActiveModel::Serializer attributes :id, :name, :presentation - - # Client-side we don't care about the property name. Send the presentation - # since this is what we want to show to the user. - def name - object.presentation - end end diff --git a/app/views/groups/_hub_filters.html.haml b/app/views/groups/_hub_filters.html.haml new file mode 100644 index 0000000000..71924d5e85 --- /dev/null +++ b/app/views/groups/_hub_filters.html.haml @@ -0,0 +1,21 @@ +.row + = render partial: 'shared/components/filter_controls' + = render partial: 'shared/components/show_profiles' + +.row.animate-show{"ng-show" => "filtersActive"} + .small-12.columns + .row.filter-box + .small-12.large-9.columns + %h5.tdhead + .light + = t :hubs_filter_by + = t :hubs_filter_type + %filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-5{"selector-set" => "filterSelectors", objects: "group_hubs | searchEnterprises:query | shipping:shippingTypes | showHubProfiles:show_profiles | taxonsOf", "active-selectors" => "activeTaxons"} + .small-12.large-3.columns + %h5.tdhead + .light + = t :hubs_filter_by + = t :hubs_filter_delivery + %shipping-type-selector + += render partial: 'shared/components/filter_box' diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 90b74c0b42..ef9e281155 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -60,23 +60,23 @@ .small-12.columns %h1 = t :groups_producers - = render "shared/components/enterprise_search" - = render "producers/filters" + = render partial: "shared/components/enterprise_search" + = render partial: "producers/filters" .row .small-12.columns .active_table %producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", - "ng-repeat" => "producer in filteredEnterprises = (group_producers | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties:'supplied_properties')", + "ng-repeat" => "producer in filteredEnterprises = (group_producers | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties)", "ng-controller" => "GroupEnterpriseNodeCtrl", "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", id: "{{producer.hash}}"} .small-12.columns - = render "producers/skinny" - = render "producers/fat" + = render partial: 'producers/skinny' + = render partial: 'producers/fat' - = render 'shared/components/enterprise_no_results' + = render partial: 'shared/components/enterprise_no_results' %tab{heading: t(:groups_hubs), active: "tabs.hubs.active", @@ -87,24 +87,24 @@ %h1 = t :groups_hubs - = render "shared/components/enterprise_search" - = render "shops/filters", resource: "group_hubs", property_filters: "| searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles" + = render partial: "shared/components/enterprise_search" + = render partial: "hub_filters" .row .small-12.columns .active_table %hub.active_table_node.row.animate-repeat{id: "{{hub.hash}}", - "ng-repeat" => "hub in filteredEnterprises = (group_hubs | searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | properties:activeProperties:'distributed_properties' | orderBy:['-active', '+orders_close_at'])", + "ng-repeat" => "hub in filteredEnterprises = (group_hubs | searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+orders_close_at'])", "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", "ng-controller" => "GroupEnterpriseNodeCtrl"} .small-12.columns - = render 'shops/skinny' - = render 'shops/fat' + = render partial: 'home/skinny' + = render partial: 'home/fat' - = render 'shared/components/enterprise_no_results' + = render partial: 'shared/components/enterprise_no_results' .small-12.medium-12.large-3.columns - = render 'contact' + = render partial: 'contact' .small-12.columns.pad-top .row.pad-top @@ -122,4 +122,4 @@ %p   -= render "shared/footer" += render partial: "shared/footer" diff --git a/app/views/shops/_fat.html.haml b/app/views/home/_fat.html.haml similarity index 100% rename from app/views/shops/_fat.html.haml rename to app/views/home/_fat.html.haml diff --git a/app/views/home/_filters.html.haml b/app/views/home/_filters.html.haml new file mode 100644 index 0000000000..bfd13fdf54 --- /dev/null +++ b/app/views/home/_filters.html.haml @@ -0,0 +1,22 @@ +.row + = render partial: 'shared/components/filter_controls' + -# .small-12.medium-6.columns   + = render partial: 'shared/components/show_profiles' + +.row.animate-show{"ng-show" => "filtersActive"} + .small-12.columns + .row.filter-box + .small-12.large-9.columns + %h5.tdhead + .light + = t :hubs_filter_by + = t :hubs_filter_type + %filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-5{ "selector-set" => "filterSelectors", objects: "visibleMatches | visible | taxonsOf", "active-selectors" => "activeTaxons" } + .small-12.large-3.columns + %h5.tdhead + .light + = t :hubs_filter_by + = t :hubs_filter_delivery + %shipping-type-selector + += render partial: 'shared/components/filter_box' diff --git a/app/views/shops/_hubs.html.haml b/app/views/home/_hubs.html.haml similarity index 89% rename from app/views/shops/_hubs.html.haml rename to app/views/home/_hubs.html.haml index 6087d2330c..e899270efc 100644 --- a/app/views/shops/_hubs.html.haml +++ b/app/views/home/_hubs.html.haml @@ -7,14 +7,14 @@ = t :hubs_intro = render "shared/components/enterprise_search" - = render "filters" + = render "home/filters" .row .small-12.columns .name-matches{"ng-show" => "nameMatchesFiltered.length > 0"} %h2 = t :hubs_matches - = render "hubs_table", enterprises: "nameMatches" + = render "home/hubs_table", enterprises: "nameMatches" .distance-matches{"ng-if" => "nameMatchesFiltered.length == 0 || distanceMatchesShown"} %h2{"ng-show" => "nameMatchesFiltered.length > 0 || query.length > 0"} @@ -22,7 +22,7 @@ %span{"ng-show" => "nameMatchesFiltered.length > 0"} {{ nameMatchesFiltered[0].name }}... %span{"ng-hide" => "nameMatchesFiltered.length > 0"} {{ query }}... - = render "hubs_table", enterprises: "distanceMatches" + = render "home/hubs_table", enterprises: "distanceMatches" .show-distance-matches{"ng-show" => "nameMatchesFiltered.length > 0 && !distanceMatchesShown"} %a{href: "", "ng-click" => "showDistanceMatches()"} diff --git a/app/views/shops/_hubs_table.html.haml b/app/views/home/_hubs_table.html.haml similarity index 67% rename from app/views/shops/_hubs_table.html.haml rename to app/views/home/_hubs_table.html.haml index 6d5803b477..edf9eb5ec8 100644 --- a/app/views/shops/_hubs_table.html.haml +++ b/app/views/home/_hubs_table.html.haml @@ -1,10 +1,10 @@ .active_table - %hub.active_table_node.row{"ng-repeat" => "hub in #{enterprises}Filtered = (#{enterprises} | filter:filterExpression | taxons:activeTaxons | properties:activeProperties:'distributed_properties' | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+distance', '+orders_close_at'])", + %hub.active_table_node.row{"ng-repeat" => "hub in #{enterprises}Filtered = (#{enterprises} | filter:filterExpression | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+distance', '+orders_close_at'])", "ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}", "ng-controller" => "HubNodeCtrl", id: "{{hub.hash}}"} .small-12.columns - = render 'skinny' - = render 'fat' + = render 'home/skinny' + = render 'home/fat' = render 'shared/components/enterprise_no_results', enterprises: "#{enterprises}Filtered" diff --git a/app/views/shops/_skinny.html.haml b/app/views/home/_skinny.html.haml similarity index 100% rename from app/views/shops/_skinny.html.haml rename to app/views/home/_skinny.html.haml diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 17f260196a..771ed932c9 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -18,6 +18,6 @@ = t :producers_filter = t :producers_filter_property .filter-shopfront.property-selectors - %filter-selector{ "selector-set" => "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | taxons:activeTaxons | propertiesOf:'supplied_properties'", "active-selectors" => "activeProperties"} + %single-line-selectors{ selectors: "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | propertiesOf", "active-selectors" => "activeProperties"} = render partial: 'shared/components/filter_box' diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index af6c2e4fd1..04048ef77e 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -16,7 +16,7 @@ .small-12.columns .active_table %producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", - "ng-repeat" => "producer in filteredEnterprises = (Enterprises.producers | visible | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties:'supplied_properties')", + "ng-repeat" => "producer in filteredEnterprises = (Enterprises.producers | visible | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties)", "ng-controller" => "ProducerNodeCtrl", "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", id: "{{producer.hash}}"} diff --git a/app/views/shop/products/_filters.html.haml b/app/views/shop/products/_filters.html.haml index 10c7c20deb..7efaba6cc9 100644 --- a/app/views/shop/products/_filters.html.haml +++ b/app/views/shop/products/_filters.html.haml @@ -1,5 +1,5 @@ .filter-shopfront.taxon-selectors.text-right - %single-line-selectors{ selectors: "taxonSelectors", objects: "Products.products | products:query | properties:activeProperties | taxonsOf", "active-selectors" => "activeTaxons"} + %single-line-selectors{ selectors: "taxonSelectors", objects: "Products.products | products:query | properties: activeProperties | taxonsOf", "active-selectors" => "activeTaxons"} .filter-shopfront.property-selectors.text-right %single-line-selectors{ selectors: "propertySelectors", objects: "Products.products | products:query | taxons:activeTaxons | propertiesOf", "active-selectors" => "activeProperties"} diff --git a/app/views/shops/_filters.html.haml b/app/views/shops/_filters.html.haml deleted file mode 100644 index 42e2b2ec28..0000000000 --- a/app/views/shops/_filters.html.haml +++ /dev/null @@ -1,34 +0,0 @@ -- resource ||= "visibleMatches" -- property_filters ||= "| filter:filterExpression | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles" - -.row - = render 'shared/components/filter_controls' - -# .small-12.medium-6.columns   - = render 'shared/components/show_profiles' - -.row.animate-show.filter-row{"ng-show" => "filtersActive"} - .small-12.columns - .row.filter-box - .small-12.large-9.columns - %h5.tdhead - .light - = t :hubs_filter_by - = t :hubs_filter_type - - %filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-5{ "selector-set" => "filterSelectors", objects: "#{resource} | visible | taxonsOf", "active-selectors" => "activeTaxons" } - .small-12.large-3.columns - %h5.tdhead - .light - = t :hubs_filter_by - = t :hubs_filter_delivery - %shipping-type-selector - - .small-12.large-12.columns - %h5.tdhead - .light - = t :hubs_filter_by - = t :hubs_filter_property - .filter-shopfront.property-selectors - %filter-selector{ "selector-set" => "filterSelectors", objects: "#{resource} #{property_filters} | propertiesOf:'distributed_properties'", "active-selectors" => "activeProperties"} - -= render 'shared/components/filter_box' diff --git a/app/views/shops/index.html.haml b/app/views/shops/index.html.haml index 7e288f4157..1b3cf547a8 100644 --- a/app/views/shops/index.html.haml +++ b/app/views/shops/index.html.haml @@ -10,5 +10,5 @@ %p.text-big = t :shops_text -= render "hubs" -= render "shared/footer" += render partial: "home/hubs" += render partial: "shared/footer" diff --git a/config/locales/en.yml b/config/locales/en.yml index 991c308c2f..1d8707a7b9 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -505,7 +505,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using hubs_filter_by: "Filter by" hubs_filter_type: "Type" hubs_filter_delivery: "Delivery" - hubs_filter_property: "Property" hubs_matches: "Did you mean?" hubs_intro: Shop in your local area hubs_distance: Closest to diff --git a/lib/open_food_network/enterprise_injection_data.rb b/lib/open_food_network/enterprise_injection_data.rb index 938c8b3aab..87516007c6 100644 --- a/lib/open_food_network/enterprise_injection_data.rb +++ b/lib/open_food_network/enterprise_injection_data.rb @@ -20,12 +20,8 @@ module OpenFoodNetwork @supplied_taxons ||= Spree::Taxon.supplied_taxons end - def all_distributed_taxons - @all_distributed_taxons ||= Spree::Taxon.distributed_taxons(:all) - end - - def current_distributed_taxons - @current_distributed_taxons ||= Spree::Taxon.distributed_taxons(:current) + def distributed_taxons + @distributed_taxons ||= Spree::Taxon.distributed_taxons end end end diff --git a/spec/features/consumer/groups_spec.rb b/spec/features/consumer/groups_spec.rb index 4a5f166d7d..039322b379 100644 --- a/spec/features/consumer/groups_spec.rb +++ b/spec/features/consumer/groups_spec.rb @@ -54,43 +54,4 @@ feature 'Groups', js: true do end end end - - describe "shops" do - describe "filtering by product property" do - let!(:group) { create(:enterprise_group, enterprises: [d1, d2], on_front_page: true) } - let!(:order_cycle) { create(:simple_order_cycle, distributors: [d1, d2], coordinator: create(:distributor_enterprise)) } - let(:producer) { create(:supplier_enterprise) } - let(:d1) { create(:distributor_enterprise) } - let(:d2) { create(:distributor_enterprise) } - let(:p1) { create(:simple_product, supplier: producer) } - let(:p2) { create(:simple_product, supplier: create(:supplier_enterprise)) } - let(:ex_d1) { order_cycle.exchanges.outgoing.where(receiver_id: d1).first } - let(:ex_d2) { order_cycle.exchanges.outgoing.where(receiver_id: d2).first } - - before do - producer.set_producer_property 'Organic', 'NASAA 12345' - p2.set_property 'Local', 'XYZ 123' - - ex_d1.variants << p1.variants.first - ex_d2.variants << p2.variants.first - - visit group_path(group, anchor: "/hubs") - end - - it "filters" do - toggle_filters - - toggle_filter 'Organic' - - expect(page).to have_content d1.name - expect(page).not_to have_content d2.name - - toggle_filter 'Organic' - toggle_filter 'Local' - - expect(page).not_to have_content d1.name - expect(page).to have_content d2.name - end - end - end end diff --git a/spec/features/consumer/shops_spec.rb b/spec/features/consumer/shops_spec.rb index f8f54a197b..2a65a73aef 100644 --- a/spec/features/consumer/shops_spec.rb +++ b/spec/features/consumer/shops_spec.rb @@ -47,7 +47,7 @@ feature 'Shops', js: true do it "should show closed shops after clicking the button" do create(:simple_product, distributors: [d1, d2]) visit shops_path - click_link_and_ensure("Show Closed Shops", -> { page.has_selector? 'hub.inactive' }) + click_link_and_ensure("Show closed shops", -> { page.has_selector? 'hub.inactive' }) page.should have_selector 'hub.inactive', text: d2.name end @@ -56,67 +56,6 @@ feature 'Shops', js: true do expect(page).to have_current_path enterprise_shop_path(distributor) end - describe "filtering by product property" do - let!(:order_cycle) { create(:simple_order_cycle, distributors: [d1, d2], coordinator: create(:distributor_enterprise)) } - let!(:p1) { create(:simple_product, supplier: producer) } - let!(:p2) { create(:simple_product, supplier: create(:supplier_enterprise)) } - let(:ex_d1) { order_cycle.exchanges.outgoing.where(receiver_id: d1).first } - let(:ex_d2) { order_cycle.exchanges.outgoing.where(receiver_id: d2).first } - - before do - p2.set_property 'Local', 'XYZ 123' - - ex_d1.variants << p1.variants.first - ex_d2.variants << p2.variants.first - - visit shops_path - end - - it "filters" do - toggle_filters - - toggle_filter 'Organic' - - expect(page).to have_content d1.name - expect(page).not_to have_content d2.name - - toggle_filter 'Organic' - toggle_filter 'Local' - - expect(page).not_to have_content d1.name - expect(page).to have_content d2.name - end - end - - describe "taxon badges" do - let!(:closed_oc) { create(:closed_order_cycle, distributors: [shop], variants: [p_closed.variants.first]) } - let!(:p_closed) { create(:simple_product, taxons: [taxon_closed]) } - let(:shop) { create(:distributor_enterprise) } - let(:taxon_closed) { create(:taxon, name: 'Closed') } - - describe "open shops" do - let!(:open_oc) { create(:open_order_cycle, distributors: [shop], variants: [p_open.variants.first]) } - let!(:p_open) { create(:simple_product, taxons: [taxon_open]) } - let(:taxon_open) { create(:taxon, name: 'Open') } - - it "shows taxons for open order cycles only" do - visit shops_path - expand_active_table_node shop.name - expect(page).to have_selector '.fat-taxons', text: 'Open' - expect(page).not_to have_selector '.fat-taxons', text: 'Closed' - end - end - - describe "closed shops" do - it "shows taxons for any order cycle" do - visit shops_path - click_link 'Show Closed Shops' - expand_active_table_node shop.name - expect(page).to have_selector '.fat-taxons', text: 'Closed' - end - end - end - describe "property badges" do let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product.variants.first]) } let(:product) { create(:simple_product, supplier: producer) } diff --git a/spec/models/producer_property_spec.rb b/spec/models/producer_property_spec.rb index 0de7aae19b..2d0009ce12 100644 --- a/spec/models/producer_property_spec.rb +++ b/spec/models/producer_property_spec.rb @@ -8,7 +8,7 @@ describe ProducerProperty do producer.set_producer_property 'Organic Certified', 'NASAA 54321' end - describe ".currently_sold_by and .ever_sold_by" do + describe ".sold_by" do let!(:shop) { create(:distributor_enterprise) } let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first]) } let(:product) { create(:simple_product, supplier: producer) } @@ -22,8 +22,7 @@ describe ProducerProperty do describe "with an associated producer property" do it "returns the producer property" do - expect(ProducerProperty.currently_sold_by(shop)).to eq [pp] - expect(ProducerProperty.ever_sold_by(shop)).to eq [pp] + expect(ProducerProperty.sold_by(shop)).to eq [pp] end end @@ -31,8 +30,7 @@ describe ProducerProperty do let!(:exchange) { create(:exchange, order_cycle: oc, incoming: true, sender: producer_other, receiver: oc.coordinator) } it "doesn't return the producer property" do - expect(ProducerProperty.currently_sold_by(shop)).not_to include pp_other - expect(ProducerProperty.ever_sold_by(shop)).not_to include pp_other + expect(ProducerProperty.sold_by(shop)).not_to include pp_other end end @@ -42,8 +40,7 @@ describe ProducerProperty do let!(:exchange) { create(:exchange, order_cycle: oc, incoming: false, sender: oc.coordinator, receiver: shop_other, variants: [product_other.variants.first]) } it "doesn't return the producer property" do - expect(ProducerProperty.currently_sold_by(shop)).not_to include pp_other - expect(ProducerProperty.ever_sold_by(shop)).not_to include pp_other + expect(ProducerProperty.sold_by(shop)).not_to include pp_other end end @@ -52,12 +49,8 @@ describe ProducerProperty do oc.update_attributes! orders_close_at: 1.week.ago end - it "doesn't return the producer property for .currently_sold_by" do - expect(ProducerProperty.currently_sold_by(shop)).not_to include pp - end - - it "returns the producer property for .ever_sold_by" do - expect(ProducerProperty.ever_sold_by(shop)).to include pp + it "doesn't return the producer property" do + expect(ProducerProperty.sold_by(shop)).not_to include pp end end @@ -66,8 +59,7 @@ describe ProducerProperty do let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first, product2.variants.first]) } it "doesn't return duplicates" do - expect(ProducerProperty.currently_sold_by(shop).to_a.count).to eq 1 - expect(ProducerProperty.ever_sold_by(shop).to_a.count).to eq 1 + expect(ProducerProperty.sold_by(shop).to_a.count).to eq 1 end end end diff --git a/spec/models/spree/property_spec.rb b/spec/models/spree/property_spec.rb index 29046a8782..6e6ed2d780 100644 --- a/spec/models/spree/property_spec.rb +++ b/spec/models/spree/property_spec.rb @@ -31,53 +31,42 @@ module Spree end end - describe ".currently_sold_by and .ever_sold_by" do + describe ".sold_by" do let!(:shop) { create(:distributor_enterprise) } let!(:shop_other) { create(:distributor_enterprise) } let!(:product) { create(:simple_product) } let!(:product_other_ex) { create(:simple_product) } let!(:product_no_oc) { create(:simple_product) } + let!(:product_closed_oc) { create(:simple_product) } let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first]) } + let!(:oc_closed) { create(:closed_order_cycle, distributors: [shop], variants: [product_closed_oc.variants.first]) } let!(:exchange_other_shop) { create(:exchange, order_cycle: oc, sender: oc.coordinator, receiver: shop_other, variants: [product_other_ex.variants.first]) } let(:property) { product.properties.last } let(:property_other_ex) { product_other_ex.properties.last } let(:property_no_oc) { product_no_oc.properties.last } + let(:property_closed_oc) { product_closed_oc.properties.last } before do product.set_property 'Organic', 'NASAA 12345' product_other_ex.set_property 'Biodynamic', 'ASDF 12345' product_no_oc.set_property 'Shiny', 'Very' + product_closed_oc.set_property 'Spiffy', 'Ooh yeah' end it "returns the property" do - expect(Property.currently_sold_by(shop)).to eq [property] - expect(Property.ever_sold_by(shop)).to eq [property] + expect(Property.sold_by(shop)).to eq [property] end it "doesn't return the property from another exchange" do - expect(Property.currently_sold_by(shop)).not_to include property_other_ex - expect(Property.ever_sold_by(shop)).not_to include property_other_ex + expect(Property.sold_by(shop)).not_to include property_other_ex end it "doesn't return the property with no order cycle" do - expect(Property.currently_sold_by(shop)).not_to include property_no_oc - expect(Property.ever_sold_by(shop)).not_to include property_no_oc + expect(Property.sold_by(shop)).not_to include property_no_oc end - describe "closed order cyces" do - let!(:product_closed_oc) { create(:simple_product) } - let!(:oc_closed) { create(:closed_order_cycle, distributors: [shop], variants: [product_closed_oc.variants.first]) } - let(:property_closed_oc) { product_closed_oc.properties.last } - - before { product_closed_oc.set_property 'Spiffy', 'Ooh yeah' } - - it "doesn't return the property for .currently_sold_by" do - expect(Property.currently_sold_by(shop)).not_to include property_closed_oc - end - - it "returns the property for .ever_sold_by" do - expect(Property.ever_sold_by(shop)).to include property_closed_oc - end + it "doesn't return the property from a closed order cycle" do + expect(Property.sold_by(shop)).not_to include property_closed_oc end context "with another product in the order cycle" do @@ -89,8 +78,7 @@ module Spree end it "doesn't return duplicates" do - expect(Property.currently_sold_by(shop).to_a.count).to eq 1 - expect(Property.ever_sold_by(shop).to_a.count).to eq 1 + expect(Property.sold_by(shop).to_a.count).to eq 1 end end end diff --git a/spec/models/spree/taxon_spec.rb b/spec/models/spree/taxon_spec.rb index 873a201013..8fb4b22dc5 100644 --- a/spec/models/spree/taxon_spec.rb +++ b/spec/models/spree/taxon_spec.rb @@ -29,18 +29,13 @@ module Spree end end - describe "finding distributed taxons" do - let!(:oc_open) { create(:open_order_cycle, distributors: [e], variants: [p_open.variants.first]) } - let!(:oc_closed) { create(:closed_order_cycle, distributors: [e], variants: [p_closed.variants.first]) } - let!(:p_open) { create(:simple_product, primary_taxon: t1) } - let!(:p_closed) { create(:simple_product, primary_taxon: t2) } + describe "finding all distributed taxons" do + let!(:oc) { create(:simple_order_cycle, distributors: [e], variants: [p1.master]) } + let!(:s) { create(:supplier_enterprise) } + let!(:p1) { create(:simple_product, supplier: s, taxons: [t1, t2]) } - it "finds all distributed taxons" do - expect(Taxon.distributed_taxons(:all)).to eq({e.id => Set.new([t1.id, t2.id])}) - end - - it "finds currently distributed taxons" do - expect(Taxon.distributed_taxons(:current)).to eq({e.id => Set.new([t1.id])}) + it "finds taxons" do + Taxon.distributed_taxons.should == {e.id => Set.new(p1.taxons.map(&:id))} end end end diff --git a/spec/serializers/enterprise_serializer_spec.rb b/spec/serializers/enterprise_serializer_spec.rb index bea2672157..f5eff4f771 100644 --- a/spec/serializers/enterprise_serializer_spec.rb +++ b/spec/serializers/enterprise_serializer_spec.rb @@ -6,8 +6,7 @@ describe Api::EnterpriseSerializer do let(:taxon) { create(:taxon) } let(:data) { OpenStruct.new(earliest_closing_times: {}, active_distributors: [], - all_distributed_taxons: {enterprise.id => [123]}, - current_distributed_taxons: {enterprise.id => [123]}, + distributed_taxons: {enterprise.id => [123]}, supplied_taxons: {enterprise.id => [456]}, shipping_method_services: {}, relatives: {enterprise.id => {producers: [123], distributors: [456]}}) }