Update stock before saving template with nested_attributes and gem cocoon

0

Friends, I have a form that uses nested_attributes and I use the cocoon gem. I have 3 models involved. Variation that contains the stock, Order, which contains the order and is the Detail parent that contains the order detail.

The save is working correctly, however I need to update each item's stock before saving.

Fields:

Details:

t.string   "order_id"
t.string   "cod_produto"
t.string   "desc_produto"
t.string   "cod_cor"
t.string   "desc_cor"
t.string   "desc_tamanho"
t.decimal  "preco"
t.integer  "quantidade"
t.datetime "created_at"
t.datetime "updated_at"
t.float    "total"

Orders:

t.string   "customer_id"
t.decimal  "valor_total"
t.integer  "item_total"
t.string   "order_num"
t.datetime "created_at"
t.datetime "updated_at"

Variations:

create_table "variations", force: true do |t|
  t.string   "product_id"
  t.string   "size_id"
  t.string   "color_id"
  t.integer  "quantity"
  t.string   "barcode"
  t.datetime "created_at"
  t.datetime "updated_at"
do

The templates are:

order.rb

class Order < ActiveRecord::Base
  has_many :details, dependent: :destroy
  belongs_to :customer

  accepts_nested_attributes_for :details, reject_if: proc { |attributes| attributes['cod_produto'].blank? }, :allow_destroy => true

  validates :customer_id, :presence => true
  after_validation :sum_details
  after_create :set_order_num

  private

  def set_order_num
    update(order_num: "#{Date.current.year}-#{self.id}")
  end

  def sum_details
    total = 0
    qtd = 0
    self.details.each do |d|
      total += (d.quantidade * d.preco) if d.quantidade.present?
      qtd += d.quantidade if d.quantidade.present?
    end
    self.valor_total = total
    self.item_total = qtd
  end
end

detail.rb

class Detail < ActiveRecord::Base
  belongs_to :order

  after_validation :update_quantity

  before_save :get_quantity

  private

  def get_quantity
    @qtd = self.quantidade
  end

  def update_quantity
    if self.quantidade > 0
      self.quantidade = self.quantidade - @qtd
    end
  end
end

What I need to do is: before saving the detail model (remembering that it is a child form of the order model), I need to find the quantity of a product that is in the variations model and update its quantity. For this you have to take the model detail the product_code + cod_cor + desc_tamanho and look for the barcode field in the variation model to update your inventory. I'm using before_save to try to get the quantity but neither is it working ... Could anyone give some light?

Thank you

EDIT: Inclusion of controllers:

orders_controller.rb

class OrdersController < ApplicationController
before_action :set_order, only: [:show, :edit, :update, :destroy]
require "json"
def consulta_produto
  @variacao = Variation.find_by(barcode:params[:barcode])
  if @variacao.present?
     hash = {:cod_produto => @variacao.product.cod ,:desc_produto => @variacao.product.descricao,:cod_cor => @variacao.color.cod, :desc_cor => @variacao.color.descricao,:desc_tamanho => @variacao.size.descricao,:preco => @variacao.product.price }
     render :json => { :resultado => hash }
  else
    render :json => {:resultado => "error"}
  end
end
# GET /orders
# GET /orders.json
def index
  @orders = Order.all
end
# GET /orders/1
# GET /orders/1.json
def show
end
# GET /orders/new
def new
  @order = Order.new
end
# GET /orders/1/edit
def edit
end
# POST /orders
# POST /orders.json
def create
  @order = Order.new(order_params)
  respond_to do |format|
  if @order.save
    format.html { redirect_to @order, notice: 'Order was successfully created.' }
    format.json { render :show, status: :created, location: @order }
  else
    format.html { render :new }
    format.json { render json: @order.errors, status: :unprocessable_entity }
  end
end
end
# PATCH/PUT /orders/1
# PATCH/PUT /orders/1.json
def update
respond_to do |format|
  if @order.update(order_params)
    format.html { redirect_to @order, notice: 'Order was successfully updated.' }
    format.json { render :show, status: :ok, location: @order }
  else
    format.html { render :edit }
    format.json { render json: @order.errors, status: :unprocessable_entity }
end
end
end
# DELETE /orders/1
# DELETE /orders/1.json
def destroy
@order.destroy
respond_to do |format|
  format.html { redirect_to orders_url, notice: 'Order was successfully destroyed.' }
  format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_order
  @order = Order.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def order_params
  params.require(:order).permit(:customer_id, :valor_total, :item_total, :order_num, details_attributes: [:id,:order_id, :cod_produto, :desc_produto, :cod_cor, :desc_cor, :desc_tamanho,:preco,:quantidade,:total, :_destroy])
end
end

details_controller.rb

before_action :set_detail, only: [:show, :edit, :update, :destroy]

# GET /details
# GET /details.json
def index
@details = Detail.all
end

# GET /details/1
# GET /details/1.json
def show
end

# GET /details/new
def new
@detail = Detail.new
end

# GET /details/1/edit
def edit
end

# POST /details
# POST /details.json
def create
@detail = Detail.new(detail_params)

respond_to do |format|
  if @detail.save
    format.html { redirect_to @detail, notice: 'Detail was successfully created.' }
    format.json { render :show, status: :created, location: @detail }
  else
    format.html { render :new }
    format.json { render json: @detail.errors, status: :unprocessable_entity }
  end
end
end

