mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-09 03:20:21 +00:00
Merge branch 'master' into redesign
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $http, BulkProducts, DisplayProperties, dataFetcher, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, SpreeApiAuth) ->
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $http, BulkProducts, DisplayProperties, dataFetcher, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, SpreeApiAuth, tax_categories) ->
|
||||
$scope.loading = true
|
||||
|
||||
$scope.StatusMessage = StatusMessage
|
||||
@@ -10,7 +10,9 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
unit: {name: "Unit", visible: true}
|
||||
price: {name: "Price", visible: true}
|
||||
on_hand: {name: "On Hand", visible: true}
|
||||
on_demand: {name: "On Demand", visible: false}
|
||||
category: {name: "Category", visible: false}
|
||||
tax_category: {name: "Tax Category", visible: false}
|
||||
inherits_properties: {name: "Inherits Properties?", visible: false}
|
||||
available_on: {name: "Available On", visible: false}
|
||||
|
||||
@@ -32,6 +34,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
|
||||
$scope.producers = producers
|
||||
$scope.taxons = Taxons.taxons
|
||||
$scope.tax_categories = tax_categories
|
||||
$scope.filterProducers = [{id: "0", name: ""}].concat $scope.producers
|
||||
$scope.filterTaxons = [{id: "0", name: ""}].concat $scope.taxons
|
||||
$scope.producerFilter = "0"
|
||||
@@ -312,9 +315,15 @@ filterSubmitProducts = (productsToFilter) ->
|
||||
if product.hasOwnProperty("on_hand") and filteredVariants.length == 0 #only update if no variants present
|
||||
filteredProduct.on_hand = product.on_hand
|
||||
hasUpdatableProperty = true
|
||||
if product.hasOwnProperty("on_demand") and filteredVariants.length == 0 #only update if no variants present
|
||||
filteredProduct.on_demand = product.on_demand
|
||||
hasUpdatableProperty = true
|
||||
if product.hasOwnProperty("category_id")
|
||||
filteredProduct.primary_taxon_id = product.category_id
|
||||
hasUpdatableProperty = true
|
||||
if product.hasOwnProperty("tax_category_id")
|
||||
filteredProduct.tax_category_id = product.tax_category_id
|
||||
hasUpdatableProperty = true
|
||||
if product.hasOwnProperty("inherits_properties")
|
||||
filteredProduct.inherits_properties = product.inherits_properties
|
||||
hasUpdatableProperty = true
|
||||
@@ -340,6 +349,9 @@ filterSubmitVariant = (variant) ->
|
||||
if variant.hasOwnProperty("on_hand")
|
||||
filteredVariant.on_hand = variant.on_hand
|
||||
hasUpdatableProperty = true
|
||||
if variant.hasOwnProperty("on_demand")
|
||||
filteredVariant.on_demand = variant.on_demand
|
||||
hasUpdatableProperty = true
|
||||
if variant.hasOwnProperty("price")
|
||||
filteredVariant.price = variant.price
|
||||
hasUpdatableProperty = true
|
||||
|
||||
@@ -19,7 +19,7 @@ angular.module("ofn.admin").factory "BulkProducts", (PagedFetcher, dataFetcher)
|
||||
# when a respond_overrride for the clone action is used.
|
||||
id = data.product.id
|
||||
dataFetcher("/api/products/" + id + "?template=bulk_show").then (newProduct) =>
|
||||
@addProducts [newProduct]
|
||||
@insertProductAfter(product, newProduct)
|
||||
|
||||
updateVariantLists: (serverProducts, productsWithUnsavedVariants) ->
|
||||
for product in productsWithUnsavedVariants
|
||||
@@ -39,6 +39,10 @@ angular.module("ofn.admin").factory "BulkProducts", (PagedFetcher, dataFetcher)
|
||||
@unpackProduct product
|
||||
@products.push product
|
||||
|
||||
insertProductAfter: (product, newProduct) ->
|
||||
index = @products.indexOf(product)
|
||||
@products.splice(index + 1, 0, newProduct)
|
||||
|
||||
unpackProduct: (product) ->
|
||||
#$scope.matchProducer product
|
||||
@loadVariantUnit product
|
||||
|
||||
@@ -23,6 +23,13 @@ Spree::Admin::OrdersController.class_eval do
|
||||
distributed_by_user(spree_current_user).
|
||||
page(params[:page]).
|
||||
per(params[:per_page] || Spree::Config[:orders_per_page])
|
||||
# Filter orders by distributor
|
||||
if params[:distributor_ids]
|
||||
@orders = @orders.where(distributor_id: params[:distributor_ids])
|
||||
end
|
||||
if params[:order_cycle_ids]
|
||||
@orders = @orders.where(order_cycle_id: params[:order_cycle_ids])
|
||||
end
|
||||
} } }
|
||||
|
||||
# Overwrite to use confirm_email_for_customer instead of confirm_email.
|
||||
|
||||
@@ -50,6 +50,10 @@ module Admin
|
||||
admin_inject_json_ams_array "ofn.admin", "products", @products, Api::Admin::ProductSerializer
|
||||
end
|
||||
|
||||
def admin_inject_tax_categories
|
||||
admin_inject_json_ams_array "ofn.admin", "tax_categories", @tax_categories, Api::Admin::TaxCategorySerializer
|
||||
end
|
||||
|
||||
def admin_inject_taxons
|
||||
admin_inject_json_ams_array "admin.taxons", "taxons", @taxons, Api::Admin::TaxonSerializer
|
||||
end
|
||||
|
||||
@@ -109,6 +109,12 @@ Spree::Product.class_eval do
|
||||
|
||||
# -- Methods
|
||||
|
||||
# Called by Spree::Product::duplicate before saving.
|
||||
def duplicate_extra(parent)
|
||||
# Spree sets the SKU to "COPY OF #{parent sku}".
|
||||
self.master.sku = ''
|
||||
end
|
||||
|
||||
def properties_including_inherited
|
||||
# Product properties override producer properties
|
||||
ps = product_properties.all
|
||||
|
||||
@@ -7,6 +7,7 @@ Spree::Variant.class_eval do
|
||||
|
||||
has_many :exchange_variants, dependent: :destroy
|
||||
has_many :exchanges, through: :exchange_variants
|
||||
has_many :variant_overrides
|
||||
|
||||
attr_accessible :unit_value, :unit_description, :images_attributes, :display_as, :display_name
|
||||
accepts_nested_attributes_for :images
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/ insert_before "div.clearfix"
|
||||
|
||||
.field-block.alpha.eight.columns
|
||||
= label_tag nil, t(:distributors)
|
||||
= select_tag(:distributor_ids,
|
||||
options_for_select(Enterprise.is_distributor.managed_by(spree_current_user).map {|e| [e.name, e.id]}, params[:distributor_ids]),
|
||||
{class: "select2 fullwidth", multiple: true})
|
||||
|
||||
.field-block.alpha.eight.columns
|
||||
= label_tag nil, t(:order_cycles)
|
||||
= select_tag(:order_cycle_ids,
|
||||
options_for_select(OrderCycle.managed_by(spree_current_user).map {|oc| [oc.name, oc.id]}, params[:order_cycle_ids]),
|
||||
{class: "select2 fullwidth", multiple: true})
|
||||
@@ -38,20 +38,26 @@
|
||||
.twelve.columns.alpha
|
||||
.six.columns.alpha
|
||||
= render 'spree/admin/products/primary_taxon_form', f: f
|
||||
.three.columns
|
||||
.two.columns
|
||||
= f.field_container :price do
|
||||
= f.label :price, t(:price)
|
||||
%span.required *
|
||||
%br/
|
||||
= f.text_field :price, class: 'fullwidth'
|
||||
= f.error_message_on :price
|
||||
.three.columns.omega
|
||||
.two.columns
|
||||
= f.field_container :on_hand do
|
||||
= f.label :on_hand, t(:on_hand)
|
||||
%span.required *
|
||||
%br/
|
||||
= f.text_field :on_hand, class: 'fullwidth'
|
||||
= f.error_message_on :on_hand
|
||||
.two.columns.omega
|
||||
= f.field_container :on_demand do
|
||||
= f.label :on_demand, t(:on_demand)
|
||||
%br/
|
||||
= f.check_box :on_demand
|
||||
= f.error_message_on :on_demand
|
||||
.twelve.columns.alpha
|
||||
.six.columns.alpha
|
||||
.three.columns
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class Api::Admin::ProductSerializer < ActiveModel::Serializer
|
||||
attributes :id, :name, :sku, :variant_unit, :variant_unit_scale, :variant_unit_name, :on_demand, :inherits_properties
|
||||
|
||||
attributes :on_hand, :price, :available_on, :permalink_live
|
||||
attributes :on_hand, :price, :available_on, :permalink_live, :tax_category_id
|
||||
|
||||
has_one :supplier, key: :producer_id, embed: :id
|
||||
has_one :primary_taxon, key: :category_id, embed: :id
|
||||
|
||||
3
app/serializers/api/admin/tax_category_serializer.rb
Normal file
3
app/serializers/api/admin/tax_category_serializer.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
class Api::Admin::TaxCategorySerializer < ActiveModel::Serializer
|
||||
attributes :id, :name
|
||||
end
|
||||
@@ -1,6 +1,7 @@
|
||||
class Api::Admin::VariantSerializer < ActiveModel::Serializer
|
||||
attributes :id, :options_text, :unit_value, :unit_description, :unit_to_display, :on_demand, :display_as, :display_name, :name_to_display
|
||||
attributes :on_hand, :price
|
||||
has_many :variant_overrides
|
||||
|
||||
def on_hand
|
||||
object.on_hand.nil? ? 0 : ( object.on_hand.to_f.finite? ? object.on_hand : "On demand" )
|
||||
|
||||
@@ -8,3 +8,4 @@
|
||||
= render 'spree/admin/products/bulk_edit/actions'
|
||||
= render 'spree/admin/products/bulk_edit/indicators'
|
||||
= render 'spree/admin/products/bulk_edit/products'
|
||||
= render 'spree/admin/products/bulk_edit/save_button_row'
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
= admin_inject_producers
|
||||
= admin_inject_taxons
|
||||
= admin_inject_tax_categories
|
||||
= admin_inject_spree_api_key
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
%col.display_as{ ng: { show: 'columns.unit.visible' } }
|
||||
%col.price{ ng: { show: 'columns.price.visible'} }
|
||||
%col.on_hand{ ng: { show: 'columns.on_hand.visible' } }
|
||||
%col.on_demand{ ng: { show: 'columns.on_demand.visible' } }
|
||||
%col.category{ ng: { show: 'columns.category.visible' } }
|
||||
%col.tax_category{ ng: { show: 'columns.tax_category.visible' } }
|
||||
%col.inherits_properties{ ng: { show: 'columns.inherits_properties.visible' } }
|
||||
%col.available_on{ ng: { show: 'columns.available_on.visible' } }
|
||||
%col.actions
|
||||
@@ -24,7 +26,9 @@
|
||||
%th.display_as{ 'ng-show' => 'columns.unit.visible' } Display As
|
||||
%th.price{ 'ng-show' => 'columns.price.visible' } Price
|
||||
%th.on_hand{ 'ng-show' => 'columns.on_hand.visible' } On Hand
|
||||
%th.on_demand{ 'ng-show' => 'columns.on_demand.visible' } On Demand
|
||||
%th.category{ 'ng-show' => 'columns.category.visible' } Category
|
||||
%th.tax_category{ 'ng-show' => 'columns.tax_category.visible' } Tax Category
|
||||
%th.inherits_properties{ 'ng-show' => 'columns.inherits_properties.visible' } Inherits Properties?
|
||||
%th.available_on{ 'ng-show' => 'columns.available_on.visible' } Av. On
|
||||
%th.actions
|
||||
|
||||
@@ -20,8 +20,13 @@
|
||||
%td.on_hand{ 'ng-show' => 'columns.on_hand.visible' }
|
||||
%span{ 'ng-bind' => 'product.on_hand', :name => 'on_hand', 'ng-show' => '!hasOnDemandVariants(product) && (hasVariants(product) || product.on_demand)' }
|
||||
%input.field{ 'ng-model' => 'product.on_hand', :name => 'on_hand', 'ofn-track-product' => 'on_hand', 'ng-hide' => 'hasVariants(product) || product.on_demand', :type => 'number' }
|
||||
%td.on_demand{ 'ng-show' => 'columns.on_demand.visible' }
|
||||
%input.field{ 'ng-model' => 'product.on_demand', :name => 'on_demand', 'ofn-track-product' => 'on_demand', :type => 'checkbox', 'ng-hide' => 'hasVariants(product)' }
|
||||
%td.category{ 'ng-if' => 'columns.category.visible' }
|
||||
%input.fullwidth{ :type => 'text', id: "p{{product.id}}_category_id", 'ng-model' => 'product.category_id', 'ofn-taxon-autocomplete' => '', 'ofn-track-product' => 'category_id', 'multiple-selection' => 'false', placeholder: 'Category' }
|
||||
%td.tax_category{ 'ng-if' => 'columns.tax_category.visible' }
|
||||
%select.select2{ name: 'product_tax_category_id', 'ofn-track-product' => 'tax_category_id', ng: {model: 'product.tax_category_id', options: 'tax_category.id as tax_category.name for tax_category in tax_categories'} }
|
||||
%option{value: ''} None
|
||||
%td.inherits_properties{ 'ng-show' => 'columns.inherits_properties.visible' }
|
||||
%input{ 'ng-model' => 'product.inherits_properties', :name => 'inherits_properties', 'ofn-track-product' => 'inherits_properties', type: "checkbox" }
|
||||
%td.available_on{ 'ng-show' => 'columns.available_on.visible' }
|
||||
|
||||
@@ -15,11 +15,15 @@
|
||||
%td{ 'ng-show' => 'columns.on_hand.visible' }
|
||||
%input.field{ 'ng-model' => 'variant.on_hand', 'ng-change' => 'updateOnHand(product)', :name => 'variant_on_hand', 'ng-hide' => 'variant.on_demand', 'ofn-track-variant' => 'on_hand', :type => 'number' }
|
||||
%span{ 'ng-bind' => 'variant.on_hand', :name => 'variant_on_hand', 'ng-show' => 'variant.on_demand' }
|
||||
%td{ 'ng-show' => 'columns.on_demand.visible' }
|
||||
%input.field{ 'ng-model' => 'variant.on_demand', :name => 'variant_on_demand', 'ofn-track-variant' => 'on_demand', :type => 'checkbox' }
|
||||
%td{ 'ng-show' => 'columns.category.visible' }
|
||||
%td{ 'ng-show' => 'columns.tax_category.visible' }
|
||||
%td{ 'ng-show' => 'columns.inherits_properties.visible' }
|
||||
%td{ 'ng-show' => 'columns.available_on.visible' }
|
||||
%td.actions
|
||||
%a{ 'ng-click' => 'editWarn(product,variant)', :class => "edit-variant icon-edit no-text", 'ng-show' => "variantSaved(variant)" }
|
||||
%td.actions
|
||||
%span.icon-warning-sign.with-tip{ 'ng-if' => 'variant.variant_overrides', title: "This variant has {{variant.variant_overrides.length}} override(s)" }
|
||||
%td.actions
|
||||
%a{ 'ng-click' => 'deleteVariant(product,variant)', "ng-class" => '{disabled: product.variants.length < 2}', :class => "delete-variant icon-trash no-text" }
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
%div.sixteen.columns.alpha{ 'ng-hide' => 'loading || products.length == 0', style: "margin-bottom: 10px" }
|
||||
%div.four.columns.alpha
|
||||
%input.four.columns.alpha{ :type => 'button', :value => 'Save Changes', 'ng-click' => 'submitProducts()'}
|
||||
@@ -216,7 +216,7 @@ feature %q{
|
||||
fill_in "variant_price", with: "4.0"
|
||||
fill_in "variant_on_hand", with: "10"
|
||||
|
||||
click_button 'Save Changes'
|
||||
first(:button, 'Save Changes').click
|
||||
expect(page.find("#status-message")).to have_content "Changes saved."
|
||||
|
||||
updated_variant = Spree::Variant.where(deleted_at: nil).last
|
||||
@@ -266,7 +266,7 @@ feature %q{
|
||||
fill_in "product_sku", with: "NEW SKU"
|
||||
end
|
||||
|
||||
click_button 'Save Changes'
|
||||
first(:button, 'Save Changes').click
|
||||
expect(page.find("#status-message")).to have_content "Changes saved."
|
||||
|
||||
p.reload
|
||||
@@ -292,7 +292,7 @@ feature %q{
|
||||
select "Items", from: "variant_unit_with_scale"
|
||||
fill_in "variant_unit_name", with: "loaf"
|
||||
|
||||
click_button 'Save Changes'
|
||||
first(:button, 'Save Changes').click
|
||||
expect(page.find("#status-message")).to have_content "Changes saved."
|
||||
|
||||
p.reload
|
||||
@@ -326,7 +326,7 @@ feature %q{
|
||||
|
||||
expect(page).to have_selector "span[name='on_hand']", text: "10"
|
||||
|
||||
click_button 'Save Changes'
|
||||
first(:button, 'Save Changes').click
|
||||
expect(page.find("#status-message")).to have_content "Changes saved."
|
||||
|
||||
v.reload
|
||||
@@ -352,7 +352,7 @@ feature %q{
|
||||
fill_in "variant_price", with: "10.0"
|
||||
end
|
||||
|
||||
click_button 'Save Changes'
|
||||
first(:button, 'Save Changes').click
|
||||
expect(page.find("#status-message")).to have_content "Changes saved."
|
||||
|
||||
v.reload
|
||||
@@ -369,21 +369,21 @@ feature %q{
|
||||
|
||||
fill_in "product_name", with: "new name 1"
|
||||
|
||||
click_button 'Save Changes'
|
||||
first(:button, 'Save Changes').click
|
||||
expect(page.find("#status-message")).to have_content "Changes saved."
|
||||
p.reload
|
||||
expect(p.name).to eq "new name 1"
|
||||
|
||||
fill_in "product_name", with: "new name 2"
|
||||
|
||||
click_button 'Save Changes'
|
||||
first(:button, 'Save Changes').click
|
||||
expect(page.find("#status-message")).to have_content "Changes saved."
|
||||
p.reload
|
||||
expect(p.name).to eq "new name 2"
|
||||
|
||||
fill_in "product_name", with: "original name"
|
||||
|
||||
click_button 'Save Changes'
|
||||
first(:button, 'Save Changes').click
|
||||
expect(page.find("#status-message")).to have_content "Changes saved."
|
||||
p.reload
|
||||
expect(p.name).to eq "original name"
|
||||
@@ -399,7 +399,7 @@ feature %q{
|
||||
|
||||
fill_in "product_name", :with => "new product name"
|
||||
|
||||
click_button 'Save Changes'
|
||||
first(:button, 'Save Changes').click
|
||||
expect(page.find("#status-message")).to have_content "Changes saved."
|
||||
p.reload
|
||||
expect(p.name).to eq "new product name"
|
||||
@@ -412,7 +412,7 @@ feature %q{
|
||||
|
||||
visit '/admin/products/bulk_edit'
|
||||
|
||||
click_button 'Save Changes'
|
||||
first(:button, 'Save Changes').click
|
||||
expect(page.find("#status-message")).to have_content "No changes to save."
|
||||
end
|
||||
end
|
||||
@@ -431,7 +431,7 @@ feature %q{
|
||||
expect(page).to have_no_field "product_name", with: p2.name
|
||||
fill_in "product_name", :with => "new product1"
|
||||
|
||||
click_button 'Save Changes'
|
||||
first(:button, 'Save Changes').click
|
||||
expect(page.find("#status-message")).to have_content "Changes saved."
|
||||
p1.reload
|
||||
expect(p1.name).to eq "new product1"
|
||||
@@ -709,7 +709,7 @@ feature %q{
|
||||
fill_in "variant_display_as", with: "Big Bag"
|
||||
end
|
||||
|
||||
click_button 'Save Changes'
|
||||
first(:button, 'Save Changes').click
|
||||
expect(page.find("#status-message")).to have_content "Changes saved."
|
||||
|
||||
p.reload
|
||||
|
||||
@@ -61,14 +61,14 @@ describe "BulkProducts service", ->
|
||||
clonedProduct =
|
||||
id: 17
|
||||
|
||||
spyOn(BulkProducts, "addProducts")
|
||||
spyOn(BulkProducts, "insertProductAfter")
|
||||
BulkProducts.products = [originalProduct]
|
||||
$httpBackend.expectGET("/admin/products/oranges/clone.json").respond 200,
|
||||
product: clonedProduct
|
||||
$httpBackend.expectGET("/api/products/17?template=bulk_show").respond 200, clonedProduct
|
||||
BulkProducts.cloneProduct BulkProducts.products[0]
|
||||
$httpBackend.flush()
|
||||
expect(BulkProducts.addProducts).toHaveBeenCalledWith [clonedProduct]
|
||||
expect(BulkProducts.insertProductAfter).toHaveBeenCalledWith originalProduct, clonedProduct
|
||||
|
||||
|
||||
describe "preparing products", ->
|
||||
|
||||
@@ -215,6 +215,7 @@ describe "filtering products for submission to database", ->
|
||||
variant_unit_scale: 1
|
||||
variant_unit_name: 'loaf'
|
||||
available_on: available_on
|
||||
tax_category_id: null
|
||||
master_attributes:
|
||||
id: 2
|
||||
unit_value: 250
|
||||
@@ -238,6 +239,7 @@ describe "AdminProductEditCtrl", ->
|
||||
module ($provide)->
|
||||
$provide.value "producers", []
|
||||
$provide.value "taxons", []
|
||||
$provide.value "tax_categories", []
|
||||
$provide.value 'SpreeApiKey', 'API_KEY'
|
||||
null
|
||||
|
||||
|
||||
Reference in New Issue
Block a user