Browse Source

new advanced search in product waste, transfers, purchases, products return

jose miguel 7 years ago
parent
commit
eefe73604e

+ 59 - 20
app/controllers/application_controller.rb

@@ -37,15 +37,32 @@ class ApplicationController < ActionController::Base
 
   def find
     query = params[:query]
-    if query.include? ':'
-      # buscar con atributos
-      product_name = query[0, query.index(':') - 1]
-      attribute =  query[query.index(':') + 1, query.length]
+    if query.include? ':' # search with attributes
+      query_array = query.split(':')
+      product_name = query_array[0]
+      query_array.shift # delete the name of the product from the array to iterate the attributes
+      attrs_query_string = ''
+      query_array.each do |attribute|
+        if attribute.present?
+          attr_type = case attribute[0]
+                      when 'c'
+                        'colors'
+                      when 't'
+                        'sizes'
+                      when 'e'
+                        'styles'
+                      end
+          attribute[0] = "" # delete the attribute type character
+          attrs_query_string.concat(" AND attributes_json::json->>'#{attr_type}' ilike '%#{attribute}%'")
+        else
+          next
+        end
+      end
     else
       product_name = query
     end
 
-    render json: query.include?(":") ? Product.name_sku_barcode_attribute_like(product_name, attribute).limit(30).to_json(methods: [:small_img, :display_attributes]) : Product.name_sku_barcode_like(params[:query]).limit(30).to_json(methods: [:small_img, :display_attributes])
+    render json: query.include?(":") ? Product.name_sku_barcode_attribute_like(product_name, attrs_query_string).limit(30).to_json(methods: [:small_img, :display_attributes]) : Product.name_sku_barcode_like(params[:query]).limit(30).to_json(methods: [:small_img, :display_attributes])
   end
 
   # para special_prices
@@ -84,30 +101,52 @@ class ApplicationController < ActionController::Base
     end
 
     if current_user.usertype == 'S'
-      render json: query.include?(":") ? Warehouse.find(current_user.warehouse_id).products.name_sku_barcode_multiple_attribute_like(product_name, attrs_query_string).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes]) : Warehouse.find(current_user.warehouse_id).products.name_sku_barcode_like(params[:query]).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes])
+      render json: query.include?(":") ? Warehouse.find(current_user.warehouse_id).products.name_sku_barcode_attribute_like(product_name, attrs_query_string).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes]) : Warehouse.find(current_user.warehouse_id).products.name_sku_barcode_like(params[:query]).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes])
     else
-      render json: query.include?(":") ? Pointsale.find(current_user.pointsale_id).products.name_sku_barcode_multiple_attribute_like(product_name, attrs_query_string).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes]) : Pointsale.find(current_user.pointsale_id).products.name_sku_barcode_like(params[:query]).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes])
+      render json: query.include?(":") ? Pointsale.find(current_user.pointsale_id).products.name_sku_barcode_attribute_like(product_name, attrs_query_string).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes]) : Pointsale.find(current_user.pointsale_id).products.name_sku_barcode_like(params[:query]).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes])
     end
   end
 
+  # rubocop:disable Metrics/BlockNesting
   def find_from_stock_by_pointsale
-    id = params[:pointsale_id][2, params[:pointsale_id].length]
-
-    query = params[:query]
-    if query.include? ':'
-      # buscar con atributos
-      product_name = query[0, query.index(':') - 1]
-      attribute =  query[query.index(':') + 1, query.length]
-    else
-      product_name = query
-    end
+    if params[:pointsale_id].present?
+      id = params[:pointsale_id][2, params[:pointsale_id].length]
+      query = params[:query]
+      if query.include? ':' # search with attributes
+        query_array = query.split(':')
+        product_name = query_array[0]
+        query_array.shift # delete the name of the product from the array to iterate the attributes
+        attrs_query_string = ''
+        query_array.each do |attribute|
+          if attribute.present?
+            attr_type = case attribute[0]
+                        when 'c'
+                          'colors'
+                        when 't'
+                          'sizes'
+                        when 'e'
+                          'styles'
+                        end
+            attribute[0] = "" # delete the attribute type character
+            attrs_query_string.concat(" AND attributes_json::json->>'#{attr_type}' ilike '%#{attribute}%'")
+          else
+            next
+          end
+        end
+      else
+        product_name = query
+      end
 