# PATCH/PUT /details/1
# PATCH/PUT /details/1.json
def update
respond_to do |format|
  if @detail.update(detail_params)
    format.html { redirect_to @detail, notice: 'Detail was successfully updated.' }
    format.json { render :show, status: :ok, location: @detail }
  else
    format.html { render :edit }
    format.json { render json: @detail.errors, status: :unprocessable_entity }
  end
end
end

# DELETE /details/1
# DELETE /details/1.json
def destroy
@detail.destroy
respond_to do |format|
  format.html { redirect_to details_url, notice: 'Detail was successfully destroyed.' }
  format.json { head :no_content }
end
end

private
# Use callbacks to share common setup or constraints between actions.
def set_detail
  @detail = Detail.find(params[:id])
end

# Never trust parameters from the scary internet, only allow the white list through.
def detail_params
  params.require(:detail).permit(:order_id, :cod_produto, :desc_produto, :cod_cor, :desc_cor, :desc_tamanho, :preco, :quantidade)
end

variations_controller.rb

class VariationsController < ApplicationController
before_action :set_variation, only: [:show, :edit, :update, :destroy]
# require 'barby/outputter/cairo_outputter'
# def barcode_output( order )
#       barcode_string = order.barcode
#       barcode = Barby::Code128B.new(barcode_string)

#       # PNG OUTPUT
#       data = barcode.to_image(height: 15, margin: 5).to_data_url
#     end
# GET /variations
# GET /variations.json
def export
@data = Variation.order(:created_at)
# @data = Variation.select(:barcode).order(created_at: :desc)
  respond_to do |format|
    format.html { redirect_to root_url }
    format.csv { send_data @data.to_csv }
  end

end
def index

# @barcode = Barby::Code128B.new("160P10") rescue nil
# @outputter = Barby::HtmlOutputter.new(@barcode)
# @blob = Barby::PngOutputter.new(@barcode).to_png #Raw PNG data

# @barcode = Barby::HtmlOutputter.new('160P10')
# @barcode_for_html = Barby::HtmlOutputter.new(@barcode)
@variations = Variation.all
# @import = Variation::Import.new
respond_to do |format|
  format.html
  format.csv { send_data @variations}
end
# def import
#   @import = Variation::Import.new variation_import_params
#   if @import.save
#     redirect_to variations_path, notice: "Importados #{@import.imported_count} Cod Barras"
#   else
#     @variations = Variation.all
#     flash[:alert] = "Foram encontrados #{@import.errors.count} erros no CSV"
#     render action: index
#   end


# end
# require 'barby/outputter/png_outputter'
# blob = Barby::PngOutputter.new("12345").to_png #Raw PNG data
# File.open('barcode.png', 'wb'){|f| f.write blob }
#Convenience method
# File.open('barcode2.png', 'wb'){|f| f.write barcode.to_png }
# @barcode = Barby::EAN13.new('000000000')
# @barcode_for_html = Barby::CairoOutputter.new("0123456789")

# Variation.new.barcode       # => Barby::Code39 object
# Variation.new.barcode_data  # => <Barby::Code39 object>.to_png
end

# GET /variations/1
# GET /variations/1.json
def show
end

# GET /variations/new
def new
@variation = Variation.new
# @variacoes_js = Variation.joins(:color, :product, :size).includes(:color, :product, :size)
# # ActiveRecord::Base.include_root_in_json = true
# gon.variacoes = @variacoes_js.to_json
# @tamanhos = Size.order(:descricao).select(:id,:descricao)
# gon.tamanhos = @tamanhos.to_json
# @produtos = Product.order(:cod).select(:cod,:descricao)
# gon.produtos = @produtos.to_json

end

# GET /variations/1/edit
def edit
end

# POST /variations
# POST /variations.json
def create
@variation = Variation.new(variation_params)

respond_to do |format|
  if @variation.save
    format.html { redirect_to variations_path, notice: 'Variation was successfully created.' }
    format.json { render :index, status: :created, location: @variation }
  else
    format.html { render :new }
    format.json { render json: @variation.errors, status: :unprocessable_entity }
  end
end
end

# PATCH/PUT /variations/1
# PATCH/PUT /variations/1.json
def update
respond_to do |format|
  if @variation.update(variation_params)
    format.html { redirect_to @variation, notice: 'Variation was successfully updated.' }
    format.json { render :show, status: :ok, location: @variation }
  else
    format.html { render :edit }
    format.json { render json: @variation.errors, status: :unprocessable_entity }
  end
end
end

# DELETE /variations/1
# DELETE /variations/1.json
def destroy
@variation.destroy
respond_to do |format|
  format.html { redirect_to variations_url, notice: 'Variation was successfully destroyed.' }
  format.json { head :no_content }
end
end

private
# Use callbacks to share common setup or constraints between actions.
def set_variation
  @variation = Variation.find(params[:id])
end

# Never trust parameters from the scary internet, only allow the white list through.
def variation_params
  params.require(:variation).permit(:product_id, :size_id, :color_id, :quantity, :barcode)
end
def variation_import_params
  params.require(:variation_import).permit(:file)

end
end
    
asked by anonymous 25.02.2016 / 17:24

1 answer

1

I advise you to create a service that does this, otherwise your model will be flooded with business rules and will not guarantee transaction reliability.

For those cases where an action will involve more than 1 record in the database, it is strongly recommended that you create transactions , which will ensure that both operations occur or none at all.

Researching a little about PORO, service, unattached business rules of the model, may require extra effort at the outset, but will get you a lot of headache in the future.

    
26.02.2016 / 15:25