class ProductsController < ApplicationController ##--- Abilities load_and_authorize_resource ##--- Breadcrum_rails add_breadcrumb I18n.t("breadcrumbs." + controller_name), :products_path, only: [:index, :new, :show, :edit] add_breadcrumb "Nuevo " + I18n.t("breadcrumbs." + controller_name).singularize, :new_product_path, only: :new add_breadcrumb "Detalle del " + I18n.t("breadcrumbs." + controller_name).singularize, :product_path, only: :show add_breadcrumb "Editar " + I18n.t("breadcrumbs." + controller_name).singularize, :edit_product_path, only: :edit add_breadcrumb "Seguimiento de productos", :product_track_path, only: :product_track before_action :set_product, only: [:show, :edit, :update, :destroy] before_action :set_product_id, only: [:list_prices, :list_prices_variants, :edit_variants, :update_variants, :edit_from_purchase, :update_from_purchase, :update_status] before_action :get_attrs, only: [:show, :edit, :update] before_action :get_filters, only: [:index, :show, :edit, :new] # GET /products # GET /products.json def index respond_to do |format| format.html format.json { render json: ProductsDatatable.new(view_context, current_user) } end end def list_prices if @product.presentation # @available_products = @product.get_available_children(false) @pointsales = @product.get_available_children(true) end end def list_prices_variants children = Product.where("parent_id = ? and status != 0 ", params[:product_id]).pluck(:id) @variants = AvailableProduct.where("pointsale_id = ? and product_id IN (?)", params[:pointsale_id], children).includes(:product) @variants_json = Array.new @variants.each do |v| @variants_json.push(name: v.product.sku + " " + v.product.name + "
" + v.product.display_attributes + "", price: v.product.get_price_sale(params[:pointsale_id]), available_product_id: v.id) end render json: @variants_json.to_json end def edit_variants; end def update_variants if @product.is_parent @product.update_attributes_to_variants(params[:new_size_list], params[:new_color_list], params[:new_style_list]) @product.save_new_attributes(params[:mynewsizes], params[:mynewcolors], params[:mynewstyles]) end respond_to do |format| if @product.save(validate: false) format.html { redirect_to products_url, success: 'Se modificaron las variantes del producto ' + @product.sku + ' - ' + @product.name + '.' } format.json { render :show, status: :ok, location: @product } else format.html { render :edit_variants } format.json { render json: @product.errors, status: :unprocessable_entity } end end end # GET /products/1 # GET /products/1.json def show; end # GET /products/new def new @product = Product.new # Default unit is 'Pieza' @product.unit = Unit.where(unit: 'Pieza').first if params[:remoto].present? @remoto = params[:remoto] @pointsale = params[:pointsale] @warehouse = params[:warehouse] @supplier = params[:supplier] @exchange = params[:exchange] end @product.price_base = nil @product.price_sale = nil end # GET /products/1/edit def edit has_variants = @product.children.any? @with_presentation = has_variants ? true : false # si aun no tiene variantes, permitir clickear el switch end # POST /products # POST /products.json # rubocop:disable Metrics/BlockLength def create @product = Product.new(product_params) if @product.presentation @product.is_parent = true end message = 'El producto ' + @product.sku + ' fue creado.' @product.category_id = params[:sub_category_id].present? ? params[:sub_category_id] : params[:product][:category_id] @product.audit_comment = message respond_to do |format| if @product.save unless @product.is_parent? @product.generate_barcode @product.save end ##--- Para cuando se agrega un producto desde purchase if params[:remoto] == "true" @product.save_variants_no_thread(current_user) ##--- Guardar pre_purchase @pre_purchases = Array.new if @product.presentation && @product.is_parent @product.children.each do |variant| save_pre_purchase(variant) set_available @pre_purchases << @pre_purchase end else save_pre_purchase(@product) set_available @pre_purchases << @pre_purchase end format.json { head :no_content } format.js else @product.save_variants(current_user) # crear available product para el p.v, cuando es sin variantes if current_user.usertype == 'G' && !@product.presentation && !@product.is_parent AvailableProduct.create(product_id: @product.id, pointsale_id: current_user.pointsale_id, stock: 0) end format.html { redirect_to products_url, success: message } format.json { render :show, status: :created, location: @product } end else format.html { render :new } format.json { render json: @product.errors, status: :unprocessable_entity } end end end # rubocop:enable Metrics/BlockLength # PATCH/PUT /products/1 # PATCH/PUT /products/1.json def update respond_to do |format| @product.skip_sku_validation = true @product.is_parent = params[:product][:presentation] == 'true' ? true : false message = 'El producto ' + @product.sku + ' fue modificado.' if params[:sub_category_id].present? params[:product][:category_id] = params[:sub_category_id] end @product.audit_comment = message if @product.update(product_params) if @product.is_parent @product.children.each_with_index do |variant, index| variant.skip_sku_validation = true params_to_edit = product_params params_to_edit[:sku] = @product.sku + (index + 1).to_s + "A" params_to_edit[:barcode] = variant.barcode variant.update_attributes(params_to_edit) end end format.html { redirect_to products_url, success: message } format.json { render :show, status: :ok, location: @product } else format.html { render :edit } format.json { render json: @product.errors, status: :unprocessable_entity } end end end def edit_from_purchase purchase_in_dollars = params[:is_in_dollars] exchange = params[:exchange].to_f if purchase_in_dollars == "true" @product.price_base_dollars = params[:product][:price_base].to_f price_in_peso = @product.price_base_dollars * exchange @product.price_base = @product.price_base.present? ? price_in_peso : nil @suggested_price_sale = (price_in_peso * (@pos_config.gain_margin / 100)) + price_in_peso else @product.price_base = params[:product][:price_base].to_f price_in_dollars = @product.price_base / exchange if exchange != 0 @product.price_base_dollars = @product.price_base_dollars.present? ? price_in_dollars : nil @suggested_price_sale = (@product.price_base * (@pos_config.gain_margin / 100)) + @product.price_base end @suggested_price_sale = 0 if @suggested_price_sale.nil? respond_to do |format| @product.audit_comment = 'El producto ' + @product.sku + ' fue modificado.' @product.save format.json { head :no_content } format.js end end def update_from_purchase ##--- Si el producto es hijo, sacar el registro del padre para cambiar todos los valores unless @product.parent_id.nil? @product = Product.find(@product.parent_id) end @product.price_base = params[:product][:price_base].to_f @product.price_sale = params[:product][:price_sale].to_f message = "Se ha modificado el precio de venta base del producto " + @product.name respond_to do |format| if @product.save @product.children.each do |variant| variant.update_attributes(product_params) variant.save end @product.audit_comment = message format.json { head :no_content } format.js { flash[:success] = message } else @suggested_price_sale = params[:suggested_price_sale].to_f format.js { render :edit_from_purchase } format.json { render json: @available_product.errors, status: :unprocessable_entity } end end end def update_status product = @product if product.active? product.status = 2 elsif product.inactive? product.status = 1 end if product.presentation product.children.each do |pv| pv.status = product.status pv.save(validate: false) end end respond_to do |format| message = "El producto " + product.name + " fue " + (product.active? ? "activado" : "desactivado") + "." product.audit_comment = message if product.save(validate: false) format.html { redirect_to products_url, warning: message } # format.json { render :show, status: :ok, location: @pointsale } format.json { head :no_content } else format.html { redirect_to products_url } format.json { render json: @product.errors, status: :unprocessable_entity } end end end # DELETE /products/1 # DELETE /products/1.json def destroy respond_to do |format| message = "El producto " + @product.name + " fue eliminado." @product.audit_comment = message if @product.update_attributes(status: 0) if @product.is_parent @product.children.each_with_index do |variant| variant.update_attributes(status: 0) variant.save end end format.html { redirect_to products_url, warning: message } format.json { head :no_content } else format.html { redirect_to products_url } format.json { render json: @product.errors, status: :unprocessable_entity } end end end def validate_unique_barcode respond_to do |format| @product = Product.find_by(barcode: params[:barcode]) if @product.blank? format.js { head :ok } else format.js end end end def product_track #--Seguimiento de productos # @sales = SalesDetail.new product_id = params[:product_id] pointsale_id = params[:pointsale_id] start_date = DateTime.parse(params[:start_date]) if params[:start_date].present? end_date = DateTime.parse(params[:end_date]) if params[:end_date].present? if product_id.present? respond_to do |format| @sales = pointsale_id.present? ? Pointsale.find(pointsale_id).sales_details.includes(:sale).where('sales.status > 1 and sales_details.product_id = ? and sales.date_sale BETWEEN ? AND ?', product_id, start_date, end_date).order("sales_details.id DESC") : SalesDetail.find_by_sql("SELECT sales_details.* FROM sales_details INNER JOIN sales ON sales_details.sale_id = sales.id INNER JOIN open_cash_registers ON sales.open_cash_register_id = open_cash_registers.id INNER JOIN cash_registers ON open_cash_registers.cash_register_id = cash_registers.id WHERE ( sales.status > 1 AND sales_details.product_id = #{product_id} and sales.date_sale BETWEEN '#{start_date}' AND '#{end_date}') ORDER BY sales_details.ID DESC") @purchases = pointsale_id.present? ? PurchaseDetail.joins(:purchase).where('purchases.pointsale_id = ? AND purchases.status != 1 and purchase_details.product_id = ? and purchases.purchase_date BETWEEN ? AND ?', pointsale_id, product_id, start_date, end_date).order('purchase_details.id DESC') : PurchaseDetail.find_by_sql("SELECT purchase_details.* FROM purchase_details INNER JOIN purchases ON purchase_details.purchase_id = purchases.id WHERE ( purchases.status != 1 AND purchase_details.product_id = #{product_id} and purchases.purchase_date BETWEEN '#{start_date}' AND '#{end_date}') ORDER BY purchase_details.ID DESC") @total_quantity = pointsale_id.present? ? @sales.sum(:quantity) : ActiveRecord::Base.connection.select_value("SELECT SUM(quantity) as quantity FROM sales LEFT OUTER JOIN sales_details ON sales_details.sale_id = sales.id WHERE (sales.status > 1 and sales_details.product_id = #{product_id} and sales.date_sale BETWEEN '#{start_date}' AND '#{end_date}')") @total_quantity_purchases = pointsale_id.present? ? @purchases.sum(:quantity) : ActiveRecord::Base.connection.select_value("SELECT SUM(quantity) as quantity FROM purchases LEFT OUTER JOIN purchase_details ON purchase_details.purchase_id = purchases.id WHERE (purchases.status != 1 and purchase_details.product_id = #{product_id} and purchases.purchase_date BETWEEN '#{start_date}' AND '#{end_date}')") @total_sales = pointsale_id.present? ? @sales.sum(:total) : ActiveRecord::Base.connection.select_value("SELECT SUM(sales.total) as total FROM sales LEFT OUTER JOIN sales_details ON sales_details.sale_id = sales.id WHERE (sales.status > 1 and sales_details.product_id = #{product_id})") format.js end end end def labels_list @product = Product.find(params[:product_id]) if @product.presentation @pointsales = @product.get_available_children(true) end end def print_labels @products = JSON.parse params[:products] @pointsale_id = params[:pointsale_id] @products.each do |obj| obj['product'] = Product.find(obj['id']) obj['price'] = @pointsale_id.present? ? obj['product'].get_price_sale(@pointsale_id) : obj['product'].price_sale end file_name = "etiquetas_#{Time.now.to_i}" pdf = render_to_string pdf: file_name, template: "products/print_labels.pdf.erb", layout: 'labels.html.erb', locals: { objs: @products }, show_as_html: params.key?('debug'), page_width: '62mm', page_height: '300mm' save_path = Rails.public_path.join("pdfs", "#{file_name}.pdf") File.open(save_path, 'wb') do |file| file << pdf end respond_to do |format| format.js { render action: "print_labels", locals: { pdf_path: "pdfs/#{file_name}.pdf" } } end end private # Use callbacks to share common setup or constraints between actions. def set_product @product = Product.find(params[:id]) end def set_product_id @product = Product.find(params[:product_id]) end def get_filters @current_page = params[:current_page].blank? ? 1 : params[:current_page] @filter = params[:filter] end # Never trust parameters from the scary internet, only allow the white list through. def product_params params.require(:product).permit(:sku, :name, :description, :price_base, :price_sale, :img_product, :img_product_cache, :presentation, :inventory, :unit_id, :content, :status, :category_id, :sub_category_id, :include_purchase_tax, :include_sale_tax, :barcode, :is_in_dollars, :price_base_dollars, size_list: [], color_list: [], style_list: [], available_products_attributes: [:id, :price_sale]) end def save_pre_purchase(product) @pre_purchase = PrePurchase.new @pre_purchase.supplier_id = params[:supplier] @pre_purchase.pointsale_id = params[:pointsale] if params[:pointsale].present? @pre_purchase.warehouse_id = params[:warehouse] if params[:warehouse].present? @pre_purchase.exchange = params[:exchange] if params[:exchange].present? @pre_purchase.user_id = current_user.id @pre_purchase.product_id = product.id @pre_purchase.quantity = 1 @pre_purchase.get_totals @pre_purchase.save end def set_available ##--- agregar a productos disponibles ya sea punto de venta o almacen if params[:pointsale].present? available_product = AvailableProduct.new available_product.pointsale_id = @pre_purchase.pointsale_id else available_product = WarehouseStock.new available_product.warehouse_id = @pre_purchase.warehouse_id end available_product.product_id = @pre_purchase.product_id available_product.stock_min = params[:stock_min] available_product.stock_max = params[:stock_max] available_product.save end def get_attrs @attrs = Array.new @product.variants_attributes.each do |attri| @attrs << attri.context end end end