_form.html.erb 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. <%= form_for(@transfer, html: { class: "form-horizontal", id: "transfer_form" }) do |f| %>
  2. <div class="portlet-body form">
  3. <% if @transfer.errors.any? %>
  4. <div class="alert alert-danger">
  5. <strong>Tiene <%= pluralize(@transfer.errors.count, "error") %> no se puede guardar el traspaso</strong><br>
  6. <ul>
  7. <% @transfer.errors.values.each do |message| %>
  8. <li><%= message.first.to_s %></li>
  9. <% end %>
  10. </ul>
  11. </div>
  12. <% end %>
  13. <div class="row">
  14. <!-- boton para resetear datos -->
  15. <div class="col-md-offset-10 col-md-2">
  16. <button id="reset_pre_transfers" type="button" class="btn btn-warning" <%= 'disabled' if @pre_transfers.blank? %> onclick="deletePreTransfers()">Restaurar traspaso</button>
  17. </div>
  18. <div class="col-md-7">
  19. <!-- fecha -->
  20. <div class="form-group">
  21. <%= f.label :transfer_date, "Fecha", {:class=>"col-md-3 control-label"} do %> Fecha
  22. <span class="required">*</span>
  23. <% end %>
  24. <%= f.hidden_field :transfer_date, { value: Date.today } %>
  25. <div class="col-sm-6" style="padding-left:0px;padding-right:0px;">
  26. <div class='input-group date' id='datetimepicker1'>
  27. <input type='text' class="form-control" disabled/>
  28. <span class="input-group-addon">
  29. <span class="glyphicon glyphicon-calendar"></span>
  30. </span>
  31. </div>
  32. </div>
  33. </div>
  34. <!-- origen -->
  35. <div class="form-group">
  36. <%= f.label :origin_id, "Punto de venta", {:class=>"col-md-3 control-label"} do %>Origen
  37. <span class="required">*</span>
  38. <% end %>
  39. <div class="input-group col-md-6 select2-bootstrap-prepend">
  40. <%= f.select :origin_id, grouped_options_for_select([
  41. ['Puntos de venta', Pointsale.activos.collect { |p| [ p.name, ('P-' + p.id.to_s) ] }],
  42. ['Almacenes', Warehouse.activos.collect { |w| [ w.name, ('W-' + w.id.to_s)] }]], :selected => @origin_id), {:prompt => "Seleccione"}, { :class => 'form-control select2', :disabled => @disable_origin} %>
  43. <%= f.hidden_field :origin_id, :value => @origin_id, :id => 'origin_id' %>
  44. </div>
  45. </div>
  46. <!-- destino -->
  47. <div class= "form-group">
  48. <%= f.label :destiny_id, "Punto de venta", {:class=>"col-md-3 control-label"} do %>Destino
  49. <span class="required">*</span>
  50. <% end %>
  51. <div class="input-group col-md-6 select2-bootstrap-prepend">
  52. <%= f.select :destiny_id, grouped_options_for_select([
  53. ['Puntos de venta', @destiny_pointsales.collect { |p| [ p.name, ('P-' + p.id.to_s)] }],
  54. ['Almacenes', Warehouse.activos.collect { |w| [ w.name, ('W-' + w.id.to_s)] }]], :selected => @destiny_id), {:prompt => "Seleccione"}, { :class => 'form-control select2', :disabled => @disable_destiny} %>
  55. <%= f.hidden_field :destiny_id, :value => @destiny_id, :id => 'destiny_id' %>
  56. </div>
  57. </div>
  58. </div>
  59. </div>
  60. <!-- agregar productos -->
  61. <h4 class="form-section">Producto(s) a traspasar</h4>
  62. <div class="row">
  63. <div class='col-md-12'>
  64. <div class="form-group">
  65. <label class="col-md-2 control-label" for="typeahead"> Producto
  66. <span class="required">*</span>
  67. </label>
  68. <div class="col-md-4">
  69. <input class="form-control" type="text" id="typeahead">
  70. </div>
  71. <button id="products_new" disabled class="btn btn-success" type="button" onclick="addRow()"> Agregar <i class="fa fa-plus"></i> </button>
  72. </div>
  73. </div>
  74. </div>
  75. <!-- lista de productos -->
  76. <h4 class="form-section"> </h4>
  77. <div class="portlet-body">
  78. <table class="table table-striped table-bordered table-hover tableadvanced" id="products_table">
  79. <thead>
  80. <tr>
  81. <th width="5%">#</th>
  82. <th width="20%">Imagen</th>
  83. <th width="20%">SKU</th>
  84. <th width="15%">Producto</th>
  85. <th>Stock actual</th>
  86. <th width="20%">Cantidad</th>
  87. <th width="10%">Acciones</th>
  88. </tr>
  89. </thead>
  90. <tbody>
  91. <%= render @pre_transfers %>
  92. </tbody>
  93. </table>
  94. </div>
  95. <!-- acciones del form -->
  96. <div class="form-actions">
  97. <div class="row">
  98. <div class="col-md-9">
  99. <!-- < %= f.submit 'Guardar', { class: "btn green", disabled: (@pre_transfers.present? ? false : true), id: "save_transfer" } %> -->
  100. <button type="button" class="btn green" onclick="addTransfer()" id="save_transfer" <%= 'disabled' if @pre_transfers.blank? %>>Guardar</button>
  101. <%= link_to 'Cancelar', transfers_path(filter: @filter, current_page: @current_page), { class: "btn default" } %>
  102. </div>
  103. </div>
  104. </div>
  105. </div>
  106. <% end %>
  107. <script type="text/javascript">
  108. var selectedProduct;
  109. var timeout = null;
  110. function addTransfer() {
  111. var origin = $('#origin_id').val();
  112. var destiny = $('#destiny_id').val();
  113. if((origin && destiny) && (origin != destiny)) {
  114. $("#transfer_form").submit();
  115. } else {
  116. toastr["error"]("Falta seleccionar datos del formulario, o el origen y el destino son los mismos.");
  117. }
  118. }
  119. $(document).on("page:change", function() {
  120. App.init();
  121. enumeratePreTransfers();
  122. $('#datetimepicker1').datetimepicker({
  123. icons: {
  124. date: "fa fa-calendar"
  125. },
  126. format: "DD/MM/YYYY",
  127. defaultDate: new Date()
  128. });
  129. });
  130. var bloodhound = new Bloodhound({
  131. datumTokenizer: function (d) {
  132. return Bloodhound.tokenizers.whitespace(d.value);
  133. },
  134. queryTokenizer: Bloodhound.tokenizers.whitespace,
  135. remote: {
  136. url: "/find_from_stock_by_pointsale?pointsale_id=ID&query=%QUERY",
  137. wildcard: '%QUERY',
  138. replace: function(url, uriEncodedQuery) {
  139. origin = $('#origin_id').val();
  140. return url.replace('ID', origin).replace('%QUERY', uriEncodedQuery)
  141. }
  142. }
  143. });
  144. bloodhound.initialize();
  145. $('#typeahead').typeahead(
  146. {
  147. minLength: 3
  148. },
  149. {
  150. displayKey: 'name',
  151. source: bloodhound.ttAdapter(),
  152. limit: Infinity,
  153. templates: {
  154. empty: [
  155. '<div class="empty-message">',
  156. 'No se encontró ningun producto. Favor de verificar',
  157. '</div>'
  158. ].join('\n'),
  159. suggestion: Handlebars.compile(
  160. '<div class="media">' +
  161. '<div class="pull-left">' +
  162. '<div class="media-object">' +
  163. '<img src="{{small_img}}" width="50" height="50"/>' +
  164. '</div>' +
  165. '</div>' +
  166. '<div class="media-body">' +
  167. '<h4 class="media-heading"><strong>{{sku}}</strong> | {{name}}</h4>' +
  168. '<p>{{barcode}}</p>' +
  169. '<p>{{description}}</p>' +
  170. '<p>{{display_attributes}}</p>' +
  171. '</div>' +
  172. '</div>')
  173. }
  174. });
  175. $(document).scannerDetection({
  176. timeBeforeScanTest: 200, // wait for the next character for upto 200ms
  177. startChar: [120], // Prefix character for the cabled scanner (OPL6845R)
  178. endChar: [13], // be sure the scan is complete if key 13 (enter) is detected
  179. avgTimeByChar: 40, // it's not a barcode if a character takes longer than 40ms
  180. onComplete: function(barcode, qty){ findProductByBarcode(barcode) } // main callback function
  181. });
  182. $('#transfer_destiny_id').on('change', function() {
  183. $('#destiny_id').val($(this).val());
  184. });
  185. $('#transfer_origin_id').on('change', function() {
  186. $('#origin_id').val($(this).val());
  187. });
  188. $('#typeahead').bind('typeahead:selected', function(event, datum, name) {
  189. selectedProduct = datum;
  190. $('#products_new').attr('disabled', false);
  191. });
  192. function addRow() {
  193. if(selectedProduct) {
  194. $('#pre_transfer_origin_id').val($('#origin_id').val());
  195. $('#pre_transfer_destiny_id').val($('#transfer_destiny_id').val());
  196. $('#pre_transfer_product_id').val(selectedProduct.id);
  197. $('#pre_transfer_quantity').val(1);
  198. $('#new_pre_transfer').submit();
  199. $('#typeahead').typeahead('val','');
  200. $('#products_new').attr('disabled', true);
  201. }
  202. }
  203. function deleteRow(input) {
  204. var table = $('#products_table').DataTable();
  205. var idText = input.closest('tr').attr('id');
  206. var preTransferId = idText.substring(idText.lastIndexOf('_') + 1, idText.length);
  207. $.ajax({
  208. type: "DELETE",
  209. url: "/pre_transfers/" + preTransferId,
  210. dataType: "json",
  211. data: "",
  212. success: function(xhr, status, error) {
  213. table.row(input.closest('tr')).remove().draw();
  214. }
  215. });
  216. }
  217. function enumeratePreTransfers() {
  218. if($('#reset_pre_transfers').prop("disabled") == false) {
  219. var table = $('#products_table').dataTable();
  220. var counter = 1;
  221. $('#products_table tbody tr').each(function() {
  222. $(this).find('td:eq(0)').html($(this).find('td:eq(0)').html().replace('#', counter));
  223. counter++;
  224. });
  225. }
  226. }
  227. function deletePreTransfers() {
  228. $.ajax({
  229. type: "get",
  230. url: '/delete_pre_transfers',
  231. dataType: 'json',
  232. success: function(xhr, status, error){
  233. $('#products_table').dataTable().fnClearTable();
  234. $("#transfer_destiny_id").select2().select2("val", null);
  235. <% if current_user.usertype == "A" || current_user.usertype == "SS" %>
  236. $("#transfer_origin_id").attr('disabled', false);
  237. $("#transfer_origin_id").select2().select2("val", null);
  238. <% end %>
  239. $("#transfer_destiny_id").attr('disabled', false);
  240. $("#reset_pre_transfers").attr('disabled', true);
  241. }
  242. });
  243. }
  244. function updateQuantity(input) {
  245. if(input.val() > 0) {
  246. clearTimeout(timeout);
  247. timeout = setTimeout(function () {
  248. var idText = input.closest('tr').attr('id');
  249. var preTransferId = idText.substring(idText.lastIndexOf('_') + 1, idText.length);
  250. $.ajax({
  251. type: "PUT",
  252. url: "/pre_transfers/" + preTransferId,
  253. dataType: "json",
  254. data: {pre_transfer: {quantity: input.val()}},
  255. success: function(xhr, status, error) {
  256. $("#save_transfer").attr("disabled", false);
  257. },
  258. statusCode: {
  259. 422: function() {
  260. $("#save_transfer").attr("disabled", true);
  261. toastr["error"]("Error, El stock es insuficiente.");
  262. }
  263. }
  264. });
  265. }, 700);
  266. } else {
  267. $("#save_transfer").attr("disabled", true);
  268. toastr["error"]("La cantidad debe ser mayor a 0");
  269. }
  270. }
  271. function findProductByBarcode(barcode) {
  272. var origin = $('#origin_id').val();
  273. var destiny = $('#destiny_id').val();
  274. if((origin && destiny) && (origin != destiny)) {
  275. $.ajax({
  276. type: "get",
  277. url: '/add_pre_transfer_by_barcode/' + barcode + "/" + origin + "/" + destiny,
  278. dataType: 'script',
  279. success: function(data) {
  280. },
  281. });
  282. } else {
  283. toastr["error"]("Falta seleccionar datos del formulario, o el origen y el destino son los mismos.");
  284. }
  285. }
  286. </script>