Browse Source

Merge branch 'apply_rubocop' of SML/pos-boutique into master

Jose Miguel Ledon 7 years ago
parent
commit
ce2d298c55
36 changed files with 569 additions and 23 deletions
  1. 17 0
      app/assets/javascripts/config.js
  2. 3 0
      app/assets/javascripts/errors.coffee
  3. 3 0
      app/assets/javascripts/reports.coffee
  4. 3 0
      app/assets/javascripts/supports.coffee
  5. 3 0
      app/assets/stylesheets/errors.scss
  6. 3 0
      app/assets/stylesheets/reports.scss
  7. 3 0
      app/assets/stylesheets/supports.scss
  8. 14 0
      app/controllers/errors_controller.rb
  9. 30 0
      app/controllers/reports_controller.rb
  10. 3 1
      app/controllers/sales_controller.rb
  11. 28 0
      app/controllers/supports_controller.rb
  12. 3 2
      app/datatables/available_products_datatable.rb
  13. 2 0
      app/helpers/errors_helper.rb
  14. 6 0
      app/helpers/reports_helper.rb
  15. 2 0
      app/helpers/supports_helper.rb
  16. 4 0
      app/mailers/application_mailer.rb
  17. 14 0
      app/mailers/support_mailer.rb
  18. 8 1
      app/models/product.rb
  19. 25 0
      app/views/errors/internal_server_error.html.erb
  20. 11 0
      app/views/errors/not_found.html.erb
  21. 5 0
      app/views/layouts/mailer.html.erb
  22. 1 0
      app/views/layouts/mailer.text.erb
  23. 10 9
      app/views/pointsales/_assign_delete_prods.html.erb
  24. 10 0
      app/views/reports/_min_max.html.erb
  25. 153 0
      app/views/reports/min_max.html.erb
  26. 14 0
      app/views/reports/min_max.js.erb
  27. 1 2
      app/views/sales/_form.html.erb
  28. 31 0
      app/views/support_mailer/contact_support.html.erb
  29. 41 0
      app/views/supports/_contact_support.html.erb
  30. 28 0
      app/views/supports/contact_support.html.erb
  31. 7 0
      app/views/supports/contact_support.js.erb
  32. 33 0
      app/views/supports/system_updates.html.erb
  33. 5 0
      config/application.rb
  34. 10 8
      config/environments/development.rb
  35. 25 0
      config/navigation.rb
  36. 10 0
      config/routes.rb

+ 17 - 0
app/assets/javascripts/config.js

@@ -1568,6 +1568,23 @@ $(document).on("page:change", function() {
 			});
 		}
 
+		if($('.select2-allow-clear-todas').get(0)){
+			$('select.select2-allow-clear-todas').select2({
+				allowClear: true,
+				placeholder: "Todas",
+				width: null,
+				placeholder: "Seleccione",
+				"language": {
+				   "noResults": function(){
+					   return "No se encontraron coincidencias";
+				   }
+				},
+				escapeMarkup: function (markup) {
+					return markup;
+				}
+			});
+		}
+
 		if($('#form').get(0) ){
 				FormValidation.init();
 		}

+ 3 - 0
app/assets/javascripts/errors.coffee

@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/

+ 3 - 0
app/assets/javascripts/reports.coffee

@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/

+ 3 - 0
app/assets/javascripts/supports.coffee

@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/

+ 3 - 0
app/assets/stylesheets/errors.scss

@@ -0,0 +1,3 @@
+// Place all the styles related to the errors controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/

+ 3 - 0
app/assets/stylesheets/reports.scss

@@ -0,0 +1,3 @@
+// Place all the styles related to the reports controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/

+ 3 - 0
app/assets/stylesheets/supports.scss

@@ -0,0 +1,3 @@
+// Place all the styles related to the supports controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/

+ 14 - 0
app/controllers/errors_controller.rb

@@ -0,0 +1,14 @@
+class ErrorsController < ApplicationController
+  def not_found
+    render(status: 404)
+  end
+
+  def internal_server_error
+    render(status: 500)
+  end
+
+  def show
+    status = params[:code] || 500
+    render status.to_s, status: status
+  end
+end

+ 30 - 0
app/controllers/reports_controller.rb