-    if params[:pointsale_id].first == 'P'
-      render json: query.include?(":") ? Pointsale.find(id).products.name_sku_barcode_attribute_like(product_name, attribute).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes]) : Pointsale.find(id).products.name_sku_barcode_like(params[:query]).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes])
+      if params[:pointsale_id].first == 'P'
+        render json: query.include?(":") ? Pointsale.find(id).products.name_sku_barcode_attribute_like(product_name, attrs_query_string).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes]) : Pointsale.find(id).products.name_sku_barcode_like(params[:query]).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes])
+      else
+        render json: query.include?(":") ? Warehouse.find(id).products.name_sku_barcode_attribute_like(product_name, attrs_query_string).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes]) : Warehouse.find(id).products.name_sku_barcode_like(params[:query]).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes])
+      end
     else
-      render json: query.include?(":") ? Warehouse.find(id).products.name_sku_barcode_attribute_like(product_name, attribute).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes]) : Warehouse.find(id).products.name_sku_barcode_like(params[:query]).where("stock > 0").limit(30).to_json(methods: [:small_img, :display_attributes])
+      render json: {}
     end
   end
+  # rubocop:enable Metrics/BlockNesting
 
   def get_subcategories
     render json: params[:category_id] != '0' ? Category.activos.where("parent_id = ?", params[:category_id]) : Category.activos.where('parent_id != 0')

+ 1 - 2
app/models/product.rb

@@ -55,8 +55,7 @@ class Product < ActiveRecord::Base
   scope :activos_children, -> { where("status = 1 and is_parent = false ").order("products.name ASC") }
   scope :vigentes_parents, -> { where("status != 0 and parent_id IS NULL ").order(" status ASC, name ASC") }
   scope :name_sku_barcode_like, ->(name) { where("status = 1 and is_parent = false and (name ilike ? or sku ilike ? or barcode ilike ?)", "%#{name}%", "%#{name}%", "%#{name}%").order("name") }
-  scope :name_sku_barcode_attribute_like, ->(name, attribute) { where("status = 1 and is_parent = false and (name ilike ? or sku ilike ? or barcode ilike ?) and attributes_json ilike ?", "%#{name}%", "%#{name}%", "%#{name}%", "%#{attribute}%").order("name") }
-  scope :name_sku_barcode_multiple_attribute_like, ->(name, attributes_string) { where("status = 1 and is_parent = false and (name ilike ? or sku ilike ? or barcode ilike ?) #{attributes_string}", "%#{name}%", "%#{name}%", "%#{name}%").order("name") }
+  scope :name_sku_barcode_attribute_like, ->(name, attributes_string) { where("status = 1 and is_parent = false and (name ilike ? or sku ilike ? or barcode ilike ?) #{attributes_string}", "%#{name}%", "%#{name}%", "%#{name}%").order("name") }
   # para special_prices
   scope :name_sku_barcode_like_sp, ->(name) { where("status = 1 and is_parent = true and (name ilike ? or sku ilike ? or barcode ilike ?)", "%#{name}%", "%#{name}%", "%#{name}%").order("name") }
 

+ 21 - 21
app/views/product_wastes/new.html.erb

@@ -22,7 +22,7 @@
 				<!-- BEGIN PAGE BREADCRUMBS -->
 				<ul class="page-breadcrumb breadcrumb">
 					<%= render_breadcrumbs :tag => :li, :separator => ' <i class="fa fa-circle"></i> ' %>
-				</ul>    
+				</ul>
 				<!-- END PAGE BREADCRUMBS -->
 				<!-- BEGIN PAGE CONTENT INNER -->
 				<div class="page-content-inner">
@@ -38,37 +38,37 @@
 									</div>
 								</div>
 								<div class="portlet-body form form-horizontal">
-									<div id="error_explanation"></div> 
+									<div id="error_explanation"></div>
 										<div class="form-body">
 											<h4 class="form-section"> Agregar producto</h4>
 											<div class="row">
 												<div class="col-md-12">
 													<div class="form-group">
 														<%= label_tag "product",  {:class=>"col-md-3 control-label"} do %>Producto <span class="required">*</span>
-														<% end %> 
-														<div class="col-md-6"> 
-															<input class="form-control" type="text" id="typeahead" data-option-url="/find_products_from_stock/%QUERY"> 
-														</div>		                    		
+														<% end %>
+														<div class="col-md-6">
+															<input class="form-control" type="text" id="typeahead">
+														</div>
 													</div>
 													<div class="form-group">
 														<%= label_tag "quantity",  {:class=>"col-md-3 control-label"} do %>Cantidad mermada <span class="required">*</span>
-														<% end %> 
+														<% end %>
 														<div class="col-md-9">
 															<%= number_field_tag "quantity", "", class: 'form-control input-small' %>
 														</div>
 													</div>
 													<div class="form-group">
 														<%= label_tag "reason", {:class=>"col-md-3 control-label"} do %> Motivo <span class="required">*</span>
