diff --git a/plugins/delivery/controllers/myprofile/delivery_plugin/admin_method_controller.rb b/plugins/delivery/controllers/myprofile/delivery_plugin/admin_method_controller.rb index 81c3c0b..0262f43 100644 --- a/plugins/delivery/controllers/myprofile/delivery_plugin/admin_method_controller.rb +++ b/plugins/delivery/controllers/myprofile/delivery_plugin/admin_method_controller.rb @@ -14,7 +14,7 @@ class DeliveryPlugin::AdminMethodController < MyProfileController def edit @delivery_method ||= profile.delivery_methods.find_by_id params[:id] - if params[:delivery_method].present? and @delivery_method.update_attributes params[:delivery_method] + if params[:delivery_method].present? and @delivery_method.update params[:delivery_method] render partial: 'list' else render partial: 'edit', locals: {delivery_method: @delivery_method} diff --git a/plugins/delivery/controllers/myprofile/delivery_plugin/admin_options_controller.rb b/plugins/delivery/controllers/myprofile/delivery_plugin/admin_options_controller.rb index c837073..64ef7d3 100644 --- a/plugins/delivery/controllers/myprofile/delivery_plugin/admin_options_controller.rb +++ b/plugins/delivery/controllers/myprofile/delivery_plugin/admin_options_controller.rb @@ -8,7 +8,13 @@ class DeliveryPlugin::AdminOptionsController < DeliveryPlugin::AdminMethodContro before_filter :load_owner def select + end + def select_all + missing_methods = profile.delivery_methods - @owner.delivery_methods + missing_methods.each do |dm| + DeliveryPlugin::Option.create! owner_id: @owner.id, owner_type: @owner.class.name, delivery_method: dm + end end def new diff --git a/plugins/delivery/db/migrate/20150623125525_add_distribution_margin_to_delivery_plugin_method.rb b/plugins/delivery/db/migrate/20150623125525_add_distribution_margin_to_delivery_plugin_method.rb new file mode 100644 index 0000000..edcd7b5 --- /dev/null +++ b/plugins/delivery/db/migrate/20150623125525_add_distribution_margin_to_delivery_plugin_method.rb @@ -0,0 +1,8 @@ +class AddDistributionMarginToDeliveryPluginMethod < ActiveRecord::Migration + + def change + add_column :delivery_plugin_methods, :distribution_margin_fixed, :decimal + add_column :delivery_plugin_methods, :distribution_margin_percentage, :decimal + end + +end diff --git a/plugins/delivery/lib/delivery_plugin/display_helper.rb b/plugins/delivery/lib/delivery_plugin/display_helper.rb index 1a02e1e..0af6c1e 100644 --- a/plugins/delivery/lib/delivery_plugin/display_helper.rb +++ b/plugins/delivery/lib/delivery_plugin/display_helper.rb @@ -9,15 +9,24 @@ module DeliveryPlugin::DisplayHelper methods = options[:methods] || profile.delivery_methods options = methods.map do |method| - cost = if method.fixed_cost.present? and method.fixed_cost > 0 then float_to_currency_cart(method.fixed_cost, environment) else nil end + cost = if method.fixed_cost.present? and method.fixed_cost > 0 then method.fixed_cost_as_currency else nil end text = if cost.present? then "#{method.name} (#{cost})" else method.name end content_tag :option, text, value: method.id, - data: {label: method.name, type: method.delivery_type, instructions: method.description.to_s}, - selected: if method == selected then 'selected' else nil end + data: {label: method.name, type: method.delivery_type, instructions: CGI::escapeHTML(method.description.to_s)}, + selected: if method.id == selected then 'selected' else nil end end.join end + def consumer_delivery_field_value order, field + # BLACK OR WHITE: do not mix existing delivery data with user's location + if order.consumer_delivery_data.present? + order.consumer_delivery_data[field] + elsif user + user.send field + end + end + def delivery_context @delivery_context || 'delivery_plugin/admin_method' end diff --git a/plugins/delivery/lib/ext/profile.rb b/plugins/delivery/lib/ext/profile.rb index a40e513..ebcd856 100644 --- a/plugins/delivery/lib/ext/profile.rb +++ b/plugins/delivery/lib/ext/profile.rb @@ -1,7 +1,9 @@ require_dependency 'profile' -class Profile +([Profile] + Profile.descendants).each do |subclass| +subclass.class_eval do - has_many :delivery_methods, class_name: 'DeliveryPlugin::Method', foreign_key: :profile_id, dependent: :destroy, order: 'id ASC' + has_many :delivery_methods, -> { order 'id ASC' }, class_name: 'DeliveryPlugin::Method', foreign_key: :profile_id, dependent: :destroy end +end diff --git a/plugins/delivery/locales/en-US.yml b/plugins/delivery/locales/en-US.yml index a9aba50..f21f262 100644 --- a/plugins/delivery/locales/en-US.yml +++ b/plugins/delivery/locales/en-US.yml @@ -12,16 +12,23 @@ delivery_type: 'Type' delivery_type_help: 'Pickup: the products will be delivered in the consumption place.
Delivery: the products will be delivered in the address asked by the consumer.' name: Name - name_help: Write the name of the Consumption Place or the - fixed_cost: Fixed cost - free_over_price: Order's minimum price for free delivery + name_help: Write the name of the Consumption Place or the + + costs_legend: Delivery's costs + fixed_cost: Fixed cost of delivery + free_over_price: Order's minimum value for free delivery + + distribution_legend: Distribution's costs + distribution_margin_percentage: Distribution's margin + distribution_margin_fixed: Distribution's margin (fixed) + instructions: Description instructions_help: "Write the address and other important informations about the place of this consumption place.
This text will be available" views: - delivery_option: - select: + delivery_option: + select: add: Add selected - _select_content: + _select_content: add: Add option add_new: "add new" are_you_sure_you_want: "Are you sure you want to remove?" @@ -29,14 +36,14 @@ choose_a_delivery_met: "Choose a delivery method from the list" edit_this: "Edit" remove_method: "Remove" - _show: + _show: x: X - select: + select: add_a_delivery_method: "Add a delivery method to the Orders' Cycle" method: index: new: "New delivery or pickup" - edit: + edit: add: Add back: back save: Save diff --git a/plugins/delivery/locales/pt-BR.yml b/plugins/delivery/locales/pt-BR.yml index 26d1e2b..da5b9c4 100644 --- a/plugins/delivery/locales/pt-BR.yml +++ b/plugins/delivery/locales/pt-BR.yml @@ -13,15 +13,21 @@ delivery_type_help: "Retirada: os produtos serão buscados pela(o) consumidor(a), por exemplo, no empreendimento, numa feira ou num Núcleo de Consumo.
Entrega: os produtos serão entregues no endereço solicitado pelo(a) consumidor(a)." name: Nome name_help: "Para opção Retirada: escreva o nome do local onde os produtos deverão ser retirados pela(o) consumidor(a), por exemplo o nome do Núcleo de Consumo, da feira ou do próprio empreendimento.
Para a opção Entrega: escreva o nome do local, (uma cidade ou região) ou a forma de entrega (Correios, transportadora)" - fixed_cost: Custo - free_over_price: "Preço mínimo do pedido para Entrega Grátis" + + costs_legend: Custos de entrega + fixed_cost: Custo de entrega + free_over_price: "Valor mínimo do pedido para Entrega Grátis" + distribution_legend: Custos de distribuição + distribution_margin_percentage: Margem de distribuição + distribution_margin_fixed: Margem de distribuição (valor fixo) + instructions: Descrição instructions_help: "Escreva informações importantes sobre esta opção de Retirada ou Entrega.
Por exemplo, o endereço completo do Núcleo de Consumo, a abrangência da região de entrega.
Este texto estará disponível no \"Finalizar pedido\" e, ao confirmar a compra, o(a) consumidor(a) receberá um email com o pedido realizado e as informações deste campo." views: - delivery_option: - select: + delivery_option: + select: add: "Adicionar selecionados" - _select_content: + _select_content: add: Adicionar opção add_new: "adicionar novo" are_you_sure_you_want: "Tem certeza de que quer remover?" @@ -29,14 +35,14 @@ choose_a_delivery_met: "Escolha um método de entrega da lista" edit_this: Editar remove_method: "Remover" - _show: + _show: x: X - select: + select: add_a_delivery_method: "Adicionar um método de entrega ao ciclo de pedidos" method: index: new: "Nova forma de entrega ou retirada" - edit: + edit: add: Adicionar back: voltar save: Salvar diff --git a/plugins/delivery/models/delivery_plugin/method.rb b/plugins/delivery/models/delivery_plugin/method.rb index 05398ed..9f03c00 100644 --- a/plugins/delivery/models/delivery_plugin/method.rb +++ b/plugins/delivery/models/delivery_plugin/method.rb @@ -1,7 +1,5 @@ class DeliveryPlugin::Method < ActiveRecord::Base - extend CurrencyHelper::ClassMethods - Types = ['pickup', 'deliver'] # see also: Profile::LOCATION_FIELDS @@ -10,7 +8,7 @@ class DeliveryPlugin::Method < ActiveRecord::Base ].map(&:to_sym) attr_accessible :profile, :delivery_type, :name, :description, - :fixed_cost, :free_over_price + :fixed_cost, :free_over_price, :distribution_margin_percentage, :distribution_margin_fixed belongs_to :profile @@ -20,8 +18,14 @@ class DeliveryPlugin::Method < ActiveRecord::Base validates_presence_of :name validates_inclusion_of :delivery_type, in: Types - scope :pickup, conditions: {delivery_type: 'pickup'} - scope :delivery, conditions: {delivery_type: 'deliver'} + scope :pickup, -> { where delivery_type: 'pickup' } + scope :delivery, -> { where delivery_type: 'deliver'} + + extend CurrencyHelper::ClassMethods + has_currency :fixed_cost + has_currency :free_over_price + has_currency :distribution_margin_percentage + has_currency :distribution_margin_fixed def pickup? self.delivery_type == 'pickup' @@ -30,22 +34,40 @@ class DeliveryPlugin::Method < ActiveRecord::Base self.delivery_type == 'deliver' end - def has_cost? order_price=nil + def has_distribution_margin? + (self.distribution_margin_percentage.present? and self.distribution_margin_percentage.nonzero?) or + (self.distribution_margin_fixed.present? and self.distribution_margin_fixed.nonzero?) + end + + def has_fixed_cost? order_price=nil if order_price.present? and order_price.nonzero? and self.free_over_price.present? and self.free_over_price.nonzero? order_price <= self.free_over_price else self.fixed_cost.present? and self.fixed_cost.nonzero? end end + + def distribution_margin order_price + value = 0 + value += self.distribution_margin_fixed if self.distribution_margin_fixed.present? + value += order_price * (self.distribution_margin_percentage/100) if self.distribution_margin_percentage.present? + value + end + + def has_cost? order_price=nil + has_cost = self.has_distribution_margin? + has_cost ||= self.has_fixed_cost? order_price + end def free? order_price=nil !self.has_cost? end def cost order_price=nil - if self.has_cost?(order_price) then self.fixed_cost.to_f else 0 end + value = 0 + value += self.fixed_cost if self.has_fixed_cost? order_price + value += self.distribution_margin order_price if self.has_distribution_margin? + value end - has_currency :fixed_cost - has_currency :free_over_price has_currency :cost protected diff --git a/plugins/delivery/public/stylesheets/delivery.scss b/plugins/delivery/public/stylesheets/delivery.scss index a38aac1..1117c65 100644 --- a/plugins/delivery/public/stylesheets/delivery.scss +++ b/plugins/delivery/public/stylesheets/delivery.scss @@ -3,7 +3,7 @@ #delivery-method-edition { @extend .container-clean; - .field-help { + .help-block { font-size: 10px; } } diff --git a/plugins/delivery/test/test_helper.rb b/plugins/delivery/test/test_helper.rb new file mode 100644 index 0000000..cca1fd3 --- /dev/null +++ b/plugins/delivery/test/test_helper.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../test/test_helper' diff --git a/plugins/delivery/test/unit/delivery_plugin/method_test.rb b/plugins/delivery/test/unit/delivery_plugin/method_test.rb new file mode 100644 index 0000000..9dec65e --- /dev/null +++ b/plugins/delivery/test/unit/delivery_plugin/method_test.rb @@ -0,0 +1,42 @@ +require "#{File.dirname(__FILE__)}/../../test_helper" + +class DeliveryPlugin::MethodTest < ActiveSupport::TestCase + + def setup + @profile = build(Profile) + end + + attr_accessor :profile + + should 'have a name and a delivery type' do + dm = DeliveryPlugin::Method.new :name => 'Delivery Deluxe', :delivery_type => 'deliver', :profile => profile + assert dm.valid? + dm = DeliveryPlugin::Method.new :profile => profile + assert !dm.valid? + end + + should 'accept only pickup and deliver as delivery types' do + dm = build(DeliveryPlugin::Method, :name => 'Delivery Deluxe', :delivery_type => 'unkown', :profile => profile) + assert !dm.valid? + dm = build(DeliveryPlugin::Method, :name => 'Delivery Deluxe', :delivery_type => 'pickup', :profile => profile) + assert dm.valid? + dm = build(DeliveryPlugin::Method, :name => 'Delivery Deluxe', :delivery_type => 'deliver', :profile => profile) + assert dm.valid? + end + + should 'filter by delivery types' do + dm_deliver = create(DeliveryPlugin::Method, :name => 'Delivery Deluxe', :delivery_type => 'deliver', :profile => profile) + dm_pickup = create(DeliveryPlugin::Method, :name => 'Delivery Deluxe', :delivery_type => 'pickup', :profile => profile) + assert_equal [dm_deliver], DeliveryPlugin::Method.delivery + assert_equal [dm_pickup], DeliveryPlugin::Method.pickup + end + + should 'have many delivery options' do + dm = create(DeliveryPlugin::Method, :name => 'Delivery Deluxe', :delivery_type => 'deliver', :profile => profile) + cycle = build(OrdersCyclePlugin::Cycle, :name => 'cycle name', :profile => profile) + option = create(DeliveryPlugin::Option, :cycle => cycle, :delivery_method => dm) + + assert_equal [option], dm.reload.delivery_options + end + +end diff --git a/plugins/delivery/test/unit/delivery_plugin/option_test.rb b/plugins/delivery/test/unit/delivery_plugin/option_test.rb new file mode 100644 index 0000000..f8a3617 --- /dev/null +++ b/plugins/delivery/test/unit/delivery_plugin/option_test.rb @@ -0,0 +1,24 @@ +require "#{File.dirname(__FILE__)}/../../test_helper" + +class DeliveryPlugin::OptionTest < ActiveSupport::TestCase + + def setup + @profile = build(Profile) + @cycle = build(OrdersCyclePluginCycle, :profile => @profile) + @delivery_method = build(OrdersCyclePluginMethod, :profile => @profile) + end + + attr_accessor :profile + attr_accessor :cycle + attr_accessor :delivery_method + + should 'be associated with a cycle and a delivery method' do + option = OrdersCyclePluginOption.new :cycle => @cycle, :delivery_method => @delivery_method + assert option.valid? + option = OrdersCyclePluginOption.new + :wa + + assert !option.valid? + end + +end diff --git a/plugins/delivery/views/delivery_plugin/_order_select.html.slim b/plugins/delivery/views/delivery_plugin/_order_select.html.slim index 4acc741..4574406 100644 --- a/plugins/delivery/views/delivery_plugin/_order_select.html.slim +++ b/plugins/delivery/views/delivery_plugin/_order_select.html.slim @@ -2,30 +2,37 @@ - edition = true if edition.nil? - readonly = !edition -div.order-delivery-select +div.order-delivery-select id='order-#{order.id}' div.supplier-delivery-data - = labelled_form_field _('Option'), - f.select(:supplier_delivery_id, supplier_delivery_options(methods: methods), {}, disabled: readonly, - onchange: 'delivery.order.select.onChange(this)', onkeyup: 'delivery.order.select.onChange(this)') - p.instructions + - if order.delivery_methods.size > 0 + = labelled_form_field _('Option'), + f.select(:supplier_delivery_id, supplier_delivery_options(methods: methods, selected: order.supplier_delivery_id), {}, disabled: readonly, + onchange: 'delivery.order.select.onChange(this)', onkeyup: 'delivery.order.select.onChange(this)') + content_tag('div', '', class: 'help-block instructions') + - elsif (name = consumer_delivery_field_value order, :name).present? + = labelled_form_field _('Option'), + f.text_field(:address, value: name, readonly: true) + div class='help-block instructions' = h(consumer_delivery_field_value order, :description) - div.consumer-delivery-data - = f.fields_for :consumer_delivery_data, order.consumer_delivery_data do |ff| - = labelled_form_field _('Address (street and number)'), - ff.text_field(:address, value: order.consumer_delivery_data[:address], readonly: readonly) - = labelled_form_field _('Address completion'), - ff.text_field(:address_line2, value: order.consumer_delivery_data[:address_line2], readonly: readonly) - = labelled_form_field _('Address reference'), - ff.text_field(:address_reference, value: order.consumer_delivery_data[:address_reference], readonly: readonly) - = labelled_form_field _('District'), - ff.text_field(:district, value: order.consumer_delivery_data[:district], readonly: readonly) - = labelled_form_field _('City'), - ff.text_field(:city, value: order.consumer_delivery_data[:city], readonly: readonly) - = labelled_form_field _('State'), - ff.text_field(:state, value: order.consumer_delivery_data[:state], readonly: readonly) - = labelled_form_field _('ZIP code'), - ff.text_field(:zip_code, value: order.consumer_delivery_data[:zip_code], readonly: readonly) + / do not render on confirmation email (@view) if supplier_delivery is pickup + - unless (@view and order.supplier_delivery_data[:delivery_type] == 'pickup') or order.delivery_methods.size == 0 + div.consumer-delivery-data + = f.fields_for :consumer_delivery_data do |ff| + = labelled_form_field _('Address (street and number)'), + ff.text_field(:address, value: consumer_delivery_field_value(order, :address), readonly: readonly) + = labelled_form_field _('Address completion'), + ff.text_field(:address_line2, value: consumer_delivery_field_value(order, :address_line2), readonly: readonly) + = labelled_form_field _('Address reference'), + ff.text_field(:address_reference, value: consumer_delivery_field_value(order, :address_reference), readonly: readonly) + = labelled_form_field _('District'), + ff.text_field(:district, value: consumer_delivery_field_value(order, :district), readonly: readonly) + = labelled_form_field _('City'), + ff.text_field(:city, value: consumer_delivery_field_value(order, :city), readonly: readonly) + = labelled_form_field _('State'), + ff.text_field(:state, value: consumer_delivery_field_value(order, :state), readonly: readonly) + = labelled_form_field _('ZIP code'), + ff.text_field(:zip_code, value: consumer_delivery_field_value(order, :zip_code), readonly: readonly) + +javascript: + delivery.order.select.onChange($('.order-delivery-select#order-#{order.id} #order_supplier_delivery_id')) - javascript: - delivery.order.select.onChange($('#order_supplier_delivery_id')) diff --git a/plugins/delivery/views/delivery_plugin/admin_method/_edit.html.slim b/plugins/delivery/views/delivery_plugin/admin_method/_edit.html.slim index 717bfd1..a1f5b24 100644 --- a/plugins/delivery/views/delivery_plugin/admin_method/_edit.html.slim +++ b/plugins/delivery/views/delivery_plugin/admin_method/_edit.html.slim @@ -12,15 +12,27 @@ = labelled_field f, :name, t('delivery_plugin.models.method.name'), f.text_field(:name), help: t('delivery_plugin.models.method.name_help') = labelled_field f, :description, t('delivery_plugin.models.method.instructions'), - f.text_area(:description, rows: 5), help: t('delivery_plugin.models.method.instructions_help') + f.text_area(:description, rows: 5, class: 'mceEditor'), help: t('delivery_plugin.models.method.instructions_help') - = labelled_field f, :fixed_cost, t('delivery_plugin.models.method.fixed_cost'), - input_group_addon(environment.currency_unit){ f.text_field :fixed_cost, type: :number, step: '0.01', value: number_with_precision(delivery_method.fixed_cost, precision: 2, locale: :en)} + fieldset + legend= t'delivery_plugin.models.method.costs_legend' + = labelled_field f, :fixed_cost, t('delivery_plugin.models.method.fixed_cost'), + input_group_addon(environment.currency_unit){ f.text_field :fixed_cost, type: :number, step: 'any', value: number_with_precision(delivery_method.fixed_cost, precision: 2, locale: :en)} - = labelled_field f, :free_over_price, t('delivery_plugin.models.method.free_over_price'), - input_group_addon(environment.currency_unit){ f.text_field :free_over_price, type: :number, step: '0.01', value: number_with_precision(delivery_method.free_over_price, precision: 2, locale: :en)} + = labelled_field f, :free_over_price, t('delivery_plugin.models.method.free_over_price'), + input_group_addon(environment.currency_unit){ f.text_field :free_over_price, type: :number, step: 'any', value: number_with_precision(delivery_method.free_over_price, precision: 2, locale: :en)} + + fieldset + legend= t'delivery_plugin.models.method.distribution_legend' + = labelled_field f, :distribution_margin_percentage, t('delivery_plugin.models.method.distribution_margin_percentage'), + input_group_addon('%'){ f.text_field :distribution_margin_percentage, type: :number, step: 'any', value: number_with_precision(delivery_method.distribution_margin_percentage, precision: 2, locale: :en)} + + = labelled_field f, :distribution_margin_fixed, t('delivery_plugin.models.method.distribution_margin_fixed'), + input_group_addon(environment.currency_unit){ f.text_field :distribution_margin_fixed, type: :number, step: 'any', value: number_with_precision(delivery_method.distribution_margin_fixed, precision: 2, locale: :en)} div = submit_button :save, if delivery_method.new_record? then t('delivery_plugin.views.method.edit.add') else t('delivery_plugin.views.method.edit.save') end = link_to_function t('delivery_plugin.views.method.edit.back'), "delivery.method.view.toggle()" += render file: 'shared/tiny_mce', locals: {mode: 'simple'} + diff --git a/plugins/delivery/views/delivery_plugin/admin_method/_show.html.slim b/plugins/delivery/views/delivery_plugin/admin_method/_show.html.slim index d9bf24f..2a52072 100644 --- a/plugins/delivery/views/delivery_plugin/admin_method/_show.html.slim +++ b/plugins/delivery/views/delivery_plugin/admin_method/_show.html.slim @@ -1,4 +1,4 @@ -td.name title="#{method.description}" +td.name title="#{strip_tags method.description}" = method.name td.actions - if request.GET[:select_ids].present? and not method.id.to_s.in? Array(request.GET[:selected_ids]) diff --git a/plugins/delivery/views/delivery_plugin/admin_options/_new.js.erb b/plugins/delivery/views/delivery_plugin/admin_options/_new.js.erb index 56977ec..688733d 100644 --- a/plugins/delivery/views/delivery_plugin/admin_options/_new.js.erb +++ b/plugins/delivery/views/delivery_plugin/admin_options/_new.js.erb @@ -1,4 +1,4 @@ -// FIXME: move to orders_cycle plugin -jQuery('#cycle-delivery-options').html('<%= j render('index', owner: @owner) %>'); +// FIXME: use generic class +$('#cycle-delivery-options').html('<%= j render('index', owner: @owner) %>'); noosfero.modal.close() diff --git a/plugins/delivery/views/delivery_plugin/admin_options/select_all.js.erb b/plugins/delivery/views/delivery_plugin/admin_options/select_all.js.erb new file mode 100644 index 0000000..ea430d1 --- /dev/null +++ b/plugins/delivery/views/delivery_plugin/admin_options/select_all.js.erb @@ -0,0 +1,3 @@ +// FIXME: use generic class +$('#cycle-delivery-options').html('<%= j render('index', owner: @owner) %>'); + diff --git a/plugins/orders/controllers/myprofile/orders_plugin_admin_controller.rb b/plugins/orders/controllers/myprofile/orders_plugin_admin_controller.rb index e5989fd..9021d22 100644 --- a/plugins/orders/controllers/myprofile/orders_plugin_admin_controller.rb +++ b/plugins/orders/controllers/myprofile/orders_plugin_admin_controller.rb @@ -43,8 +43,8 @@ class OrdersPluginAdminController < MyProfileController @orders_method = if @actor_name == :supplier then :sales else :purchases end @order = profile.send(@orders_method).find params[:id] - return render_access_denied unless @order.verify_actor? profile, @actor_name - @order.update_attributes params[:order] + return render_access_denied unless @user_is_admin or @order.verify_actor? profile, @actor_name + @order.update params[:order] respond_to do |format| format.js{ render 'orders_plugin_admin/edit' } diff --git a/plugins/orders/controllers/myprofile/orders_plugin_admin_item_controller.rb b/plugins/orders/controllers/myprofile/orders_plugin_admin_item_controller.rb index 0085a19..0cc3d32 100644 --- a/plugins/orders/controllers/myprofile/orders_plugin_admin_item_controller.rb +++ b/plugins/orders/controllers/myprofile/orders_plugin_admin_item_controller.rb @@ -15,7 +15,7 @@ class OrdersPluginAdminItemController < MyProfileController @actor_name = params[:actor_name].to_sym @order = if @actor_name == :consumer then @item.purchase else @item.sale end - @item.update_attributes! params[:item] + @item.update! params[:item] end def add_search diff --git a/plugins/orders/controllers/myprofile/orders_plugin_item_controller.rb b/plugins/orders/controllers/myprofile/orders_plugin_item_controller.rb index 66180e6..f1d5a70 100644 --- a/plugins/orders/controllers/myprofile/orders_plugin_item_controller.rb +++ b/plugins/orders/controllers/myprofile/orders_plugin_item_controller.rb @@ -23,7 +23,7 @@ class OrdersPluginItemController < MyProfileController if params[:item].present? and set_quantity_consumer_ordered params[:item][:quantity_consumer_ordered] params[:item][:quantity_consumer_ordered] = @quantity_consumer_ordered - @item.update_attributes! params[:item] + @item.update! params[:item] end end diff --git a/plugins/orders/controllers/profile/orders_plugin_order_controller.rb b/plugins/orders/controllers/profile/orders_plugin_order_controller.rb index ea9d691..606a186 100644 --- a/plugins/orders/controllers/profile/orders_plugin_order_controller.rb +++ b/plugins/orders/controllers/profile/orders_plugin_order_controller.rb @@ -8,6 +8,7 @@ class OrdersPluginOrderController < ProfileController before_filter :load_order, except: [:new] before_filter :check_access, only: [:confirm, :remove, :cancel] before_filter :set_actor_name + before_filter :disable_purechat helper OrdersPlugin::TranslationHelper helper OrdersPlugin::DisplayHelper @@ -19,7 +20,7 @@ class OrdersPluginOrderController < ProfileController def load_order @order = hmvc_orders_context::Sale.find_by_id params[:id] - render_access_denied if @order.present? and not @order.may_view? user + render_access_denied if @order.present? and (not @user_is_admin or not @order.may_view? user) end def check_access access = 'view' @@ -40,4 +41,8 @@ class OrdersPluginOrderController < ProfileController extend HMVC::ClassMethods hmvc OrdersPlugin, orders_context: OrdersPlugin + def disable_purechat + @disable_purechat = true + end + end diff --git a/plugins/orders/db/migrate/20150627232432_add_status_to_orders_plugin_item.rb b/plugins/orders/db/migrate/20150627232432_add_status_to_orders_plugin_item.rb new file mode 100644 index 0000000..bbef9aa --- /dev/null +++ b/plugins/orders/db/migrate/20150627232432_add_status_to_orders_plugin_item.rb @@ -0,0 +1,15 @@ +class AddStatusToOrdersPluginItem < ActiveRecord::Migration + + def change + add_column :orders_plugin_items, :status, :string + add_column :orders_plugin_orders, :building_next_status, :boolean + + say_with_time "filling items' statuses..." do + OrdersPlugin::Item.includes(:order).find_each batch_size: 50 do |item| + next item.destroy if item.order.nil? + item.fill_status + end + end + end + +end diff --git a/plugins/orders/lib/code_numbering.rb b/plugins/orders/lib/code_numbering.rb new file mode 100644 index 0000000..843cc33 --- /dev/null +++ b/plugins/orders/lib/code_numbering.rb @@ -0,0 +1,58 @@ +module CodeNumbering + module ClassMethods + def code_numbering field, options = {} + class_attribute :code_numbering_field + class_attribute :code_numbering_options + + self.code_numbering_field = field + self.code_numbering_options = options + + before_create :create_code_numbering + + include CodeNumbering::InstanceMethods + end + end + + module InstanceMethods + + def code + self.attributes[self.code_numbering_field.to_s] + end + + def code_scope + scope = self.code_numbering_options[:scope] + case scope + when Symbol + self.send scope + when Proc + instance_exec &scope + else + self.class + end + end + + def code_maximum + self.code_scope.maximum(self.code_numbering_field) || 0 + end + + def create_code_numbering + max = self.code_numbering_options[:start].to_i - 1 if self.code_numbering_options[:start] + max = self.code_maximum + self.send "#{self.code_numbering_field}=", max+1 + end + + def reset_scope_code_numbering + max = self.code_numbering_options[:start].to_i - 1 if self.code_numbering_options[:start] + max ||= 1 + + self.code_scope.order(:created_at).each do |record| + record.update_column self.code_numbering_field, max + max += 1 + end + self.reload + end + + end +end + +ActiveRecord::Base.extend CodeNumbering::ClassMethods diff --git a/plugins/orders/lib/ext/profile.rb b/plugins/orders/lib/ext/profile.rb index e78a842..03cdcff 100644 --- a/plugins/orders/lib/ext/profile.rb +++ b/plugins/orders/lib/ext/profile.rb @@ -1,39 +1,42 @@ require_dependency 'profile' +require_dependency 'community' -# FIXME move to core -class Profile - - def has_admin? person - return unless person - person.has_permission? 'edit_profile', self - end - -end - -class Profile +([Profile] + Profile.descendants).each do |subclass| +subclass.class_eval do # cannot use :order because of months/years named_scope has_many :orders, class_name: 'OrdersPlugin::Sale', foreign_key: :profile_id has_many :sales, class_name: 'OrdersPlugin::Sale', foreign_key: :profile_id has_many :purchases, class_name: 'OrdersPlugin::Purchase', foreign_key: :consumer_id - has_many :ordered_items, through: :orders, source: :items, order: 'name ASC' + has_many :ordered_items, -> { order 'name ASC' }, through: :orders, source: :items has_many :sales_consumers, through: :sales, source: :consumer - has_many :purchases_consumers, through: :purchases, source: :consumer + has_many :purchases_consumers, through: :sales, source: :consumer has_many :sales_profiles, through: :sales, source: :profile - has_many :purchases_profiles, through: :purchases, source: :profile + has_many :purchases_profiles, through: :sales, source: :profile + +end +end + +class Profile + + # FIXME move to core + def has_admin? person + return unless person + person.has_permission? 'edit_profile', self + end def sales_all_consumers consumers = self.sales_consumers.order 'name ASC' - consumers.concat self.consumers.except_self.order('name ASC') if self.respond_to? :consumers + consumers.concat self.suppliers.except_self.order('name ASC') if self.respond_to? :suppliers consumers.uniq end - def purchases_all_suppliers - suppliers = self.purchases_profiles.order 'name ASC' - suppliers.concat self.suppliers.except_self.order('name ASC') if self.respond_to? :suppliers - suppliers.uniq + def purchases_all_consumers + consumers = self.purchases_consumers.order 'name ASC' + consumers.concat self.consumers.except_self.order('name ASC') if self.respond_to? :consumers + consumers.uniq end def self.create_orders_manager_role env_id diff --git a/plugins/orders/lib/ext/session_store.rb b/plugins/orders/lib/ext/session_store.rb index 678e4c5..a8617b1 100644 --- a/plugins/orders/lib/ext/session_store.rb +++ b/plugins/orders/lib/ext/session_store.rb @@ -1,6 +1,6 @@ -require 'active_record/session_store' +require_dependency 'session' -class ActiveRecord::SessionStore::Session +class Session has_many :orders, primary_key: :session_id, foreign_key: :session_id, class_name: 'OrdersPlugin::Order' diff --git a/plugins/orders/lib/orders_plugin/display_helper.rb b/plugins/orders/lib/orders_plugin/display_helper.rb index 46220d8..a45bb24 100644 --- a/plugins/orders/lib/orders_plugin/display_helper.rb +++ b/plugins/orders/lib/orders_plugin/display_helper.rb @@ -2,6 +2,8 @@ module OrdersPlugin::DisplayHelper protected + include HelpHelper + include OrdersPlugin::TranslationHelper include OrdersPlugin::PriceHelper include OrdersPlugin::DateHelper @@ -9,7 +11,8 @@ module OrdersPlugin::DisplayHelper include OrdersPlugin::TableHelper include OrdersPlugin::AdminHelper include OrdersPlugin::JavascriptHelper - include HelpHelper + + include DeliveryPlugin::DisplayHelper # come on, you can't replace a rails api method (button_to_function was)! def submit_to_function name, function, html_options={} diff --git a/plugins/orders/lib/orders_plugin/field_helper.rb b/plugins/orders/lib/orders_plugin/field_helper.rb index 13216a4..2ab0287 100644 --- a/plugins/orders/lib/orders_plugin/field_helper.rb +++ b/plugins/orders/lib/orders_plugin/field_helper.rb @@ -6,7 +6,7 @@ module OrdersPlugin::FieldHelper help = options.delete(:help) content_tag :div, if form then form.label field, label, class: 'control-label' else label_tag field, label, class: 'control-label' end + - content_tag('div', help, class: 'field-help') + + content_tag('div', help, class: 'help-block') + content_tag('div', field_html, class: 'field-box') + content_tag('div', '', style: 'clear: both'), options.merge(class: options[:class].to_s + ' field form-group') diff --git a/plugins/orders/lib/orders_plugin/mailer.rb b/plugins/orders/lib/orders_plugin/mailer.rb index 7cf4cd7..4d45f47 100644 --- a/plugins/orders/lib/orders_plugin/mailer.rb +++ b/plugins/orders/lib/orders_plugin/mailer.rb @@ -4,8 +4,6 @@ class OrdersPlugin::Mailer < Noosfero::Plugin::MailerBase helper ApplicationHelper helper OrdersPlugin::DisplayHelper - helper OrdersPlugin::DateHelper - helper OrdersPlugin::TranslationHelper attr_accessor :environment attr_accessor :profile @@ -82,4 +80,10 @@ class OrdersPlugin::Mailer < Noosfero::Plugin::MailerBase end end + # for order/show_simple form + def protect_against_forgery? + false + end + helper_method :protect_against_forgery? + end diff --git a/plugins/orders/lib/orders_plugin/report.rb b/plugins/orders/lib/orders_plugin/report.rb index 779b274..ba6145b 100644 --- a/plugins/orders/lib/orders_plugin/report.rb +++ b/plugins/orders/lib/orders_plugin/report.rb @@ -142,6 +142,7 @@ module OrdersPlugin::Report productsStart = sbs+5 productsEnd = 0 selled_sum = 0 + total_price_without_margin = 0 orders.each do |order| sheet.add_row [t('lib.report.order_code'), t('lib.report.member_name'), '', t('lib.report.phone'), '', t('lib.report.mail'), ''], style: bluecell_b_top @@ -188,6 +189,7 @@ module OrdersPlugin::Report style: [default,default,default,default,default,currency,currency], formula_values: [nil,nil,nil,nil,nil,nil,formula_value_s] selled_sum += item.status_quantity * item.price rescue 0 + total_price_without_margin += item.price_without_margins * item.status_quantity sbe += 1 sum += formula_value @@ -200,12 +202,11 @@ module OrdersPlugin::Report sbs = sbe + 2 end - sheet.add_row [t('lib.report.selled_total'), '', "=SUM(G#{productsStart}:G#{productsEnd})"], - formula_values: [nil,nil, selled_sum], - style: [redcell,redcell,currency] - - ["A#{sbs}:B#{sbs}"].each{ |c| sheet.merge_cells c } + sheet.add_row [t('lib.report.selled_total'), '', "=SUM(G#{productsStart}:G#{productsEnd})", t('lib.report.total_price_without_margin'),"","", total_price_without_margin], + formula_values: [nil, nil, selled_sum, nil, nil, nil, nil], + style: [redcell, redcell, currency, redcell, redcell, redcell, currency] + ["A#{sbs}:B#{sbs}", "D#{sbs}:F{sbs}"].each{ |c| sheet.merge_cells c } sheet.column_widths 15,30,30,9,8,10,11 end # closes spreadsheet diff --git a/plugins/orders/locales/en-US.yml b/plugins/orders/locales/en-US.yml index d7c3858..6fd6a81 100644 --- a/plugins/orders/locales/en-US.yml +++ b/plugins/orders/locales/en-US.yml @@ -1,4 +1,9 @@ -"en-US": &en-US +en-US: &en-US + + number: + currency: + format: + xlsx_currency: "[$$-409]* #.##0,00;[RED]-[$$-409]* #.##0,00" orders_plugin: terms: @@ -77,6 +82,7 @@ supplier: "%{terms.supplier.singular.capitalize}" total_parcel_value: "Total value using stock" total_selled_value: "Total selled value" + total_price_without_margin: "Total price without margin" total_value: "Total Value" un: un. value: value @@ -299,8 +305,8 @@ supplier_product: "%{terms.supplier.singular.capitalize}/Product" total: "TOTAL:" -'en_US': +en_US: <<: *en-US -'en': +en: <<: *en-US diff --git a/plugins/orders/locales/pt-BR.yml b/plugins/orders/locales/pt-BR.yml index afc983d..1680442 100644 --- a/plugins/orders/locales/pt-BR.yml +++ b/plugins/orders/locales/pt-BR.yml @@ -1,4 +1,9 @@ -"pt-BR": &pt-BR +pt-BR: &pt-BR + + number: + currency: + format: + xlsx_currency: "[$R$-416]* #,##0.00;[RED]-[$R$-416]* #,##0.00" orders_plugin: terms: @@ -78,6 +83,7 @@ supplier: "%{terms.supplier.singular.capitalize}" total_parcel_value: "Valor total usando estoque" total_selled_value: "Valor total vendido" + total_price_without_margin: "Valor total sem a margem" total_value: "total pago" un: un. value: Valor @@ -299,8 +305,8 @@ supplier_product: "%{terms.supplier.singular.capitalize}/Produto" total: "TOTAL:" -'pt_BR': +pt_BR: <<: *pt-BR -'pt': +pt: <<: *pt-BR diff --git a/plugins/orders/models/orders_plugin/item.rb b/plugins/orders/models/orders_plugin/item.rb index 7f0c3ba..add5f13 100644 --- a/plugins/orders/models/orders_plugin/item.rb +++ b/plugins/orders/models/orders_plugin/item.rb @@ -7,6 +7,13 @@ class OrdersPlugin::Item < ActiveRecord::Base # flag used by items to compare them with products attr_accessor :product_diff + Statuses = %w[ordered accepted separated delivered received] + DbStatuses = %w[draft planned cancelled] + Statuses + UserStatuses = %w[open forgotten planned cancelled] + Statuses + StatusText = {}; UserStatuses.map do |status| + StatusText[status] = "orders_plugin.models.order.statuses.#{status}" + end + # should be Order, but can't reference it here so it would create a cyclic reference StatusAccessMap = { 'ordered' => :consumer, @@ -28,9 +35,9 @@ class OrdersPlugin::Item < ActiveRecord::Base serialize :data - belongs_to :order, class_name: 'OrdersPlugin::Order', foreign_key: :order_id, touch: true - belongs_to :sale, class_name: 'OrdersPlugin::Sale', foreign_key: :order_id, touch: true - belongs_to :purchase, class_name: 'OrdersPlugin::Purchase', foreign_key: :order_id, touch: true + belongs_to :order, class_name: '::OrdersPlugin::Order', foreign_key: :order_id, touch: true + belongs_to :sale, class_name: '::OrdersPlugin::Sale', foreign_key: :order_id, touch: true + belongs_to :purchase, class_name: '::OrdersPlugin::Purchase', foreign_key: :order_id, touch: true belongs_to :product has_one :supplier, through: :product @@ -40,28 +47,30 @@ class OrdersPlugin::Item < ActiveRecord::Base # FIXME: don't work because of load order #if defined? SuppliersPlugin - has_many :from_products, through: :product, source: :orders + has_many :from_products, through: :product + has_one :from_product, through: :product has_many :to_products, through: :product - has_many :sources_supplier_products, through: :product, source: :items - has_many :supplier_products, through: :product, source: :enterprise + has_one :to_product, through: :product + has_many :sources_supplier_products, through: :product + has_one :sources_supplier_product, through: :product + has_many :supplier_products, through: :product + has_one :supplier_product, through: :product has_many :suppliers, through: :product + has_one :supplier, through: :product #end - def from_product - self.from_products.first - end - def supplier_product - self.supplier_products.first - end - scope :ordered, conditions: ['orders_plugin_orders.status = ?', 'ordered'], joins: [:order] - scope :for_product, lambda{ |product| {conditions: {product_id: product.id}} } + scope :ordered, -> { joins(:order).where 'orders_plugin_orders.status = ?', 'ordered' } + scope :for_product, -> (product) { where product_id: product.id } default_scope include: [:product] validate :has_order validates_presence_of :product + validates_inclusion_of :status, in: DbStatuses + before_validation :set_defaults before_save :save_calculated_prices + before_save :step_status before_create :sync_fields # utility for other classes @@ -104,6 +113,9 @@ class OrdersPlugin::Item < ActiveRecord::Base def price self[:price] || (self.product.price_with_discount || 0 rescue nil) end + def price_without_margins + self.product.price_without_margins rescue self.price + end def unit self.product.unit end @@ -121,8 +133,15 @@ class OrdersPlugin::Item < ActiveRecord::Base end end - def status - self.order.status + def calculated_status + status = self.order.status + index = Statuses.index status + next_status = Statuses[index+1] if index + next_quantity = "quantity_#{StatusDataMap[next_status]}" if next_status + if next_status and self.send next_quantity then next_status else status end + end + def on_next_status? + self.order.status != self.calculated_status end # product used for comparizon when repeating an order @@ -144,13 +163,13 @@ class OrdersPlugin::Item < ActiveRecord::Base def status_quantity_field @status_quantity_field ||= begin - status = StatusDataMap[self.order.status] || 'consumer_ordered' + status = StatusDataMap[self.status] || 'consumer_ordered' "quantity_#{status}" end end def status_price_field @status_price_field ||= begin - status = StatusDataMap[self.order.status] || 'consumer_ordered' + status = StatusDataMap[self.status] || 'consumer_ordered' "price_#{status}" end end @@ -184,10 +203,10 @@ class OrdersPlugin::Item < ActiveRecord::Base def quantity_price_data actor_name data = {flags: {}} - statuses = OrdersPlugin::Order::Statuses + statuses = ::OrdersPlugin::Order::Statuses statuses_data = data[:statuses] = {} - current = statuses.index(self.order.status) || 0 + current = statuses.index(self.status) || 0 next_status = self.order.next_status actor_name next_index = statuses.index(next_status) || current + 1 goto_next = actor_name == StatusAccessMap[next_status] @@ -266,8 +285,11 @@ class OrdersPlugin::Item < ActiveRecord::Base # Set access statuses_data.each.with_index do |(status, status_data), i| - status_data[:flags][:editable] = true if StatusAccessMap[status] == actor_name - # code to only allow last status + #consumer_may_edit = actor_name == :consumer and status == 'ordered' and self.order.open? + if StatusAccessMap[status] == actor_name + status_data[:flags][:editable] = true + end + # only allow last status #status_data[:flags][:editable] = true if status_data[:access] == actor_name and (status_data[:flags][:admin] or self.order.open?) end @@ -279,6 +301,14 @@ class OrdersPlugin::Item < ActiveRecord::Base self.save_calculated_prices end + # used by db/migrate/20150627232432_add_status_to_orders_plugin_item.rb + def fill_status + status = self.calculated_status + return if self.status == status + self.update_column :status, status + self.order.update_column :building_next_status, true if self.order.status != status and not self.order.building_next_status + end + protected def save_calculated_prices @@ -288,6 +318,17 @@ class OrdersPlugin::Item < ActiveRecord::Base end end + def set_defaults + self.status ||= Statuses.first + end + + def step_status + status = self.calculated_status + return if self.status == status + self.status = status + self.order.update_column :building_next_status, true if self.order.status != status and not self.order.building_next_status + end + def has_order self.order or self.sale or self.purchase end diff --git a/plugins/orders/models/orders_plugin/order.rb b/plugins/orders/models/orders_plugin/order.rb index 66f991a..72a0378 100644 --- a/plugins/orders/models/orders_plugin/order.rb +++ b/plugins/orders/models/orders_plugin/order.rb @@ -1,11 +1,12 @@ class OrdersPlugin::Order < ActiveRecord::Base - Statuses = %w[ordered accepted separated delivered received] - DbStatuses = %w[draft planned cancelled] + Statuses - UserStatuses = %w[open forgotten planned cancelled] + Statuses - StatusText = {}; UserStatuses.map do |status| - StatusText[status] = "orders_plugin.models.order.statuses.#{status}" - end + # if abstract_class is true then it will trigger https://github.com/rails/rails/issues/20871 + #self.abstract_class = true + + Statuses = ::OrdersPlugin::Item::Statuses + DbStatuses = ::OrdersPlugin::Item::DbStatuses + UserStatuses = ::OrdersPlugin::Item::UserStatuses + StatusText = ::OrdersPlugin::Item::StatusText # oh, we need a payments plugin! PaymentMethods = { @@ -31,18 +32,14 @@ class OrdersPlugin::Order < ActiveRecord::Base ] # copy, for easiness. can't be declared to here to avoid cyclic reference - StatusDataMap = OrdersPlugin::Item::StatusDataMap - StatusAccessMap = OrdersPlugin::Item::StatusAccessMap + StatusDataMap = ::OrdersPlugin::Item::StatusDataMap + StatusAccessMap = ::OrdersPlugin::Item::StatusAccessMap StatusesByActor = { consumer: StatusAccessMap.map{ |s, a| s if a == :consumer }.compact, supplier: StatusAccessMap.map{ |s, a| s if a == :supplier }.compact, } - # workaround for STI - self.table_name = :orders_plugin_orders - self.abstract_class = true - attr_accessible :status, :consumer, :profile, :supplier_delivery_id, :consumer_delivery_id, :supplier_delivery_data, :consumer_delivery_data @@ -51,17 +48,17 @@ class OrdersPlugin::Order < ActiveRecord::Base belongs_to :supplier, foreign_key: :profile_id, class_name: 'Profile' belongs_to :consumer, class_name: 'Profile' - belongs_to :session, primary_key: :session_id, foreign_key: :session_id, class_name: 'ActiveRecord::SessionStore::Session' + belongs_to :session, primary_key: :session_id, foreign_key: :session_id, class_name: 'Session' - has_many :items, class_name: 'OrdersPlugin::Item', foreign_key: :order_id, dependent: :destroy, order: 'name ASC' + has_many :items, -> { order 'name ASC' }, class_name: 'OrdersPlugin::Item', foreign_key: :order_id, dependent: :destroy has_many :products, through: :items belongs_to :supplier_delivery, class_name: 'DeliveryPlugin::Method' belongs_to :consumer_delivery, class_name: 'DeliveryPlugin::Method' - scope :alphabetical, -> { joins(:consumer).order 'profiles.name ASC' } - scope :latest, -> { order 'code ASC' } - scope :default_order, -> { order 'code DESC' } + scope :alphabetical, -> { joins(:consumer).reorder 'profiles.name ASC' } + scope :latest, -> { reorder 'code ASC' } + scope :default_order, -> { reorder 'code DESC' } scope :of_session, -> session_id { where session_id: session_id } scope :of_user, -> session_id, consumer_id=nil do @@ -73,53 +70,50 @@ class OrdersPlugin::Order < ActiveRecord::Base scope :latest, order: 'created_at DESC' - scope :draft, conditions: {status: 'draft'} - scope :planned, conditions: {status: 'planned'} - scope :cancelled, conditions: {status: 'cancelled'} - scope :not_cancelled, conditions: ["status <> 'cancelled'"] - scope :ordered, conditions: ['ordered_at IS NOT NULL'] - scope :confirmed, conditions: ['ordered_at IS NOT NULL'] - scope :accepted, conditions: ['accepted_at IS NOT NULL'] - scope :separated, conditions: ['separated_at IS NOT NULL'] - scope :delivered, conditions: ['delivered_at IS NOT NULL'] - scope :received, conditions: ['received_at IS NOT NULL'] - - scope :for_profile, lambda{ |profile| {conditions: {profile_id: profile.id}} } - scope :for_profile_id, lambda{ |profile_id| {conditions: {profile_id: profile_id}} } - scope :for_supplier, lambda{ |profile| {conditions: {profile_id: profile.id}} } - scope :for_supplier_id, lambda{ |profile_id| {conditions: {profile_id: profile_id}} } - scope :for_consumer, lambda{ |consumer| {conditions: {consumer_id: (consumer.id rescue nil)}} } - scope :for_consumer_id, lambda{ |consumer_id| {conditions: {consumer_id: consumer_id}} } - - scope :months, select: 'DISTINCT(EXTRACT(months FROM orders_plugin_orders.created_at)) as month', order: 'month DESC' - scope :years, select: 'DISTINCT(EXTRACT(YEAR FROM orders_plugin_orders.created_at)) as year', order: 'year DESC' - - scope :by_month, lambda { |month| - where 'EXTRACT(month FROM orders_plugin_orders.created_at) <= :month AND EXTRACT(month FROM orders_plugin_orders.created_at) >= :month',{ month: month } + scope :draft, -> { where status: 'draft' } + scope :planned, -> { where status: 'planned' } + scope :cancelled, -> { where status: 'cancelled' } + scope :not_cancelled, -> { where "status <> 'cancelled'" } + scope :ordered, -> { where 'ordered_at IS NOT NULL' } + scope :confirmed, -> { where 'ordered_at IS NOT NULL' } + scope :accepted, -> { where 'accepted_at IS NOT NULL' } + scope :separated, -> { where 'separated_at IS NOT NULL' } + scope :delivered, -> { where 'delivered_at IS NOT NULL' } + scope :received, -> { where 'received_at IS NOT NULL' } + + scope :for_profile, -> (profile) { where profile_id: profile.id } + scope :for_profile_id, -> (profile_id) { where profile_id: profile_id } + scope :for_supplier, -> (profile) { where profile_id: profile.id } + scope :for_supplier_id, -> (profile_id) { where profile_id: profile_id } + scope :for_consumer, -> (consumer) { where consumer_id: (consumer.id rescue nil) } + scope :for_consumer_id, -> (consumer_id) { where consumer_id: consumer_id } + + scope :months, -> { select('DISTINCT(EXTRACT(months FROM orders_plugin_orders.created_at)) as month').order('month DESC') } + scope :years, -> { select('DISTINCT(EXTRACT(YEAR FROM orders_plugin_orders.created_at)) as year').order('year DESC') } + + scope :by_month, -> (month) { + where 'EXTRACT(month FROM orders_plugin_orders.created_at) <= :month AND EXTRACT(month FROM orders_plugin_orders.created_at) >= :month', month: month } - scope :by_year, lambda { |year| - where 'EXTRACT(year FROM orders_plugin_orders.created_at) <= :year AND EXTRACT(year FROM orders_plugin_orders.created_at) >= :year', { year: year } + scope :by_year, -> (year) { + where 'EXTRACT(year FROM orders_plugin_orders.created_at) <= :year AND EXTRACT(year FROM orders_plugin_orders.created_at) >= :year', year: year } - scope :by_range, lambda { |start_time, end_time| - where 'orders_plugin_orders.created_at >= :start AND orders_plugin_orders.created_at <= :end', { start: start_time, end: end_time } + scope :by_range, -> (start_time, end_time) { + where 'orders_plugin_orders.created_at >= :start AND orders_plugin_orders.created_at <= :end', start: start_time, end: end_time } - scope :with_status, lambda { |status| - where status: status - } - scope :with_code, lambda { |code| - where code: code - } + scope :with_status, -> (status) { where status: status } + scope :with_code, -> (code) { where code: code } validates_presence_of :profile # consumer is optional, as orders can be made by unlogged users validates_inclusion_of :status, in: DbStatuses before_validation :check_status + before_validation :change_status after_save :send_notifications extend CodeNumbering::ClassMethods - code_numbering :code, scope: proc{ self.profile.orders } + code_numbering :code, scope: -> { self.profile.orders } serialize :data @@ -165,17 +159,17 @@ class OrdersPlugin::Order < ActiveRecord::Base # / Items # / \ OfferedProduct (column product_id) # Order / \ SourceProduct from DistributedProduct (quantity=1, always) - # \ SourceProduct from Product* (quantity be more than 1 if DistributedProduct is an agregate product) + # \ SourceProduct from Product* (multiple for each if is an aggregate product) # for order outside cycle we have # / Items # / \ SourceProduct from DistributedProduct (quantity=1, always) - # Order / \ SourceProduct from Product* (quantity be more than 1 if DistributedProduct is an agregate product) + # Order / \ SourceProduct from Product* (multiple for each if is an aggregate product) # # *suppliers usually don't distribute using cycles, so they only have Product # def self.supplier_products_by_suppliers orders products_by_supplier = {} - items = OrdersPlugin::Item.where(order_id: orders.map(&:id)).includes({sources_supplier_products: [:supplier, :from_product]}) + items = self.parent::Item.where(order_id: orders.map(&:id)).includes(sources_supplier_products: [:supplier, :from_product]) items.each do |item| if item.sources_supplier_products.present? item.sources_supplier_products.each do |source_sp| @@ -358,15 +352,14 @@ class OrdersPlugin::Order < ActiveRecord::Base # total_price considering last state def total_price actor_name = :consumer, admin = false - if not self.pre_order? and admin and status = self.next_status(actor_name) - self.fill_items_data self.status, status + # for admins, we want the next_status while we concluded the finish status change + if admin + price = :status_price else - status = self.status + data = StatusDataMap[self.status] || StatusDataMap[Statuses.first] + price = "price_#{data}".to_sym end - data = StatusDataMap[status] || StatusDataMap[Statuses.first] - price = "price_#{data}".to_sym - items ||= (self.ordered_items rescue nil) || self.items items.collect(&price).inject(0){ |sum, p| sum + p.to_f } end @@ -379,7 +372,8 @@ class OrdersPlugin::Order < ActiveRecord::Base end has_currency :total - def fill_items_data from_status, to_status, save = false + def fill_items from_status, to_status, save = false + # check for status advance return if (Statuses.index(to_status) <= Statuses.index(from_status) rescue true) from_data = StatusDataMap[from_status] @@ -405,15 +399,22 @@ class OrdersPlugin::Order < ActiveRecord::Base self.status ||= 'draft' # backwards compatibility self.status = 'ordered' if self.status == 'confirmed' + end + + def change_status + return if self.status_was == self.status - self.fill_items_data self.status_was, self.status, true + self.fill_items self.status_was, self.status, true + self.items.update_all status: self.status + self.building_next_status = false + # fill dates on status advance if self.status_on? 'ordered' Statuses.each do |status| self.send "#{self.status}_at=", Time.now if self.status_was != status and self.status == status end else - # for draft, planned, forgotten, cancelled, etc + # status rewind for draft, planned, forgotten, cancelled, etc Statuses.each do |status| self.send "#{status}_at=", nil end diff --git a/plugins/orders/models/orders_plugin/sale.rb b/plugins/orders/models/orders_plugin/sale.rb index b8dd778..f59b1b3 100644 --- a/plugins/orders/models/orders_plugin/sale.rb +++ b/plugins/orders/models/orders_plugin/sale.rb @@ -1,5 +1,7 @@ class OrdersPlugin::Sale < OrdersPlugin::Order + before_validation :fill_default_supplier_delivery + def orders_name 'sales' end @@ -19,6 +21,17 @@ class OrdersPlugin::Sale < OrdersPlugin::Order has_number_with_locale :purchase_quantity_total has_currency :purchase_price_total + def supplier_delivery + super || (self.delivery_methods.first rescue nil) + end + def supplier_delivery_id + self[:supplier_delivery_id] || (self.supplier_delivery.id rescue nil) + end + + def fill_default_supplier_delivery + self[:supplier_delivery_id] ||= self.supplier_delivery.id if self.supplier_delivery + end + protected end diff --git a/plugins/orders/orders b/plugins/orders/orders new file mode 120000 index 0000000..cd47dfd --- /dev/null +++ b/plugins/orders/orders @@ -0,0 +1 @@ +/home/braulio/Projects/noosfero-ecosol/noosfero/plugins/orders \ No newline at end of file diff --git a/plugins/orders/public/javascripts/orders.js b/plugins/orders/public/javascripts/orders.js index 5f5e070..e5b4738 100644 --- a/plugins/orders/public/javascripts/orders.js +++ b/plugins/orders/public/javascripts/orders.js @@ -139,21 +139,12 @@ orders = { }, }, - set_orders_container_max_height: function() + setOrderMaxHeight: function() { ordersH = $(window).height(); - ordersH -= 100 ordersH -= $('#cirandas-top-bar').outerHeight() - ordersH -= $('.order-status-message').outerHeight() - ordersH -= $('.order-message-title').outerHeight() - ordersH -= $('#order-column .order-items .table-header').last().outerHeight() - ordersH -= $('#order-column .order-total').last().outerHeight() - ordersH -= $('#order-column #actor-data-box').last().outerHeight() - ordersH -= $('#order-column .delivery-box').outerHeight() - ordersH -= $('#order-column .order-message-text').outerHeight() - ordersH -= $('#order-column .order-message-actions').outerHeight() - ordersH -= $('#order-column .actions').outerHeight() - $('.order-items-container .order-items-scroll').css('max-height', ordersH); + ordersH -= $('.order-view form > .actions').outerHeight(true) + $('.order-view .order-data').css('max-height', ordersH); }, daterangepicker: { @@ -180,6 +171,7 @@ orders = { }, }; -$(document).ready(orders.set_orders_container_max_height); -$(window).resize(orders.set_orders_container_max_height); +$(document).ready(orders.setOrderMaxHeight); +$(window).resize(orders.setOrderMaxHeight); +$('#order_supplier_delivery_id').change(orders.setOrderMaxHeight); diff --git a/plugins/orders/public/public b/plugins/orders/public/public new file mode 120000 index 0000000..20e6770 --- /dev/null +++ b/plugins/orders/public/public @@ -0,0 +1 @@ +/home/braulio/Projects/noosfero-ecosol/noosfero/config/plugins/orders/public \ No newline at end of file diff --git a/plugins/orders/public/stylesheets/_field.scss b/plugins/orders/public/stylesheets/_field.scss index aadadf4..32d1dcd 100644 --- a/plugins/orders/public/stylesheets/_field.scss +++ b/plugins/orders/public/stylesheets/_field.scss @@ -25,9 +25,8 @@ float: left; width: 100%; } - .field-help { + .help-block { clear: both; - margin-bottom: $half-margin; font-size: 10px; } diff --git a/plugins/orders/public/stylesheets/_items.scss b/plugins/orders/public/stylesheets/_items.scss index ff1d9a1..413cb91 100644 --- a/plugins/orders/public/stylesheets/_items.scss +++ b/plugins/orders/public/stylesheets/_items.scss @@ -102,9 +102,6 @@ .table-content { - .order-items-scroll { - max-height: 350px; - } .item { &.product-unavailable { diff --git a/plugins/orders/public/stylesheets/orders.scss b/plugins/orders/public/stylesheets/orders.scss index eeb00ef..b4149f0 100644 --- a/plugins/orders/public/stylesheets/orders.scss +++ b/plugins/orders/public/stylesheets/orders.scss @@ -9,10 +9,10 @@ @import 'items'; .controller-profile_editor a.control-panel-orders-purchases-sales { - background-image: url("/plugins/orders/images/control-panel/purchases-sales.png") + background-image: url("/plugins/orders/images/control-panel/purchases-sales.png"); } .controller-profile_editor .msie6 a.control-panel-orders-purchases-sales { - background-image: url("/plugins/orders/images/control-panel/purchases-sales.gif") + background-image: url("/plugins/orders/images/control-panel/purchases-sales.gif"); } .orders-admin-index { @@ -125,14 +125,13 @@ } .order-view { - - &, .order-items-scroll, .order-items, .item { + &, .order-items, .item { width: $order-items-width; } &.admin { width: $order-items-admin-width; - .order-items-scroll, .order-items, .item { + .order-items, .item { width: $order-items-admin-width - 2*$border; } } @@ -160,16 +159,14 @@ margin: 0; border: none; + + overflow: hidden; + overflow-y: auto; + &.admin { border: $border solid black; } - .order-items-scroll { - overflow-y: auto; - padding-right: $intercolumn; - box-sizing: content-box; - } - .order-header { padding: $half-padding $padding; border-bottom: $border solid black; @@ -223,7 +220,10 @@ padding-bottom: 200px; } -.action-orders_cycle_plugin_order-edit .purechat { - left: 40px; - right: none; +.controller-orders_cycle_plugin_order, +.controller-consumers_coop_plugin_order { + .purechat { + left: 40px; + right: none; + } } diff --git a/plugins/orders/test/test_helper.rb b/plugins/orders/test/test_helper.rb new file mode 100644 index 0000000..cca1fd3 --- /dev/null +++ b/plugins/orders/test/test_helper.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../test/test_helper' diff --git a/plugins/orders/test/unit/orders_plugin/item_test.rb b/plugins/orders/test/unit/orders_plugin/item_test.rb new file mode 100644 index 0000000..b96de82 --- /dev/null +++ b/plugins/orders/test/unit/orders_plugin/item_test.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/../../../../test/test_helper' + +class OrdersPlugin::ItemTest < ActiveSupport::TestCase + + def setup + @item = build(OrdersPlugin::Item, + :quantity_shipped => 1.0, :quantity_consumer_ordered => 2.0, :quantity_accepted => 3.0, + :price_shipped => 10.0, :price_consumer_ordered => 20.0, :price_accepted => 30.0) + end + + should 'calculate prices' do + end + +end diff --git a/plugins/orders/test/unit/orders_plugin/order_test.rb b/plugins/orders/test/unit/orders_plugin/order_test.rb new file mode 100644 index 0000000..bd771b2 --- /dev/null +++ b/plugins/orders/test/unit/orders_plugin/order_test.rb @@ -0,0 +1,121 @@ +require "test_helper" + +class OrdersPlugin::OrderTest < ActiveSupport::TestCase + + def setup + @order = build(OrdersPlugin::Order) + end + + should 'report supplier products when distributing aggregate products' do + env = Environment.create! name: 'megacoop' + supplier = Enterprise.create! identifier: 'supplier', name: 'supplier', environment: env + p1 = supplier.products.create! product_category: ProductCategory.create!(name: 'banana', environment: env) + p2 = supplier.products.create! product_category: ProductCategory.create!(name: 'aipim', environment: env) + + coop = Community.create! identifier: 'blah', name: 'blah', environment: env + coop.suppliers.create! profile: supplier, consumer: coop + aggregate_product = SuppliersPlugin::DistributedProduct.new profile: coop + aggregate_product.sources_from_products.build quantity: 1, from_product: p1, to_product: aggregate_product + aggregate_product.sources_from_products.build quantity: 5, from_product: p2, to_product: aggregate_product + aggregate_product.save! + + # hack + person = coop + + # this also create offered products + cycle = OrdersCyclePlugin::Cycle.create! name: 'blah', profile: coop, start: Time.now, finish: Time.now+1.day, delivery_start: Time.now+2.days, delivery_finish: Time.now+3.days, status: 'orders' + sale = cycle.sales.create! profile: person + sale.items.create! quantity_consumer_ordered: 3, product: aggregate_product + + r = OrdersPlugin::Order.supplier_products_by_suppliers [sale] + quantities = r.first.last.map(&:quantity_ordered).map(&:to_i) + assert_equal [3*1,3*5], quantities + end + + should 'format code with cycle code' do + @order.save! + assert_equal "#{@order.cycle.code}.#{@order.attributes['code']}", @order.code + end + + should 'use as draft default status' do + @order = create(OrdersPlugin::Order, status: nil) + assert_equal 'draft', @order.status + end + + ### + # Status + ### + + should 'define and validate list of statuses' do + @order.status = 'blah' + @order.valid? + assert @order.errors.invalid?('status') + + ['draft', 'planned', 'ordered', 'cancelled'].each do |i| + @order.status = i + @order.valid? + assert !@order.errors.invalid?('status') + end + end + + should 'define status question methods' do + ['draft', 'planned', 'ordered', 'cancelled'].each do |i| + @order.status = i + assert @order.send("#{@order.status}?") + end + end + + should 'define forgotten and open status' do + @order.status = 'draft' + assert @order.draft? + assert @order.cycle.orders? + assert @order.open? + @order.cycle.status = 'closed' + assert !@order.open? + assert @order.forgotten? + end + + should 'return current status using forgotten and open too' do + @order.status = 'draft' + assert @order.open? + assert_equal 'open', @order.current_status + @order.cycle.status = 'closed' + assert @order.forgotten? + assert_equal 'forgotten', @order.current_status + end + + should 'define status_message method' do + assert @order.respond_to?(:status_message) + end + + ### + # Delivery + ### + + should 'give default value to supplier delivery if not present' do + @order.save! + @order.profile.save! + + @order.cycle.delivery_methods = [] + @order.supplier_delivery = nil + assert_nil @order.supplier_delivery + + default = @order.cycle.delivery_methods.create! profile: @order.profile, name: 'method', delivery_type: 'deliver' + assert_equal default, @order.supplier_delivery + assert_equal default.id, @order.supplier_delivery_id + end + + ### + # Totals + ### + + should 'give total price and quantity asked' do + @order.cycle.profile.save! + product = create(SuppliersPlugin::DistributedProduct, price: 2.0, profile: @order.cycle.profile, supplier: @order.cycle.profile.self_supplier) + @order.save! + @order.item.create! product: @order.cycle.products.first, quantity_consumer_ordered: 2.0 + assert_equal 2.0, @order.total_quantity_consumer_ordered + assert_equal 4.0, @order.total_price_consumer_ordered + end + +end diff --git a/plugins/orders/views/orders_plugin/mailer/order_confirmation.html.slim b/plugins/orders/views/orders_plugin/mailer/order_confirmation.html.slim new file mode 100644 index 0000000..3631aaf --- /dev/null +++ b/plugins/orders/views/orders_plugin/mailer/order_confirmation.html.slim @@ -0,0 +1,30 @@ +doctype html +html + head + meta content=("text/html; charset=utf-8") http-equiv="Content-Type" + = stylesheet_link_tag 'plugins/responsive/bootstrap/all.css' if defined? ResponsivePlugin + = stylesheet_link_tag 'plugins/orders/style.css' + body + p= t'orders_plugin.views.mailer.order_confirmation.dear_name', name: @consumer.name + + p= t'orders_plugin.views.mailer.order_confirmation.your_order_made_on_co', + name: @profile.name, date: day_time(@order.updated_at) + + - if @order.respond_to? :cycle + p= t'orders_plugin.views.mailer.order_confirmation.the_delivery_period_w', + date: datetime_period_with_from(@order.cycle.delivery_start, @order.cycle.delivery_finish) + + p= t'orders_plugin.views.mailer.order_confirmation.order_data_confirmed' + + = render "orders_plugin_order/show_simple", order: @order, actor_name: :consumer + + p + = t('orders_plugin.views.mailer.order_confirmation.your_order_can_be_che') + br + = link_to t('orders_plugin.views.mailer.order_confirmation.order_code_of_profile') % {code: @order.code, name: @profile.name }, + {controller: :orders_cycle_plugin_order, action: :edit, profile: @profile.identifier, id: @order.id, protocol: "http"} + + p + |-- + br + = t'orders_plugin.views.mailer.order_confirmation.greetings' diff --git a/plugins/orders/views/orders_plugin/shared/daterangepicker/_init.html.slim b/plugins/orders/views/orders_plugin/shared/daterangepicker/_init.html.slim index c32fbb8..924fdec 100644 --- a/plugins/orders/views/orders_plugin/shared/daterangepicker/_init.html.slim +++ b/plugins/orders/views/orders_plugin/shared/daterangepicker/_init.html.slim @@ -1,7 +1,7 @@ = content_for :head do = stylesheet_link_tag '/assets/plugins/orders/stylesheets/daterangepicker-bs3.css' / in case it is not loaded for this theme - = stylesheet_link_tag '/assets/designs/icons/awesome/scss/font-awesome.css' + = stylesheet_link_tag 'designs/icons/awesome/scss/font-awesome.css' = javascript_include_tag '/assets/plugins/orders/javascripts/moment-with-locales.js' = javascript_include_tag '/assets/plugins/orders/javascripts/daterangepicker.js' diff --git a/plugins/orders/views/orders_plugin_admin/_filter_fields.html.slim b/plugins/orders/views/orders_plugin_admin/_filter_fields.html.slim index 0407471..6750f0d 100644 --- a/plugins/orders/views/orders_plugin_admin/_filter_fields.html.slim +++ b/plugins/orders/views/orders_plugin_admin/_filter_fields.html.slim @@ -3,21 +3,21 @@ div= render 'orders_plugin/shared/daterangepicker/init' .field.state - label for="status" = t'views.filter.status' + label= t'views.filter.status' div= select_tag :status, options_for_select([[t('views.filter.all'), ""]] + OrdersPlugin::Order::StatusText.map{ |id, name| [t(name), id] }, params[:status]) .field.code - label for="code" = t'views.filter.code' + label= t'views.filter.code' div= text_field_tag :code, params[:code] div class="field #{actor_name}" - label for="#{actor_name}_id" = t"terms.#{actor_name}.singular", transformation: :capitalize + label= t"terms.#{actor_name}.singular", transformation: :capitalize div= select_tag "#{actor_name}_id", options_for_select([[t('views.filter.all'), ""]] + actors.map{ |a| [a.name, a.id] }, params["#{actor_name}_id"]) .field.delivery - label for="delivery_method_id" = t'views.filter.delivery' + label= t'views.filter.delivery' div= select_tag :delivery_method_id, options_for_select([[t('views.filter.all'), ""]] + orders_owner.delivery_methods.map{ |dm| [dm.name, dm.id] }, params[:delivery_method_id]) diff --git a/plugins/orders/views/orders_plugin_admin/_index.html.erb b/plugins/orders/views/orders_plugin_admin/_index.html.erb index 5ac36b3..12ca3ce 100644 --- a/plugins/orders/views/orders_plugin_admin/_index.html.erb +++ b/plugins/orders/views/orders_plugin_admin/_index.html.erb @@ -12,14 +12,14 @@ <% if @purchases.present? %>
- <%= render 'orders_plugin_admin/purchases', actors: profile.purchases_all_suppliers, + <%= render 'orders_plugin_admin/purchases', actors: profile.sales_all_consumers, orders_owner: profile, orders: @purchases, month: @purchases_month, year: @purchases_year, wireframe_size: false %>
<% end %> <% if @sales.present? %>
- <%= render 'orders_plugin_admin/sales', actors: profile.sales_all_consumers, + <%= render 'orders_plugin_admin/sales', actors: profile.purchases_all_consumers, orders_owner: profile, orders: @sales, month: @sales_month, year: @purchases_year, wireframe_size: false %>
<% end %> diff --git a/plugins/orders/views/orders_plugin_admin/_order.html.slim b/plugins/orders/views/orders_plugin_admin/_order.html.slim new file mode 100644 index 0000000..1bbaa9c --- /dev/null +++ b/plugins/orders/views/orders_plugin_admin/_order.html.slim @@ -0,0 +1,21 @@ +- other_actor_name = if actor_name == :supplier then :consumer else :supplier end +- edit = true if edit.nil? + +div class="order value-row #{order.status}" data-id=order.id id="order-row-#{order.id}" onclick="orders.admin.load_edit(this, '#{url_for action: :edit, id: order.id, actor_name: actor_name}')" toggle-edit="orders.admin.toggle_edit();" + + .box-view.with-inner + .box-field.select toggle-ignore="" = check_box_tag "order_ids[]", order.id + .box-view-inner + span.box-field.code= order.code + span.box-field.actor-name= order.send("#{other_actor_name}_data")[:name] + span.box-field.order-date= datetime_full order.created_at + span.box-field.last-update= datetime_full order.updated_at + span.box-field.total= order.total_price_as_currency_number actor_name + span.box-field.situation= order_situation order + = edit_arrow "#order-row-#{order.id}", true, class: 'actions' + .clean + + div class="box-edit #{'loading' if not edit}" + = render 'orders_plugin_admin/edit', order: order, actor_name: actor_name, other_actor_name: other_actor_name if edit + + .clean diff --git a/plugins/orders/views/orders_plugin_item/_edit_fields.html.slim b/plugins/orders/views/orders_plugin_item/_edit_fields.html.slim index 8a468fb..41a3a5f 100644 --- a/plugins/orders/views/orders_plugin_item/_edit_fields.html.slim +++ b/plugins/orders/views/orders_plugin_item/_edit_fields.html.slim @@ -4,7 +4,7 @@ .box-field.product title=item.name = item.name .box-field.quantity-price-table - item_data[:statuses].each do |status, status_data| - - next if status_data[:flags][:not_modified] and not status_data[:flags][:admin] + - next if status_data[:flags][:not_modified] and not status_data[:flags][:editable] = render 'orders_plugin_item/quantity_price', item: item, order: order, status: status, data: item_data, status_data: status_data, actor_name: actor_name .more @@ -12,12 +12,15 @@ / actionmailer doesn't have an user, rescue error - if (order.may_edit? user, @admin rescue false) - if @admin - = link_to_function t('views.item._edit.remove_from_order'), "orders.item.admin_remove(this, '#{url_for(controller: :orders_plugin_admin_item, action: :edit, id: item.id, actor_name: actor_name)}')", class: 'action-button' - = link_to_function t('views.item._edit.submit'), "orders.item.submit(this, '#{url_for(controller: :orders_plugin_admin_item, action: :edit, id: item.id, actor_name: actor_name)}')", class: 'submit action-button' + = link_to_function t('views.item._edit.remove_from_order'), + "orders.item.admin_remove(this, '#{url_for(controller: :orders_plugin_admin_item, action: :edit, id: item.id, actor_name: actor_name)}')" + = link_to_function t('views.item._edit.submit'), + "orders.item.submit(this, '#{url_for(controller: :orders_plugin_admin_item, action: :edit, id: item.id, actor_name: actor_name)}')", class: 'submit action-button' - else = link_to t('views.item._edit.remove_from_order'), {controller: :orders_plugin_item, action: :destroy, id: item.id}, remote: true, data: {loading: "#item-#{item.id}"} = link_to_function t('views.item._edit.submit'), "orders.item.submit(this, '#{url_for(controller: :orders_plugin_item, action: :edit, id: item.id)}')", class: 'submit action-button' - = price_with_unit_span item.price_as_currency_number, (item.product.unit rescue item.price_as_currency_number), nil, class: 'box-field' unless @simple + + = price_with_unit_span item.price_as_currency_number, (item.product.unit rescue item.price_as_currency_number), nil, class: 'box-field' unless @view .clean diff --git a/plugins/orders/views/orders_plugin_item/_index.html.slim b/plugins/orders/views/orders_plugin_item/_index.html.slim index 8a73ad2..310c9cf 100644 --- a/plugins/orders/views/orders_plugin_item/_index.html.slim +++ b/plugins/orders/views/orders_plugin_item/_index.html.slim @@ -13,12 +13,11 @@ div class="order-items-container #{"empty" if order.items.size == 0} #{"admin" i - if @admin .box-field.status= t'views.item._index.status' .table-content - .order-items-scroll - - order.items.each do |item| - = render "orders_plugin_item/edit", order: order, item: item, product: item.product, actor_name: actor_name + - order.items.each do |item| + = render "orders_plugin_item/edit", order: order, item: item, product: item.product, actor_name: actor_name .order-total .title= t'views.consumer._total.total' - .value= price_span order.total_price_as_currency_number actor_name + .value= price_span order.total_price_as_currency_number actor_name, @admin - else = t'views.item._index.empty_order' diff --git a/plugins/orders/views/orders_plugin_item/_quantity_price.html.slim b/plugins/orders/views/orders_plugin_item/_quantity_price.html.slim index d0fc075..54c148c 100644 --- a/plugins/orders/views/orders_plugin_item/_quantity_price.html.slim +++ b/plugins/orders/views/orders_plugin_item/_quantity_price.html.slim @@ -6,7 +6,7 @@ div class="quantity-price-row #{status} #{status_data[:flags].keys.join ' '}" = t'views.item._edit.removed' - else = quantity_localized - - if not @simple and status_data[:flags][:editable] + - if not @view and status_data[:flags][:editable] = number_field_tag "item[quantity_#{status_data[:field]}]", status_data[:quantity], step: 'any', onkeydown: 'orders.item.quantity_keydown(this, event)' - unless status_data[:flags][:removed] |  diff --git a/plugins/orders/views/orders_plugin_order/_data.html.slim b/plugins/orders/views/orders_plugin_order/_data.html.slim new file mode 100644 index 0000000..0b4c10a --- /dev/null +++ b/plugins/orders/views/orders_plugin_order/_data.html.slim @@ -0,0 +1,6 @@ += render "orders_plugin_item/index", order: order, actor_name: actor_name, f: f + += render 'orders_plugin_order/actor_data', order: order, f: f, actor_name: other_actor_name if @admin += render 'orders_plugin_order/delivery', order: order, f: f, actor_name: actor_name += render 'orders_plugin_order/payment', order: order + diff --git a/plugins/orders/views/orders_plugin_order/_delivery.html.slim b/plugins/orders/views/orders_plugin_order/_delivery.html.slim new file mode 100644 index 0000000..93f73d0 --- /dev/null +++ b/plugins/orders/views/orders_plugin_order/_delivery.html.slim @@ -0,0 +1,8 @@ +/ read as: selectable or visualizable +- if order.delivery_methods.size > 0 or order.supplier_delivery_data.present? + .delivery-box.order-section + h3= _'Delivery or pickup method' + + - edition = order.may_edit?(user, @admin) && order.delivery_methods.size > 0 if edition.nil? + = render 'delivery_plugin/order_select', f: f, order: order, methods: order.delivery_methods, edition: edition + diff --git a/plugins/orders/views/orders_plugin_order/_show.html.slim b/plugins/orders/views/orders_plugin_order/_show.html.slim index fc73edf..f38e316 100644 --- a/plugins/orders/views/orders_plugin_order/_show.html.slim +++ b/plugins/orders/views/orders_plugin_order/_show.html.slim @@ -30,8 +30,11 @@ div class="order-view #{"editable" if order.may_edit? user, @admin rescue false} - elsif order.open? div = hidden_field_tag "order[status]", 'ordered' - = f.submit t('views.order._show.confirm_order'), confirm: t('views.order._show.confirming_this_order') + = f.submit t('views.order._show.confirm_order'), data: {confirm: t('views.order._show.confirming_this_order')} |  = link_to_function t('views.order._show.cancel_order'), "orders.order.reload(this, '#{url_for controller: :orders_plugin_order, action: :cancel, id: @order.id}')" +javascript: + orders.setOrderMaxHeight() + diff --git a/plugins/orders/views/orders_plugin_order/_show_simple.html.slim b/plugins/orders/views/orders_plugin_order/_show_simple.html.slim new file mode 100644 index 0000000..6085f4d --- /dev/null +++ b/plugins/orders/views/orders_plugin_order/_show_simple.html.slim @@ -0,0 +1,12 @@ +- actor_name ||= :consumer +- other_actor_name = if actor_name == :supplier then :consumer else :supplier end +- @view = true + +.order-view id="order-#{order.id}" + = form_for order, as: :order, url: '', html: {onsubmit: 'return false'} do |f| + .order-data + = render "orders_plugin_item/index", order: order, actor_name: actor_name + = render 'orders_plugin_order/delivery', order: order, actor_name: actor_name, edition: false, f: f + +javascript: + orders.setOrderMaxHeight() diff --git a/plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_cycle_controller.rb b/plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_cycle_controller.rb index a9f94d8..8a71fe1 100644 --- a/plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_cycle_controller.rb +++ b/plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_cycle_controller.rb @@ -22,23 +22,24 @@ class OrdersCyclePluginCycleController < OrdersPluginAdminController end def new - if request.put? + if request.patch? + # can't use profile.orders_cycle here @cycle = OrdersCyclePlugin::Cycle.find params[:id] params[:cycle][:status] = 'orders' if @open = params[:open] == '1' - @success = @cycle.update_attributes params[:cycle] + @success = @cycle.update params[:cycle] if @success session[:notice] = t('controllers.myprofile.cycle_controller.cycle_created') if params[:sendmail] OrdersCyclePlugin::Mailer.delay(run_at: @cycle.start).open_cycle( - @cycle.profile, @cycle ,t('controllers.myprofile.cycle_controller.new_open_cycle')+": "+@cycle.name, @cycle.opening_message) + @cycle.profile, @cycle, "#{t'controllers.myprofile.cycle_controller.new_open_cycle'}: #{@cycle.name}", @cycle.opening_message) end else render action: :edit end else - count = OrdersCyclePlugin::Cycle.count conditions: {profile_id: profile} + count = profile.orders_cycles.maximum(:code) || 1 @cycle = OrdersCyclePlugin::Cycle.create! profile: profile, status: 'new', name: t('controllers.myprofile.cycle_controller.cycle_n_n') % {n: count+1} end @@ -48,13 +49,13 @@ class OrdersCyclePluginCycleController < OrdersPluginAdminController # editing an order return super if params[:actor_name] - @cycle = OrdersCyclePlugin::Cycle.find params[:id] + @cycle = profile.orders_cycles.find params[:id] @products = products if request.xhr? if params[:commit] params[:cycle][:status] = 'orders' if @open = params[:open] == '1' - @success = @cycle.update_attributes params[:cycle] + @success = @cycle.update params[:cycle] if params[:sendmail] OrdersCyclePlugin::Mailer.delay(run_at: @cycle.start).open_cycle(@cycle.profile, @@ -65,7 +66,7 @@ class OrdersCyclePluginCycleController < OrdersPluginAdminController end def products_load - @cycle = OrdersCyclePlugin::Cycle.find params[:id] + @cycle = profile.orders_cycles.find params[:id] @products = products if @cycle.add_products_job @@ -76,34 +77,34 @@ class OrdersCyclePluginCycleController < OrdersPluginAdminController end def destroy - @cycle = OrdersCyclePlugin::Cycle.find params[:id] + @cycle = profile.orders_cycles.find params[:id] @cycle.destroy redirect_to action: :index end def step - @cycle = OrdersCyclePlugin::Cycle.find params[:id] + @cycle = profile.orders_cycles.find params[:id] @cycle.step @cycle.save! redirect_to action: :edit, id: @cycle.id end def step_back - @cycle = OrdersCyclePlugin::Cycle.find params[:id] + @cycle = profile.orders_cycles.find params[:id] @cycle.step_back @cycle.save! redirect_to action: :edit, id: @cycle.id end def add_missing_products - @cycle = OrdersCyclePlugin::Cycle.find params[:id] + @cycle = profile.orders_cycles.find params[:id] @cycle.add_products render partial: 'suppliers_plugin/shared/pagereload' end def report_products return super if params[:ids].present? - @cycle = OrdersCyclePlugin::Cycle.find params[:id] + @cycle = profile.orders_cycles.find params[:id] report_file = report_products_by_supplier @cycle.supplier_products_by_suppliers(@cycle.sales.ordered) send_file report_file, type: 'application/xlsx', @@ -114,7 +115,7 @@ class OrdersCyclePluginCycleController < OrdersPluginAdminController def report_orders return super if params[:ids].present? - @cycle = OrdersCyclePlugin::Cycle.find params[:id] + @cycle = profile.orders_cycles.find params[:id] report_file = report_orders_by_consumer @cycle.sales.ordered send_file report_file, type: 'application/xlsx', diff --git a/plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_item_controller.rb b/plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_item_controller.rb index 0599094..6cfc8a9 100644 --- a/plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_item_controller.rb +++ b/plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_item_controller.rb @@ -31,12 +31,12 @@ class OrdersCyclePluginItemController < OrdersPluginItemController @item.sale = @order @item.product = @offered_product if set_quantity_consumer_ordered(params[:quantity_consumer_ordered] || 1) - @item.update_attributes! quantity_consumer_ordered: @quantity_consumer_ordered + @item.update! quantity_consumer_ordered: @quantity_consumer_ordered end end def edit - return redirect_to params.merge(action: :admin_edit) if @admin_edit + return redirect_to url_for(params.merge action: :admin_edit) if @admin_edit super @offered_product = @item.product @cycle = @order.cycle @@ -50,7 +50,7 @@ class OrdersCyclePluginItemController < OrdersPluginItemController #update on association for total @order.items.each{ |i| i.attributes = params[:item] if i.id == @item.id } - @item.update_attributes = params[:item] + @item.update params[:item] end def destroy diff --git a/plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_product_controller.rb b/plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_product_controller.rb index 8769e80..2e5a10f 100644 --- a/plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_product_controller.rb +++ b/plugins/orders_cycle/controllers/myprofile/orders_cycle_plugin_product_controller.rb @@ -25,7 +25,7 @@ class OrdersCyclePluginProductController < SuppliersPlugin::ProductController def cycle_edit @product = OrdersCyclePlugin::OfferedProduct.find params[:id] if request.xhr? - @product.update_attributes! params[:product] + @product.update! params[:product] respond_to do |format| format.js end diff --git a/plugins/orders_cycle/controllers/profile/orders_cycle_plugin_order_controller.rb b/plugins/orders_cycle/controllers/profile/orders_cycle_plugin_order_controller.rb index b4974b6..f162835 100644 --- a/plugins/orders_cycle/controllers/profile/orders_cycle_plugin_order_controller.rb +++ b/plugins/orders_cycle/controllers/profile/orders_cycle_plugin_order_controller.rb @@ -38,7 +38,7 @@ class OrdersCyclePluginOrderController < OrdersPluginOrderController @order.consumer = @consumer @order.cycle = @cycle @order.save! - redirect_to params.merge(action: :edit, id: @order.id) + redirect_to url_for(params.merge action: :edit, id: @order.id) end end @@ -55,7 +55,7 @@ class OrdersCyclePluginOrderController < OrdersPluginOrderController end @repeat_order.supplier_delivery = @order.supplier_delivery @repeat_order.save! - redirect_to params.merge(action: :edit, id: @repeat_order.id) + redirect_to url_for(params.merge action: :edit, id: @repeat_order.id) else @orders = @cycle.consumer_previous_orders(@consumer).last(5).reverse @orders.each{ |o| o.enable_product_diff } @@ -72,7 +72,7 @@ class OrdersCyclePluginOrderController < OrdersPluginOrderController if status == 'ordered' if @order.items.size > 0 @order.to_yaml # most strange workaround to avoid a crash in the next line - @order.update_attributes! params[:order] + @order.update! params[:order] session[:notice] = t('orders_plugin.controllers.profile.consumer.order_confirmed') else session[:notice] = t('orders_plugin.controllers.profile.consumer.can_not_confirm_your_') @@ -117,12 +117,12 @@ class OrdersCyclePluginOrderController < OrdersPluginOrderController end def reopen - @order.update_attributes! status: 'draft' + @order.update! status: 'draft' render 'edit' end def cancel - @order.update_attributes! status: 'cancelled' + @order.update! status: 'cancelled' session[:notice] = t('orders_plugin.controllers.profile.consumer.order_cancelled') render 'edit' end @@ -162,7 +162,7 @@ class OrdersCyclePluginOrderController < OrdersPluginOrderController end def supplier_balloon - @supplier = SuppliersPlugin::Supplier.find params[:id] + @supplier = profile.suppliers.find params[:id] end def product_balloon @product = OrdersCyclePlugin::OfferedProduct.find params[:id] diff --git a/plugins/orders_cycle/db/migrate/20140406155248_refactor_orders_cycle_plugin_cycle_order.rb b/plugins/orders_cycle/db/migrate/20140406155248_refactor_orders_cycle_plugin_cycle_order.rb index e63742f..a73d0dd 100644 --- a/plugins/orders_cycle/db/migrate/20140406155248_refactor_orders_cycle_plugin_cycle_order.rb +++ b/plugins/orders_cycle/db/migrate/20140406155248_refactor_orders_cycle_plugin_cycle_order.rb @@ -4,9 +4,7 @@ class RefactorOrdersCyclePluginCycleOrder < ActiveRecord::Migration rename_column :orders_cycle_plugin_cycle_orders, :order_id, :sale_id add_column :orders_cycle_plugin_cycle_orders, :purchase_id, :integer - add_index :orders_cycle_plugin_cycle_orders, :sale_id add_index :orders_cycle_plugin_cycle_orders, :purchase_id - add_index :orders_cycle_plugin_cycle_orders, [:cycle_id, :sale_id] add_index :orders_cycle_plugin_cycle_orders, [:cycle_id, :purchase_id], name: :index_orders_cycle_plugin_cycle_orders_cycle_purchase end diff --git a/plugins/orders_cycle/lib/ext/delivery_plugin/option.rb b/plugins/orders_cycle/lib/ext/delivery_plugin/option.rb index 33787fc..b3a8471 100644 --- a/plugins/orders_cycle/lib/ext/delivery_plugin/option.rb +++ b/plugins/orders_cycle/lib/ext/delivery_plugin/option.rb @@ -2,7 +2,8 @@ require_dependency 'delivery_plugin/option' class DeliveryPlugin::Option - belongs_to :cycle, class_name: 'OrdersCyclePlugin::Cycle', - foreign_key: :owner_id, conditions: ["delivery_plugin_options.owner_type = 'OrdersCyclePlugin::Cycle'"] + belongs_to :cycle, -> { + where "delivery_plugin_options.owner_type = 'OrdersCyclePlugin::Cycle'" + }, class_name: 'OrdersCyclePlugin::Cycle', foreign_key: :owner_id end diff --git a/plugins/orders_cycle/lib/ext/profile.rb b/plugins/orders_cycle/lib/ext/profile.rb index 953dcc7..cdd91b5 100644 --- a/plugins/orders_cycle/lib/ext/profile.rb +++ b/plugins/orders_cycle/lib/ext/profile.rb @@ -1,19 +1,30 @@ require_dependency 'profile' +require_dependency 'community' -class Profile +([Profile] + Profile.descendants).each do |subclass| +subclass.class_eval do + + has_many :orders_cycles, -> { + order('created_at DESC'). + where "orders_cycle_plugin_cycles.status <> 'new'" + }, foreign_key: :profile_id, class_name: 'OrdersCyclePlugin::Cycle', dependent: :destroy - has_many :orders_cycles, class_name: 'OrdersCyclePlugin::Cycle', dependent: :destroy, order: 'created_at DESC', - conditions: ["orders_cycle_plugin_cycles.status <> 'new'"] - has_many :orders_cycles_without_order, class_name: 'OrdersCyclePlugin::Cycle', - conditions: ["orders_cycle_plugin_cycles.status <> 'new'"] + has_many :orders_cycles_without_order, -> { + where "orders_cycle_plugin_cycles.status <> 'new'" + }, foreign_key: :profile_id, class_name: 'OrdersCyclePlugin::Cycle' has_many :orders_cycles_sales, through: :orders_cycles, source: :sales has_many :orders_cycles_purchases, through: :orders_cycles, source: :purchases - has_many :offered_products, class_name: 'OrdersCyclePlugin::OfferedProduct', order: 'products.name ASC' + has_many :offered_products, -> { reorder 'products.name ASC' }, class_name: 'OrdersCyclePlugin::OfferedProduct' + +end +end + +class Profile def orders_cycles_closed_date_range - list = self.orders_cycles.closing.all order: 'start ASC' + list = self.orders_cycles.closing.order('start ASC').all return DateTime.now..DateTime.now if list.blank? list.first.start.to_date..list.last.finish.to_date end diff --git a/plugins/orders_cycle/models/orders_cycle_plugin/cycle.rb b/plugins/orders_cycle/models/orders_cycle_plugin/cycle.rb index 5d3f178..d6a1269 100644 --- a/plugins/orders_cycle/models/orders_cycle_plugin/cycle.rb +++ b/plugins/orders_cycle/models/orders_cycle_plugin/cycle.rb @@ -32,30 +32,32 @@ class OrdersCyclePlugin::Cycle < ActiveRecord::Base belongs_to :profile - has_many :delivery_options, class_name: 'DeliveryPlugin::Option', dependent: :destroy, - as: :owner, conditions: ["delivery_plugin_options.owner_type = 'OrdersCyclePlugin::Cycle'"] + has_many :delivery_options, -> { + where "delivery_plugin_options.owner_type = 'OrdersCyclePlugin::Cycle'" + }, class_name: 'DeliveryPlugin::Option', dependent: :destroy, as: :owner has_many :delivery_methods, through: :delivery_options, source: :delivery_method - has_many :cycle_orders, class_name: 'OrdersCyclePlugin::CycleOrder', foreign_key: :cycle_id, dependent: :destroy, order: 'id ASC' + has_many :cycle_orders, -> { order 'id ASC' }, class_name: 'OrdersCyclePlugin::CycleOrder', foreign_key: :cycle_id, dependent: :destroy # cannot use :order because of months/years named_scope has_many :sales, through: :cycle_orders, source: :sale has_many :purchases, through: :cycle_orders, source: :purchase has_many :cycle_products, foreign_key: :cycle_id, class_name: 'OrdersCyclePlugin::CycleProduct', dependent: :destroy - has_many :products, through: :cycle_products, source: :product, order: 'products.name ASC', - include: [ :from_2x_products, :from_products, {profile: :domains}, ] + has_many :products, -> { + includes(:from_2x_products, :from_products, {profile: :domains}) + }, through: :cycle_products, class_name: 'OrdersCyclePlugin::OfferedProduct', source: :product - has_many :consumers, through: :sales, source: :consumer, order: 'name ASC', uniq: true - has_many :suppliers, through: :products, source: :suppliers, order: 'suppliers_plugin_suppliers.name ASC', uniq: true - has_many :orders_suppliers, through: :sales, source: :profile, order: 'name ASC' + has_many :consumers, -> { distinct.reorder 'name ASC' }, through: :sales, source: :consumer + has_many :suppliers, -> { group 'suppliers_plugin_suppliers.id' }, through: :products + has_many :orders_suppliers, -> { reorder 'name ASC' }, through: :sales, source: :profile - has_many :from_products, through: :products, order: 'name ASC', uniq: true - has_many :supplier_products, through: :products, order: 'name ASC', uniq: true - has_many :product_categories, through: :products, order: 'name ASC', uniq: true + has_many :from_products, -> { distinct.reorder 'name ASC' }, through: :products + has_many :supplier_products, -> { distinct.reorder 'name ASC' }, through: :products + has_many :product_categories, -> { distinct.reorder 'name ASC' }, through: :products - has_many :orders_confirmed, through: :cycle_orders, source: :sale, order: 'id ASC', - conditions: ['orders_plugin_orders.ordered_at IS NOT NULL'] + has_many :orders_confirmed, -> { reorder('id ASC').where 'orders_plugin_orders.ordered_at IS NOT NULL' }, + through: :cycle_orders, source: :sale has_many :items_selled, through: :sales, source: :items has_many :items_purchased, through: :purchases, source: :items @@ -64,16 +66,16 @@ class OrdersCyclePlugin::Cycle < ActiveRecord::Base has_many :ordered_suppliers, through: :orders_confirmed, source: :suppliers - has_many :ordered_offered_products, through: :orders_confirmed, source: :offered_products, uniq: true, include: [:suppliers] - has_many :ordered_distributed_products, through: :orders_confirmed, source: :distributed_products, uniq: true, include: [:suppliers] - has_many :ordered_supplier_products, through: :orders_confirmed, source: :supplier_products, uniq: true, include: [:suppliers] + has_many :ordered_offered_products, -> { distinct.includes :suppliers }, through: :orders_confirmed, source: :offered_products + has_many :ordered_distributed_products, -> { distinct.includes :suppliers }, through: :orders_confirmed, source: :distributed_products + has_many :ordered_supplier_products, -> { distinct.includes :suppliers }, through: :orders_confirmed, source: :supplier_products has_many :volunteers_periods, class_name: 'VolunteersPlugin::Period', as: :owner has_many :volunteers, through: :volunteers_periods, source: :profile attr_accessible :volunteers_periods_attributes accepts_nested_attributes_for :volunteers_periods, allow_destroy: true - scope :has_volunteers_periods, -> {uniq.joins [:volunteers_periods]} + scope :has_volunteers_periods, -> { distinct.joins :volunteers_periods } # status scopes scope :on_edition, -> { where status: 'edition' } @@ -83,33 +85,29 @@ class OrdersCyclePlugin::Cycle < ActiveRecord::Base scope :on_delivery, -> { where status: 'delivery' } scope :on_closing, -> { where status: 'closing' } - scope :defuncts, conditions: ["status = 'new' AND created_at < ?", 2.days.ago] - scope :not_new, conditions: ["status <> 'new'"] - scope :on_orders, lambda { - {conditions: ["status = 'orders' AND ( (start <= :now AND finish IS NULL) OR (start <= :now AND finish >= :now) )", - {now: DateTime.now}]} + scope :defuncts, -> { where "status = 'new' AND created_at < ?", 2.days.ago } + scope :not_new, -> { where "status <> 'new'" } + scope :on_orders, -> { + where "status = 'orders' AND ( (start <= :now AND finish IS NULL) OR (start <= :now AND finish >= :now) )", now: DateTime.now } - scope :not_on_orders, lambda { - {conditions: ["NOT (status = 'orders' AND ( (start <= :now AND finish IS NULL) OR (start <= :now AND finish >= :now) ) )", - {now: DateTime.now}]} + scope :not_on_orders, -> { + where "NOT (status = 'orders' AND ( (start <= :now AND finish IS NULL) OR (start <= :now AND finish >= :now) ) )", now: DateTime.now } - scope :opened, conditions: ["status <> 'new' AND status <> 'closing'"] - scope :closing, conditions: ["status = 'closing'"] - scope :by_status, lambda { |status| { conditions: {status: status} } } + scope :opened, -> { where "status <> 'new' AND status <> 'closing'" } + scope :closing, -> { where "status = 'closing'" } + scope :by_status, -> (status) { where status: status } - scope :months, select: 'DISTINCT(EXTRACT(months FROM start)) as month', order: 'month DESC' - scope :years, select: 'DISTINCT(EXTRACT(YEAR FROM start)) as year', order: 'year DESC' + scope :months, -> { order('month DESC').select 'DISTINCT(EXTRACT(months FROM start)) as month' } + scope :years, -> { order('year DESC').select 'DISTINCT(EXTRACT(YEAR FROM start)) as year' } - scope :by_month, lambda { |month| { - conditions: [ 'EXTRACT(month FROM start) <= :month AND EXTRACT(month FROM finish) >= :month', { month: month } ]} + scope :by_month, -> (month) { + where 'EXTRACT(month FROM start) <= :month AND EXTRACT(month FROM finish) >= :month', month: month } - scope :by_year, lambda { |year| { - conditions: [ 'EXTRACT(year FROM start) <= :year AND EXTRACT(year FROM finish) >= :year', { year: year } ]} + scope :by_year, -> (year) { + where 'EXTRACT(year FROM start) <= :year AND EXTRACT(year FROM finish) >= :year', year: year } - scope :by_range, lambda { |range| { - conditions: [ 'start BETWEEN :start AND :finish OR finish BETWEEN :start AND :finish', - { start: range.first, finish: range.last } - ]} + scope :by_range, -> (range) { + where 'start BETWEEN :start AND :finish OR finish BETWEEN :start AND :finish', start: range.first, finish: range.last } validates_presence_of :profile @@ -122,7 +120,7 @@ class OrdersCyclePlugin::Cycle < ActiveRecord::Base validate :validate_orders_dates, if: :not_new? validate :validate_delivery_dates, if: :not_new? - before_validation :step_new + before_save :step_new before_validation :update_orders_status before_save :add_products_on_edition_state after_create :delay_purge_profile_defuncts @@ -212,9 +210,7 @@ class OrdersCyclePlugin::Cycle < ActiveRecord::Base end def products_for_order - # FIXME name alias conflict - #self.products.unarchived.with_price.order('products.name ASC') - self.products.unarchived.with_price + self.products.unarchived.alphabetically.with_price end def supplier_products_by_suppliers orders = self.sales.ordered @@ -261,27 +257,27 @@ class OrdersCyclePlugin::Cycle < ActiveRecord::Base end def step_new - return if new_record? + return if self.new_record? self.step if self.new? end def update_sales_status from, to sales = self.sales.where(status: from.to_s) sales.each do |sale| - sale.update_attributes status: to.to_s + sale.update status: to.to_s end end def update_purchases_status from, to purchases = self.purchases.where(status: from.to_s) purchases.each do |purchase| - purchase.update_attributes status: to.to_s + purchase.update status: to.to_s end end def update_orders_status - # step orders to next_status on status change - return if self.new? or self.status_was == "new" or self.status_was == self.status + return if self.new? or self.status_was == "new" + return if self.status_was == self.status # Don't rewind confirmed sales unless self.status_was == 'orders' and self.status == 'edition' diff --git a/plugins/orders_cycle/models/orders_cycle_plugin/offered_product.rb b/plugins/orders_cycle/models/orders_cycle_plugin/offered_product.rb index 3affbcc..704fdb0 100644 --- a/plugins/orders_cycle/models/orders_cycle_plugin/offered_product.rb +++ b/plugins/orders_cycle/models/orders_cycle_plugin/offered_product.rb @@ -1,5 +1,8 @@ class OrdersCyclePlugin::OfferedProduct < SuppliersPlugin::BaseProduct + # we work use frozen attributes + self.default_delegate_enable = false + # FIXME: WORKAROUND for https://github.com/rails/rails/issues/6663 # OrdersCyclePlugin::Sale.find(3697).cycle.suppliers returns empty without this def self.finder_needs_type_condition? @@ -19,10 +22,10 @@ class OrdersCyclePlugin::OfferedProduct < SuppliersPlugin::BaseProduct has_one :sources_supplier_product, through: :from_product, source: :sources_from_product # necessary only due to the override of sources_supplier_products, as rails somehow caches the old reference # copied from suppliers/lib/ext/product - has_many :supplier_products, through: :sources_supplier_products, source: :from_product, order: 'id ASC' - has_one :supplier_product, through: :sources_supplier_product, source: :from_product, order: 'id ASC', autosave: true - has_many :suppliers, through: :sources_supplier_products, uniq: true, order: 'id ASC' - has_one :supplier, through: :sources_supplier_product, order: 'id ASC' + has_many :supplier_products, -> { order 'id ASC' }, through: :sources_supplier_products, source: :from_product + has_one :supplier_product, -> { order 'id ASC' }, through: :sources_supplier_product, source: :from_product, autosave: true + has_many :suppliers, -> { distinct.order 'id ASC' }, through: :sources_supplier_products + has_one :supplier, -> { order 'id ASC' }, through: :sources_supplier_product instance_exec &OrdersPlugin::Item::DefineTotals extend CurrencyHelper::ClassMethods @@ -31,9 +34,7 @@ class OrdersCyclePlugin::OfferedProduct < SuppliersPlugin::BaseProduct # test this before use! #validates_presence_of :cycle - # remove on rails4 - scope :with_price, conditions: 'products.price > 0' - scope :with_product_category_id, lambda { |id| { conditions: {product_category_id: id} } } + # override SuppliersPlugin::BaseProduct def self.search_scope scope, params scope = scope.from_supplier_id params[:supplier_id] if params[:supplier_id].present? scope = scope.with_available(if params[:available] == 'true' then true else false end) if params[:available].present? @@ -50,19 +51,20 @@ class OrdersCyclePlugin::OfferedProduct < SuppliersPlugin::BaseProduct op.profile = product.profile op.type = self.name - op.from_products << product + op.from_product = product cycle.products << op if cycle op end # always recalculate in case something has changed + # FIXME: really? it is already copied! def margin_percentage - return self['margin_percentage'] if price.nil? or buy_price.nil? or price.zero? or buy_price.zero? + return super if price.nil? or buy_price.nil? or price.zero? or buy_price.zero? ((price / buy_price) - 1) * 100 end def margin_percentage= value - self['margin_percentage'] = value + super value self.price = self.price_with_margins buy_price end @@ -71,22 +73,15 @@ class OrdersCyclePlugin::OfferedProduct < SuppliersPlugin::BaseProduct end # reimplement to don't destroy this, keeping history in cycles - # offered products copy attributes + # as offered products copy attributes. def dependent? false end - # cycle products freezes properties and don't use the original - DEFAULT_ATTRIBUTES.each do |a| - define_method "default_#{a}" do - nil - end - end - FROOZEN_DEFAULT_ATTRIBUTES = DEFAULT_ATTRIBUTES def freeze_default_attributes from_product FROOZEN_DEFAULT_ATTRIBUTES.each do |attr| - self[attr] = from_product.send(attr) if from_product[attr] or from_product.respond_to? attr + self.send "#{attr}=", from_product.send(attr) if from_product[attr] or from_product.respond_to? attr end end diff --git a/plugins/orders_cycle/models/orders_cycle_plugin/order_base.rb b/plugins/orders_cycle/models/orders_cycle_plugin/order_base.rb index 5446b18..9f47b3b 100644 --- a/plugins/orders_cycle/models/orders_cycle_plugin/order_base.rb +++ b/plugins/orders_cycle/models/orders_cycle_plugin/order_base.rb @@ -14,26 +14,18 @@ module OrdersCyclePlugin::OrderBase self.cycle_sales.includes(:cycle).map(&:cycle) + self.cycle_purchases.includes(:cycle).map(&:cycle) end - # TODO: test if the has_one defined on Sale/Purchase works and these are not needed - def cycle - self.cycles.first - end - def cycle= cycle - self.cycles = [cycle] - end - scope :for_cycle, -> (cycle) { where('orders_cycle_plugin_cycles.id = ?', cycle.id). joins(:cycles) } - has_many :items, class_name: 'OrdersCyclePlugin::Item', foreign_key: :order_id, dependent: :destroy, order: 'name ASC' + has_many :items, -> { order 'name ASC' }, class_name: 'OrdersCyclePlugin::Item', foreign_key: :order_id, dependent: :destroy - has_many :offered_products, through: :items, source: :offered_product, uniq: true - has_many :distributed_products, through: :offered_products, source: :from_products, uniq: true - has_many :supplier_products, through: :distributed_products, source: :from_products, uniq: true + has_many :offered_products, -> { distinct }, through: :items, source: :offered_product + has_many :distributed_products, -> { distinct }, through: :offered_products, source: :from_products + has_many :supplier_products, -> { distinct }, through: :distributed_products, source: :from_products - has_many :suppliers, through: :supplier_products, uniq: true + has_many :suppliers, -> { distinct }, through: :supplier_products extend CodeNumbering::ClassMethods code_numbering :code, scope: (proc do diff --git a/plugins/orders_cycle/models/orders_cycle_plugin/sale.rb b/plugins/orders_cycle/models/orders_cycle_plugin/sale.rb index 1b1ccc2..eca127d 100644 --- a/plugins/orders_cycle/models/orders_cycle_plugin/sale.rb +++ b/plugins/orders_cycle/models/orders_cycle_plugin/sale.rb @@ -24,10 +24,6 @@ class OrdersCyclePlugin::Sale < OrdersPlugin::Sale super and self.cycle.orders? end - def supplier_delivery - super || (self.cycle.delivery_methods.first rescue nil) - end - def change_purchases return unless self.status_was.present? if self.ordered_at_was.nil? and self.ordered_at.present? diff --git a/plugins/orders_cycle/test/factories.rb b/plugins/orders_cycle/test/factories.rb new file mode 100644 index 0000000..021fdaf --- /dev/null +++ b/plugins/orders_cycle/test/factories.rb @@ -0,0 +1,57 @@ +module OrdersCyclePlugin::Factory + + def defaults_for_suppliers_plugin_supplier + {:profile => build(Profile), + :consumer => build(Profile)} + end + + def defaults_for_suppliers_plugin_distributed_product attrs = {} + profile = attrs[:profile] || build(Profile) + {:profile => profile, :name => "product-#{factory_num_seq}", :price => 2.0, + :product => build(Product, :enterprise => profile.profile, :price => 2.0), + :supplier => build(SuppliersPlugin::Supplier, :profile => profile, :consumer => profile)} + end + + def defaults_for_orders_cycle_plugin_offered_product attrs = {} + hash = defaults_for_orders_cycle_plugin_product(attrs) + profile = hash[:profile] + hash.merge({ + :from_products => [build(SuppliersPlugin::DistributedProduct, :profile => profile)]}) + end + + def defaults_for_delivery_plugin_method + {:profile => build(OrdersCyclePlugin::Profile), + :name => "My delivery #{factory_num_seq.to_s}", + :delivery_type => 'deliver'} + end + + def defaults_for_delivery_plugin_option + {:cycle => build(OrdersCyclePlugin::Cycle), + :delivery_method => build(DeliveryPlugin::Method)} + end + + def defaults_for_orders_plugin_order attrs = {} + profile = attrs[:profile] || build(OrdersCyclePlugin::Profile) + {:status => 'ordered', + :cycle => build(OrdersCyclePlugin::Cycle, :profile => profile), + :consumer => build(OrdersCyclePlugin::Profile), + :supplier_delivery => build(DeliveryPlugin::Method, :profile => profile), + :consumer_delivery => build(DeliveryPlugin::Method, :profile => profile)} + end + + def defaults_for_orders_plugin_items + {:order => build(OrdersPlugin::Order), + :product => build(OrdersCyclePlugin::OfferedProduct), + :quantity_shipped => 1.0, :quantity_ordered => 2.0, :quantity_accepted => 3.0, + :price_shipped => 10.0, :price_ordered => 20.0, :price_accepted => 30.0} + end + + def defaults_for_orders_cycle_plugin_cycle + {:profile => build(OrdersCyclePlugin::Profile), :status => 'orders', + :name => 'weekly', :start => Time.now, :finish => Time.now+1.days} + end + +end + +Noosfero::Factory.register_extension OrdersCyclePlugin::Factory + diff --git a/plugins/orders_cycle/test/functional/orders_cycle_plugin/order_controller_test.rb b/plugins/orders_cycle/test/functional/orders_cycle_plugin/order_controller_test.rb new file mode 100644 index 0000000..9a93fce --- /dev/null +++ b/plugins/orders_cycle/test/functional/orders_cycle_plugin/order_controller_test.rb @@ -0,0 +1,12 @@ +require "#{File.dirname(__FILE__)}/../../test_helper" + +class OrdersCyclePlugin::OrderControllerTest < Test::Unit::TestCase + + def setup + @controller = OrdersCyclePluginOrderController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + +end diff --git a/plugins/orders_cycle/test/functional/orders_cycle_plugin/session_controller_test.rb b/plugins/orders_cycle/test/functional/orders_cycle_plugin/session_controller_test.rb new file mode 100644 index 0000000..7ab2402 --- /dev/null +++ b/plugins/orders_cycle/test/functional/orders_cycle_plugin/session_controller_test.rb @@ -0,0 +1,14 @@ +require "#{File.dirname(__FILE__)}/../../test_helper" + +class OrdersCyclePlugin::CycleControllerTest < Test::Unit::TestCase + + def setup + @controller = OrdersCyclePluginCycleController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + end + + should 'create a new cycle' do + end + +end diff --git a/plugins/orders_cycle/test/test_helper.rb b/plugins/orders_cycle/test/test_helper.rb new file mode 100644 index 0000000..3f0b088 --- /dev/null +++ b/plugins/orders_cycle/test/test_helper.rb @@ -0,0 +1,6 @@ +require File.dirname(__FILE__) + '/../../../test/test_helper' +require 'spec' + +class ActiveRecord::TestCase < ActiveSupport::TestCase + include OrdersCyclePluginFactory +end diff --git a/plugins/orders_cycle/test/unit/orders_cycle_plugin/cycle_test.rb b/plugins/orders_cycle/test/unit/orders_cycle_plugin/cycle_test.rb new file mode 100644 index 0000000..7c09b02 --- /dev/null +++ b/plugins/orders_cycle/test/unit/orders_cycle_plugin/cycle_test.rb @@ -0,0 +1,27 @@ +require "#{File.dirname(__FILE__)}/../../test_helper" + +class OrdersCyclePlugin::CycleTest < ActiveSupport::TestCase + + def setup + @profile = Enterprise.create!(:name => "trocas verdes", :identifier => "trocas-verdes") + @pc = ProductCategory.create!(:name => 'frutas', :environment_id => 1) + @profile.products = [Product.create!(:name => 'banana', :product_category => @pc), + Product.new(:name => 'mandioca', :product_category => @pc), Product.new(:name => 'alface', :product_category => @pc)] + + profile.offered_products = @profile.products.map{ |p| OrdersCyclePlugin::OfferedProduct.create!(:product => p) } + DeliveryPlugin::Method.create! :name => 'at home', :delivery_type => 'pickup', :profile => @profile + @cycle = OrdersCyclePlugin::Cycle.create!(:profile => @profile) + end + + should 'add products from profile after create' do + assert_equal @cycle.products.collect(&:product_id), @profile.products.collect(&:id) + end + + should 'have at least one delivery method unless in edition status' do + cycle = OrdersCyclePlugin::Cycle.create! :profile => @profile, :name => "Testes batidos", :start => DateTime.now, :status => 'edition' + assert cycle + cycle.status = 'orders' + assert_nil cycle.save! + end + +end diff --git a/plugins/orders_cycle/test/unit/orders_cycle_plugin/offered_product_test.rb b/plugins/orders_cycle/test/unit/orders_cycle_plugin/offered_product_test.rb new file mode 100644 index 0000000..7a92fde --- /dev/null +++ b/plugins/orders_cycle/test/unit/orders_cycle_plugin/offered_product_test.rb @@ -0,0 +1,6 @@ +require "#{File.dirname(__FILE__)}/../../test_helper" + +class OrdersCyclePlugin::OfferedProductTest < ActiveSupport::TestCase + + +end diff --git a/plugins/orders_cycle/test/unit/profile_test.rb b/plugins/orders_cycle/test/unit/profile_test.rb new file mode 100644 index 0000000..2d656fb --- /dev/null +++ b/plugins/orders_cycle/test/unit/profile_test.rb @@ -0,0 +1,127 @@ +require "#{File.dirname(__FILE__)}/../../test_helper" + +class OrdersCyclePlugin::ProfileTest < ActiveRecord::TestCase + + def setup + @profile = build(Profile) + @invisible_profile = build(Enterprise, :visible => false) + @other_profile = build(Enterprise) + @profile = build(OrdersCyclePlugin::profile, :profile => @profile) + @self_supplier = build(OrdersCyclePlugin::Supplier, :consumer => @profile, :profile => @profile) + @dummy_supplier = build(OrdersCyclePlugin::Supplier, :consumer => @profile, :profile => @dummy_profile) + @other_supplier = build(OrdersCyclePlugin::Supplier, :consumer => @profile, :profile => @other_profile) + end + + attr_accessor :profile, :invisible_profile, :other_profile, + :self_supplier, :dummy_supplier, :other_supplier + + should 'respond to name methods' do + profile.expects(:name).returns('name') + assert_equal 'name', profile.name + end + + should 'respond to dummy methods' do + profile.dummy = true + assert_equal true, profile.dummy? + profile.dummy = false + assert_equal false, profile.dummy + end + + should "return closed cycles' date range" do + DateTime.expects(:now).returns(1).at_least_once + assert_equal 1..1, profile.orders_cycles_closed_date_range + s1 = create(OrdersCyclePlugin::Cycle, :profile => profile, :start => Time.now-1.days, :finish => nil) + s2 = create(OrdersCyclePlugin::Cycle, :profile => profile, :finish => Time.now+1.days, :start => Time.now) + assert_equal (s1.start.to_date..s2.finish.to_date), profile.orders_cycles_closed_date_range + end + + should 'return abbreviation or the name' do + profile.name_abbreviation = 'coll.' + profile.profile.name = 'collective' + assert_equal 'coll.', profile.abbreviation_or_name + profile.name_abbreviation = nil + assert_equal 'collective', profile.abbreviation_or_name + end + + ### + # Products + ### + + should "default products's margins when asked" do + profile.update! :margin_percentage => 10 + product = create(SuppliersPlugin::DistributedProduct, :profile => profile, :supplier => profile.self_supplier, + :price => 10, :default_margin_percentage => false) + cycle = create(OrdersCyclePlugin::Cycle, :profile => profile) + sproduct = cycle.products.first + sproduct.update! :margin_percentage => 5 + cycleclosed = create(OrdersCyclePlugin::Cycle, :profile => profile, :status => 'closed') + + profile.orders_cycles_products_default_margins + product.reload + sproduct.reload + assert_equal true, product.default_margin_percentage + assert_equal sproduct.margin_percentage, profile.margin_percentage + end + + should 'return not yet distributed products' do + profile.save! + other_profile.save! + other_supplier.save! + product = create(SuppliersPlugin::DistributedProduct, :profile => other_profile, :supplier => other_profile.self_supplier) + profile.add_supplier_products other_supplier + product2 = create(SuppliersPlugin::DistributedProduct, :profile => other_profile, :supplier => other_profile.self_supplier) + assert_equal [product2], profile.not_distributed_products(other_supplier) + end + + ### + # Suppliers + ### + + should 'add supplier' do + @profile.save! + @other_profile.save! + + assert_difference OrdersCyclePlugin::Supplier, :count do + @profile.add_supplier @other_profile + end + assert @profile.suppliers_profiles.include?(@other_profile) + assert @other_profile.consumers_profiles.include?(@profile) + end + + should "add all supplier's products when supplier is added" do + @profile.save! + @other_profile.save! + product = create(SuppliersPlugin::DistributedProduct, :profile => @other_profile) + @profile.add_supplier @other_profile + assert_equal [product], @profile.from_products + end + + should 'remove supplier' do + @profile.save! + @other_profile.save! + + @profile.add_supplier @other_profile + assert_difference OrdersCyclePlugin::Supplier, :count, -1 do + assert_difference RoleAssignment, :count, -1 do + @profile.remove_supplier @other_profile + end + end + assert !@profile.suppliers_profiles.include?(@other_profile) + end + + should "archive supplier's products when supplier is removed" do + @profile.save! + @other_profile.save! + product = create(SuppliersPlugin::DistributedProduct, :profile => @other_profile) + @profile.add_supplier @other_profile + @profile.remove_supplier @other_profile + assert_equal [product], @profile.from_products + assert_equal 1, @profile.distributed_products.archived.count + end + + should 'create self supplier automatically' do + profile = create(OrdersCyclePlugin::profile, :profile => @profile) + assert_equal 1, profile.suppliers.count + end + +end diff --git a/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_cycle_sales.html.slim b/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_cycle_sales.html.slim index 052c676..550e7ac 100644 --- a/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_cycle_sales.html.slim +++ b/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_cycle_sales.html.slim @@ -1,2 +1,3 @@ = render 'orders_plugin_admin/sales', actors: @cycle.consumers, orders_owner: @cycle, owner_id: @cycle.id, orders: @cycle.sales.default_order.paginate(per_page: 30, page: params[:page]) + diff --git a/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_edit_fields.html.slim b/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_edit_fields.html.slim index 2e10b03..241b9a2 100644 --- a/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_edit_fields.html.slim +++ b/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_edit_fields.html.slim @@ -53,6 +53,5 @@ h3= t('views.cycle._edit_fields.general_settings') = link_to t('views.cycle._edit_fields.cancel_changes'), @cycle.new? ? {action: :index} : params - unless @cycle.new? |  - = link_to t('views.cycle._edit_fields.remove'), {action: :destroy, id: @cycle.id}, confirm: t('views.cycle._edit_fields.confirm_remove') - + = link_to t('views.cycle._edit_fields.remove'), {action: :destroy, id: @cycle.id}, data: {confirm: t('views.cycle._edit_fields.confirm_remove')} diff --git a/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_product_lines.html.erb b/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_product_lines.html.erb index 36591fb..47ae96d 100644 --- a/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_product_lines.html.erb +++ b/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_product_lines.html.erb @@ -1,7 +1,7 @@
<%= pagination_links @products %>
- <%= t('views.cycle._product_lines.showing_pcount_produc') % {:pcount => @products.length, :allpcount => @cycle.products.count} %> + <%= t('views.cycle._product_lines.showing_pcount_produc') % {pcount: @products.length, allpcount: @cycle.products.count} %>
<%= t('views.cycle._product_lines.category') %> @@ -17,7 +17,7 @@
<% @products.each do |p| %>
- <%= render 'orders_cycle_plugin_product/cycle_edit', :p => p %> + <%= render 'orders_cycle_plugin_product/cycle_edit', p: p %>
<% end %> <%= javascript_tag do %> diff --git a/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_products_loading.html.erb b/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_products_loading.html.erb index 36b3933..1a68fbd 100644 --- a/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_products_loading.html.erb +++ b/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_products_loading.html.erb @@ -3,7 +3,7 @@ <%= t('views.cycle._products_loading') %> <%= javascript_tag do %> - orders_cycle.cycle.products.load_url = <%= url_for(:action => :products_load, :id => @cycle.id).to_json %> + orders_cycle.cycle.products.load_url = <%= url_for(action: :products_load, id: @cycle.id).to_json %> orders_cycle.cycle.products.load() <% end %>
diff --git a/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_timeline.html.slim b/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_timeline.html.slim new file mode 100644 index 0000000..d09d083 --- /dev/null +++ b/plugins/orders_cycle/views/orders_cycle_plugin_cycle/_timeline.html.slim @@ -0,0 +1,30 @@ +- actions = true if actions.nil? and @admin +- listing = false if listing.nil? +- view_status = if OrdersCyclePlugin::Cycle::Statuses.index(params[:view]) then params[:view] else cycle.status end +- status_text = t"models.cycle.statuses.#{view_status}" + +.cycle-timeline + - OrdersCyclePlugin::Cycle::UserStatuses.each do |status| + - klass = "cycle-timeline-item #{timeline_class cycle, status, view_status}" + - name = t("models.cycle.statuses.#{status}") + = link_to name, params.merge(action: :edit, id: cycle.id, view: status), class: klass + +- if listing + .dates-brief + .date + span.field-title= t'views.cycle._brief.orders' + |  + span= datetime_period_short cycle.start, cycle.finish + .date + span.field-title= t'views.cycle._brief.delivery' + |  + span= datetime_period_short cycle.delivery_start, cycle.delivery_finish + +- if actions + .actions-bar + - if cycle.status == view_status and cycle.status != 'closing' + = link_to t('views.cycle._timeline.close_status') % {status: status_text}, + {action: :step, id: cycle.id, method: :post}, + {confirm: t('views.cycle._timeline.are_you_sure_you_want_to_close') % {status: status_text}, class: 'action-button'} + = render "orders_cycle_plugin_cycle/actions/#{view_status}", cycle: cycle rescue nil + diff --git a/plugins/orders_cycle/views/orders_cycle_plugin_cycle/actions/_closed.html.slim b/plugins/orders_cycle/views/orders_cycle_plugin_cycle/actions/_closed.html.slim new file mode 100644 index 0000000..c419533 --- /dev/null +++ b/plugins/orders_cycle/views/orders_cycle_plugin_cycle/actions/_closed.html.slim @@ -0,0 +1,4 @@ +- if cycle.status == 'closing' + = link_to t('views.cycle._timeline.reopen_orders_period'), {action: :step_back, id: cycle.id, method: :post}, + id: 'cycle-open-cycle', class: 'action-button', data: {confirm: t('views.cycle._timeline.are_you_sure_you_want_to_reopen')} + diff --git a/plugins/orders_cycle/views/orders_cycle_plugin_cycle/edit.js.erb b/plugins/orders_cycle/views/orders_cycle_plugin_cycle/edit.js.erb index f208e88..d526bce 100644 --- a/plugins/orders_cycle/views/orders_cycle_plugin_cycle/edit.js.erb +++ b/plugins/orders_cycle/views/orders_cycle_plugin_cycle/edit.js.erb @@ -1,8 +1,8 @@ <% if params[:commit] %> <% if @success and @open %> - window.location = <%= url_for(:action => :edit, :id => @cycle.id).to_json %> + window.location = <%= url_for(action: :edit, id: @cycle.id).to_json %> <% else %> - noosfero.modal.html(<%= render('edit_popin', :cycle => @cycle).to_json %>) + noosfero.modal.html(<%= render('edit_popin', cycle: @cycle).to_json %>) <% end %> <% else %> jQuery("#cycle-products .table").replaceWith('<%= escape_javascript render('product_lines') %>') diff --git a/plugins/orders_cycle/views/orders_cycle_plugin_gadgets/cycles.html.erb b/plugins/orders_cycle/views/orders_cycle_plugin_gadgets/cycles.html.erb index 7fb4f12..df6695e 100644 --- a/plugins/orders_cycle/views/orders_cycle_plugin_gadgets/cycles.html.erb +++ b/plugins/orders_cycle/views/orders_cycle_plugin_gadgets/cycles.html.erb @@ -2,11 +2,11 @@
<% profile.orders_cycles.on_orders.each do |cycle| %> - <%= render :partial => 'orders_cycle_plugin_gadgets/cycle', :locals => {:cycle => cycle} %> + <%= render 'orders_cycle_plugin_gadgets/cycle', cycle: cycle %> <% end %>
- <%= link_to t('views.gadgets.cycles.all_cycles'), {:controller => :orders_cycle_plugin_order, :profile => profile.identifier, :action => :index}, :id => "all-cycles" %> + <%= link_to t('views.gadgets.cycles.all_cycles'), {controller: :orders_cycle_plugin_order, profile: profile.identifier, action: :index}, id: "all-cycles" %>
diff --git a/plugins/orders_cycle/views/orders_cycle_plugin_order/cycle_edit.rjs b/plugins/orders_cycle/views/orders_cycle_plugin_order/cycle_edit.rjs index 824a49c..d2020df 100644 --- a/plugins/orders_cycle/views/orders_cycle_plugin_order/cycle_edit.rjs +++ b/plugins/orders_cycle/views/orders_cycle_plugin_order/cycle_edit.rjs @@ -1,3 +1,3 @@ -page.replace_html "order-#{@order.id}", :partial => 'cycle_edit', :locals => {:order => @order} -page.replace_html "cycle-products-sums", :partial => 'orders_cycle_plugin_cycle/orders_suppliers', :locals => {:cycle => @order.cycle} +page.replace_html "order-#{@order.id}", partial: 'cycle_edit', locals: {order: @order} +page.replace_html "cycle-products-sums", partial: 'orders_cycle_plugin_cycle/orders_suppliers', locals: {cycle: @order.cycle} page << "toggle_edit.value_row.reload();" diff --git a/plugins/shopping_cart/controllers/shopping_cart_plugin_controller.rb b/plugins/shopping_cart/controllers/shopping_cart_plugin_controller.rb index 67b6a67..107c6db 100644 --- a/plugins/shopping_cart/controllers/shopping_cart_plugin_controller.rb +++ b/plugins/shopping_cart/controllers/shopping_cart_plugin_controller.rb @@ -119,7 +119,8 @@ class ShoppingCartPluginController < OrdersPluginController @settings = cart_profile.shopping_cart_settings @cart = cart @profile = cart_profile - @order = profile.sales.build consumer: user + supplier_delivery = profile.delivery_methods.first + @order = build_order self.cart[:items], supplier_delivery last_delivery_option_id = session[:cart][:last_delivery_option_id] if session[:cart] @order.supplier_delivery = profile.delivery_methods.where(id: last_delivery_option_id).first if last_delivery_option_id @@ -192,7 +193,8 @@ class ShoppingCartPluginController < OrdersPluginController @profile = cart_profile supplier_delivery = @profile.delivery_methods.where(id: params[:order][:supplier_delivery_id]).first order = build_order self.cart[:items], supplier_delivery - total_price = order.total_price + order.supplier_delivery = supplier_delivery + total_price = order.total render json: { ok: true, delivery_price: float_to_currency_cart(supplier_delivery.cost(total_price), environment, unit: ''), diff --git a/plugins/shopping_cart/db/migrate/20121022190819_move_fields_included_on_profiles_table_to_settings.rb b/plugins/shopping_cart/db/migrate/20121022190819_move_fields_included_on_profiles_table_to_settings.rb index a32a1ec..136af28 100644 --- a/plugins/shopping_cart/db/migrate/20121022190819_move_fields_included_on_profiles_table_to_settings.rb +++ b/plugins/shopping_cart/db/migrate/20121022190819_move_fields_included_on_profiles_table_to_settings.rb @@ -1,6 +1,6 @@ class MoveFieldsIncludedOnProfilesTableToSettings < ActiveRecord::Migration def self.up - Profile.find_each do |profile| + Enterprise.find_each do |profile| settings = profile.shopping_cart_settings settings.enabled = profile.shopping_cart settings.delivery = profile.shopping_cart_delivery diff --git a/plugins/shopping_cart/db/migrate/20131226125124_move_shopping_cart_purchase_order_to_orders_plugin_order.rb b/plugins/shopping_cart/db/migrate/20131226125124_move_shopping_cart_purchase_order_to_orders_plugin_order.rb index dbd57dc..9f7749c 100644 --- a/plugins/shopping_cart/db/migrate/20131226125124_move_shopping_cart_purchase_order_to_orders_plugin_order.rb +++ b/plugins/shopping_cart/db/migrate/20131226125124_move_shopping_cart_purchase_order_to_orders_plugin_order.rb @@ -2,7 +2,7 @@ OrdersPlugin.send :remove_const, :Item if defined? OrdersPlugin::Item OrdersPlugin.send :remove_const, :Order if defined? OrdersPlugin::Order class ShoppingCartPlugin::PurchaseOrder < ActiveRecord::Base - acts_as_having_settings :field => :data + acts_as_having_settings field: :data module Status OPENED = 0 @@ -13,17 +13,17 @@ class ShoppingCartPlugin::PurchaseOrder < ActiveRecord::Base end class Profile - has_many :orders, :class_name => 'OrdersPlugin::Order' + has_many :orders, class_name: 'OrdersPlugin::Order' end class OrdersPlugin::Item < ActiveRecord::Base - belongs_to :order, :class_name => 'OrdersPlugin::Order' + belongs_to :order, class_name: 'OrdersPlugin::Order' end class OrdersPlugin::Order < ActiveRecord::Base - has_many :items, :class_name => 'OrdersPlugin::Item', :foreign_key => :order_id + has_many :items, class_name: 'OrdersPlugin::Item', foreign_key: :order_id extend CodeNumbering::ClassMethods - code_numbering :code, :scope => proc{ self.profile.orders } + code_numbering :code, scope: proc{ self.profile.orders } end StatusTransform = { @@ -37,10 +37,10 @@ class MoveShoppingCartPurchaseOrderToOrdersPluginOrder < ActiveRecord::Migration def self.up OrdersPlugin::Order.record_timestamps = false - ShoppingCartPlugin::PurchaseOrder.all(:order => 'created_at ASC').each do |purchase_order| + ShoppingCartPlugin::PurchaseOrder.order('created_at ASC').find_each do |purchase_order| data = purchase_order.data - order = OrdersPlugin::Order.new :profile_id => purchase_order.seller_id, :consumer_id => purchase_order.customer_id + order = OrdersPlugin::Order.new profile_id: purchase_order.seller_id, consumer_id: purchase_order.customer_id order.consumer_data = {} ['contact_phone','name','email'].each do |prop| @@ -58,7 +58,7 @@ class MoveShoppingCartPurchaseOrderToOrdersPluginOrder < ActiveRecord::Migration order.supplier_delivery_data = {} data[:products_list].each do |id, data| - item = order.items.build :product_id => id, :name => data[:name], :quantity_consumer_ordered => data[:quantity], :price => data[:price] + item = order.items.build product_id: id, name: data[:name], quantity_consumer_ordered: data[:quantity], price: data[:price] item.order = order end diff --git a/plugins/shopping_cart/features/delivery_admin.feature b/plugins/shopping_cart/features/delivery_admin.feature index 9101a40..091ba5a 100644 --- a/plugins/shopping_cart/features/delivery_admin.feature +++ b/plugins/shopping_cart/features/delivery_admin.feature @@ -36,7 +36,6 @@ Feature: delivery administration And I follow "New delivery or pickup" And I select "Deliver" from "Type" And I fill in "Name" with "Bike" - And I fill in "Description" with "Beers delivered with my old bike." And I fill in "Fixed cost" with "8.00" And I fill in "Order's minimum price for free delivery" with "35.50" When I press "Add" @@ -49,7 +48,6 @@ Feature: delivery administration And I follow "New delivery or pickup" And I select "Pickup" from "Type" And I fill in "Name" with "Bar" - And I fill in "Description" with "Come to my bar and pick it yourself." And I fill in "Fixed cost" with "0.00" When I press "Add" Then I should see "Bar" diff --git a/plugins/shopping_cart/features/features b/plugins/shopping_cart/features/features new file mode 120000 index 0000000..68471f0 --- /dev/null +++ b/plugins/shopping_cart/features/features @@ -0,0 +1 @@ +/home/braulio/Projects/noosfero-ecosol/noosfero/config/plugins/shopping_cart/features \ No newline at end of file diff --git a/plugins/shopping_cart/lib/shopping_cart_plugin.rb b/plugins/shopping_cart/lib/shopping_cart_plugin.rb index 69ddeab..50059dc 100644 --- a/plugins/shopping_cart/lib/shopping_cart_plugin.rb +++ b/plugins/shopping_cart/lib/shopping_cart_plugin.rb @@ -1,6 +1,4 @@ class ShoppingCartPlugin < Noosfero::Plugin - include ModalHelper - include ActionView::Helpers::UrlHelper def self.plugin_name "Shopping Basket" @@ -34,10 +32,6 @@ class ShoppingCartPlugin < Noosfero::Plugin buttons end - def controller - context - end - def add_to_cart_button item, options = {} profile = item.profile return unless profile.shopping_cart_enabled and item.available diff --git a/plugins/shopping_cart/lib/shopping_cart_plugin/cart_helper.rb b/plugins/shopping_cart/lib/shopping_cart_plugin/cart_helper.rb index 53f0377..b3c24fa 100644 --- a/plugins/shopping_cart/lib/shopping_cart_plugin/cart_helper.rb +++ b/plugins/shopping_cart/lib/shopping_cart_plugin/cart_helper.rb @@ -61,7 +61,8 @@ module ShoppingCartPlugin::CartHelper def items_table(items, delivery_method = nil, by_mail = false) # partial key needed in mailer context - render partial: 'shopping_cart_plugin/items', locals: {order: build_order(items, delivery_method), by_mail: by_mail} + order = @order || build_order(items, delivery_method) + render partial: 'shopping_cart_plugin/items', locals: {order: order, by_mail: by_mail} end def float_to_currency_cart value, environment, _options = {} diff --git a/plugins/shopping_cart/po/pt/shopping_cart.po b/plugins/shopping_cart/po/pt/shopping_cart.po index d77d0a2..b0dc160 100644 --- a/plugins/shopping_cart/po/pt/shopping_cart.po +++ b/plugins/shopping_cart/po/pt/shopping_cart.po @@ -13,7 +13,7 @@ msgid "" msgstr "" "Project-Id-Version: 1.3~rc2-1-ga15645d\n" "POT-Creation-Date: 2015-10-30 16:34-0300\n" -"PO-Revision-Date: 2015-09-29 20:23-0300\n" +"PO-Revision-Date: 2015-11-15 18:17-0300\n" "Last-Translator: Michal Čihař \n" "Language-Team: Portuguese \n" @@ -32,6 +32,48 @@ msgstr "Funcionalidade de cesto de compras para empreendimentos" msgid "Shopping basket" msgstr "Cesto de compras" +#: plugins/shopping_cart/lib/shopping_cart_plugin.rb:63 +msgid "Purchase reports" +msgstr "Relatórios de compras" + +#: plugins/shopping_cart/lib/shopping_cart_plugin/purchase_order.rb:40 +msgid "Opened" +msgstr "Aberto" + +#: plugins/shopping_cart/lib/shopping_cart_plugin/purchase_order.rb:40 +msgid "Confirmed" +msgstr "Confirmado" + +#: plugins/shopping_cart/lib/shopping_cart_plugin/purchase_order.rb:40 +msgid "Shipped" +msgstr "Enviado" + +#: plugins/shopping_cart/lib/shopping_cart_plugin/cart_helper.rb:41 +msgid "Free delivery" +msgstr "Frete grátis" + +#: plugins/shopping_cart/lib/shopping_cart_plugin/cart_helper.rb:43 +#: plugins/shopping_cart/views/shopping_cart_plugin_myprofile/edit.html.erb:7 +msgid "Delivery" +msgstr "Entrega" + +#: plugins/shopping_cart/views/shopping_cart_plugin_myprofile/edit.html.erb:7 +msgid "Delivery or pickup" +msgstr "Forma de retirada ou entrega" + +#: plugins/delivery/views/delivery_plugin/_order_select.html.slim +msgid "Instructions" +msgstr "Instruções" + +#: plugins/shopping_cart/lib/shopping_cart_plugin/cart_helper.rb:53 +msgid "Item" +msgstr "Item" + +#: plugins/shopping_cart/lib/shopping_cart_plugin/cart_helper.rb:76 +#: plugins/shopping_cart/views/cart.html.erb:7 +msgid "Total:" +msgstr "Total:" + #: plugins/shopping_cart/lib/shopping_cart_plugin/cart_helper.rb:11 msgid "Add to basket" msgstr "Adicionar ao cesto" @@ -112,9 +154,8 @@ msgid "Shopping checkout" msgstr "Finalizar pedido" #: plugins/shopping_cart/views/public/_cart.html.erb:8 -#, fuzzy msgid "Basket is empty" -msgstr "Cesto exibido." +msgstr "Cesto vazio." #: plugins/shopping_cart/views/public/_cart.html.erb:14 msgid "Basket" @@ -124,11 +165,6 @@ msgstr "Cesto" msgid "Clean basket" msgstr "Limpar cesto" -#: plugins/shopping_cart/views/public/_cart.html.erb:20 -#: plugins/shopping_cart/views/shopping_cart_plugin/_items.html.erb:42 -msgid "Total:" -msgstr "Total:" - #: plugins/shopping_cart/views/public/_cart.html.erb:23 msgid "Show basket" msgstr "Mostrar cesto" @@ -163,7 +199,8 @@ msgstr "Tem certeza que quer limpar seu cesto?" #: plugins/shopping_cart/views/public/_cart.html.erb:54 msgid "repeat order" -msgstr "" +msgstr "repetir pedido" + #: plugins/shopping_cart/views/shopping_cart_plugin/_items.html.erb:7 msgid "Item name" @@ -179,39 +216,37 @@ msgid "Hi %s!" msgstr "Olá %s!" #: plugins/shopping_cart/views/shopping_cart_plugin/mailer/customer_notification.html.erb:10 -#, fuzzy -msgid "" -"This is a notification e-mail about your buy request on the enterprise %s." -msgstr "Esse é um email de notificação sobre o seu pedido de compra em %s." +msgid "This is a notification e-mail about your buy request on the enterprise %s." +msgstr "Esse é um email de notificação sobre o seu pedido de compra no empreendimento %s." #: plugins/shopping_cart/views/shopping_cart_plugin/mailer/customer_notification.html.erb:11 -#, fuzzy msgid "" "The enterprise already received your buy request and will contact you for " "confirmation." msgstr "" -"O fornecedor já recebeu o seu pedido de compra e deve te contactar para " +"O empreendimento já recebeu o seu pedido de compra e entrará em contato para " +"confirmação." + "confirmação." #: plugins/shopping_cart/views/shopping_cart_plugin/mailer/customer_notification.html.erb:12 -#, fuzzy msgid "If you have any doubts about your order, write to us at: %s." -msgstr "Se você tem alguma dúvida, nos contacte em: %s" +msgstr "Se você tem alguma dúvida sobre o seu pedido, nos escreva: %s." #: plugins/shopping_cart/views/shopping_cart_plugin/mailer/customer_notification.html.erb:13 msgid "Review below the informations of your order:" -msgstr "" +msgstr "Abaixo, revise as informações do seu pedido:" #: plugins/shopping_cart/views/shopping_cart_plugin/mailer/customer_notification.html.erb:19 #: plugins/shopping_cart/views/shopping_cart_plugin/mailer/supplier_notification.html.erb:17 msgid "Phone number" msgstr "" +#: plugins/shopping_cart/views/shopping_cart_plugin_myprofile/_orders_list.html.erb:35 #: plugins/shopping_cart/views/shopping_cart_plugin/mailer/customer_notification.html.erb:22 #: plugins/shopping_cart/views/shopping_cart_plugin/buy.html.erb:22 -#, fuzzy msgid "Payment's method" -msgstr "Pagamento" +msgstr "Forma de pagamento" #: plugins/shopping_cart/views/shopping_cart_plugin/mailer/customer_notification.html.erb:24 #: plugins/shopping_cart/views/shopping_cart_plugin/mailer/supplier_notification.html.erb:22 @@ -219,31 +254,30 @@ msgstr "Pagamento" msgid "shopping_cart|Change" msgstr "Troco para" -#: plugins/shopping_cart/views/shopping_cart_plugin/mailer/customer_notification.html.erb:28 -msgid "Delivery or pickup" -msgstr "Forma de retirada ou entrega" +#: plugins/shopping_cart/views/shopping_cart_plugin_myprofile/_products_list.html.erb:7 +msgid "Quantity" +msgstr "Quantidade" -#: plugins/shopping_cart/views/shopping_cart_plugin/mailer/customer_notification.html.erb:63 +#: plugins/shopping_cart/views/shopping_cart_plugin/mailer/customer_notification.html.erb:47 msgid "Here are the products you bought:" -msgstr "" +msgstr "Aqui estão os produtos que você pediu:" -#: plugins/shopping_cart/views/shopping_cart_plugin/mailer/customer_notification.html.erb:67 +#: plugins/shopping_cart/views/shopping_cart_plugin/mailer/customer_notification.html.erb:51 msgid "Thanks for buying with us!" -msgstr "" +msgstr "Obrigado por comprar conosco!" -#: plugins/shopping_cart/views/shopping_cart_plugin/mailer/customer_notification.html.erb:70 -#: plugins/shopping_cart/views/shopping_cart_plugin/mailer/supplier_notification.html.erb:61 +#: plugins/shopping_cart/views/shopping_cart_plugin/mailer/customer_notification.html.erb:54 +#: plugins/shopping_cart/views/shopping_cart_plugin/mailer/supplier_notification.html.erb:51 msgid "A service of %s." -msgstr "" +msgstr "Um serviço de %s." #: plugins/shopping_cart/views/shopping_cart_plugin/mailer/supplier_notification.html.erb:10 -#, fuzzy msgid "This is a buy request made by %s." -msgstr "[%s] Você tem um novo pedido de compra de %s." +msgstr "Esse é um pedido de compra feito por %s." #: plugins/shopping_cart/views/shopping_cart_plugin/mailer/supplier_notification.html.erb:11 msgid "Below follows the customer informations:" -msgstr "" +msgstr "Abaixo seguem as informações do consumidor:" #: plugins/shopping_cart/views/shopping_cart_plugin/mailer/supplier_notification.html.erb:20 #: plugins/shopping_cart/views/shopping_cart_plugin/buy.html.erb:25 @@ -251,20 +285,18 @@ msgid "Payment" msgstr "Pagamento" #: plugins/shopping_cart/views/shopping_cart_plugin/mailer/supplier_notification.html.erb:55 +#: plugins/shopping_cart/views/shopping_cart_plugin/mailer/supplier_notification.html.erb:45 msgid "And here are the items bought by this customer:" -msgstr "" +msgstr "E aqui estão os itens pedidos por esse consumidor:" -#: plugins/shopping_cart/views/shopping_cart_plugin/mailer/supplier_notification.html.erb:59 +#: plugins/shopping_cart/views/shopping_cart_plugin/mailer/supplier_notification.html.erb:49 msgid "If there are any problems with this email contact the admin of %s." msgstr "" +"Se houver algum problema com esse email contacte o administrador de %s." -#: plugins/shopping_cart/views/shopping_cart_plugin/buy.html.erb:4 -msgid "haven't finished yet: back to shopping" -msgstr "" - -#: plugins/shopping_cart/views/shopping_cart_plugin/buy.html.erb:12 +#: plugins/shopping_cart/views/shopping_cart_plugin/buy.html.erb:9 msgid "Personal identification" -msgstr "" +msgstr "Identificação pessoal" #: plugins/shopping_cart/views/shopping_cart_plugin/buy.html.erb:15 msgid "Name" @@ -290,36 +322,21 @@ msgstr "Seu Pedido" msgid "Send buy request" msgstr "Enviar pedido de compra" -#~ msgid "Purchase reports" -#~ msgstr "Relatórios de compras" - -#~ msgid "Opened" -#~ msgstr "Aberto" - -#~ msgid "Canceled" -#~ msgstr "Cancelado" - -#~ msgid "Confirmed" -#~ msgstr "Confirmado" - -#~ msgid "Shipped" -#~ msgstr "Enviado" - -#~ msgid "Free delivery" -#~ msgstr "Frete grátis" - -#~ msgid "Delivery" -#~ msgstr "Entrega" - -#~ msgid "Instructions" -#~ msgstr "Instruções" +#: plugins/shopping_cart/views/shopping_cart_plugin/buy.html.erb:15 +msgid "Address completion" +msgstr "Complemento (p.ex. apto)" -#~ msgid "Option wasn't updated successfully." -#~ msgstr "Opção não foi atualizada com sucesso." +#: plugins/shopping_cart/views/shopping_cart_plugin/buy.html.erb +msgid "haven't finished yet: back to shopping" +msgstr "ainda não concluí: voltar às compras" -#~ msgid "Request sent successfully. Check your email." -#~ msgstr "Requisição enviada com sucesso. Cheque seu email." +#: plugins/shopping_cart/views/shopping_cart_plugin/_items.html.erb +msgid "Qtty" +msgstr "Qtde" +#: plugins/shopping_cart/views/shopping_cart_plugin/_items.html.erb +msgid "Unit price" +msgstr "Preço unitário" #~ msgid "Can't join items from different enterprises." #~ msgstr "Não é possível juntar itens de empreendimentos diferentes." diff --git a/plugins/shopping_cart/public/cart.js b/plugins/shopping_cart/public/cart.js index 07b0048..b52a5ff 100644 --- a/plugins/shopping_cart/public/cart.js +++ b/plugins/shopping_cart/public/cart.js @@ -63,12 +63,6 @@ function Cart(config) { var input = $("input", li)[0]; input.lastValue = input.value; input.productId = item.id; - input.ajustSize = function() { - var len = this.value.toString().length; - if(len > 2) len--; - this.style.width = len+"em"; - }; - input.ajustSize(); input.onchange = function() { me.updateQuantity(this, this.productId, this.value); }; diff --git a/plugins/shopping_cart/public/public b/plugins/shopping_cart/public/public new file mode 120000 index 0000000..72c6701 --- /dev/null +++ b/plugins/shopping_cart/public/public @@ -0,0 +1 @@ +/home/braulio/Projects/noosfero-ecosol/noosfero/config/plugins/shopping_cart/public \ No newline at end of file diff --git a/plugins/shopping_cart/shopping_cart b/plugins/shopping_cart/shopping_cart new file mode 120000 index 0000000..8d62156 --- /dev/null +++ b/plugins/shopping_cart/shopping_cart @@ -0,0 +1 @@ +/home/braulio/Projects/noosfero-ecosol/noosfero/plugins/shopping_cart \ No newline at end of file diff --git a/plugins/shopping_cart/views/public/_cart.html.erb b/plugins/shopping_cart/views/public/_cart.html.erb index 11728c8..866bf22 100644 --- a/plugins/shopping_cart/views/public/_cart.html.erb +++ b/plugins/shopping_cart/views/public/_cart.html.erb @@ -16,7 +16,7 @@ <%=_('Clean basket')%>
- <%= button 'cart', _('Shopping checkout'), "/plugin/shopping_cart/buy", :class => 'cart-buy modal-toggle' %> + <%= button 'cart', _('Shopping checkout'), "/plugin/shopping_cart/buy", class: 'cart-buy' %>
<%=_('Total:')%>
@@ -31,7 +31,7 @@
{{item.name}}
- {{item.priceTxt}} + {{item.priceTxt}}
diff --git a/plugins/shopping_cart/views/shopping_cart_plugin/_items.html.erb b/plugins/shopping_cart/views/shopping_cart_plugin/_items.html.erb index ebc5cec..fe6184d 100644 --- a/plugins/shopping_cart/views/shopping_cart_plugin/_items.html.erb +++ b/plugins/shopping_cart/views/shopping_cart_plugin/_items.html.erb @@ -3,45 +3,51 @@ style="<%= 'border-collapse: collapse' if by_mail %>"> - - <%= _('Item name') %> + > + <%= _('Item') %> - - <%= if by_mail then ' # ' else '#' end %> + > + <%= if by_mail then ' '+_('Qtty')+' ' else _('Qtty') end %> - - <%= _('Price') + " (#{@environment.currency_unit})" %> + > + <%= _('Unit price') + " (#{@environment.currency_unit})" %> + + > + <%= _('Total') + " (#{@environment.currency_unit})" %> <% order.items.each do |item| %> - + > <%= item.name %> - - <%= item.quantity_consumer_ordered %> + > + <%= "%03d" % item.quantity_consumer_ordered %> + + > + <%= get_price item.product, @environment, 1, unit: '' %> - + > <%= get_price item.product, @environment, item.quantity_consumer_ordered, unit: '' %> <% end %> - - + + <%= order.supplier_delivery.name if order.supplier_delivery %> - + > <%= float_to_currency_cart order.supplier_delivery.cost(order.total_price), @environment, unit: '' if order.supplier_delivery %> - + > <%= _('Total:') %> - + > <%= float_to_currency_cart order.total, @environment %> diff --git a/plugins/shopping_cart/views/shopping_cart_plugin/buy.html.erb b/plugins/shopping_cart/views/shopping_cart_plugin/buy.html.erb index 245db4a..c7d23c8 100644 --- a/plugins/shopping_cart/views/shopping_cart_plugin/buy.html.erb +++ b/plugins/shopping_cart/views/shopping_cart_plugin/buy.html.erb @@ -1,13 +1,19 @@
-

- <%= _('Shopping checkout') %> - <%= button :back, _("haven't finished yet: back to shopping"), 'javascript:history.back()', class: 'cart-go-back' %> -

+

<%= _('Shopping checkout') %>

+ <%= button :back, _("haven't finished yet: back to shopping"), 'javascript:history.back()', class: 'cart-go-back' %> <%= form_for :order, url: {action: :send_request}, html: {onsubmit: "return Cart.send_request(this)", id: 'cart-request-form'} do |f| %> -
+
+
+ <%=s_('Your Order')%> + <% supplier_delivery = @order.supplier_delivery || profile.delivery_methods.first %> + <%= items_table @cart[:items], @profile, supplier_delivery %> +
+
+ +
<%=_('Personal identification')%> @@ -30,21 +36,15 @@ <% if profile.delivery_methods.size > 0 %>
<%=_('Delivery or pickup method')%> + <%= render 'delivery_plugin/order_select', f: f, order: @order %>
<% end %>
-
-
- <%=s_('Your Order')%> - <% supplier_delivery = @order.supplier_delivery || profile.delivery_methods.first %> - <%= items_table @cart[:items], supplier_delivery %> -
-
-
- <%= submit_button(:send, _('Send buy request')) %> + <%= button :back, _("haven't finished yet: back to shopping"), 'javascript:history.back()' %> + <%= submit_button(:send, _('Send buy request'), option:"success") %>
<% end %>
diff --git a/plugins/suppliers/controllers/myprofile/suppliers_plugin/basket_controller.rb b/plugins/suppliers/controllers/myprofile/suppliers_plugin/basket_controller.rb index d403709..27434f9 100644 --- a/plugins/suppliers/controllers/myprofile/suppliers_plugin/basket_controller.rb +++ b/plugins/suppliers/controllers/myprofile/suppliers_plugin/basket_controller.rb @@ -52,10 +52,12 @@ class SuppliersPlugin::BasketController < MyProfileController extend HMVC::ClassMethods hmvc SuppliersPlugin - def default_url_options - # avoid rails' use_relative_controller! - {use_route: '/'} + # inherit routes from core skipping use_relative_controller! + def url_for options + options[:controller] = "/#{options[:controller]}" if options.is_a? Hash and options[:controller] and not options[:controller].to_s.starts_with? '/' + super options end + helper_method :url_for def set_allowed_user @allowed_user = true diff --git a/plugins/suppliers/controllers/myprofile/suppliers_plugin/product_controller.rb b/plugins/suppliers/controllers/myprofile/suppliers_plugin/product_controller.rb index 3fef0de..76b03a9 100644 --- a/plugins/suppliers/controllers/myprofile/suppliers_plugin/product_controller.rb +++ b/plugins/suppliers/controllers/myprofile/suppliers_plugin/product_controller.rb @@ -32,7 +32,7 @@ class SuppliersPlugin::ProductController < MyProfileController def edit @product = profile.products.supplied.find params[:id] - @product.update_attributes params["product_#{@product.id}"] + @product.update params["product_#{@product.id}"] end def import @@ -79,6 +79,7 @@ class SuppliersPlugin::ProductController < MyProfileController @supplier = SuppliersPlugin::Supplier.where(id: params[:supplier_id]).first if params[:supplier_id].present? + # FIXME: joins(:from_products) is hiding own products (except baskets) @scope = profile.products.unarchived.joins :from_products, :suppliers @scope = SuppliersPlugin::BaseProduct.search_scope @scope, params @products_count = @scope.supplied_for_count.count @@ -95,9 +96,11 @@ class SuppliersPlugin::ProductController < MyProfileController extend HMVC::ClassMethods hmvc SuppliersPlugin - def default_url_options - # avoid rails' use_relative_controller! - {use_route: '/'} + # inherit routes from core skipping use_relative_controller! + def url_for options + options[:controller] = "/#{options[:controller]}" if options.is_a? Hash and options[:controller] and not options[:controller].to_s.starts_with? '/' + super options end + helper_method :url_for end diff --git a/plugins/suppliers/controllers/myprofile/suppliers_plugin_myprofile_controller.rb b/plugins/suppliers/controllers/myprofile/suppliers_plugin_myprofile_controller.rb index 3266894..9ebb945 100644 --- a/plugins/suppliers/controllers/myprofile/suppliers_plugin_myprofile_controller.rb +++ b/plugins/suppliers/controllers/myprofile/suppliers_plugin_myprofile_controller.rb @@ -21,7 +21,7 @@ class SuppliersPluginMyprofileController < MyProfileController end def new - @new_supplier.update_attributes! params[:supplier] + @new_supplier.update! params[:supplier] @supplier = @new_supplier session[:notice] = t('controllers.myprofile.supplier_created') end @@ -33,7 +33,7 @@ class SuppliersPluginMyprofileController < MyProfileController def edit @supplier = profile.suppliers.find params[:id] - @supplier.update_attributes params[:supplier] + @supplier.update params[:supplier] end def margin_change @@ -58,8 +58,8 @@ class SuppliersPluginMyprofileController < MyProfileController def search @query = params[:query].downcase - @enterprises = environment.enterprises.enabled.public.all limit: 12, order: 'name ASC', - conditions: ['LOWER(name) LIKE ? OR LOWER(name) LIKE ? OR identifier LIKE ?', "#{@query}%", "% #{@query}%", "#{@query}%"] + @enterprises = environment.enterprises.enabled.is_public.limit(12).order('name ASC'). + where('name ILIKE ? OR name ILIKE ? OR identifier LIKE ?', "#{@query}%", "% #{@query}%", "#{@query}%") @enterprises -= profile.suppliers.collect(&:profile) end diff --git a/plugins/suppliers/lib/default_delegate.rb b/plugins/suppliers/lib/default_delegate.rb index 02bdfbe..ce7b8b1 100644 --- a/plugins/suppliers/lib/default_delegate.rb +++ b/plugins/suppliers/lib/default_delegate.rb @@ -15,6 +15,9 @@ module DefaultDelegate # TODO: add some documentation about the methods being added def default_delegate field, options = {} + class_attribute :default_delegate_enable unless respond_to? :default_delegate_enable + self.default_delegate_enable = true if self.default_delegate_enable.nil? + # rake db:migrate run? return unless self.table_exists? @@ -91,6 +94,8 @@ module DefaultDelegate end define_method "#{field}_with_default" do + return self.send own_field unless self.default_delegate_enable + if self.send default_setting # delegated_field may return nil, so use own instead # this is the case with some associations (e.g. Product#product_qualifiers) @@ -101,6 +106,8 @@ module DefaultDelegate end end define_method "#{field}_with_default=" do |*args| + return self.send "#{own_field}=", *args unless self.default_delegate_enable + own = self.send "#{own_field}=", *args # break/set the default setting automatically, used for interfaces # that don't have the default setting (e.g. manage_products) diff --git a/plugins/suppliers/lib/ext/product.rb b/plugins/suppliers/lib/ext/product.rb index 4207159..75ad780 100644 --- a/plugins/suppliers/lib/ext/product.rb +++ b/plugins/suppliers/lib/ext/product.rb @@ -7,20 +7,22 @@ class Product has_currency :price has_currency :discount - scope :available, conditions: {available: true} - scope :unavailable, conditions: ['products.available <> true'] - scope :archived, conditions: {archived: true} - scope :unarchived, conditions: ['products.archived <> true'] + scope :alphabetically, -> { order 'products.name ASC' } - scope :with_available, lambda { |available| where available: available } - scope :with_price, conditions: 'products.price > 0' - scope :with_product_category_id, lambda { |id| { conditions: {product_category_id: id} } } + scope :available, -> { where available: true } + scope :unavailable, -> { where 'products.available <> true' } + scope :archived, -> { where archived: true } + scope :unarchived, -> { where 'products.archived <> true' } + + scope :with_available, -> (available) { where available: available } + scope :with_price, -> { where 'products.price > 0' } # FIXME: transliterate input and name column - scope :name_like, lambda { |name| { conditions: ["LOWER(products.name) LIKE ?", "%#{name}%"] } } + scope :name_like, -> (name) { where "name ILIKE ?", "%#{name}%" } + scope :with_product_category_id, -> (id) { where product_category_id: id } - scope :by_profile, lambda { |profile| { conditions: {profile_id: profile.id} } } - scope :by_profile_id, lambda { |profile_id| { conditions: {profile_id: profile_id} } } + scope :by_profile, -> (profile) { where profile_id: profile.id } + scope :by_profile_id, -> (profile_id) { where profile_id: profile_id } def self.product_categories_of products ProductCategory.find products.collect(&:product_category_id).compact.select{ |id| not id.zero? } @@ -36,16 +38,16 @@ end class Product - attr_accessible :from_products, :supplier_id, :supplier + attr_accessible :from_products, :from_product, :supplier_id, :supplier has_many :sources_from_products, foreign_key: :to_product_id, class_name: 'SuppliersPlugin::SourceProduct', dependent: :destroy has_one :sources_from_product, foreign_key: :to_product_id, class_name: 'SuppliersPlugin::SourceProduct' has_many :sources_to_products, foreign_key: :from_product_id, class_name: 'SuppliersPlugin::SourceProduct', dependent: :destroy has_one :sources_to_product, foreign_key: :from_product_id, class_name: 'SuppliersPlugin::SourceProduct' - has_many :to_products, through: :sources_to_products, order: 'id ASC' - has_one :to_product, through: :sources_to_product, order: 'id ASC', autosave: true - has_many :from_products, through: :sources_from_products, order: 'id ASC' - has_one :from_product, through: :sources_from_product, order: 'id ASC', autosave: true + has_many :to_products, -> { order 'id ASC' }, through: :sources_to_products + has_one :to_product, -> { order 'id ASC' }, through: :sources_to_product, autosave: true + has_many :from_products, -> { order 'id ASC' }, through: :sources_from_products + has_one :from_product, -> { order 'id ASC' }, through: :sources_from_product, autosave: true has_many :sources_from_2x_products, through: :from_products, source: :sources_from_products has_one :sources_from_2x_product, through: :from_product, source: :sources_from_product @@ -59,15 +61,15 @@ class Product # semantic alias for supplier_from_product(s) has_many :sources_supplier_products, foreign_key: :to_product_id, class_name: 'SuppliersPlugin::SourceProduct' has_one :sources_supplier_product, foreign_key: :to_product_id, class_name: 'SuppliersPlugin::SourceProduct' - has_many :supplier_products, through: :sources_supplier_products, source: :from_product, order: 'id ASC' - has_one :supplier_product, through: :sources_supplier_product, source: :from_product, order: 'id ASC', autosave: true - has_many :suppliers, through: :sources_supplier_products, uniq: true, order: 'id ASC' - has_one :supplier, through: :sources_supplier_product, order: 'id ASC' + has_many :supplier_products, -> { order 'id ASC' }, through: :sources_supplier_products, source: :from_product + has_one :supplier_product, -> { order 'id ASC' }, through: :sources_supplier_product, source: :from_product, autosave: true + has_many :suppliers, -> { distinct.order 'id ASC' }, through: :sources_supplier_products + has_one :supplier, -> { order 'id ASC' }, through: :sources_supplier_product - has_many :consumers, through: :to_products, source: :profile, uniq: true, order: 'id ASC' - has_one :consumer, through: :to_product, source: :profile, order: 'id ASC' + has_many :consumers, -> { distinct.order 'id ASC' }, through: :to_products, source: :profile + has_one :consumer, -> { order 'id ASC' }, through: :to_product, source: :profile - # overhide original + # overhide original, FIXME: rename to available_and_supplier_active scope :available, -> { joins(:suppliers). where 'products.available = ? AND suppliers_plugin_suppliers.active = ?', true, true @@ -81,23 +83,24 @@ class Product where "products.available #{op} ? #{cond} suppliers_plugin_suppliers.active #{op} ?", true, true } - scope :name_like, lambda { |name| where "from_products_products.name ILIKE ?", "%#{name}%" } - scope :with_product_category_id, lambda { |id| where 'from_products_products.product_category_id = ?', id } + scope :fp_name_like, -> (name) { where "from_products_products.name ILIKE ?", "%#{name}%" } + scope :fp_with_product_category_id, -> (id) { where 'from_products_products.product_category_id = ?', id } # prefer distributed_products has_many to use DistributedProduct scopes and eager loading scope :distributed, -> { where type: 'SuppliersPlugin::DistributedProduct'} scope :own, -> { where type: nil } scope :supplied, -> { - where(type: [nil, 'SuppliersPlugin::DistributedProduct']). - # this allow duplicates and sorting on the fields - group('products.id') + # this remove duplicates and allow sorting on the fields, unlike distinct + group('products.id'). + where type: [nil, 'SuppliersPlugin::DistributedProduct'] } scope :supplied_for_count, -> { - where(type: [nil, 'SuppliersPlugin::DistributedProduct']).uniq + distinct. + where type: [nil, 'SuppliersPlugin::DistributedProduct'] } - scope :from_supplier, lambda { |supplier| { conditions: ['suppliers_plugin_suppliers.id = ?', supplier.id] } } - scope :from_supplier_id, lambda { |supplier_id| { conditions: ['suppliers_plugin_suppliers.id = ?', supplier_id] } } + scope :from_supplier, -> (supplier) { joins(:suppliers).where 'suppliers_plugin_suppliers.id = ?', supplier.id } + scope :from_supplier_id, -> (supplier_id) { joins(:suppliers).where 'suppliers_plugin_suppliers.id = ?', supplier_id } after_create :distribute_to_consumers @@ -132,8 +135,8 @@ class Product def distribute_to_consumer consumer, attrs = {} distributed_product = consumer.distributed_products.where(profile_id: consumer.id, from_products_products: {id: self.id}).first - distributed_product ||= SuppliersPlugin::DistributedProduct.create! profile: consumer, from_products: [self] - distributed_product.update_attributes! attrs if attrs.present? + distributed_product ||= SuppliersPlugin::DistributedProduct.create! profile: consumer, from_product: self + distributed_product.update! attrs if attrs.present? distributed_product end diff --git a/plugins/suppliers/lib/ext/profile.rb b/plugins/suppliers/lib/ext/profile.rb index be25627..5092560 100644 --- a/plugins/suppliers/lib/ext/profile.rb +++ b/plugins/suppliers/lib/ext/profile.rb @@ -1,20 +1,25 @@ require_dependency 'profile' +require_dependency 'community' -# FIXME: The lines bellow should be on the core -class Profile +# FIXME: should be on the core +([Profile] + Profile.descendants).each do |subclass| +subclass.class_eval do - has_many :products + has_many :products, foreign_key: :profile_id +end +end +class Profile def create_product? true end - end -class Profile +([Profile] + Profile.descendants).each do |subclass| +subclass.class_eval do # use profile.products.supplied to include own products - has_many :distributed_products, class_name: 'SuppliersPlugin::DistributedProduct' + has_many :distributed_products, class_name: 'SuppliersPlugin::DistributedProduct', foreign_key: :profile_id has_many :from_products, through: :products has_many :to_products, through: :products @@ -24,6 +29,11 @@ class Profile has_many :consumers, class_name: 'SuppliersPlugin::Consumer', foreign_key: :profile_id, dependent: :destroy, include: [{profile: [:domains], consumer: [:domains]}], order: 'name ASC' +end +end + +class Profile + def supplier_settings @supplier_settings ||= Noosfero::Plugin::Settings.new self, SuppliersPlugin end diff --git a/plugins/suppliers/lib/suppliers_plugin/import.rb b/plugins/suppliers/lib/suppliers_plugin/import.rb index 0b57ee8..590593b 100644 --- a/plugins/suppliers/lib/suppliers_plugin/import.rb +++ b/plugins/suppliers/lib/suppliers_plugin/import.rb @@ -123,11 +123,11 @@ class SuppliersPlugin::Import product ||= supplier.profile.products.build attrs # let update happen only on dummy suppliers if product.persisted? and supplier.dummy? - product.update_attributes! attrs + product.update! attrs elsif product.new_record? # create products as not available attrs[:available] = false if not supplier.dummy? - product.update_attributes! attrs + product.update! attrs end distributed_product = product.distribute_to_consumer consumer, distributed_attrs diff --git a/plugins/suppliers/models/suppliers_plugin/base_product.rb b/plugins/suppliers/models/suppliers_plugin/base_product.rb index 842b76d..4d76305 100644 --- a/plugins/suppliers/models/suppliers_plugin/base_product.rb +++ b/plugins/suppliers/models/suppliers_plugin/base_product.rb @@ -19,7 +19,8 @@ class SuppliersPlugin::BaseProduct < Product } ] - self.abstract_class = true + # if abstract_class is true then it will trigger https://github.com/rails/rails/issues/20871 + #self.abstract_class = true settings_items :minimum_selleable, type: Float, default: nil settings_items :margin_percentage, type: Float, default: nil @@ -75,11 +76,12 @@ class SuppliersPlugin::BaseProduct < Product Unit.new(singular: I18n.t('suppliers_plugin.models.product.unit'), plural: I18n.t('suppliers_plugin.models.product.units')) end + # override SuppliersPlugin::BaseProduct def self.search_scope scope, params scope = scope.from_supplier_id params[:supplier_id] if params[:supplier_id].present? scope = scope.with_available(if params[:available] == 'true' then true else false end) if params[:available].present? - scope = scope.name_like params[:name] if params[:name].present? - scope = scope.with_product_category_id params[:category_id] if params[:category_id].present? + scope = scope.fp_name_like params[:name] if params[:name].present? + scope = scope.fp_with_product_category_id params[:category_id] if params[:category_id].present? scope end @@ -98,7 +100,7 @@ SQL def self.archive_orphans self.where(id: self.orphans_ids).find_each batch_size: 50 do |product| # need full save to trigger search index - product.update_attributes archived: true + product.update archived: true end end @@ -173,10 +175,10 @@ SQL # FIXME: move to core def archive - self.update_attributes! archived: true + self.update! archived: true end def unarchive - self.update_attributes! archived: false + self.update! archived: false end protected diff --git a/plugins/suppliers/models/suppliers_plugin/supplier.rb b/plugins/suppliers/models/suppliers_plugin/supplier.rb index a601012..e3ac8cd 100644 --- a/plugins/suppliers/models/suppliers_plugin/supplier.rb +++ b/plugins/suppliers/models/suppliers_plugin/supplier.rb @@ -16,21 +16,21 @@ class SuppliersPlugin::Supplier < ActiveRecord::Base scope :alphabetical, -> { order 'name ASC' } - scope :active, conditions: {active: true} + scope :active, -> { where active: true } scope :dummy, -> { joins(:profile).where profiles: {visible: false} } - scope :of_profile, lambda { |p| { conditions: {profile_id: p.id} } } - scope :of_profile_id, lambda { |id| { conditions: {profile_id: id} } } - scope :of_consumer, lambda { |c| { conditions: {consumer_id: c.id} } } - scope :of_consumer_id, lambda { |id| { conditions: {consumer_id: id} } } + scope :of_profile, -> (p) { where profile_id: p.id } + scope :of_profile_id, -> (id) { where profile_id: id } + scope :of_consumer, -> (c) { where consumer_id: c.id } + scope :of_consumer_id, -> (id) { where consumer_id: id } - scope :from_supplier_id, lambda { |supplier_id| { conditions: ['suppliers_plugin_suppliers.id = ?', supplier_id] } } + scope :from_supplier_id, -> (supplier_id) { where 'suppliers_plugin_suppliers.id = ?', supplier_id } - scope :with_name, lambda { |name| if name then {conditions: ["LOWER(suppliers_plugin_suppliers.name) LIKE ?","%#{name.downcase}%"]} else {} end } - scope :by_active, lambda { |active| if active then {conditions: {active: active}} else {} end } + scope :with_name, -> (name) { where "suppliers_plugin_suppliers.name ILIKE ?", "%#{name.downcase}%" if name } + scope :by_active, -> (active) { where active: active if active } - scope :except_people, { conditions: ['profiles.type <> ?', Person.name], joins: [:consumer] } - scope :except_self, { conditions: 'profile_id <> consumer_id' } + scope :except_people, -> { joins(:consumer).where 'profiles.type <> ?', Person.name } + scope :except_self, -> { where 'profile_id <> consumer_id' } after_create :add_admins, if: :dummy? after_create :save_profile, if: :dummy? diff --git a/plugins/suppliers/test/test_helper.rb b/plugins/suppliers/test/test_helper.rb new file mode 100644 index 0000000..cca1fd3 --- /dev/null +++ b/plugins/suppliers/test/test_helper.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + '/../../../test/test_helper' diff --git a/plugins/suppliers/test/unit/code_numbering_test.rb b/plugins/suppliers/test/unit/code_numbering_test.rb new file mode 100644 index 0000000..0fcb79a --- /dev/null +++ b/plugins/suppliers/test/unit/code_numbering_test.rb @@ -0,0 +1,7 @@ +require File.dirname(__FILE__) + '/../../../../test/test_helper' + +class CodeNumberingTest < ActiveSupport::TestCase + + +end + diff --git a/plugins/suppliers/test/unit/default_delegate_test.rb b/plugins/suppliers/test/unit/default_delegate_test.rb new file mode 100644 index 0000000..525796d --- /dev/null +++ b/plugins/suppliers/test/unit/default_delegate_test.rb @@ -0,0 +1,6 @@ +require 'test_helper' + +class DefaultDelegateTest < ActiveSupport::TestCase + + +end diff --git a/plugins/suppliers/test/unit/suppliers_plugin/distributed_product_test.rb b/plugins/suppliers/test/unit/suppliers_plugin/distributed_product_test.rb new file mode 100644 index 0000000..ddcd396 --- /dev/null +++ b/plugins/suppliers/test/unit/suppliers_plugin/distributed_product_test.rb @@ -0,0 +1,108 @@ +require "#{File.dirname(__FILE__)}/../../test_helper" + +class SuppliersPlugin::DistributedProductTest < ActiveSupport::TestCase + + def setup + @product_category = create(ProductCategory, :name => 'parent') + @profile = build(Enterprise) + @invisible_profile = build(Enterprise, :visible => false) + @other_profile = build(Enterprise) + @self_supplier = build(SuppliersPlugin::Supplier, :consumer => @profile, :profile => @profile) + @dummy_supplier = build(SuppliersPlugin::Supplier, :consumer => @profile, :profile => @dummy_profile) + @other_supplier = build(SuppliersPlugin::Supplier, :consumer => @profile, :profile => @other_profile) + end + + attr_accessor :product_category, + :profile, :invisible_profile, :other_profile, + :profile, :dummy_profile, :other_profile, :self_supplier, :dummy_supplier, :other_supplier + + should 'return default settings considering dummy supplier' do + product = build(SuppliersPlugin::DistributedProduct, :profile => @profile, :supplier => @dummy_supplier) + assert_equal nil, product.default_name + assert_equal nil, product.default_description + product = build(SuppliersPlugin::DistributedProduct, :profile => @profile, :supplier => @other_supplier) + assert_equal true, product.default_name + assert_equal true, product.default_description + end + + should 'return price without margins if it is own product' do + product = build(SuppliersPlugin::DistributedProduct, :price => 10, :margin_percentage => 10, :profile => @profile, :supplier => @self_supplier) + assert_equal 10.0, product.price.to_f + end + + should 'return price without margins if supplier product has no price' do + supplier_product = build(SuppliersPlugin::DistributedProduct, :profile => @other_profile, :supplier => @other_profile.self_supplier) + product = build(SuppliersPlugin::DistributedProduct, :price => 10, :margin_percentage => 10, :profile => @profile, :supplier => @other_supplier) + assert_equal 10.0, product.price.to_f + end + + should 'return price with margins' do + supplier_product = build(SuppliersPlugin::DistributedProduct, :price => 10, :margin_percentage => 10, :profile => @other_profile, :supplier => @other_profile.self_supplier) + product = build(SuppliersPlugin::DistributedProduct, :price => 10, :margin_percentage => 10, :supplier_product => supplier_product, :profile => @profile, :supplier => @other_supplier) + + product.default_margin_percentage = false + assert_equal 11.0, product.price.to_f + profile.margin_percentage = 20 + product.default_margin_percentage = true + assert_equal 12.0, product.price.to_f + end + + should 'allow set of supplier product' do + product = build(SuppliersPlugin::DistributedProduct, :price => 10, :margin_percentage => 10, :profile => @profile, :supplier => @self_supplier) + + product.from_product = build(SuppliersPlugin::DistributedProduct, :profile => @profile, :supplier => @self_supplier) + assert_nothing_raised do + product.supplier_product = {:price => 10, :margin_percentage => 10} + product.supplier_product = SuppliersPlugin::DistributedProduct.new :price => 5 + end + end + + should 'create a supplier product for a dummy supplier' do + product = build(SuppliersPlugin::DistributedProduct, :profile => @profile, :supplier => @dummy_supplier) + assert product.supplier_product + # negative assertion + product = build(SuppliersPlugin::DistributedProduct, :profile => @profile, :supplier => @other_supplier) + assert !product.supplier_product + end + + should 'respond to supplier_product_id setter and getter' do + product = create(SuppliersPlugin::DistributedProduct, :profile => @profile, :supplier => @dummy_supplier) + assert_equal product.supplier_product.id, product.supplier_product_id + product.expects(:distribute_from) + product.supplier_product_id = 1 + end + + should 'respond to distribute_from' do + product = create(SuppliersPlugin::DistributedProduct, :profile => @profile, :supplier => @profile.self_supplier) + + assert_raise RuntimeError do + supplier_product = build(SuppliersPlugin::DistributedProduct, :profile => @other_profile) + product.distribute_from(supplier_product) + end + + supplier_product = create(SuppliersPlugin::DistributedProduct, :profile => @other_profile) + product.profile.add_supplier @other_profile + product.distribute_from supplier_product + assert_equal product.supplier.profile, supplier_product.profile + assert_equal product.supplier.profile, supplier_product.profile + end + + should 'return json for category hierarchy' do + grandparent = create(ProductCategory, :name => 'grand parent') + parent = create(ProductCategory, :name => 'parent') + child = product_category + + product = SuppliersPlugin::DistributedProduct.new :category => parent + hash = {:own_name => "parent", :id => "2", :subcats => [], :name => "parent", + :hierarchy => [{:own_name => "parent", :subcats => [], :name => "parent", :id => "2"}]} + assert_equal hash, product.json_for_category + end + + should 'block own product distribution' do + product = Product.create :enterprise => @profile, :product_category => product_category + distributed = SuppliersPlugin::DistributedProduct.new :enterprise => @profile, :from_products => [product] + + assert distributed.invalid? + end + +end diff --git a/plugins/suppliers/test/unit/suppliers_plugin/product_test.rb b/plugins/suppliers/test/unit/suppliers_plugin/product_test.rb new file mode 100644 index 0000000..947ba74 --- /dev/null +++ b/plugins/suppliers/test/unit/suppliers_plugin/product_test.rb @@ -0,0 +1,49 @@ +require "test_helper" + +class SuppliersPlugin::ProductTest < ActiveSupport::TestCase + + def setup + @product = build(SuppliersPlugin::BaseProduct) + end + + should 'return first from product as supplier product' do + fp = build(SuppliersPlugin::BaseProduct, :profile => @product.profile) + @product.from_products = [fp] + assert_equal fp, @product.from_product + assert_equal fp, @product.supplier_product + end + + should 'respond to dummy and own' do + assert !@product.dummy? + assert @product.own? + end + + should 'return price with margins' do + supplier_product = build(SuppliersPlugin::DistributedProduct, :price => 10, :margin_percentage => 10, :profile => @product.profile, :supplier => @product.profile.self_supplier) + product = build(SuppliersPlugin::DistributedProduct, :price => 10, :margin_percentage => 10, :supplier_product => supplier_product, :profile => @product.profile, :supplier => @product.profile.self_supplier) + + product.default_margin_percentage = false + assert_equal 11.0, product.price_with_margins + @product.profile.margin_percentage = 20 + product.default_margin_percentage = true + assert_equal 12.0, product.price_with_margins + end + + should 'build default unit if none exists' do + assert_equal 0, Unit.count + assert 'unit', @product.unit.singular + end + + should 'avoid destroy by raising an exception' do + assert_raise RuntimeError do + @product.destroy + end + end + + should 'accept price in different formats' do + @product.price = '2,45' + assert_equal 2.45, @product.price + end + + +end diff --git a/plugins/suppliers/test/unit/suppliers_plugin/source_product_test.rb b/plugins/suppliers/test/unit/suppliers_plugin/source_product_test.rb new file mode 100644 index 0000000..a043536 --- /dev/null +++ b/plugins/suppliers/test/unit/suppliers_plugin/source_product_test.rb @@ -0,0 +1,8 @@ +require "#{File.dirname(__FILE__)}/../../test_helper" + +class SuppliersPlugin::SourceProductTest < ActiveSupport::TestCase + + def setup + end + +end diff --git a/plugins/suppliers/test/unit/suppliers_plugin/supplier_test.rb b/plugins/suppliers/test/unit/suppliers_plugin/supplier_test.rb new file mode 100644 index 0000000..f3d53c9 --- /dev/null +++ b/plugins/suppliers/test/unit/suppliers_plugin/supplier_test.rb @@ -0,0 +1,8 @@ +require "#{File.dirname(__FILE__)}/../../test_helper" + +class SuppliersPlugin::SupplierTest < ActiveSupport::TestCase + + def setup + end + +end diff --git a/plugins/suppliers/views/suppliers_plugin_myprofile/margin_change.html.slim b/plugins/suppliers/views/suppliers_plugin_myprofile/margin_change.html.slim new file mode 100644 index 0000000..ad19eac --- /dev/null +++ b/plugins/suppliers/views/suppliers_plugin_myprofile/margin_change.html.slim @@ -0,0 +1,17 @@ +#suppliers-plugin-margin-change.popin + h1= t'views.myprofile.margin_change.change_default_margin' + + = form_for @profile, as: :profile_data, remote: true, url: {controller: :suppliers_plugin_myprofile, action: :margin_change} do |f| + div= t'views.myprofile.margin_change.notice' + + = labelled_field f, :margin_percentage, t('views.myprofile.margin_change.new_margin'), + input_group_addon(t'views.myprofile.margin_change.%'){ f.number_field :margin_percentage, step: 'any' } + + .checkbox + label name='apply_to_all' + = check_box_tag :apply_to_all, 1, false + = t'views.myprofile.margin_change.apply_to_all' + .clean + + = submit_button :save, t('views.myprofile.margin_change.confirm') + = modal_close_link t('views.myprofile.margin_change.cancel') -- libgit2 0.21.2