@@ -0,0 +1,30 @@
+class ReportsController < ApplicationController
+  ##--- Breadcrum_rails
+  add_breadcrumb I18n.t("breadcrumbs." + controller_name), :reports_path
+  add_breadcrumb "Reporte de mínimos y máximos", :min_max_path, only: :min_max
+
+  def min_max
+    @pointsales = Pointsale.activos
+    respond_to do |format|
+      if params[:pointsale_id].present?
+        @products = AvailableProduct.joins(:product, :categories).activos.where(pointsale_id: params[:pointsale_id]).where("available_products.stock <= available_products.stock_min and available_products.stock_max > ?", 0)
+        @products = get_products_category(@products, params[:category], params[:subcategory]) if params[:category].present?
+        format.js
+      else
+        @products = AvailableProduct.where(pointsale_id: @pointsales.first.id).where("available_products.stock <= available_products.stock_min and available_products.stock_min > ?", 0)
+        format.html
+      end
+    end
+  end
+
+  def get_products_category(products, category, subcategory)
+    ids =
+      if subcategory.present?
+        subcategory
+      else
+        category = Category.find(category)
+        [category.id, category.children.ids].flatten
+      end
+    products.where(categories: { id: ids })
+  end
+end

+ 3 - 1
app/controllers/sales_controller.rb

@@ -45,8 +45,10 @@ class SalesController < ApplicationController
     @disabled_select = false
     @disabled_button = true
     @enable_radios = true
-    @opened_cash_registers = Pointsale.find(current_user.pointsale_id).open_cash_registers.abiertas
+    pointsale = Pointsale.find(current_user.pointsale_id)
+    @opened_cash_registers = pointsale.open_cash_registers.abiertas
     @sale.open_cash_register_id = session[:open_cash_register_id] || nil
+    @seller = @sale.seller_id.present? ? @sale.seller_id : pointsale.sales.activas.last.seller_id
     if @pre_sales.present?
       @sale.saletype = @pre_sales[0].sale_type
       @sale.customer_id = @pre_sales[0].customer_id

+ 28 - 0
app/controllers/supports_controller.rb

@@ -0,0 +1,28 @@
+class SupportsController < ApplicationController
+  ##--- Breadcrum_rails
+  add_breadcrumb I18n.t("breadcrumbs." + controller_name), :supports_path
+  add_breadcrumb "Soporte Técnico", :contact_support_path, only: :contact_support
+
+  def contact_support
+    if params[:support].present?
+      returns = false
+      params[:support].map { |_x, y| returns = true if y.blank? }
+      respond_to do |format|
+        if returns
+          format.js { render "contact_support", locals: { notice: "Debe llenar todos los campos del formulario." } }
+        else
+          SupportMailer.contact_support(params[:support], current_user).deliver_now
+          format.js
+        end
+      end
+    end
+  end
+
+  def system_updates # change the following
+    @date = "2018/08/02" # yyyy/mm/dd
+    @change_points = {
+      "key1" => "Change point 1",
+      "key2" => "Change point 2"
+    }
+  end
+end

+ 3 - 2
app/datatables/available_products_datatable.rb

@@ -1,5 +1,5 @@
 class AvailableProductsDatatable
-  delegate :params, :fa_icon, :available_products_path, to: :@view
+  delegate :params, :fa_icon, :available_products_path, :number_to_currency, to: :@view
 
   def initialize(view, pointsale)
     @view = view
@@ -40,7 +40,8 @@ class AvailableProductsDatatable
           '1' => product.sku,
           '2' => get_display_name(product),
           '3' => (category.parent_id.zero? ? category.category : category.parent.category),
-          '4' => (category.parent_id != 0 ? category.category : ' ')
+          '4' => (category.parent_id != 0 ? category.category : ' '),
+          '5' => number_to_currency(product.price_sale, precision: 2)
         }.compact.reject { |_k, v| v.nil? }
       end
     end

+ 2 - 0
app/helpers/errors_helper.rb

@@ -0,0 +1,2 @@
+module ErrorsHelper
+end

+ 6 - 0
app/helpers/reports_helper.rb

@@ -0,0 +1,6 @@
+module ReportsHelper
+  def calculate_restock(available)
+    stock = (available.stock_max - available.stock)
+    stock
+  end
+end

+ 2 - 0
app/helpers/supports_helper.rb

@@ -0,0 +1,2 @@
+module SupportsHelper
+end

+ 4 - 0
app/mailers/application_mailer.rb