-														<% end %> 
+														<% end %>
 														<div class="col-md-6">
 															<%= text_area_tag "reason", "", class: 'form-control', rows: 5 %>
 														</div>
-													</div> 
+													</div>
 													<div class="form-group">
 														<div class="col-md-offset-3 col-md-9">
 															<button id="products_new" disabled class="btn btn-success" type="button" onclick="addRow()"> Agregar <i class="fa fa-plus"></i> </button>
 														</div>
-													</div>									                   	
+													</div>
 												</div>
 											</div>
 											<!-- lista de productos -->
@@ -94,11 +94,11 @@
 													<%= render 'form' %>
 												</div>
 											</div>
-										</div>	
+										</div>
 										<div class="form-actions">
 										</div>
-									</div>              	
-								</div>  
+									</div>
+								</div>
 							</div>
 						</div>
 					</div>
@@ -119,7 +119,7 @@
 		},
 		queryTokenizer: Bloodhound.tokenizers.whitespace,
 		remote: {
-			url: $('#typeahead').data('option-url'),
+			url: '/find_products_from_stock?query=%QUERY',
 			wildcard: '%QUERY'
 		}
 	});
@@ -129,11 +129,11 @@
 	$('#typeahead').typeahead(
 		{
 			minLength: 3
-		}, 
+		},
 		{
 			displayKey: 'name',
 			source: bloodhound.ttAdapter(),
-			limit: Infinity,    
+			limit: Infinity,
 			templates: {
 				empty: [
 					'<div class="empty-message">',
@@ -151,7 +151,7 @@
 									'<h4 class="media-heading"><strong>{{name}}</strong> | {{sku}}</h4>' +
 									'<p>{{barcode}}</p>' +
 									'<p>{{description}}</p>' +
-									'<p>{{display_attributes}}</p>' +                  
+									'<p>{{display_attributes}}</p>' +
 							'</div>' +
 						'</div>')
 			}
@@ -169,13 +169,13 @@
 			$('#product_waste_quantity').val($('#quantity').val());
 			$('#product_waste_reason').val($('#reason').val());
 			$('#new_product_waste').submit();
-		$('#typeahead').typeahead('val',''); 
+		$('#typeahead').typeahead('val','');
 				$('#products_new').attr('disabled', true);
 				$('#quantity').val("");
 				$('#reason').val("");
 		} else {
 		toastr["error"]("Error, Se debe indicar la cantidad.");
-		} 
+		}
 	}
 
 		function deleteRow(input) {
@@ -190,10 +190,10 @@
 				success: function(xhr, status, error) {
 					table.row(input.closest('tr')).remove().draw();
 				}
-			});    
+			});
 		}
 
-	 
+
 </script>
 
 

+ 6 - 6
app/views/products/product_track.html.erb

@@ -60,7 +60,7 @@
 											<div class="col-md-6">
 												<div class="search-label uppercase">Producto <span class="required">*</span></div>
 												<div class="col-md-12">
-													<input class="form-control" type="text" id="typeahead" data-option-url="/find_products/%QUERY"> 
+													<input class="form-control" type="text" id="typeahead">
 													<%= hidden_field_tag :product_id %>
 												</div>
 											</div>
@@ -121,7 +121,7 @@
 			},
 			queryTokenizer: Bloodhound.tokenizers.whitespace,
 			remote: {
-				url: "/find_products/" +"%QUERY",
+				url: '/find_products?query=%QUERY',
 				wildcard: '%QUERY'
 			}
 		});
@@ -130,7 +130,7 @@
 		$('#typeahead').typeahead(
 			{
 				minLength: 3
-			}, 
+			},
 			{
 				displayKey: 'name',
 				source: bloodhound.ttAdapter(),
@@ -152,7 +152,7 @@
 									'<h4 class="media-heading"><strong>{{sku}}</strong> | {{name}}</h4>' +
 									'<p>{{barcode}}</p>' +
 									'<p>{{description}}</p>' +
-									'<p>{{display_attributes}}</p>' +                    
+									'<p>{{display_attributes}}</p>' +
 								'</div>' +
 							'</div>')
 				}
@@ -160,7 +160,7 @@
 
 		$('#typeahead').bind('typeahead:selected', function(event, datum, name) {
 			selectedProduct = datum;
-			$('#btn_search_by_period').attr('disabled', false);       
+			$('#btn_search_by_period').attr('disabled', false);
 		});
 		//buscar ventas por periodo de tiempo
 		function findSalesByPeriod() {
@@ -193,7 +193,7 @@
 						success: function(data) {
 							App.unblockUI($("#track_detail"));
 						}
-					});       
+					});
 				} else {
 					toastr["error"]("Es necesario indicar un producto.");
 				}

