class CashOutsController < ApplicationController ##--- Abilities load_and_authorize_resource ##--- Breadcrum_rails add_breadcrumb I18n.t("breadcrumbs." + controller_name), :cash_outs_path add_breadcrumb "Nueva Corte de caja ", :new_cash_out_path, only: :new add_breadcrumb "Detalle del corte de caja ", :cash_out_path, only: :show add_breadcrumb "Cajas abiertas ", :opened_cash_registers_path, only: :opened_cash_registers before_action :set_cash_out, only: [:show] before_action :set_data, only: [:new, :create] before_action :get_filters, only: [:index, :show, :new] # GET /cash_outs.json def index case current_user.usertype when "A", "SS" @cash_outs = CashOut.all.includes(:open_cash_register, :user, :received_by).order('cash_outs.created_at desc') when "G" @cash_outs = Pointsale.find(current_user.pointsale_id).cash_outs.includes(:open_cash_register, :user, :received_by).order('cash_outs.created_at desc') when "C" @cash_outs = Pointsale.find(current_user.pointsale_id).cash_outs.includes(:open_cash_register, :user, :received_by).where("cash_outs.user_id = ?", current_user.id).order('cash_outs.created_at desc') end end # GET /cash_outs/1 # GET /cash_outs/1.json def show @incomings = CashRegistersMove.includes(:open_cash_register, :credit_payment, :payment_method).where(open_cash_register_id: @cash_out.open_cash_register.id, move_type: 1, status: 1).order('created_at') @outgoings = CashRegistersMove.includes(:payment_method).where(open_cash_register_id: @cash_out.open_cash_register.id, move_type: 0, status: 1).order('created_at') @sales_total = @incomings.sum(:quantity) @expenses_total = @outgoings.sum(:quantity) end # GET /cash_outs/new def new @cash_out = CashOut.new @cash_out.cash_out_details.new @cash_out.received_cash = nil @cash_out.physical_cash = nil @cash_out.cash_fund = nil end # GET /cash_outs/1/edit def edit; end # POST /cash_outs # POST /cash_outs.json def create final_cash = 0 @cash_out = CashOut.new(cash_out_params) open_cash_register = OpenCashRegister.find(params[:open_cash_register_id]) @cash_out.amount_in = 0 @cash_out.amount_out = 0 @cash_out.open_cash_register_id = open_cash_register.id @cash_out.user_id = current_user.id @cash_out.cash_out_details.each do |detail| @cash_out.amount_in = @cash_out.amount_in + detail.incoming @cash_out.amount_out = @cash_out.amount_out + detail.outgoing if detail.payment_method_id == @cash_payment_method_id final_cash = detail.adjustment end end open_cash_register.expenses.update_all(status: 2) # registered respond_to do |format| message = "Corte de caja de #{@cash_out.open_cash_register.cash_register.name} realizado correctamente" @cash_out.audit_comment = message if @cash_out.save # eliminar el id del open cash de la sesion session.delete(:open_cash_register_id) open_cash_register.update_attributes(status: 'closed', final_cash: final_cash) format.js { flash[:success] = message } else format.js format.json { render json: @cash_out.errors, status: :unprocessable_entity } end end end def get_open_cash_registers respond_to do |format| format.js end end def opened_cash_registers @opened_cash_registers = OpenCashRegister.abiertas end def select_open_cash_to_close @open_cash_register_id = params[:open_cash_register_id] respond_to do |format| format.js end end def find_cash_outs_by_date if params[:begin_date] != "null" && params[:end_date] != "null" start_date = params[:begin_date].in_time_zone(Time.zone).beginning_of_day + 1.days end_date = params[:end_date].in_time_zone(Time.zone).end_of_day + 1.days else start_date = DateTime.now end_date = DateTime.now end @cash_outs = params[:pointsale_id] != "null" ? Pointsale.find(params[:pointsale_id]).cash_outs.includes(:open_cash_register, :user, :received_by).where(created_at: start_date..end_date).order(" id DESC ") : CashOut.all.includes(:open_cash_register, :user, :received_by).where(created_at: start_date..end_date).order('cash_outs.created_at desc') respond_to do |format| format.js end end def print_receipt # ticket para la venta respond_to do |format| @cash_out = CashOut.find(params[:cash_out_id]) products_ids = @cash_out.open_cash_register.sales_details.joins(:sale).where("sales.status != 1").pluck(:product_id).join(",") @pointsale = OpenCashRegister.get_pointsale(@cash_out.open_cash_register_id, "open_cash_register") @initial_cash = @cash_out.open_cash_register.initial_cash @details = @cash_out.open_cash_register.products.present? ? ActiveRecord::Base.connection.exec_query("SELECT SUM(sales_details.quantity) as quantity, SUM(sales_details.total) as total, sales_details.product_id, sub.name as product_name, sub.category, sub.parent FROM sales_details INNER JOIN sales ON sales_details.sale_id = sales.id INNER JOIN (SELECT products. ID as product_id, products.category_id, categories.category, products. NAME, categories.parent_id, parents.category as parent FROM products INNER JOIN categories_products ON categories_products.product_id = products. ID INNER JOIN categories ON categories. ID = categories_products.category_id LEFT JOIN categories as parents ON parents.ID = categories.parent_id WHERE (products. ID IN (#{products_ids}))) sub ON (sales_details.product_id = sub.product_id) WHERE sales.open_cash_register_id = #{@cash_out.open_cash_register_id} and sales.status != 1 GROUP BY sales_details.product_id, sub.category, sub.name, sub.parent ORDER BY sub.category, sub.parent") : Array.new all_sales = Sale.where("open_cash_register_id = (?) and status != 1", @cash_out.open_cash_register_id) @cash_sales = CashRegistersMove.where("open_cash_register_id = (?) and move_type = '1' and status = 1 and sale_id IN (?)", @cash_out.open_cash_register_id, all_sales.where(saletype: 1).pluck(:id)).sum(:quantity) @credit_sales = CashRegistersMove.where("open_cash_register_id = (?) and move_type = '1' and status = 1 and concept = 3", @cash_out.open_cash_register_id).sum(:quantity) @reserved_sales = CashRegistersMove.where("open_cash_register_id = (?) and move_type = '1' and status = 1 and concept IN (4, 6, 7)", @cash_out.open_cash_register_id).sum(:quantity) @details.each do |detail| detail["price_sale"] = Product.find(detail['product_id']).get_price_sale(@pointsale.id) detail["total_without_discount"] = detail["price_sale"] * detail['quantity'].to_f detail["discount"] = detail["total_without_discount"] - detail["total"].to_f end @expenses = Expense.where(open_cash_register_id: @cash_out.open_cash_register_id).activos format.pdf do render pdf: "ticket_corte_#{@cash_out.id}", template: "cash_outs/receipt.pdf.erb", layout: 'receipt.html.erb', locals: { cash_out: @cash_out, details: @details, pointsale: @pointsale, expenses: @expenses, initial_cash: @initial_cash, sales_total: @cash_sales, credit_sales: @credit_sales, reserved_sales: @reserved_sales }, show_as_html: params.key?('debug'), page_width: '80mm', page_height: '300mm' end end end def general_public_invoice @cash_out = CashOut.find(params[:cash_out_id]) crms = CashRegistersMove.where(open_cash_register_id: @cash_out.open_cash_register_id, move_type: 1, status: 1).map(&:sale_id).uniq @sales = Sale.where(id: crms, saletype: 1, require_invoice: false).order(id: :asc) @sales_amount = @sales.sum(:amount) @sales_total = @sales.sum(:total) @sales_tax = @sales.sum(:tax) respond_to do |format| format.js end end def generate_gpi cash_out = CashOut.find(params[:cash_out_id]) subtotal = params[:amount_for_invoice].to_f total_tax = params[:tax_for_invoice].to_f total = subtotal + total_tax sales = CashRegistersMove.where(open_cash_register_id: cash_out.open_cash_register_id, move_type: 1, status: 1).map(&:sale_id).uniq result = invoice_cash_out(cash_out, subtotal, total_tax, total.round(2), sales) respond_to do |format| flash[:notice] = result["invoice"] format.js end end def invoice_cash_out(cash_out, subtotal, total_tax, total, sales) invoice = '' response = Array.new concepts = [] sales = Sale.where(id: sales, saletype: 1, require_invoice: false).order(id: :asc) sales.each do |sale| concepts << { "Quantity" => format('%0.2f', 1).to_s, "UnitKey" => "ACT", "IdNumber" => sale.sale_code, "ProductKey" => "01010101", "Description" => "Venta Publico General - #{sale.sale_code}", "Price" => format('%0.2f', sale.amount).to_s, "Amount" => format('%0.2f', sale.amount).to_s, "Tax" => format('%0.2f', sale.tax).to_s } end save_path = false save_path = create_invoice(cash_out, subtotal, total_tax, total, concepts) xml = true stamp = true if save_path.blank? || save_path == false invoice = "No se pudo generar el XML para la factura electrónica" xml = false end if check_stamper_status.to_i != 200 stamp = false end if xml == true && stamp == true response = stamper(save_path, cash_out, concepts) end if xml == true && stamp == false response = { "code" => 1, "message" => "Servicio de timbrado no esta disponible" } end if xml == false && stamp == true response = { "code" => 2, "message" => "XML no se pudo generar" } end if xml == false && stamp == false response = { "code" => 3, "message" => "XML no se pudo generar y servicio de timbrado no disponible" } end pdf_path = nil if response["code"].to_i.zero? pdf_path = response["message"] invoice = " Factura electrónica generada." else invoice = "#{response['code']} : #{response['message']}" end result = { "invoice" => invoice, "pdf_path" => pdf_path } result end def create_invoice(cash_out, subtotal, total_tax, total, concepts) pointsale = current_user.pointsale save_path = Rails.public_path.join('invoice/xml_origin', "cfdi_gpi_#{cash_out.id}.xml") builder = Nokogiri::XML::Builder.new do |xml| xml.Comprobante(get_namespaces("invoice").merge(get_gpi_attributes(cash_out, subtotal, total, pointsale.postal_code))) do cfdi = xml.doc.root.add_namespace_definition('cfdi', 'http://www.sat.gob.mx/cfd/3') xml.doc.root.namespace = cfdi xml.Emisor(Rfc: pointsale.federal_taxpayer_registration.to_s, Nombre: pointsale.business_name.to_s, RegimenFiscal: pointsale.tax_regime.to_s) xml.Receptor(Rfc: "XAXX010101000", UsoCFDI: "P01") xml.Conceptos do concepts.each do |concept| xml.Concepto(ClaveProdServ: concept['ProductKey'].to_s, ClaveUnidad: concept['UnitKey'].to_s, Cantidad: concept['Quantity'].to_s, NoIdentificacion: concept['IdNumber'].to_s, Descripcion: concept['Description'].to_s, ValorUnitario: concept['Price'].to_s, Importe: concept['Amount'].to_s) do if concept['Tax'].to_f > 0.00 xml.Impuestos { xml.Traslados { xml.Traslado(TipoFactor: "Tasa", TasaOCuota: "#{@pos_config.tax_percent / 100}0000", Impuesto: "002", Base: concept['Amount'].to_s, Importe: format('%0.2f', concept['Tax']).to_s) } } end end end end if total_tax > 0.00 xml.Impuestos(TotalImpuestosTrasladados: format('%0.2f', total_tax).to_s) { xml.Traslados { xml.Traslado(TipoFactor: "Tasa", TasaOCuota: "#{@pos_config.tax_percent / 100}0000", Impuesto: Rails.application.config.issuing['Impuesto'].to_s, Importe: format('%0.2f', total_tax).to_s) } } end end end File.open(save_path, 'w') do |file| file << builder.to_xml end save_path rescue return false end def get_gpi_attributes(cash_out, subtotal, total, postal_code) attributes = { "Version" => Rails.application.config.issuing['Version'].to_s, "Serie" => Rails.application.config.issuing['SerieContado'].to_s, # "Folio" => "", "Fecha" => cash_out.created_at.strftime("%FT%T").to_s, "FormaPago" => "01", "SubTotal" => format('%0.2f', subtotal).to_s, "Moneda" => "MXN", "Total" => format('%0.2f', total).to_s, "TipoDeComprobante" => Rails.application.config.issuing['CveIngreso'].to_s, "MetodoPago" => Rails.application.config.issuing['MetodoPago'].to_s, "LugarExpedicion" => postal_code.to_s } end def stamper(save_path, cash_out, concepts) response = Array.new @stamper = Timbradocfdi::Generator.new(Rails.application.config.issuing['Password'].to_s) t = Time.now check_directorys(t, "ingreso") result = @stamper.timbraCFDI(save_path, cash_out.id).to_json result_json = JSON.parse(result) if result_json['code'].to_i.zero? cash_out_id = cash_out.id @doc = Nokogiri::XML(result_json['xml']) uuid = @doc.xpath("//@UUID") create_xml_stamped(t, "#{uuid}_gpi_#{cash_out_id}.xml", result_json['xml'], "ingreso") create_invoice_qr(t, "qr_#{uuid}_gpi_#{cash_out_id}.png", result_json['qr'], "ingreso") remove_xml_origin(save_path) cash_out.update(invoice_num: uuid) cfdi_type = @doc.xpath("//cfdi:Comprobante//@TipoDeComprobante") invoice_reason = "Venta Publico General" rfc_receptor = @doc.xpath("//cfdi:Receptor//@Rfc") generating_date = @doc.xpath("//@Fecha").to_s stamping_date = @doc.xpath("//@FechaTimbrado").to_s storing_url = "invoice/cfdi/#{t.strftime('%Y')}/#{t.strftime('%m')}/" InvoiceDetail.create(uuid: uuid, cfdi_type: cfdi_type, invoice_reason: invoice_reason, rfc_receptor: rfc_receptor, generating_date: generating_date, stamping_date: stamping_date, storing_url: storing_url) qr_path = "invoice/cfdi/#{t.strftime('%Y')}/#{t.strftime('%m')}/qr/ingreso/qr_#{uuid}_gpi_#{cash_out_id}.png" create_pdf_invoice(t, uuid, cash_out_id, concepts, @doc, result_json['details'], qr_path) pdf_path = "invoice/cfdi/#{t.strftime('%Y')}/#{t.strftime('%m')}/pdf/ingreso/#{uuid}_gpi_#{cash_out_id}.pdf" response = { "code" => result_json['code'].to_i, "message" => pdf_path } else response = { "code" => result_json['code'].to_i, "message" => result_json['message'] } end rescue response = { "code" => -1, "message" => "Ha ocurrido un error inesperado durante el timbrado de la factura" } end def print_invoice uuid = CashOut.find(params[:cash_out_id]).invoice_num storing_url = InvoiceDetail.find_by(uuid: uuid).storing_url respond_to do |format| unless storing_url.blank? pdf_path = "#{storing_url}pdf/ingreso/#{uuid}_gpi_#{params[:cash_out_id]}.pdf" format.js { render action: "print_invoice", locals: { pdf_path: pdf_path } } end format.json { head :no_content } end end private def set_data @cash_out.cash_out_details.destroy_all @cash_payment_method_id = PaymentMethod.find_by(isCash: 1).id @opened_cash_register = (params[:open_cash_register_id].blank? ? OpenCashRegister.find(session[:open_cash_register_id]) : OpenCashRegister.find(params[:open_cash_register_id])) if @opened_cash_register.present? @initial_cash = @opened_cash_register.initial_cash @incomings = CashRegistersMove.incomings(@opened_cash_register.id).order('cash_registers_moves.created_at') @outgoings = CashRegistersMove.outgoings(@opened_cash_register.id).order('cash_registers_moves.created_at') # all_sales = Sale.where("open_cash_register_id = (?) and status != 1", @opened_cash_register.id) sales_ids = CashRegistersMove.where("open_cash_register_id = (?) and move_type = '1' and status = 1", @opened_cash_register.id).pluck("DISTINCT sale_id") all_sales = Sale.activas.where("id IN (?)", sales_ids) @cash_sales = CashRegistersMove.where("open_cash_register_id = (?) and move_type = '1' and status = 1 and sale_id IN (?)", @opened_cash_register.id, all_sales.where(saletype: 1).pluck(:id)).sum(:quantity) @credit_sales = CashRegistersMove.where("open_cash_register_id = (?) and move_type = '1' and status = 1 and concept = 3", @opened_cash_register.id).sum(:quantity) @reserved_sales = CashRegistersMove.where("open_cash_register_id = (?) and move_type = '1' and status = 1 and sale_id IN (?)", @opened_cash_register.id, all_sales.where(saletype: 2).pluck(:id)).sum(:quantity) @expenses_total = @outgoings.sum(:quantity) end @payments = ActiveRecord::Base.connection.exec_query(" SELECT DISTINCT(crm.payment_method_id), pm.method, i.total as incoming, o.total as outgoing, SUM(crm.quantity) AS total from cash_registers_moves as crm LEFT JOIN ( SELECT DISTINCT(payment_method_id), SUM(quantity) as total FROM cash_registers_moves WHERE move_type = '1' and status = 1 and open_cash_register_id = #{@opened_cash_register.id} group by payment_method_id ) as i ON (i.payment_method_id = crm.payment_method_id) LEFT JOIN ( SELECT DISTINCT(payment_method_id), SUM(quantity) as total FROM cash_registers_moves WHERE move_type = '0' and status = 1 and open_cash_register_id = #{@opened_cash_register.id} group by payment_method_id ) as o ON (o.payment_method_id=crm.payment_method_id), payment_methods as pm WHERE pm.id = crm.payment_method_id and crm.open_cash_register_id = #{@opened_cash_register.id} group by crm.payment_method_id, pm.method, i.total, o.total") @payments.each do |payment| payment["incoming"] = "0" if payment["incoming"].nil? payment["outgoing"] = "0" if payment["outgoing"].nil? payment["total"] = payment["incoming"].to_f - payment["outgoing"].to_f # si es el efectivo sumarle el fondo if payment["payment_method_id"].to_i == @cash_payment_method_id payment["total"] += @initial_cash end @cash_out.cash_out_details.build end end def create_pdf_invoice(t, uuid, cash_out_id, concepts, doc, details, qr_path) unless File.exist?(Rails.public_path.join("invoice/cfdi/#{t.strftime('%Y')}/#{t.strftime('%m')}/pdf/ingreso", "#{uuid}_gpi_#{cash_out_id}.pdf")) pdf = render_to_string pdf: "#{uuid}_gpi_#{cash_out_id}", template: "cash_outs/cfdi_gpi.pdf.erb", layout: 'cfdi.html.erb', locals: { doc: doc, uuid: uuid, details: details, qr_path: qr_path, user: current_user, concepts: concepts, pos_config: @pos_config }, show_as_html: params.key?('debug'), page_width: '216mm', page_height: '279mm' save_path = Rails.public_path.join("invoice/cfdi/#{t.strftime('%Y')}/#{t.strftime('%m')}/pdf/ingreso", "#{uuid}_gpi_#{cash_out_id}.pdf") File.open(save_path, 'wb') do |file| file << pdf end end end # Use callbacks to share common setup or constraints between actions. def set_cash_out @cash_out = CashOut.includes(:cash_out_details, cash_out_details: :payment_method).find(params[: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 cash_out_params params.require(:cash_out).permit(:received_by_id, :received_cash, :cash_fund, :physical_cash, :observations, cash_out_details_attributes: [:payment_method_id, :observations, :incoming, :outgoing, :total, :adjustment]) end end