@@ -0,0 +1,4 @@
+class ApplicationMailer < ActionMailer::Base
+  default from: "from@example.com"
+  layout 'mailer'
+end

+ 14 - 0
app/mailers/support_mailer.rb

@@ -0,0 +1,14 @@
+class SupportMailer < ApplicationMailer
+  default from: 'noreply@sml.mx'
+
+  def contact_support(params, user)
+    @user = user
+    @error_descriptor = params[:error_descriptor]
+    @comments = params[:comments]
+    @usertype = params[:usertype]
+    @sucursal = params[:sucursal]
+    mail(to: Rails.application.config.support_mails, subject: 'Soporte Técnico POS Boutique') do |format|
+      format.html
+    end
+  end
+end

+ 8 - 1
app/models/product.rb

@@ -50,7 +50,7 @@ class Product < ActiveRecord::Base
   end
 
   ##--- Tipo de vistas / consultas
-  scope :vigentes, -> { where.not(status: 0).order(" products.status ASC, products.name ASC") }
+  scope :vigentes, -> { where.not(products: { status: 0 }).order(" products.status ASC, products.name ASC") }
   scope :activos, -> { where(status: 1).order("products.name ASC") }
   scope :activos_children, -> { activos.where(is_parent: false).order("products.name ASC") }
   scope :vigentes_parents, -> { vigentes.where("parent_id IS NULL") }
@@ -67,6 +67,13 @@ class Product < ActiveRecord::Base
     sku.to_s + " | " + name.to_s + " | " + display_attributes.to_s
   end
 
+  def full_display
+    show_name = name + "\n" + "SKU: " + sku + "\n"
+    show_name += "\n" + display_attributes.to_s if parent_id.present?
+    show_name += " Código de barras: " + barcode if parent_id.present? && barcode.present?
+    show_name
+  end
+
   def stock_in_pointsale(pointsale_id)
     stock = 0
     # checar si hay existencias en los almacenes.

+ 25 - 0
app/views/errors/internal_server_error.html.erb

@@ -0,0 +1,25 @@
+<div class="page-container">
+  <div class="page-content-wrapper">
+    <div class="page-head">
+      <div class="container-fluid">
+        <div class="page-title">
+          <h1>Error del sistema </h1>
+        </div>
+      </div>
+    </div>
+    <div class="page-content">
+      <div class="container-fluid">
+        <div class="row">
+          <div class="col-md-12">
+            <div class="portlet light bordered">
+              <div class="portlet-body">
+                Por favor contacte al administrador del sistema. </span>
+                <%= render "supports/contact_support" %>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 11 - 0
app/views/errors/not_found.html.erb

@@ -0,0 +1,11 @@
+<div class="page-container">
+  <div class="page-content-wrapper">
+    <div class="page-head">
+      <div class="container-fluid">
+        <div class="page-title">
+          <h1>No se encontró la página </h1>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 5 - 0
app/views/layouts/mailer.html.erb

@@ -0,0 +1,5 @@
+<html>
+  <body>
+    <%= yield %>
+  </body>
+</html>

+ 1 - 0
app/views/layouts/mailer.text.erb

@@ -0,0 +1 @@
+<%= yield %>

+ 10 - 9
app/views/pointsales/_assign_delete_prods.html.erb

@@ -46,8 +46,8 @@
 												<div class="note note-success">
 													<h4>Productos disponibles para asignar al punto de venta</h4>
 													<p> En esta tabla se muestran todos los productos disponibles para asignarse al punto de venta para vender.</p><br>
-													<p> Para hacer una busqueda avanzada utiliza el siguiente formato, nombre del producto :atributo a buscar<br>
-														ejemplo. <strong>blusa :verde</strong> (Solo se puede buscar un atributo, ya sea estilo, talla ó color).
+													<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 ó color).
 													</p>
 												</div>
 											</div>
@@ -60,8 +60,9 @@
 														</th>
 														<th>SKU</th>
 														<th>Producto</th>
-														<th>Linea</th>
-														<th>Sub linea</th>
+														<th>Línea</th>
+														<th>Sub línea</th>
+														<th>Precio de venta</th>
 													  </tr>
 													</thead>
 													<tbody>
@@ -83,8 +84,8 @@
 												<div class="note note-success">
 													<h4>Productos asignados al punto de venta</h4>
 													<p> En esta tabla se muestran todos los productos que se han asignado al punto de venta para vender. </p><br>