+ 4 - 4
app/views/products_returns/_form.html.erb

@@ -90,7 +90,7 @@
                   <div class="form-group">
                     <label class="col-md-1 control-label" for="typeahead" style="padding-right:0px">Producto</label>
                     <div class="col-md-4">
-                      <input class="form-control" type="text" id="typeahead" data-option-url="/find_products/%QUERY">
+                      <input class="form-control" type="text" id="typeahead">
                     </div>
                     <button type="button" id="btn_search_by_period" class="btn green" style="margin-left:10px" onclick="clearTypeahead()">Limpiar</button>
                   </div>
@@ -248,7 +248,7 @@
                     <span class="required">*</span>
                   </label>
                   <div class="col-md-4">
-                    <input class="form-control" type="text" id="typeahead2" data-option-url="/find_products_from_stock/%QUERY">
+                    <input class="form-control" type="text" id="typeahead2">
                   </div>
                   <button id="products_new" class="btn btn-success" type="button" onclick="addnewProd()"> Agregar <i class="fa fa-plus"></i> </button>
                 </div>
@@ -340,7 +340,7 @@
     },
     queryTokenizer: Bloodhound.tokenizers.whitespace,
     remote: {
-      url: "/find_products/" +"%QUERY",
+      url: '/find_products?query=%QUERY',
       wildcard: '%QUERY'
     }
   });
@@ -388,7 +388,7 @@
     },
     queryTokenizer: Bloodhound.tokenizers.whitespace,
     remote: {
-      url: $('#typeahead2').data('option-url'),
+      url: '/find_products_from_stock?query=%QUERY',
       wildcard: '%QUERY'
     }
   });

+ 78 - 78
app/views/purchases/_form.html.erb

@@ -11,7 +11,7 @@
 				<span class="input-group-addon"><i class="fa fa-barcode"></i></span>
 				<%= f.text_field :purchase_code, {:class=>"form-control", :readonly => true} %>
 			</div>
-		</div>  
+		</div>
 		<!-- fecha -->
 		<div class="form-group">
 			<%= f.label :purchase_date, {:class=>"col-md-2 control-label"} do %> Fecha
@@ -21,26 +21,26 @@
 				<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
 				<%= f.date_field :purchase_date, {:value=>Date.today, :class=>"form-control", :readonly => true} %>
 			</div>
-		</div> 
+		</div>
 		<!-- tipo de destino -->
 		<div class="form-group">
