views:

160

answers:

2

hi i have in my model:

validate :check_product_stock

def check_product_stock

  @thisproduct = product.id

   @productbeingchecked = Product.find_by_id(@thisproduct)

   @stocknumber = @productbeingchecked.stock_number

  if producto.en_stock == 0
   raise "El Producto no tiene stock suficiente para completar la venta"

   #errors.add :venta, "Producto con pedos de stock"
   return false
  end
true
end

end

i need to be able to validate on creation of a model (sale), if it's association (product), hasn't reached zero in a product.column called stock_number.

i think i need to rewrite the entire thing but now with validate :check_product_stock then built a method from scratch that checks if product hasn't reached zero and it it has it should throw a flash notice and stay in the same place (sales/new)

class Venta < ActiveRecord::Base

  hobo_model # Don't put anything above this

  belongs_to :cliente, :accessible => true
  belongs_to :producto, :accessible => true
  belongs_to :marca, :accessible => true
  belongs_to :vendedor
  belongs_to :instalador
  has_many :devolucions



  fields do
    numero_de_serie     :string
    precio_de_venta      :integer
    precio_de_instalacion :integer, :default => "0"
    forma_de_pago enum_string(:contado, :tarjeta)
    status enum_string(:activa, :cancelada)
    timestamps
  end

  validates_presence_of :cliente, :precio_de_venta, :vendedor, :precio_de_instalacion

  validate_on_create :check_product_stock

  after_save :descontar_precio_de_instalacion_si_el_instalador_es_a_destajo

#def stock_error

  #flash[:notice] = "Producto con pedos de stock"

#  redirect_to :controller => :venta, :action => :stock_error

     #errors.add_to_base("Producto con pedos de stock") 

 # end

def check_product_stock

if producto.en_stock == 0
 raise "El Producto no tiene stock suficiente para completar la venta"

 #errors.add :venta, "Producto con pedos de stock"
   return false
  end
true
end

#def check_product_stock
#  if producto.en_stock == 0
 #  errors.add :producto, "El Producto no tiene stock suficiente para completar la venta"
 #  return false
#  end
#  true # guards against returning nil which is interpreted as false.
#end




def descontar_precio_de_instalacion_si_el_instalador_es_a_destajo





  @este_instalador_id = instalador.id

  @instalador = Instalador.find_by_id(@este_instalador_id)


  if @instalador.a_destajo?

    @last_venta = Venta.find(:last)

    @vid = @last_venta.id

    @precio_de_instalacion_original = precio_de_instalacion

    @mitad_de_instalacion = @precio_de_instalacion_original/2

    #Venta.update(@vid, :precio_de_instalacion => @mitad_de_instalacion)

    ActiveRecord::Base.connection.execute "UPDATE ventas SET precio_de_instalacion = #{@mitad_de_instalacion} WHERE id = #{@vid};"



  end


end








#after_save :reduce_product_stock_number

# def reduce_product_stock_number
 #  Producto.decrement_counter(:en_stock, producto.id)
#  end




  # --- Permissions --- #

  def create_permitted?
    true
  end

  def update_permitted?
    false
  end

  def destroy_permitted?
    false
  end

  def view_permitted?(field)
    true
  end

end

And this is my observer that diminishes the en_stock column from producto:

class VentaObserver < ActiveRecord::Observer

def after_save(venta)

      @venta_as_array = venta




      if venta.producto_id?

      @pid = @venta_as_array[:producto_id]

      Producto.decrement_counter(:en_stock, @pid)

      end

      if venta.cart_id

        @cid = @venta_as_array[:cart_id] 

        @cart = Cart.find_by_id(@cid)  

        for item in @cart.cart_items do
         #  @pid = @cart.cart_items.producto.id



             Producto.decrement_counter(:en_stock, item.producto.id)

        end

        #si el instalador es a destajo se debe descontar la mitad del rpecio de instalacion






        end

end

end
+2  A: 

flash is not available in the model. You need to do something like this:

errors.add :stocknumber, "Producto con pedos de stock"

And then work with flash in the controller and views.

James Thompson
i'm lost, can you please go deep into this? thanks in advance, what i want is to check if an association (producto) to the main model (venta) hasn't reach zero in the en_stock field.
Carlos Barbosa
Your code is basically fine. The only problem is the call to flash[] which is not accessible within an ActiveRecord model. The right way to handle errors in ActiveRecord is to call errors.add.
James Thompson
if i do: def check_product_stock @thisproduct = producto.id @productbeingchecked = Producto.find_by_id(@thisproduct) @stocknumber = @productbeingchecked.en_stock if @stocknumber == 0 errors.add :stocknumber, "El producto tiene zero existencias disponibles, por lo tanto no puede completarse la venta." endendi get -1 when trying to make a sale with a product with stock in zero, so it's pointless
Carlos Barbosa
+4  A: 

It seems you've got a lot going wrong here.

First of all, you're doing way too much work. This is all you really need.

before_save :check_product_stock

def check_product_stock
  if product.stocknumber == 0
   flash[:notice] = "Producto con pedos de stock"
  end
end

Secondly, the flash hash is not available in models. You can use the ActiveRecord error object to make errors available to the controller and views by replacing

flash[:notice] = with errors.add_to_base

I used errors.add_to_base because the error is not exactly a part of this model, yet is still blocking the save.

Thirdly, it seems like you're reducing product.stocknumber at some point. Probably as a before_validation so it's highly possible that product.stocknumber is less than 0 during the check if product.stocknumber was 0 before the save call.

So let's change the if condition to reflect that.

unless product.stocknumber > 0

Finally, you're using a before_save callback, so just adding an error will not cancel the transaction. You need to return false for a before/after save/create/update/valdiaiton callback to cancel the transaction.

Putting this all together gives you

before_save :check_product_stock

def check_product_stock
  unless product.stocknumber > 0
   errors.add_to_base "Producto con pedos de stock"
   return false
  end
  true # guards against returning nil which is interpreted as false.
end

As for displaying these errors you can either use the nice error_messages_for helper on the object in the view. Or copy the errors to the flash hash in the controller.

In the view:

<%= error_mesages_for :order %>

Or, in the controller in the else block of if @order.save:

 flash[:errors] = @order.errors.full_messages.join "<br />"

I prefer the errors over notice when it comes to passing errors in the flash hash because it makes it easy to distinguish the two via CSS if an action happens to produce both a notices or an error. Also it's more DRY to always display flash[:errors] with a class that gives red text, the write the logic into your view to determine if the contents of flash[:notice] are an error or a notice.

EmFi