-													<p> Para hacer una busqueda avanzada utiliza el siguiente formato, nombre del producto :atributo a buscar<br>
-														ejemplo. <strong>blusa :verde</strong> (Solo se puede buscar un atributo, ya sea estilo, talla ó color).
+													<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 ó color).
 												</div>
 											</div>
 											<div class="col-md-12">
@@ -94,8 +95,8 @@
 														<th class="text-center"><input name="select_all" value="1" id="select-all" type="checkbox" /></th>
 														<th>SKU</th>
 														<th>Producto</th>
-														<th>Linea</th>
-														<th>Sub linea</th>
+														<th>Línea</th>
+														<th>Sub línea</th>
 														<th>Stock</th>
 													  </tr>
 													</thead>
@@ -125,7 +126,7 @@
 	var rows_selected_2 = [];
 	var class_1 = '.table_availables';
 	var class_2 = '.table_prod_pointsale';
-	var columns_1 = [{ "data": "0"}, { "data": "1" }, { "data": "2" }, { "data": "3" }, { "data": "4" }];
+	var columns_1 = [{ "data": "0"}, { "data": "1" }, { "data": "2" }, { "data": "3" }, { "data": "4" }, { "data": "5" }];
 	var columns_2 = [{ "data": "0"}, { "data": "1" }, { "data": "2" }, { "data": "3" }, { "data": "4" }, { "data": "5" }];
 	var order_1 = 2;
 	var order_2 = 2;

+ 10 - 0
app/views/reports/_min_max.html.erb

@@ -0,0 +1,10 @@
+<% category = available.product.categories[0] %>
+<tr>
+  <td><%= key += 1 %></td>
+  <td><%= available.product.full_display %></td>
+  <td><%= number_to_currency(available.product.price_base, precision: 2) %></td>
+  <td><%= category.parent_id.zero? ? category.category : category.parent.category %></td>
+  <td><%= category.category %></td>
+  <td class="success"><%= quantity = calculate_restock(available) %></td>
+  <td><%= number_to_currency((quantity * available.product.price_base), precision: 2) %></td>
+</tr>

+ 153 - 0
app/views/reports/min_max.html.erb