-			<%= label_tag 'destiny', {:class=>"col-md-2 control-label"} do %> Destino del producto 
+			<%= label_tag 'destiny', {:class=>"col-md-2 control-label"} do %> Destino del producto
 			<span class="required">*</span>
 			<% end %>
 			<div class="col-md-3" style="padding-left:0px;padding-right:0px">
 				<%= check_box_tag('destiny', 'warehouse', (@destiny == 'warehouse' ? true : false),
-					{ 
+					{
 						class: "make-switch",
 						disabled: @disable_destiny,
 						data: {
 							on_color: "success",
 							off_color: "warning",
-							on_text: "Almacén", 
+							on_text: "Almacén",
 							off_text: "Punto de venta"
 						}
 					}) %>
 			</div>
-		</div>       
+		</div>
 		<!-- punto de venta -->
 		<div class= "form-group <%=(@destiny == 'pointsale' ? '' : 'hidden')%>"  id='pointsale_div'>
 			<%= f.label :pointsale_id, "Punto de venta", {:class=>"col-md-2 control-label"} do %> Punto de venta
@@ -50,7 +50,7 @@
 				<%= f.collection_select :pointsale_id, Pointsale.activos, :id, :name, {:prompt => "Seleccione"}, {:class => "form-control select2", :disabled => @disable_pointsale} %>
 				<%= f.hidden_field :pointsale_id, {:id => 'pointsale'} %>
 			</div>
-		</div>   
+		</div>
 		<!-- almacen -->
 		<div class= "form-group <%=(@destiny == 'warehouse' ? '' : 'hidden')%>"  id='warehouse_div'>
 			<%= f.label :warehouse_id, "Almacén", {:class=>"col-md-2 control-label"} do %> Almacén
@@ -60,7 +60,7 @@
 				<%= f.collection_select :warehouse_id, Warehouse.activos, :id, :name, {:prompt => "Seleccione"}, {:class => "form-control select2", :disabled => @disable_warehouse} %>
 				<%= f.hidden_field :warehouse_id, {:id => 'warehouse'} %>
 			</div>
-		</div>            
+		</div>
 		<!-- proveedor -->
 		<div class="form-group">
 			<%= f.label :supplier_id, "Proveedor", {:class=>"col-md-2 control-label"} do %> Proveedor
@@ -70,24 +70,24 @@
 				<%= f.collection_select :supplier_id, Supplier.activos, :id, :nick_name, {:prompt => "Seleccione"}, {:class => "form-control select2", :disabled => @disable_supplier} %>
 				<%= f.hidden_field :supplier_id, {:id => 'supplier'} %>
 			</div>
-		</div> 
+		</div>
 		<div class="form-group">
-			<%= f.label :is_in_dollars, {:class=>"col-md-2 control-label"} do %> tipo de Moneda 
+			<%= f.label :is_in_dollars, {:class=>"col-md-2 control-label"} do %> tipo de Moneda
 				<span class="required">*</span>
 			<% end %>
 			<div class="col-md-3"  style="padding-left:0px;padding-right:0px">
-				<%= f.check_box(:is_in_dollars,   
+				<%= f.check_box(:is_in_dollars,
 					{
 						class: "make-switch",
 						disabled: @disable_is_in_dollars,
 						data: {
 							on_color: "success",
 							off_color: "warning",
-							on_text: "Dolares", 
+							on_text: "Dolares",
 							off_text: "Pesos"
 						}
 					},
-					"true", "false"  
+					"true", "false"
 				) %>
 			</div>
 			<%= f.hidden_field :is_in_dollars, {:id => 'is_in_dollars'} %>
@@ -97,34 +97,34 @@
 			<span class="required">*</span>
 			<% end %>
 			<div class="col-md-3 input-group">
-				<span class="input-group-addon"><i class="fa fa-usd"></i></span>        
+				<span class="input-group-addon"><i class="fa fa-usd"></i></span>
 				<%= f.number_field :exchange, {:class=>"form-control", :step=>"any"} %>
-			</div>      
+			</div>
 		</div>
 		<!-- boton para resetear datos -->
 		<div class="col-md-offset-10 col-md-2">
 			<button id="reset_pre_purchases" type="button" class="btn btn-warning" <%= @disabled_button ? 'disabled' : '' %> onclick="deletePrePurchases()">Restaurar compra</button>
-		</div>    
+		</div>
 		<!-- agregar productos -->
 		<h4 class="form-section"> Agregar producto</h4>
 		<div class="row">
-			<div class='col-md-12'> 
+			<div class='col-md-12'>
 				<div class="col-md-10">
 					<div class="form-group">
 						<label class="col-md-2 control-label" for="typeahead"> Producto
 							<span class="required">*</span>
 						</label>
-						<div class="col-md-4"> 
-							<input class="form-control" type="text" id="typeahead" data-option-url="/find_products/%QUERY"> 
+						<div class="col-md-4">
+							<input class="form-control" type="text" id="typeahead">
 						</div>
-						<button id="products_new" disabled class="btn btn-success" type="button" onclick="addRow()"> <i class="fa fa-plus"></i> Agregar </button>  
-					</div>          
+						<button id="products_new" disabled class="btn btn-success" type="button" onclick="addRow()"> <i class="fa fa-plus"></i> Agregar </button>
+					</div>
 				</div>
 				<div class="col-md-2">
-					<button id="products_add_new" class="btn btn-success" type="button" onclick="addNewProduct()">  <i class="fa fa-plus"></i> Nuevo Producto </button>           
+					<button id="products_add_new" class="btn btn-success" type="button" onclick="addNewProduct()">  <i class="fa fa-plus"></i> Nuevo Producto </button>
 				</div>
 			</div>
-		</div> 
+		</div>
 		<!-- lista de productos -->
 		<h4 class="form-section"> Lista de productos</h4>
 		<div class="portlet-body">
@@ -159,7 +159,7 @@
 				 </div>
 			 </div>
 			<div class="col-md-offset-1 col-md-5">
-					<div class="well">         
+					<div class="well">
 							<div class="row static-info align-reverse">
 									<div class="col-md-4 name"> Sub Total: </div>
 									<div class="col-md-8 value " id="amount_div">
@@ -175,7 +175,7 @@
 									<div class="col-md-8 value " id="tax_div">
 											<div class="input-group">
 												<span class="input-group-addon">$ </span>
-												<%= f.text_field :tax, {:class=>"form-control descto", :readonly => true, :id => "tax"}  %> 
+												<%= f.text_field :tax, {:class=>"form-control descto", :readonly => true, :id => "tax"}  %>
 												<span class="input-group-addon"></span>
 											</div>
 									</div>
@@ -186,32 +186,32 @@
 											<div class="input-group">
 												<span class="input-group-addon">$ </span>
 												<%= f.text_field :total, {:class=>"form-control descto", :readonly => true, :id => "total"}  %>
-												<span class="input-group-addon"></span> 
+												<span class="input-group-addon"></span>
 											</div>
 									</div>
 							</div>
 					</div>
 			</div>
 			<div class="col-md-offset-7 col-md-5 hidden" id="total_in_mxn_div">
-					<div class="well">         
+					<div class="well">
 						<div class="row static-info align-reverse">
 								<div class="col-md-4 name"> Total en pesos: </div>
 								<div class="col-md-8 value ">
 										<div class="input-group">
 											<span class="input-group-addon">$ </span>
 												<%= text_field_tag :total_in_mxn, '' , :class=>"form-control", :readonly => true %>
-											<span class="input-group-addon">MXN</span> 
+											<span class="input-group-addon">MXN</span>
 										</div>
 								</div>
 						</div>
 					</div>
-			</div>      
-		</div>   
+			</div>
+		</div>
 		<!-- acciones del form -->
 		<div class="form-actions">
 			<div class="row">
 				<div class="col-md-offset-2 col-md-9">
-					<%= f.submit 'Guardar', {:class=>"btn green"} %> 
+					<%= f.submit 'Guardar', {:class=>"btn green"} %>
 					<%= link_to 'Cancelar', purchases_path(:filter => @filter, :current_page => @current_page), {:class=>"btn default"} %>
 				</div>
 			</div>
@@ -239,12 +239,12 @@
 		$('#purchase_is_in_dollars').on('switchChange.bootstrapSwitch', function(event, state) {
 			showExchangeField(state);
 			$('#is_in_dollars').val(state);
-		});    
+		});
 
 		$("#new_pre_purchase").bind('ajax:complete', function() {
 			calculateTotals();
-			$('#purchase_is_in_dollars').bootstrapSwitch('disabled', true);  
-			$('#destiny').bootstrapSwitch('disabled', true);  
+			$('#purchase_is_in_dollars').bootstrapSwitch('disabled', true);
+			$('#destiny').bootstrapSwitch('disabled', true);
 		});
 
 		$('#purchase_supplier_id').on('change', function() {
@@ -276,7 +276,7 @@
 
 		$('body').barcodeListener().on('barcode.valid', function(e, code) {
 			findProductByBarcode(code);
-		}); 
+		});
 
 			var bloodhound = new Bloodhound({
 				datumTokenizer: function (d) {
@@ -284,7 +284,7 @@
 				},
 				queryTokenizer: Bloodhound.tokenizers.whitespace,
 				remote: {
-					url: "/find_products/" +"%QUERY",
+					url: '/find_products?query=%QUERY',
 					wildcard: '%QUERY'
 				}
 			});
