class SalesController < ApplicationController ##--- Abilities load_and_authorize_resource ##--- Breadcrum_rails add_breadcrumb I18n.t("breadcrumbs." + controller_name), :sales_path add_breadcrumb "Nueva " + I18n.t("breadcrumbs." + controller_name).singularize, :new_sale_path, only: :new add_breadcrumb "Detalle de la " + I18n.t("breadcrumbs." + controller_name).singularize , :sale_path, only: :show add_breadcrumb "Editar " + I18n.t("breadcrumbs." + controller_name).singularize , :edit_sale_path, only: :edit before_action :set_sale, only: [:show, :edit, :update, :destroy] before_action :get_filters, only: [:index, :show, :edit, :new, :sales_reserved] # GET /sales # GET /sales.json def index today = Date.current thirty_day_ago = today - 30 if current_user.usertype == 'A' @sales = Sale.includes(:customer, :user, :seller).where(:date_sale => thirty_day_ago..today).where('saletype != 2').order(" created_at DESC ") else @sales = Pointsale.find(current_user.pointsale_id).sales.includes(:customer, :user, :seller).where(:date_sale => thirty_day_ago..today).where('saletype != 2').order(" created_at DESC ") end end def sales_reserved beg_of_month = Date.current.beginning_of_month end_of_month = Date.current.end_of_month if current_user.usertype == 'A' @sales = Sale.where(:saletype => 2).order(" created_at DESC ") else @sales = Pointsale.find(current_user.pointsale_id).sales.where(:saletype => 2).order(" created_at DESC") end end # GET /sales/1 # GET /sales/1.json def show @payments = CashRegistersMove.where(:sale_id => @sale.id, :status => 1) # saca la devolucion si es que hay. @products_return = ProductsReturn.find_by(:sale_id => @sale.id) @returned_prods_ids = Array.new @returned_prods_ids = @products_return.products_return_ins.pluck(:product_id) if @products_return.present? end # GET /sales/new def new @sale = Sale.new @sale.sales_details.new @general_public_id = Customer.find_by(:is_public => 1).id @pre_sales = PreSale.where(:user_id => current_user.id) @sale.saletype = 'cash' #se desactivan cuando tienen pre sales, para mantener la congruencia de los datos. @disabled_select = false @disabled_button = true @enable_radios = true if current_user.usertype != "G" @open_cash_register = current_user.get_open_cash_register end if @pre_sales.size > 0 @sale.saletype = @pre_sales[0].sale_type @sale.customer_id = @pre_sales[0].customer_id @sale.open_cash_register_id = @pre_sales[0].open_cash_register_id @disabled_select = true @disabled_button = false @enable_radios = false end end # GET /sales/1/edit def edit end # POST /sales # POST /sales.json def create respond_to do |format| @sale = Sale.new(sale_params) @pre_sales = PreSale.where(:user_id => current_user.id) @sale.user_id = current_user.id @sale.open_cash_register_id = current_user.pointsale.get_open_cash_register.id @sale.status = :notpaid @sale.expiration_date = Date.today + @pos_config.days_cancel_reserved if @sale.reserved? @sale.audit_comment = "Venta #{@sale.sale_code} por #{@sale.total} creada." if @sale.save # agregar detalles de la venta @pre_sales.each do |pre_sale| detail = SalesDetail.new detail.product_id = pre_sale.product_id detail.unit_price = pre_sale.unit_price detail.quantity = pre_sale.quantity detail.amount = pre_sale.amount detail.tax = pre_sale.tax detail.discount = pre_sale.discount detail.total = pre_sale.total detail.special_price_id = pre_sale.special_price_id detail.status = :active @sale.sales_details << detail pre_sale.destroy # actualizar stock del producto stockProduct = AvailableProduct.find_by(:product_id => detail.product_id, :pointsale_id => @sale.get_pointsale.id) unless stockProduct.blank? if stockProduct.stock.present? stockProduct.stock = stockProduct.stock - detail.quantity stockProduct.save else errors.add(:base, "No se tiene registrado el stock de alguno de los productos, es necesario configurarlo antes de generar una venta") format.json { render json: @sale.errors.values, status: :unprocessable_entity } end # guardar en bitacora de inventario move = InventoriesMove.new move.product_id = detail.product_id move.sale_id = @sale.id move.quantity = detail.quantity move.move_type = "outgoing" move.reason = "sale" move.save end end # dependiendo el tipo de venta: contado/credito determina que hacer if @sale.cash? format.js { redirect_to new_cash_registers_move_path(:sale => @sale.id) } elsif @sale.credit? credit = Credit.new credit.customer_id = @sale.customer_id credit.pointsale_id = current_user.pointsale_id credit.sale_id = @sale.id credit.total = @sale.total credit.rest = @sale.total credit.status = "active" credit.credit_note = @sale.credit_note if @sale.credit_note.present? credit.save flash[:success] = "Venta a credito registrada al cliente: #{@sale.customer.nick_name} por $ #{@sale.total}" format.js { render 'create_credit_sale' } elsif @sale.reserved? format.js { redirect_to new_cash_registers_move_path(:sale => @sale.id) } end else format.js format.json { render json: @sale.errors, status: :unprocessable_entity } end end end # PATCH/PUT /sales/1 # PATCH/PUT /sales/1.json def update respond_to do |format| if @sale.update(sale_params) format.html { redirect_to @sale, notice: 'Venta modificada.' } format.json { render :show, status: :ok, location: @sale } else format.html { render :edit } format.json { render json: @sale.errors, status: :unprocessable_entity } end end end # DELETE /sales/1 # DELETE /sales/1.json def destroy respond_to do |format| @sale.audit_comment = "Venta #{@sale.sale_code} cancelada." if @sale.update_attributes(:status => :cancelled) if @sale.reserved? return_cash = params[:return_cash] if return_cash == 'true' moves = CashRegistersMove.where(:sale_id => @sale.id, :move_type => 1) if moves.present? if moves[0].open_cash_register.closed? quantity_to_return = moves.sum(:quantity) new_cash_move = CashRegistersMove.new new_cash_move.skip_received_validation = true new_cash_move.open_cash_register_id = current_user.get_open_cash_register.id new_cash_move.payment_method_id = PaymentMethod.find_by(:isCash => 1).id new_cash_move.quantity = quantity_to_return new_cash_move.move_type = :egreso new_cash_move.sale_id = @sale.id new_cash_move.concept = :sale new_cash_move.status = :active new_cash_move.save else moves.destroy_all end end end elsif @sale.cash? #checa si hay pagos de esta venta moves = CashRegistersMove.where(:sale_id => @sale.id) #si la caja sigue abierta, solo elimina los moves, si ya cortó, genera un egreso por esa cantidad if moves.present? if moves[0].open_cash_register.closed? new_cash_move = CashRegistersMove.new new_cash_move.skip_received_validation = true new_cash_move.open_cash_register_id = current_user.pointsale.get_open_cash_register.id new_cash_move.payment_method_id = PaymentMethod.find_by(:isCash => true).id new_cash_move.quantity = moves.sum(:quantity) new_cash_move.move_type = :egreso new_cash_move.sale_id = moves[0].sale_id new_cash_move.concept = :sale new_cash_move.ticket = moves[0].sale.sale_code new_cash_move.status = :active new_cash_move.save else moves.destroy_all end end elsif @sale.credit? credit = Credit.find_by(:sale_id => @sale.id, :customer_id => @sale.customer_id) credit.update_attributes(:status => :cancelled) end @sale.sales_details.each do |detail| detail.update_attributes(:status => :inactive) stockProduct = AvailableProduct.find_by(:product_id => detail.product_id, :pointsale_id => @sale.get_pointsale.id) unless stockProduct.blank? # sumarle al stock del producto stock = stockProduct.stock + detail.quantity stockProduct.update_attributes(:stock => stock) # guardar en bitacora de inventario move = InventoriesMove.new move.product_id = detail.product_id move.sale_id = @sale.id move.quantity = detail.quantity move.move_type = "incoming" move.reason = @sale.reserved? ? "sale_reserved_cancelled" : "sale_cancel" move.save end end format.html { redirect_to (@sale.reserved? ? sales_reserved_path : sales_url), warning: (@sale.reserved? ? "Apartado con folio #{@sale.sale_code} cancelado." : "Venta con folio #{@sale.sale_code} cancelado.") } format.json { head :no_content } end end end def find_sales_by_date respond_to do |format| startDate = DateTime.parse(params[:begin_date]) endDate = DateTime.parse(params[:end_date]) if current_user.usertype == 'A' @sales = Sale.where(:date_sale => startDate..endDate).where('saletype != 2').order(" created_at DESC ") else @sales = Pointsale.find(current_user.pointsale_id).sales.where(:date_sale => startDate..endDate).where('saletype != 2').order(" created_at DESC ") end format.js end end def find_customer_sales_by_date respond_to do |format| startDate = DateTime.parse(params[:begin_date]) endDate = DateTime.parse(params[:end_date]) cliente = params[:cliente] @sales = Sale.where(:date_sale => startDate..endDate, :customer_id => cliente).where('saletype != 2').order(" id DESC ") format.js { render :action => "find_sales_by_date" } end end def find_reserved_sales_by_date respond_to do |format| startDate = DateTime.parse(params[:begin_date]) endDate = DateTime.parse(params[:end_date]) if current_user.usertype == 'A' @sales = Sale.where(:date_sale => startDate..endDate, :saletype => 2).order(" created_at DESC ") else @sales = Pointsale.find(current_user.pointsale_id).sales.where(:date_sale => startDate..endDate).where('saletype = 2').order(" created_at DESC ") end format.js end end def return_expired @sale = Sale.find(params[:sale_id]) respond_to do |format| if @sale.update_attributes(:status => :cancelled_by_expiration) @sale.sales_details.each do |detail| detail.update_attributes(:status => :inactive) stockProduct = AvailableProduct.find_by(:product_id => detail.product_id, :pointsale_id => @sale.get_pointsale.id) unless stockProduct.blank? # sumarle al stock del producto stock = stockProduct.stock + detail.quantity stockProduct.update_attributes(:stock => stock) # guardar en bitacora de inventario move = InventoriesMove.new move.product_id = detail.product_id move.sale_id = @sale.id move.quantity = detail.quantity move.move_type = "incoming" move.reason = "sale_expired" move.save end end format.html { redirect_to sales_reserved_url, warning: "Productos reingresados al inventario del apartado #{@sale.sale_code}." } format.json { head :no_content } end end end def liquidate_reserve respond_to do |format| @sale = Sale.find(params[:sale_id]) @payments = CashRegistersMove.where(:sale_id => @sale.id, :status => 1) format.js { redirect_to new_cash_registers_move_path(:sale => @sale.id) } end end def cancel_reserved_sale @sale = Sale.find(params[:sale_id]) end def print_receipt #ticket para la venta respond_to do |format| sale = Sale.find(params[:sale_id]) format.pdf do render pdf: "ticket_venta_#{sale.id}", template: "sales/receipt.pdf.erb", layout: 'receipt.html.erb', locals: { :sale => sale }, show_as_html: params.key?('debug'), page_width: '80mm', page_height: '300mm' end end end def print_reserve_receipt #ticket para apartado respond_to do |format| sale = Sale.find(params[:sale_id]) # debt = sale.cash_registers_moves.first.quantity debt = sale.cash_registers_moves.sum(:quantity) format.pdf do render pdf: "ticket_apartado_#{sale.id}", template: "sales/receipt_reserve.pdf.erb", layout: 'receipt.html.erb', locals: { :sale => sale, :debt => debt }, show_as_html: params.key?('debug'), page_width: '80mm', page_height: '300mm' end end end def print_credit_receipt #ticket para credito respond_to do |format| sale = Sale.find(params[:sale_id]) debt = 0 sale.customer.credits.activos.each do |credit| debt += credit.rest end format.pdf do render pdf: "ticket_credito_#{sale.id}", template: "sales/receipt_credit.pdf.erb", layout: 'receipt.html.erb', locals: { :sale => sale, :debt => debt }, show_as_html: params.key?('debug'), page_width: '80mm', page_height: '300mm' end end end def print_partial_payment_receipt #ticket para abonos a apartado respond_to do |format| sale = Sale.find(params[:sale_id]) new_moves = CashRegistersMove.where(id: params[:new_moves_array]) quantity = new_moves.sum(:quantity) format.pdf do render pdf: "ticket_abono_apartado_#{sale.id}", template: "sales/receipt_partial_payment.pdf.erb", layout: 'receipt.html.erb', locals: { :sale => sale, :new_payments_quantity => quantity, :moves => new_moves }, show_as_html: params.key?('debug'), page_width: '80mm', page_height: '300mm' end end end def print_credit_payment_receipt #ticket para abonos a credito respond_to do |format| sale = Sale.find(params[:sale_id]) deuda = params[:debts] cash_move = CashRegistersMove.where(:sale_id => sale.id).last quantity = cash_move.quantity debt = Credit.where(:customer_id => sale.customer_id).sum(:rest) format.pdf do render pdf: "ticket_abono_credito_#{sale.id}", template: "sales/receipt_credit_payment.pdf.erb", layout: 'receipt.html.erb', locals: { :sale => sale, :new_payment => quantity, :debt => debt, :deuda => deuda, :move => cash_move }, show_as_html: params.key?('debug'), page_width: '80mm', page_height: '300mm' end end end def add_haggle @pre_sale = PreSale.find(params[:pre_sale]) @suggested_haggle = (@pos_config.haggle_in_sale_percent.to_f / 100) * @pre_sale.unit_price end def create_haggle respond_to do |format| @pre_sale = PreSale.find(params[:pre_sale]) @pre_sale.haggle = params[:haggle].to_f @pre_sale.get_totals if @pre_sale.save format.js end end end def find_sales_by_dates_or_code respond_to do |format| if params[:sale_code].present? @sales = Pointsale.find(current_user.pointsale_id).sales.activas.where(:sale_code => params[:sale_code], :saletype => 1).order("id DESC") else start_date = DateTime.parse(params[:start_date]) end_date = DateTime.parse(params[:end_date]) product_id = params[:product_id] if product_id.present? @sales = Pointsale.find(current_user.pointsale_id).sales.activas.where(:date_sale => start_date..end_date, :saletype => 1).joins(:sales_details).where('sales_details.product_id = (?)', product_id).order("id DESC") else @sales = Pointsale.find(current_user.pointsale_id).sales.activas.where(:date_sale => start_date..end_date, :saletype => 1).joins(:sales_details).order("id DESC") end end format.js end end private # Use callbacks to share common setup or constraints between actions. def set_sale @sale = Sale.find(params[:id]) end def get_filters if params[:current_page].blank? @current_page = 1 else @current_page = params[:current_page] end @filter = params[:filter] end # Never trust parameters from the scary internet, only allow the white list through. def sale_params params.require(:sale).permit(:customer_id, :saletype, :amount, :tax, :discount, :total, :date_sale, :user_id, :seller_id, :sale_code, :credit_note) end end