@@ -0,0 +1,153 @@
+<div class="page-container">
+  <div class="page-content-wrapper">
+    <div class="page-head">
+      <div class="container-fluid">
+        <div class="page-title">
+          <h1>Reporte de mínimos y máximos por punto de venta</h1>
+        </div>
+      </div>
+    </div>
+    <div class="page-content">
+      <div class="container-fluid">
+        <ul class="page-breadcrumb breadcrumb">
+
+        </ul>
+        <div class="page-content-inner">
+          <div id="notice"><%= notice %></div>
+          <div class="portlet light hidden-print">
+            <div class="portlet-body">
+              <div class="row">
+                <div class="col-md-12">
+                  <div class="booking-search">
+                    <%= form_tag(min_max_path, method: "get", remote: true, id: "minmax_form") do %>
+                      <div class="row form-group">
+                        <!-- punto de venta -->
+                        <%= label :pointsale_id, "", { class: "col-md-1 col-sm-2 control-label" } do %>Punto de venta<% end %>
+                        <div class="col-md-4 col-sm-5 select2-bootstrap-prepend">
+                          <%= select_tag :pointsale_id, options_from_collection_for_select(@pointsales, :id, :name, selected: @pointsales.first), class: "form-control select2" %>
+                        </div>
+                      </div>
+                      <div class="row form-group">
+                        <!-- categoria -->
+                        <%= label :category, "", { class: "col-md-1 col-sm-1 control-label" } do %>Línea <% end %>
+                        <div class="col-md-4 col-sm-4 select2-bootstrap-prepend">
+                          <%= select_tag :category, options_for_select(Category.activos_padre.collect{ |p| [ "#{p.category} - #{p.description}", p.id ] }), include_blank: "Todas", class: "form-control select2-allow-clear-todas input-medium", onchange: 'getSubCategories($(this).val())' %>
+                        </div>
+                        <!-- sub- categoria -->
+                        <%= label :subcategory, "", { class: "col-md-1 col-sm-1 control-label" } do %>Sublínea <% end %>
+                        <div class="col-md-4 col-sm-4 select2-bootstrap-prepend">
+                          <div class="select2-bootstrap-prepend">
+                            <%= collection_select("", :subcategory, ({}), :id, :category_and_description, options = { include_blank: "Todas" }, html_options = { class: 'form-control select2-allow-clear-todas input-medium' }) %>
+                          </div>
+                        </div>
+                        <div class="col-md-2 col-sm-1">
+                          <button type="button" onclick="applyFilter()" class="btn blue">Buscar</button>
+                        </div>
+                      </div>
+                    <% end %>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class="portlet light">
+            <div class="portlet-title">
+              <div class="caption">
+                <i class="fa fa-list "></i>
+                <span class="caption-subject bold uppercase">Lista de productos</span>
+              </div>
+            </div>
+            <div class="portlet-body ">
+              <div id="error_explanation"></div>
+              <%= hidden_field_tag 'title_for_print', "Reporte de mínimos y máximos por punto de venta" %>
+              <!-- lista de productos -->
+              <table class="table table-hover table-bordered table-striped tableadvancedprintable" id="minmax_table">
+                <thead>
+                  <th>#</th>
+                  <th width="25%">Producto</th>
+                  <th>Precio<br>unitario</th>
+                  <th width="25%">Línea</th>
+                  <th>Sublínea</th>
+                  <th class="success">Cantidad recomendada<br> a comprar</th>
+                  <th>Total</th>
+                </thead>
+                <tbody>
+                  <% total = 0 %>
+                  <% @products.each_with_index do |available, key| %>
+                    <% category = available.product.categories[0] %>
+                    <tr>
+                      <td><%= key += 1 %></td>
+                      <td><%= available.product.full_display %></td>
+                      <td><%= number_to_currency(available.product.price_base, precision: 2) %></td>
+                      <td><%= category.parent_id.zero? ? category.category : category.parent.category %></td>
+                      <td><%= category.category %></td>
+                      <td class="success"><%= quantity = calculate_restock(available) %></td>
+                      <td><%= number_to_currency((quantity * available.product.price_base), precision: 2) %></td>
+                    </tr>
+                    <% total += (quantity * available.product.price_base) %>
+                  <% end %>
+                  <%= hidden_field_tag :total, total %>
+                </tbody>
+              </table>
+            </div>
+          </div>
+          <div class="row">
+            <div class="col-md-offset-4 col-md-3">
+              <div class="text-center well" id="container_total_prods" style="margin-bottom: 0px">
+                <div class="font-grey-mint font-sm">Total </div>
+                <div class="uppercase font-hg font-blue-sharp" id="total_prods"></div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+
+<script type="text/javascript">
+  $(document).ready(function(){
+    $('#total_prods').html(accounting.formatMoney($("#total").val()) + ' MXN');
+  });
+
+  function applyFilter() {
+    $("#minmax_form").submit();
+  }
+
+  function getSubCategories(value) {
+    $('#_subcategory').html('');
+    $('#_subcategory').select2("destroy").select2({
+      placeholder: 'Seleccione',
+      "language": {
+        "noResults": function(){
+          return "No se encontraron coincidencias";
+        }
+      }
+    });
+    $('#_subcategory').select2('val', null);
+    if(value) {
+      $.ajax({
+        type: "get",
+        url: '/getcategories/' + value,
+        dataType: 'json',
+        success: function(data) {
+          if(data.length > 0) {
+            $('#_subcategory').append('<option></option>')
+            for(i in data) {
+              $('#_subcategory').append("<option value='" + data[i].id + "'>" + data[i].category + "</option>")
+            }
+            $('#_subcategory').select2({
+              allowClear: true,
+              placeholder: 'Todas',
+              "language": {
+                "noResults": function(){
+                  return "No se encontraron coincidencias";
+                }
+              }
+            });
+          }
+        }
+      });
+    }
+  }
+</script>

+ 14 - 0
app/views/reports/min_max.js.erb

@@ -0,0 +1,14 @@
+var table = $('#minmax_table').DataTable();
+$('#minmax_table').dataTable().fnClearTable();
+total = 0
+<% @products.each_with_index do |available, key| %>
+  total += <%= available.product.price_base * (available.stock_max - available.stock) %>
+  var row = $('<%= j render partial: "min_max", locals: { available: available, key: key } %>');
+  table.row.add(row).draw();
+<% end %>
+total = parseFloat(total).toFixed(2);
+$("#total").val(total);
+total = "$ " + total + " MXN";
+$("#total_prods").html(total);
+// $('#total_prods').html(accounting.formatMoney($("#total").val()) + ' MXN');
+// $('#total_prods').html(accounting.formatMoney(total + "MXN");

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