@@ -293,7 +293,7 @@
 		$('#typeahead').typeahead(
 			{
 				minLength: 3
-			}, 
+			},
 			{
 				displayKey: 'name',
 				source: bloodhound.ttAdapter(),
@@ -313,9 +313,9 @@
 								'</div>' +
 								'<div class="media-body">' +
 										'<h4 class="media-heading"><strong>{{sku}}</strong> | {{name}}</h4>' +
-										'<p>{{barcode}}</p>' +                    
+										'<p>{{barcode}}</p>' +
 										'<p>{{description}}</p>' +
-										'<p>{{display_attributes}}</p>' +                    
+										'<p>{{display_attributes}}</p>' +
 								'</div>' +
 							'</div>')
 				}
@@ -330,7 +330,7 @@
 			var warehouse = $('#purchase_warehouse_id').val();
 
 			if( (supplier && pointsale) || (supplier && warehouse) ) {
-				$('#products_new').attr('disabled', false);       
+				$('#products_new').attr('disabled', false);
 			} else {
 				toastr["error"]("Se debe seleccionar proveedor y destino de la compra.");
 			}
@@ -345,7 +345,7 @@
 			if( (supplier && pointsale) || (supplier && warehouse) ) {
 				$.ajax({
 					type: "GET",
-					url: "/products/new", 
+					url: "/products/new",
 					dataType: "script",
 					data: {
 						remoto: true,
@@ -355,7 +355,7 @@
 						exchange: exchange
 					},
 					success: function(xhr, status, error) {}
-				});   
+				});
 			} else {
 				toastr["error"]("Se debe seleccionar proveedor y destino de la compra.");
 			}
@@ -375,7 +375,7 @@
 				$('#pre_purchase_total').val(0);
 
 				$('#new_pre_purchase').submit();
-				$('#typeahead').typeahead('val',''); 
+				$('#typeahead').typeahead('val','');
 				$('#products_new').attr('disabled', true);
 			}
 		}
@@ -393,11 +393,11 @@
 					table.row(input.closest('tr')).remove().draw();
 					calculateTotals();
 				}