@@ -112,8 +112,7 @@
 					<span class="required">*</span>
 					<% end %>
 					<div class="input-group col-md-6 select2-bootstrap-prepend">
-						<%= f.collection_select :seller_id, Seller.where(:pointsale_id => current_user.pointsale_id, :status => '1'), :id, :full_name, {:prompt => "Seleccione",
-							:selected => @seller.blank? ? '' : @seller_id.to_i}, {:class => "form-control select2"} %>
+						<%= f.collection_select :seller_id, Seller.where(pointsale_id: current_user.pointsale_id, status: '1'), :id, :full_name, { prompt: "Seleccione", selected: @seller.blank? ? '' : @seller.to_i }, { class: "form-control select2" } %>
 					</div>
 				</div>
 			</div>

+ 31 - 0
app/views/support_mailer/contact_support.html.erb

@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
+  </head>
+  <body>
+    <h1>SOPORTE TÉCNICO </h1>
+    <p>
+      Por favor analice la siguiente información y hágala llegar a los encargados de POS Boutique
+      <br>
+      <table>
+        <thead>
+          <th>Registró</th>
+          <th>Sucursal</th>
+          <th>Tipo de usuario</th>
+          <th>Descripción del error</th>
+          <th>Observaciones/Comentarios</th>
+        </thead>
+        <tbody>
+          <tr>
+            <td><%= @user.full_name %><br><small><%= @user.userid %></small></td>
+            <td><%= @sucursal %></td>
+            <td class="text-center"><%= @usertype %></td>
+            <td><%= @error_descriptor %></td>
+            <td><%= @comments %></td>
+          </tr>
+        </tbody>
+      </table>
+    </p>
+  </body>
+</html>

+ 41 - 0
app/views/supports/_contact_support.html.erb

@@ -0,0 +1,41 @@
+<%= form_tag(contact_support_path, { method: "get", remote: true, id: "contact_support_form", class: "form-horizontal" }) do %>
+  <div class="portlet-body form">
+    <div class="form-body col-md-offset-1">
+      <div class="note note-danger">
+        <h4 class="block">Por favor llene el siguiente formulario, describiendo el problema y el proceso que le llevó a él lo más detalladamente posible. Al terminar, presione Enviar.</h4>
+      </div>
+      <div class="form-group ">
+        <%= label :sucursal, "", { class: "col-md-2 col-sm-2 control-label" } do %>Sucursal <span class="required">*</span> <% end %>
+        <div class="col-md-4 col-sm-5">
+          <%= text_field_tag :sucursal, "", class: "form-control input-large", name: "support[sucursal]" %>
+        </div>
+      </div>
+      <div class="form-group">
+        <%= label :usertype, "", { class: "col-md-2 col-sm-2 control-label" } do %>Tipo de pefil <span class="required">*</span> <span class="tooltips" title="El tipo de perfil con el que se experimentó el error"><i class="fa fa-question-circle"></i></span> <% end %>
+        <div class="col-md-4 col-sm-4">
+          <%= select_tag :usertype, options_for_select(Rails.application.config.usertypes_for_admin), { class: 'form-control input-medium', name: "support[usertype]" } %>
+        </div>
+      </div>
+      <div class="form-group">
+        <%= label :error_descriptor, "", { class: "col-md-2 col-sm-2 control-label" } do %>Descripción del error <span class="required">*</span> <% end %>
+        <div class="col-md-4 col-sm-4">
+          <%= text_area_tag :error_descriptor, "", class: "form-control", name: "support[error_descriptor]", rows: 5 %>
+        </div>
+      </div>
+      <div class="form-group">
+        <%= label :comments, "", { class: "col-md-2 col-sm-2 control-label" } do %>Observaciones <span class="required">*</span> <% end %>
+        <div class="col-md-4 col-sm-4">
+          <%= text_area_tag :comments, "", class: "form-control", name: "support[comments]", rows: 5 %>
+        </div>
+      </div>
+    </div>
+    <div class="form-actions">
+      <div class="row">
+        <div class="col-md-offset-3 col-md-9 col-sm-offset-2 col-sm-3">
+          <%= submit_tag 'Enviar', { class: "btn green" } %>
+          <%= link_to 'Cancelar', root_path, { class: "btn default" } %>
+        </div>
+      </div>
+    </div>
+  </div>
+<% end %>

+ 28 - 0
app/views/supports/contact_support.html.erb

@@ -0,0 +1,28 @@
+<div class="page-container">
+  <div class="page-content-wrapper">
+    <div class="page-head">
+      <div class="container-fluid">
+        <div class="page-title">
+          <h1>Soporte Técnico</h1>
+        </div>
+      </div>
+    </div>
+    <div class="page-content">
+      <div class="container-fluid">
+        <ul class="page-breadcrumb breadcrumb">
+
+        </ul>
+        <div class="page-content-inner">
+          <div class="note note-warning hidden" id="notice">
+            <h4 class="block"></h4>
+          </div>
+          <div class="portlet light">
+            <div class="portlet-body ">
+              <%= render 'contact_support' %>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 7 - 0
app/views/supports/contact_support.js.erb

@@ -0,0 +1,7 @@
+<% if notice %>
+  $("#notice").removeClass("hidden");
+  $("#notice").html("<%= notice %>");
+<% else %>
+  location.reload();
+  alert("La información ha sido enviada al administrador del sitio.");
+<% end %>

+ 33 - 0
app/views/supports/system_updates.html.erb

@@ -0,0 +1,33 @@
+<div class="page-container">
+  <div class="page-content-wrapper">
+    <div class="page-head">
+      <div class="container-fluid">
+        <div class="page-title">
+          <h1>Últimas actualizaciones del sistema</h1>
+        </div>
+      </div>
+    </div>
+    <div class="page-content">
+      <div class="container-fluid">
+        <ul class="page-breadcrumb breadcrumb">
+        </ul>
+        <div class="page-content-inner">
+          <div class="note note-warning hidden" id="notice">
+            <h4 class="block"></h4>
+          </div>
+          <div class="portlet light">
+            <div class="portlet-body ">
+              <h2>Fecha: <%= l(@date.to_date, format: '%d de %B del %Y') %></h2>
+              <br>
+              <ul style="font-size: 150%">
+                <% @change_points.each do |_key, value| %>
+                  <li><%= value %></li>
+                <% end %>
+              </ul>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 5 - 0
config/application.rb

@@ -22,6 +22,7 @@ module Pos
     # config.i18n.default_locale = :de
 
     # Do not swallow errors in after_commit/after_rollback callbacks.
+    config.exceptions_app = self.routes
     config.action_view.embed_authenticity_token_in_remote_forms = true
     config.active_record.raise_in_transactional_callbacks = true
     config.usertypes_for_super = {
@@ -43,5 +44,9 @@ module Pos
       "Almacenista" => "S",
       "Caja" => "C"
     }
+
+    config.support_mails = [
+      "daniel.mendoza@sml.mx"
+    ]
   end
 end

+ 10 - 8
config/environments/development.rb

@@ -44,16 +44,18 @@ Rails.application.configure do
 	# config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
 	config.action_mailer.default_url_options = { :host => 'localhost:3000' }
 	config.active_support.deprecation = :log
+	config.action_mailer.delivery_method = :smtp
 
 	config.action_mailer.smtp_settings ={
-		:address            => 'mail.sml.mx',
-		:port               => 25,
-		:tls                => false,
-		:domain             => 'sml.mx',
-		:authentication     => :login,
-		:user_name          => 'noreply@sml.mx',
-		:password           => 'NoReply123',
-		:enable_starttls_auto => false
+		address:               'smtp.sml.mx',
+		port:                  587,
+		tls:                   false,
+		domain:                'sml.mx',
+		authentication:        :login,
+		user_name:             'noreply@sml.mx',
+		password:              'NoReply123',
+		enable_starttls_auto:  false,
+		return_response:       true
 	}
 
 

+ 25 - 0
config/navigation.rb

@@ -111,6 +111,7 @@ SimpleNavigation::Configuration.run do |navigation|
       primary.item :reports, { icon: "fa fa-bar-chart", text: "Reportes" }, '#', class: 'menu-dropdown classic-menu-dropdown' do |sub_nav|
         sub_nav.dom_attributes = { class: 'dropdown-menu pull-left' }
         sub_nav.item :sales_per_month, 'Ventas por mes', sales_per_month_report_path