-			});    
+			});
 		}
 
 		function updateQuantity(input) {
-			if(input.val()) {       
+			if(input.val()) {
 				clearTimeout(timeout);
 				timeout = setTimeout(function () {
 					tax = 0;
@@ -413,9 +413,9 @@
 						taxPercent = parseFloat($('#tax_percent').val()) / 100
 						tax =  (taxPercent  * amount) / (1 + taxPercent);
 					}
-					input.closest('tr').find('td:eq(6)').text(Math.round(tax * 100) / 100); 
-					input.closest('tr').find('td:eq(7)').text(Math.round(amount * 100) / 100);  
-					calculateTotals(); 
+					input.closest('tr').find('td:eq(6)').text(Math.round(tax * 100) / 100);
+					input.closest('tr').find('td:eq(7)').text(Math.round(amount * 100) / 100);
+					calculateTotals();
 
 					var idText = input.closest('tr').attr('id');
 					var prePurchaseId = idText.substring(idText.lastIndexOf('_') + 1, idText.length);
@@ -427,8 +427,8 @@
 							data: {pre_purchase: {quantity: quantity }},
 							success: function(xhr, status, error) {
 							}
-					});           
-				}, 700);       
+					});
+				}, 700);
 			}
 		}
 
@@ -456,8 +456,8 @@
 										taxPercent = parseFloat($('#tax_percent').val()) / 100
 										tax =  (taxPercent  * amount) / (1 + taxPercent);
 									}
-									input.closest('tr').find('td:eq(6)').text(Math.round(tax * 100) / 100);  
-									input.closest('tr').find('td:eq(7)').text(Math.round(amount * 100) / 100);  
+									input.closest('tr').find('td:eq(6)').text(Math.round(tax * 100) / 100);
+									input.closest('tr').find('td:eq(7)').text(Math.round(amount * 100) / 100);
 									var preIdText = input.closest('tr').attr('id');
 									var prePurchaseId = preIdText.substring(preIdText.lastIndexOf('_') + 1, preIdText.length);
 									$.ajax({
@@ -466,25 +466,25 @@
 											dataType: "json",
 											data: {pre_purchase: {quantity: quantity }},
 											success: function(xhr, status, error) {
-												calculateTotals(); 
+												calculateTotals();
 											}
-									});     
+									});
 							}
-					});                
-				}, 600);    
+					});
+				}, 600);
 			}
 		}
 
 		function calculateTotals() {
 			var amount = 0;
 			var tax    = 0;
-			var total  = 0;  
+			var total  = 0;
 			$('#products_table tbody tr td:nth-child(7)').each(function() {
 				 tax+= parseFloat($(this).text());
-			});  
+			});
 			$('#products_table tbody tr td:nth-child(8)').each(function() {
 				 amount+= parseFloat($(this).text());
-			});  
+			});
 			amount = amount - tax;
 			total = amount + tax;
 			$('#tax').val(Math.round(tax * 100) / 100);
@@ -508,20 +508,20 @@
 					$('#purchase_purchase_code').val('');
 					$("#purchase_supplier_id").select2().select2("val", null);
 					$("#purchase_supplier_id").attr('disabled',false);
-					$("#purchase_pointsale_id").select2().select2("val", null); 
-					$("#purchase_pointsale_id").attr('disabled',false); 
-					$("#purchase_warehouse_id").select2().select2("val", null); 
-					$("#purchase_warehouse_id").attr('disabled',false);                        
+					$("#purchase_pointsale_id").select2().select2("val", null);
+					$("#purchase_pointsale_id").attr('disabled',false);
+					$("#purchase_warehouse_id").select2().select2("val", null);
+					$("#purchase_warehouse_id").attr('disabled',false);
 					$("#reset_pre_purchases").attr('disabled',true);
-					$('#destiny').bootstrapSwitch('disabled',false); 
+					$('#destiny').bootstrapSwitch('disabled',false);
 					$('#purchase_is_in_dollars').bootstrapSwitch('disabled', false);
-					$('#purchase_is_in_dollars').bootstrapSwitch('state', false);            
+					$('#purchase_is_in_dollars').bootstrapSwitch('state', false);
 					calculateTotals();
 				}
 			});
 		}
 
-		function addPurchase() {     
+		function addPurchase() {
 			$('#purchase_form').submit();
 		}
 
@@ -533,8 +533,8 @@
 					dataType: 'text',
 					success: function(data) {
 						$('#purchase_purchase_code').val(data);
-					},      
-				});         
+					},
+				});
 			} else if($('#purchase_warehouse_id').val()) {
 				$.ajax({
 					type: "get",
@@ -542,8 +542,8 @@
 					dataType: 'text',
 					success: function(data) {
 						$('#purchase_purchase_code').val(data);
-					},      
-				});   
+					},
+				});
 			}
 		}
 