+        sub_nav.item :minmax_report, 'Mínimos y Máximos', min_max_path
       end
       # configuracion
       primary.item :config, { icon: "fa fa-fw fa-cog", text: "Configuración" }, '#', class: 'menu-dropdown classic-menu-dropdown' do |sub_nav|
@@ -122,6 +123,12 @@ SimpleNavigation::Configuration.run do |navigation|
         sub_nav.item :divider_after_list_transfers, '#', divider: true
         sub_nav.item :list_users, 'Usuarios del sistema', users_path
       end
+      # soporte
+      primary.item :support, { icon: "fa fa-fw fa-group", text: "Soporte" }, '#', class: 'menu-dropdown classic-menu-dropdown' do |sub_nav|
+        sub_nav.dom_attributes = { class: "dropdown-menu pull-left" }
+        sub_nav.item :send_info, "Soporte técnico", contact_support_path
+        sub_nav.item :updates, "Actualizaciones", system_updates_path
+      end
     end
 
     if current_user.usertype == 'G'
@@ -200,6 +207,12 @@ SimpleNavigation::Configuration.run do |navigation|
         sub_nav.item :divider_after_list_transfers, '#', divider: true
         sub_nav.item :list_users, 'Usuarios del sistema', users_path
       end
+      # soporte
+      primary.item :support, { icon: "fa fa-fw fa-group", text: "Soporte" }, '#', class: 'menu-dropdown classic-menu-dropdown' do |sub_nav|
+        sub_nav.dom_attributes = { class: "dropdown-menu pull-left" }
+        sub_nav.item :send_info, "Soporte técnico", contact_support_path
+        sub_nav.item :updates, "Actualizaciones", system_updates_path
+      end
     end
 
     if current_user.usertype == 'C'
@@ -248,6 +261,12 @@ SimpleNavigation::Configuration.run do |navigation|
         sub_nav.item :new_transfer, 'Nuevo traspaso', new_transfer_path
         sub_nav.item :list_expenses, 'Lista de traspasos', transfers_path
       end
+      # soporte
+      primary.item :support, { icon: "fa fa-fw fa-group", text: "Soporte" }, '#', class: 'menu-dropdown classic-menu-dropdown' do |sub_nav|
+        sub_nav.dom_attributes = { class: "dropdown-menu pull-left" }
+        sub_nav.item :send_info, "Soporte técnico", contact_support_path
+        sub_nav.item :updates, "Actualizaciones", system_updates_path
+      end
     end
 
     if current_user.usertype == 'S'
@@ -269,6 +288,12 @@ SimpleNavigation::Configuration.run do |navigation|
         sub_nav.item :initial_stock, 'Inventario inicial', products_initial_stock_path(current_user.warehouse_id)
         sub_nav.item :stock_adjustment, 'Ajuste de inventario', products_stock_path(current_user.warehouse_id)
       end
+      # soporte
+      primary.item :support, { icon: "fa fa-fw fa-group", text: "Soporte" }, '#', class: 'menu-dropdown classic-menu-dropdown' do |sub_nav|
+        sub_nav.dom_attributes = { class: "dropdown-menu pull-left" }
+        sub_nav.item :send_info, "Soporte técnico", contact_support_path
+        sub_nav.item :updates, "Actualizaciones", system_updates_path
+      end
     end
 
     class BootstrapBreadcrumbs < SimpleNavigation::Renderer::Base

+ 10 - 0
config/routes.rb

@@ -14,6 +14,9 @@ Rails.application.routes.draw do
     sign_up: 'cmon_let_me_in'
   }
 
+  match "/404", to: "errors#not_found", via: :all
+  match "/500", to: "errors#internal_server_error", via: :all
+
   devise_scope :user do
     get "login", to: "devise/sessions#new"
     get "logout", to: "devise/sessions#destroy"
@@ -245,5 +248,12 @@ Rails.application.routes.draw do
 
   get "products_by_category_pointsale/:pointsale_id/:category_id" => "application#products_by_category_pointsale", :as => "products_by_category_pointsale", :format => :json
   get "verify_transfer/:transfer_id" => "transfers#verify_transfer", :as => "verify_transfer"
+
+  ## reports
+  get "min_max" => "reports#min_max"
+
+  ## soporte
+  get "contact_support" => "supports#contact_support"
+  get "system_updates" => "supports#system_updates"
 end
 # rubocop:enable Metrics/BlockLength