@@ -564,8 +564,8 @@
 					dataType: 'script',
 					success: function(data) {
 						calculateTotals();
-					},      
-				});             
+					},
+				});
 			} else {
 				toastr["error"]("Se debe seleccionar proveedor y destino de la compra.");
 			}
@@ -578,7 +578,7 @@
 				$('#products_table tbody tr').each(function() {
 					$(this).find('td:eq(0)').html($(this).find('td:eq(0)').html().replace('#', counter));
 					counter++;
-				}); 
+				});
 			}
 		}
 
@@ -588,18 +588,18 @@
 			if (state) {
 				$('#warehouse_div').removeClass('hidden');
 				$("#purchase_warehouse_id").select2();
-				$('#pointsale_div').addClass('hidden');   
+				$('#pointsale_div').addClass('hidden');
 				<% if current_user.usertype == 'A' %>
 					$('#purchase_pointsale_id').select2('val', null);
-				<% end %>     
+				<% end %>
 			} else {
 				$('#pointsale_div').removeClass('hidden');
-				$("#purchase_pointsale_id").select2();        
+				$("#purchase_pointsale_id").select2();
 				$('#warehouse_div').addClass('hidden');
 				<% if current_user.usertype == 'A' %>
 					$('#purchase_warehouse_id').select2('val', null);
 				<% end %>
-			}      
+			}
 		}
 
 		function showExchangeField(state) {
@@ -617,7 +617,7 @@
 				$('#tax_div div span:last-child').html('MXN');
 				$('#total_div div span:last-child').html('MXN');
 				$("#total_in_mxn_div").addClass('hidden');
-			} 
+			}
 		}
 </script>
 

+ 5 - 1
app/views/sales/_form.html.erb

@@ -153,7 +153,11 @@
 			<div class="col-md-12">
 				<div class="note note-info">
 					<h4 class="block">¡Nota!</h4>
-					<p> Para hacer una búsqueda avanzada utiliza el siguiente formato, nombre del producto :atributo a buscar<br> ejemplo. <strong>blusa :verde</strong> (Sólo se puede buscar un atributo, ya sea estilo, talla o color).</p>
+					<p>
+						Para hacer una búsqueda avanzada utiliza el siguiente formato: <br>
+						Nombre del producto:(inicial del atributo a buscar)atributo a buscar<br>
+						Ejemplo: <strong>Blusa:cverde:tch:elargo</strong> (Donde C es Color, T es Talla y E es Estilo, pueden tener cualquier orden, siempre y cuando tenga ese formato)
+					</p>
 				</div>
 			</div>
 			<div class='col-md-12'>

+ 2 - 2
app/views/transfers/_form.html.erb

@@ -58,7 +58,7 @@
             <span class="required">*</span>
           </label>
           <div class="col-md-4">
-            <input class="form-control" type="text" id="typeahead" data-option-url="/find_products_from_stock/ID/%QUERY">
+            <input class="form-control" type="text" id="typeahead">
           </div>
           <button id="products_new" disabled class="btn btn-success" type="button" onclick="addRow()"> Agregar <i class="fa fa-plus"></i> </button>
         </div>
@@ -121,7 +121,7 @@
       },
       queryTokenizer: Bloodhound.tokenizers.whitespace,
       remote: {
-        url: "/find_from_stock_by_pointsale/ID/" + "%QUERY",
+        url: "/find_from_stock_by_pointsale?pointsale_id=ID&query=%QUERY",
         wildcard: '%QUERY',
         replace: function(url, uriEncodedQuery) {
             origin = $('#origin_id').val();

+ 2 - 2
config/routes.rb

@@ -228,12 +228,12 @@ Rails.application.routes.draw do
   get 'total_invested_in_pointsale' => 'available_products#total_invested_in_pointsale', :format => :json
 
   # find de productos para el typeahead
-  get 'find_products/:query' => 'application#find', :format => :json
+  get 'find_products' => 'application#find', :format => :json
   # para special_prices
   get 'find_products_sp/:query' => 'application#find_sp', :format => :json
   #
   get 'find_products_from_stock' => 'application#find_from_stock', :format => :json
-  get 'find_from_stock_by_pointsale/:pointsale_id/:query' => 'application#find_from_stock_by_pointsale', :format => :json
+  get 'find_from_stock_by_pointsale' => 'application#find_from_stock_by_pointsale', :format => :json
 
   get "getcategories/:category_id" => "application#get_subcategories", :as => "get_subcategories", :format => :json
   get 'get_max_product_id' => 'application#get_max_product_id', :format => :json