templates/incassi.html.twig line 1

Open in your IDE?
  1. {% extends 'base.html.twig' %}
  2. {% set currentPath = path(app.request.attributes.get('_route')) %}
  3. {% block body %}
  4. <div class="container">
  5.   <div class="row">
  6.       <div id="loader" class="col s12 progress" style="display:none"><div class="indeterminate"></div></div>
  7.       <div class="col s12">
  8.       <div class="card">
  9.           <div class="card-content">
  10.               <!-- <span class="card-title">Filters</span> -->
  11.               <div class="row">
  12.                 <h5>Gestione Incassi / Rimborsi</h5>
  13.                 <p class="hint blue-grey lighten-5">HINT - Per l'assegnazione delle Note di Credito selezionare Fatture/Rimborsi</p>
  14.                 <div class="col s2">
  15.                     <select name="filter-order-type">
  16.                         <option value="fatture">Fatture</option>
  17.                         <option value="note-credito">Note Credito</option>
  18.                         <option value="corrispettivi">Corrispettivi</option>
  19.                     </select>
  20.                 </div>
  21.                 <div class="col s2">
  22.                     <select name="filter-tipo">
  23.                         <option value="charge" selected>Incassi</option>
  24.                         <option value="refund">Rimborsi</option>
  25.                         <option value="not-managed">Non gestiti (chargeback / payment reversal / ecc...)</option>
  26.                     </select>
  27.                 </div>
  28.                 <div class="col s2">
  29.                     <select name="filter-source">
  30.                         <option value="">Tipo pagamento</option>
  31.                         <option value="shopify">Shopify</option>
  32.                         <option value="paypal">Paypal</option>
  33.                         <option value="amazon">Amazon</option>
  34.                         <option value="klarna">Klarna</option>
  35.                     </select>
  36.                 </div>
  37.             </div>
  38.             <div class="row">
  39.                   <div class="col s2">
  40.                       <label>Transazione DA:</label>
  41.                       <input type="text" name="filter-date-from" class="datepicker">
  42.                   </div>
  43.                   <div class="col s2">
  44.                       <label>Transazione A:</label>
  45.                       <input type="text" name="filter-date-to" class="datepicker">
  46.                   </div>
  47.                   <div class="col s3">
  48.                     <div id="filter-orders-ids" class="chips chips-placeholder">
  49.                               <input name="filter-orders-ids" placeholder="Filtra per ID Ordine">
  50.                       </div>
  51.                   </div>
  52.               </div>
  53.             <div class="row">
  54.                 <div class="col s2">
  55.                       <input id="filter-credit-notes-from" name="filter-credit-notes-from" placeholder="Note Credito DA">
  56.                   </div>
  57.                 <div class="col s2">
  58.                     <input id="filter-credit-notes-to" name="filter-credit-notes-to" placeholder="Note Credito A">
  59.                   </div>
  60.                   <div class="col s2">
  61.                       <button type="button" onclick="Manebi.getIncassi()" name="submit-filter" class="btn waves-effect waves-light">RECUPERA</button>
  62.                   </div>
  63.               </div>
  64.           </div>
  65.          </div>
  66.       </div>
  67.   </div>
  68.   <div class="row">
  69.       <div class="col s12">
  70.       <div class="card">
  71.           <div class="card-content">
  72.               <div id="incassi-table-results">
  73.                   <div class="row">
  74.                       <div class="col s4">Risultati: <span id="incassi-table-results-total"></span></div>
  75.                       <div id="incassi-table-results-actions" class="col s8"></div>
  76.                   </div>
  77.               </div>
  78.               <div class="row">
  79.                   <div class="col s12"><div class="incassi-table-pagination"></div></div>
  80.               </div>
  81.               <table id="incassi-table" class="striped fixed_header">
  82.                   <thead></thead>
  83.                   <tbody></tbody>
  84.               </table>
  85.               
  86.               <div class="row">
  87.                   <div class="col s12"><div class="incassi-table-pagination"></div></div>
  88.                   <div class="col s2"><label for="incassi-table-page-size-list">Page size: <select class="incassi-table-page-size-list" name="incassi-table-page-size-list" after-render="initMaterializeSelect"></select></label></div>
  89.               </div>
  90.           </div>
  91.          </div>
  92.       </div>
  93.   </div>
  94.   {% if incassiSenzaOrdine|length > 0 %}
  95.   <div class="row">
  96.       <div class="col s12 alert">
  97.           <div class="card">
  98.               <div class="card-content" style="color:red">
  99.               <strong>Attenzione! Ci sono {{ incassiSenzaOrdine|length }} incassi/rimborsi per i quali non è possibile associare un ordine (Fattura/Corrispettivo). Occorre importare gli ordini relativi a questi incassi/rimborsi per poterli esportare massivamente in Profis.</strong>
  100.               <hr/>
  101.               <table id="incassiSenzaOrdine" class="table">
  102.                   <thead>
  103.                       <tr>
  104.                           <td>Ordine</td>
  105.                           <td>Gestito</td>
  106.                           <td>PaymentReference</td>
  107.                           <td>Sorgente</td>
  108.                           <td>Tipo (Incasso/Rimborso)</td> 
  109.                           <td>Totale</td> 
  110.                           <td>Data Transazione</td>
  111.                           <td>Azioni</td>
  112.                       </tr>
  113.                 </thead>
  114.                   <tbody>
  115.                       {% for i in incassiSenzaOrdine %}
  116.                       <tr id="iso-{{ i.id }}">
  117.                           <td>{{ i.Order }}</td>
  118.                           <td>{{ i.Gestito }}</td>
  119.                           <td>{{ i.PaymentReference }}</td>
  120.                           <td>{{ i.Source }}</td>
  121.                           <td>{{ i.Type }}</td> 
  122.                           <td>{% if i.Type == "charge" %}{{ i['ChargeAmount'] }}{% else %}{{ i['RefundAmount'] }}{% endif %}</td> 
  123.                           <td>{{ i.Date }}</td>
  124.                           <td><button type="button" onclick="Manebi.eliminaIncasso({{ i.id }})" class="btn-floating btn-small waves-effect waves-light red">X</button></td>
  125.                       </tr>
  126.                       {% endfor %}                                                
  127.                   </tbody>
  128.               </table>
  129.               </div>
  130.           </div>
  131.       </div>
  132.   </div>
  133.   {% endif %}
  134. </div>
  135. <!-- Modal Structure -->
  136. <div id="NotaCreditoPreviewModal" class="modal modal-fixed-footer modal-fixed-header">
  137.   <div class="modal-header"></div>
  138.   <div class="modal-content"></div>
  139.   <div class="modal-footer">
  140.     <a href="#!" class="modal-close waves-effect waves-green btn btn-small">OK</a>
  141.   </div>
  142. </div>
  143. <div id="genericPopup" class="modal modal-fixed-footer modal-fixed-header">
  144.   <div class="modal-header"></div>
  145.   <div class="modal-content"></div>
  146.   <div class="modal-footer">
  147.     <a href="#!" class="modal-close waves-effect waves-green btn btn-small">CHIUDI</a>
  148.   </div>
  149. </div>
  150. {% block javascripts %}
  151. <script src="{{ asset('tmb-data-table.v1_0.min.js') }}"></script>
  152. <script>
  153. var Manebi = {};
  154. var urlAjax = "{{ currentPath }}";
  155. var filterInstances = {'collapsible': {}, 'dates': {}, 'chips': {}, 'modals': {}, 'selects': {}};
  156. var tableInvoices = null;
  157. var incassiTableColumns =  {
  158.                     'Data Tansazione': {'headerName': 'Data Transazione', 'value': 'Date', 'sortable': true},
  159.                     'Tipo': {'headerName': 'Tipo', 'value': 'Type', 'sortable': true},
  160.                     'Source': {'headerName': 'Source', 'value': 'Source', 'sortable': true},
  161.                     'Order': {'headerName': 'Ordine', 'value': 'Order', 'sortable': true}, 
  162.                     'Fattura': {'headerName': 'Fattura', 'value': function(data){ return '<b>' + data['Fattura'] + '</b>'}, 'sortable': true},
  163.                     'Corrispettivo': {'headerName': 'Corrispettivo', 'value': function(data){ return '<b>' + data['Corrispettivo'] + '</b>'}, 'sortable': true},
  164.                     'Nota Credito': {'headerName': 'Nota Credito', 'value': function(data){ return '<b>' + data['NotaCreditoFormatted'] + '</b>'}, 'type': 'int', 'sortable': true, 'sort-by-value': 'NotaCredito'}, 
  165.                     'Total Amount': {'headerName': 'Incasso Totale', 'value': function(data){ return getPrice(data.ChargeAmount,2) + ' '+ getCurrencySymbol(data.Currency)}, 'type': 'float', 'sortable': true, 'sort-by-value': 'ChargeAmount'},
  166.                     'Charge Amount': {'headerName': 'Incasso Netto', 'value': function(data){ return getPrice(data.ChargeNet,2) + ' '+ getCurrencySymbol(data.Currency)}, 'type': 'float', 'sortable': true, 'sort-by-value': 'ChargeNet'},                
  167.                     'Charge Fee': {'headerName': 'Commissione', 'value': function(data){ return getPrice(data.ChargeFee,2) + ' '+ getCurrencySymbol(data.Currency)}, 'type': 'float', 'sortable': true, 'sort-by-value': 'ChargeFee'}
  168.                     };
  169. var rimborsiTableColumns =  {
  170.                     'Data Tansazione': {'headerName': 'Data Transazione', 'value': 'Date', 'sortable': true},
  171.                     'Tipo': {'headerName': 'Tipo', 'value': 'Type', 'sortable': true},
  172.                     'Source': {'headerName': 'Source', 'value': 'Source', 'sortable': true},
  173.                     'Order': {'headerName': 'Ordine', 'value': 'Order', 'sortable': true}, 
  174.                     'Paese': {'headerName': 'Paese', 'value': 'Shipping Country', 'sortable': true}, 
  175.                     'Fattura': {'headerName': 'Fattura', 'value': function(data){ return '<b>' + data['Fattura'] + '</b>'}, 'sortable': true},
  176.                     'Importo Fattura': {'headerName': 'Importo Fattura', 'value': function(data) { return getPrice(data.Total,2) + ' ' + getCurrencySymbol(data.Currency) }, 'sortable': true},
  177.                     'Nota Credito': {'headerName': 'Nota Credito', 'value': function(data){ return '<b>' + data['NotaCreditoFormatted'] + '</b>'}, 'type': 'int', 'sortable': true, 'sort-by-value': 'NotaCredito'}, 
  178.                     'Total Amount': {'headerName': 'Rimborso Totale', 'value': function(data){ return getPrice(data.RefundAmount,2) + ' '+ getCurrencySymbol(data.Currency) + ( (Math.abs(data.RefundAmount - data.Total) > 0.00 && Math.abs(data.RefundAmount - data.Total) <= 0.05) ? (' <i class="arrot">' + (data.RefundAmount - data.Total > 0 ? '+' : '') + getPrice(data.RefundAmount - data.Total,2) + ' ' + getCurrencySymbol(data.Currency) + '</i>') : '')}, 'type': 'float', 'sortable': true, 'sort-by-value': 'RefundAmount'},
  179.                     'Rimborso Amount': {'headerName': 'Rimborso Netto', 'value': function(data){ return getPrice(data.RefundNet,2) + ' '+ getCurrencySymbol(data.Currency)}, 'type': 'float', 'sortable': true, 'sort-by-value': 'RefundNet'},                    
  180.                     'Rimborso Fee': {'headerName': 'Rimborso Commissione', 'value': function(data){ return getPrice(data.RefundFee,2) + ' '+ getCurrencySymbol(data.Currency)}, 'type': 'float', 'sortable': true, 'sort-by-value': 'RefundFee'},
  181.                     'Azioni': {'headerName': '', 'value': function(data){
  182.                                             var o = '<div id="notacredito-actions-'+data.id+'" style="width: 120px;">' +
  183.                                             (data['NotaCredito'] != '' ? ('<a href="/admin/pdf/note-credito/'+data['NotaCredito']+'?Order=' + encodeURIComponent(data['Order']) + '" class="btn-floating btn-small waves-effect waves-light red"><i class="material-icons">picture_as_pdf</i></a>') : '') +
  184.                                                 (data['NotaCredito'] != '' && ( (Math.abs(data.RefundAmount - data.Subtotal) > 0.05) && (Math.abs(data.RefundAmount - data.Total) > 0.05) ) ? '&nbsp;<button class="btn-floating btn-small blue" onclick="refundDetails('+data.id+',\'' + data.Order + '\',\'' + data['NotaCredito'] + '\')"><i class="material-icons">table_view</i></button>' : '') +
  185.                                                 (data['NotaCredito'] != '' && ( (Math.abs(data.RefundAmount - data.Subtotal) > 0.05) && (Math.abs(data.RefundAmount - data.Total) > 0.05) && (data['NC_Prodotti'] == 0 && data['NC_Spedizioni'] == 0 )) ? '&nbsp;<button class="btn-floating btn-small orange"><b style="color:black;font-size:16px">!</b></button>' : '') +
  186.                                                 '</div>';
  187.                                             return o;
  188.                                             }
  189.                               }
  190.                     };
  191. function getPrice(price, decimal)
  192. {
  193.     var price =  parseFloat(price);
  194.     return price.toFixed(decimal);
  195. }
  196. function getCurrencySymbol(cur)
  197. {
  198.     switch(cur){
  199.         case 'EUR': return '€';
  200.         case 'USD': return '$';
  201.         default: return '';
  202.     }
  203. }
  204. function toggleElement(elId){
  205.   var x = document.getElementById(elId);
  206.   
  207.   if (x.style.display === "none") {
  208.     x.style.display = "block";
  209.   } else {
  210.     x.style.display = "none";
  211.   }
  212. }
  213. function initMaterializeSelect(el) {
  214.     M.FormSelect.init(el, {});
  215. }
  216. document.addEventListener('DOMContentLoaded', function() {
  217.     //Initialize Collapsible
  218.     var elems = document.querySelectorAll('.collapsible');
  219.     
  220.     for(var i = 0; i < elems.length; i++)
  221.     {
  222.       key = typeof(elems[i].getAttribute('id')) !== "undefined" ? elems[i].getAttribute('id') : i;
  223.       filterInstances.collapsible[key] = M.Collapsible.init(elems[i]);
  224.     }
  225.   
  226.     // Initialize DatePicker
  227.     var elems = document.querySelectorAll('.datepicker');
  228.     
  229.     for(var i = 0; i < elems.length; i++)
  230.     {
  231.         key = elems[i].getAttribute('name');
  232.         filterInstances.dates[key] = M.Datepicker.init(elems[i], {autoClose: true, format: "yyyy-mm-dd", showClearBtn: true});
  233.     }
  234.     // Initialize Chips
  235.     var elems = document.querySelectorAll('.chips');
  236.     
  237.     for(var i = 0; i < elems.length; i++)
  238.     {
  239.         key = elems[i].getAttribute('id');
  240.         filterInstances.chips[key] = M.Chips.init(elems[i]);
  241.     }
  242.     
  243.     var elems = document.querySelectorAll('select');
  244.     for(var i = 0; i < elems.length; i++)
  245.     {
  246.         key = elems[i].getAttribute('name');
  247.         filterInstances.selects[key] = M.FormSelect.init(elems[i]);
  248.     }
  249.     // Initialize Modals
  250.     var elems = document.querySelectorAll('.modal');
  251.     
  252.     for(var i = 0; i < elems.length; i++)
  253.     {
  254.         key = elems[i].getAttribute('id');
  255.         filterInstances.modals[key] = M.Modal.init(elems[i], {'startingTop': '0%', 'endingTop': '0%', 'endingBottom': '10%'});
  256.     }
  257.     
  258.     //Get Invoices
  259.     Manebi.getIncassi = function(){
  260.                             window.toggleElement('loader');
  261.                             var filter_type = document.querySelector('select[name="filter-tipo"]').value;
  262.                             var filter_order_type = document.querySelector('select[name="filter-order-type"]').value;
  263.                             var filter_source = document.querySelector('select[name="filter-source"]').value;
  264.                                                         
  265.                             $.ajax({
  266.                                 url: urlAjax,
  267.                                 dataType: "json",
  268.                                 data: {
  269.                                     'filter': 1,
  270.                                     'filter-type': filter_type,
  271.                                     'filter-date-from': filterInstances.dates['filter-date-from'].toString(),
  272.                                     'filter-date-to': filterInstances.dates['filter-date-to'].toString(),
  273.                                     'filter-tipo': filterInstances.selects['filter-tipo'].el.value,
  274.                                     'filter-order-type': filterInstances.selects['filter-order-type'].el.value,
  275.                                     'filter-orders-ids': filterInstances.chips['filter-orders-ids'].chipsData,
  276.                                     'filter-credit-notes-from': document.querySelector('#filter-credit-notes-from').value,
  277.                                     'filter-credit-notes-to': document.querySelector('#filter-credit-notes-to').value,
  278.                                     'filter-source': filterInstances.selects['filter-source'].el.value,
  279.                                 }
  280.                             }).then(function(data){
  281.                                 var actions = '';
  282.                                 
  283.                                 if(filter_type == 'charge')
  284.                                     tableInvoices = new TmbDataTable('incassi-table', incassiTableColumns, {'pageSize': 50, 'selectable': true});
  285.                                 else
  286.                                     tableInvoices = new TmbDataTable('incassi-table', rimborsiTableColumns, {'pageSize': 50, 'selectable': true});
  287.                                 
  288.                                 tableInvoices.setData(data.data).generateTable();
  289.                                 
  290.                                 if( (filter_type == 'refund') && (filter_order_type == 'note-credito' || filter_order_type == 'corrispettivi') )
  291.                                 {
  292.                                     actions += '<button type="button" class="btn btn-small waves-effect waves-light" style="float:right;background-color:#36a700" onclick=\'Manebi.exportFile(\"' + filter_type + '\", \"exportCSVDetails\")\'><i class="material-icons">file_download</i> <span>CSV - DETTAGLI (TODO)</span></button>';
  293.                                 }
  294.                                 actions += '<button type="button" class="btn btn-small waves-effect waves-light" style="float:right;background-color:#36a700" onclick=\'Manebi.exportFile(\"' + filter_type + '\", \"exportCSV\")\'><i class="material-icons">file_download</i> <span>CSV</span></button>';
  295.                                 
  296.                                 
  297.                                 if( (filter_type == 'charge')  || ( (filter_type == 'refund') && (filter_order_type == 'note-credito' || filter_order_type == 'corrispettivi') ) )
  298.                                 {
  299.                                     actions += '<button type="button" class="btn btn-small waves-effect waves-light" style="float:right;background-color:#36a700" onclick=\'Manebi.exportFile(\"' + filter_type + '\", \"exportProfis\")\'><i class="material-icons">import_export</i>XML PROFIS</button>';
  300.                                     
  301.                                     if((filter_type == 'refund') && (filter_order_type == 'note-credito'))
  302.                                         actions += '<button type="button" class="btn btn-small waves-effect waves-light" style="float:right;background-color:#36a700" onclick=\'Manebi.exportFile(\"' + filter_type + '\", \"exportFatturaElettronica\")\'><i class="material-icons">import_export</i>Fattura Elettronica (Nota Credito)</button>';
  303.                                 }
  304.                                 
  305.                                 if(filter_type == 'refund' && filter_order_type == "fatture")
  306.                                 {
  307.                                     actions += '<button type="button" class="btn btn-small waves-effect waves-light" style="margin-let:20px;float:right;background-color:#bb001a" onclick="Manebi.checkNumerazioneNotaCredito()">Assegna numerazione per Note di Credito</button>';
  308.                                 }
  309.                                 
  310.                                 tableInvoices.setAction(actions);
  311.                                 
  312.                                 window.toggleElement('loader');
  313.                             });
  314.                         }
  315.     Manebi.numerazioneNoteCredito = [];
  316.     
  317.     /// Controlla la numerazione delle Note Credito
  318.     Manebi.checkNumerazioneNotaCredito = function() {
  319.         window.toggleElement('loader');
  320.         
  321.         $.ajax({
  322.                 url: urlAjax + '/assignNumNotaCredito', 
  323.                 dataType: "json",
  324.                 data: {
  325.                     'preview': true,
  326.                     'filter-date-from': filterInstances.dates['filter-date-from'].toString(),
  327.                     'filter-date-to': filterInstances.dates['filter-date-to'].toString(),
  328.                 }
  329.                }).then(function(data){
  330.                       if(data.status == 'ERROR'){
  331.                               alert(data.message);
  332.                       }
  333.                       
  334.                       Manebi.numerazioneNoteCredito = data.rimborsi;
  335.                       Manebi.popupPreviewNotaCredito(data);
  336.                       
  337.                    window.toggleElement('loader');
  338.                });
  339.     }
  340.     
  341.     /// Conferma e assegna i Numeri di Nota Credito
  342.     Manebi.confirmNumerazioneNotaCredito = function()
  343.     {
  344.         if(Manebi.numerazioneNoteCredito.length > 0)
  345.         {
  346.             $.ajax({
  347.                 type: 'POST',
  348.                 url: urlAjax + '/assignNumNotaCredito?confirm=1&preview=false', 
  349.                 dataType: "json",
  350.                 contentType: "application/json; charset=utf-8",
  351.                 data: JSON.stringify(Manebi.numerazioneNoteCredito)
  352.                }).then(function(data){
  353.                       if(data.status == 'ERROR'){
  354.                               alert(data.message);
  355.                       }
  356.                       
  357.                       filterInstances.modals['NotaCreditoPreviewModal'].el.querySelector('.modal-content').innerHTML = '<p style="color:#339e00;font-weight:bold">'+ data.message + '<p>';
  358.                });
  359.         }
  360.     }
  361.     
  362.     // Elimina incasso
  363.     Manebi.eliminaIncasso = function(id)
  364.     {
  365.         popup = filterInstances.modals['genericPopup'];
  366.         popup.el.querySelector('.modal-content').innerHTML = 'Sei sicuro di voler rimuovere l\'incasso/il rimborso selezionato? <div style="text:align_center"><button class="btn red" onclick="Manebi.eliminaIncassoConfirm('+id+')">CONFERMA RIMOZIONE INCASSO/RIMBORSO</button></div>';
  367.         popup.open();
  368.     }
  369.     
  370.     Manebi.eliminaIncassoConfirm = function(id)
  371.     {
  372.         $.ajax({
  373.             url: urlAjax + '/delete/' + id,
  374.             type: "POST",
  375.             dataType: "json",
  376.         }).then(function(data){
  377.             if(data.status == 'OK'){;
  378.                    popup = filterInstances.modals['genericPopup'];
  379.                    popup.el.querySelector('.modal-content').innerHTML = '<b>Incasso/Rimborso eliminato!</b>';
  380.                    
  381.                    var elem = document.querySelector('#iso-'+id);
  382.                 elem.parentNode.removeChild(elem);
  383.                }else{
  384.                    popup = filterInstances.modals['genericPopup'];
  385.                    popup.el.querySelector('.modal-content').innerHTML = '<b>Attenzione! Non è stato possibile rimuovere l\'incasso/rimborso selezionato</b>';
  386.                }
  387.         });
  388.     }
  389.     
  390.     Manebi.popupPreviewNotaCredito = function(data)
  391.     {
  392.         var rimborsi = data.rimborsi;
  393.         var message = typeof(data.message) !== "undefined" ? data.message : "";
  394.         
  395.         filterInstances.modals['NotaCreditoPreviewModal'].el.querySelector('.modal-header').innerHTML = '<h4>Anteprima Note Credito</h4>';
  396.         
  397.         var o = '<p><b>Ultima Nota di Credito assegnata</b></p><table id="note-credito-last" class="table"><tbody>\
  398.         <thead><tr><th>Ordine</th><th>Sorgente</th><th>Data Rimborso</th><th>Numero NC</th></tr></thead>';
  399.         for(i=0; i < 1; i++)
  400.         {  
  401.             o += '<tr class="'+(rimborsi[i].Order == null ? 'error' : '')+'"><td><b>' + rimborsi[i].Order +'</b></td><td>' + rimborsi[i].Source + '</td><td>' + rimborsi[i].Date +'</td><td class="num-notacredito"><b>' + rimborsi[i].NotaCredito +'</b></td></tr>';
  402.         }
  403.         o += '<tr></tr></tbody></table>';
  404.         
  405.         if(rimborsi.length > 1)
  406.         {
  407.             o += '<p>'+ message +'</p><table id="note-credito-preview" class="table"><tbody>\
  408.             <thead><tr><th>Ordine</th><th>Sorgente</th><th>Data Rimborso</th><th>Numero NC da assegnare</th></tr></thead>';
  409.             for(i=1; i<rimborsi.length; i++)
  410.             {  
  411.                 o += '<tr class="'+(rimborsi[i].Order == null ? 'error' : '')+'"><td><b>' + rimborsi[i].Order +'</b></td><td>' + rimborsi[i].Source + '</td><td>' + rimborsi[i].Date +'</td><td class="num-notacredito"><b>' + rimborsi[i].NotaCredito +'</b></td></tr>';
  412.             }
  413.             o += '<tr></tr></tbody></table>';    
  414.         }else{
  415.             o += '<p><b>Non ci sono Note di Credito da assegnare</b></p>'
  416.         }
  417.         
  418.         if((data.status == "OK"))
  419.         {
  420.             if(rimborsi.length > 1)
  421.             {
  422.                 o = '<div style="text-align:center"><input type="button" class="btn waves-effect waves-light" onclick="Manebi.confirmNumerazioneNotaCredito()" value="CONFERMA E ASSEGNA NUMERAZIONE" /></div>' + o;                
  423.             }
  424.         }
  425.         
  426.         filterInstances.modals['NotaCreditoPreviewModal'].el.querySelector('.modal-content').innerHTML = o;
  427.         filterInstances.modals['NotaCreditoPreviewModal'].open();
  428.     }
  429.     // Get Invoice
  430.     Manebi.getIncasso = function(id) {
  431.         window.toggleElement('loader');
  432.         
  433.         $.ajax({
  434.                 url: urlAjax + '/' + id, 
  435.                 dataType: "json"
  436.                }).then(function(data){
  437.                        if(data.status == 'OK' && (data.data.length > 0)){
  438.                            var invoice = data.data[0];
  439.                            Manebi.viewInvoice(invoice);
  440.                        }
  441.                     
  442.                    window.toggleElement('loader');
  443.                });
  444.     }
  445.     
  446.     // Export Invoices in Profis XML
  447.     Manebi.exportFile = function(filter_type, export_type) {
  448.             var form = document.createElement("form");
  449.             
  450.             form.setAttribute("id", export_type);
  451.             form.method = "POST";
  452.             form.action = urlAjax;
  453.             form.target = '_blank';    
  454.             
  455.             document.body.appendChild(form);
  456.             f = document.createElement("input");f.type='hidden';
  457.             f.setAttribute('name', 'filter-tipo');f.setAttribute('value', filterInstances.selects['filter-tipo'].el.value);
  458.             form.appendChild(f);
  459.             f = document.createElement("input");f.type='hidden';
  460.             f.setAttribute('name', 'filter-source');f.setAttribute('value', filterInstances.selects['filter-source'].el.value);
  461.             form.appendChild(f);
  462.             
  463.             f = document.createElement("input");f.type='hidden';
  464.             f.setAttribute('name', 'filter-order-type');f.setAttribute('value', filterInstances.selects['filter-order-type'].el.value);
  465.             form.appendChild(f);
  466.             
  467.             f = document.createElement("input");f.type='hidden';
  468.             f.setAttribute('name', export_type);f.setAttribute('value', 1);
  469.             form.appendChild(f);
  470.             
  471.             f = document.createElement("input");f.type='hidden';
  472.             f.setAttribute('name', 'filter');f.setAttribute('value', 1);
  473.             form.appendChild(f);
  474.             
  475.             f = document.createElement("input");f.type='hidden';
  476.             f.setAttribute('name', 'filter-date-from');f.setAttribute('value', filterInstances.dates['filter-date-from'].toString());
  477.             form.appendChild(f);
  478.             
  479.             f = document.createElement("input");f.type='hidden';
  480.             f.setAttribute('name', 'filter-date-to');f.setAttribute('value', filterInstances.dates['filter-date-to'].toString());
  481.             form.appendChild(f);
  482.             
  483.             var chips = filterInstances.chips['filter-orders-ids'].chipsData;
  484.             
  485.             for(var i=0; i < chips.length; i++){
  486.                 f = document.createElement("input");f.type='hidden';
  487.                 f.setAttribute('name', 'filter-orders-ids['+i+'][tag]');f.setAttribute('value', chips[i].tag);
  488.                 form.appendChild(f);
  489.             }
  490.             f = document.createElement("input");f.type='hidden';
  491.             f.setAttribute('name', 'filter-credit-notes-from');f.setAttribute('value', document.querySelector('#filter-credit-notes-from').value);
  492.             form.appendChild(f);
  493.             f = document.createElement("input");f.type='hidden';
  494.             f.setAttribute('name', 'filter-credit-notes-to');f.setAttribute('value', document.querySelector('#filter-credit-notes-to').value);
  495.             form.appendChild(f);
  496.             
  497.             form.submit();
  498.     }                
  499.   });
  500.   
  501.   /**
  502.    * Refund Details
  503.    */
  504.   function refundDetails(id, order, credit_note) {
  505.       console.log(order);
  506.       $.ajax({
  507.                 url: '/admin/note-credito/' + credit_note,
  508.                 data: {
  509.                     'Order': order
  510.                 }, 
  511.                 dataType: "json"
  512.                }).then(function(data){
  513.                        $('tr.credit-note-detail').remove();
  514.                        if(data.status == 'OK'){
  515.                         var prodotti_ordine = data.data.prodotti_ordine;
  516.                         var prodotti_notacredito = data.data.prodotti_notacredito;
  517.                         var shipping_notacredito = data.data.shipping_notacredito;
  518.                         var o = '<tr class="credit-note-detail">';
  519.                         o += '<td colspan="11"> \
  520.                                     <div style="text-align:center"><h5>Informazioni Nota Credito '+credit_note+'<h5></div>\
  521.                                     <table id="creditnote-detail-'+id+'"  class="table table-striped credit-note-detail-table" style="background-color:#EEE">\
  522.                                         <thead><tr><th>Nome riga</th><th>SKU</th><th>Quantità</th><th>Prezzo</th><th>Quantità da rimborsare</th><th>Prezzo da rimborsare</th></tr></thead>\
  523.                                         <tbody>';
  524.                         for(var i=0; i < prodotti_ordine.length; i++) {
  525.                             var refundedQty = 0;
  526.                             var refundedPrice = 0.00;
  527.                             for (var j=0; j< prodotti_notacredito.length; j++) {
  528.                                 if(prodotti_notacredito[j].SKU == prodotti_ordine[i].SKU) {
  529.                                     refundedQty = prodotti_notacredito[j].QuantityRefund;
  530.                                     refundedPrice = Math.round(prodotti_notacredito[j].PriceRefund,2);
  531.                                 }
  532.                             }
  533.                             o += '<tr class="credit-note-product">\
  534.                                         <td><span class="creditnote-detail-name">'+prodotti_ordine[i].Name+'</span></td>\
  535.                                         <td><span class="creditnote-detail-sku">'+prodotti_ordine[i].SKU+'</span></td>\
  536.                                         <td><span class="creditnote-detail-quantity" data-value="'+prodotti_ordine[i].Quantity+'">' + prodotti_ordine[i].Quantity +'</span></td>\
  537.                                         <td><span class="creditnote-detail-price" data-value="'+prodotti_ordine[i].Price+'">' + getPrice(prodotti_ordine[i].Price, 2) + ' ' + getCurrencySymbol(data.data.Currency) +'</span></td>\
  538.                                         <td><input class="creditnote-detail-refund-quantity" type="number" value="'+refundedQty+'" min="0" max="'+prodotti_ordine[i].Quantity+'" onchange="calcRefundPrice(this)"></td>\
  539.                                         <td><input class="creditnote-detail-refund-price" type="text" value="'+refundedPrice+'" onchange="calcTotal()">'+ getCurrencySymbol(data.data.Currency) +'</td>\
  540.                                     </tr>';
  541.                         }
  542.                         for(var i=0; i < prodotti_notacredito.length; i++) {
  543.                             if (prodotti_notacredito[i].SKU == '') {
  544.                                 o += '<tr class="creditnote-detail-new-row">\
  545.                                     <td><input class="creditnote-detail-name" "type="text" value="'+prodotti_notacredito[i].Name+'" placeholder="Nuova riga" style="width:100%"></td>\
  546.                                     <td></td><td></td><td></td>\
  547.                                     <td><input class="creditnote-detail-new-row-quantity" type="number" value="'+prodotti_notacredito[i].QuantityRefund+'" min="0"></td>\
  548.                                     <td><input class="creditnote-detail-new-row-price" type="text" value="'+getPrice(prodotti_notacredito[i].PriceRefund,2)+'" onchange="calcTotal()"> ' + getCurrencySymbol(data.data.Currency) +'</td></tr>';
  549.                             }
  550.                         }
  551.                         o += '<tr class="creditnote-detail-new-row" style="display:none">\
  552.                                 <td><input class="creditnote-detail-name" "type="text" value="" placeholder="Nuova riga" style="width:100%"></td>\
  553.                                 <td></td><td></td><td></td>\
  554.                                 <td><input class="creditnote-detail-new-row-quantity" type="number" value="0" min="0"></td>\
  555.                                 <td><input class="creditnote-detail-new-row-price" type="text" value="0.00" onchange="calcTotal()"> ' + getCurrencySymbol(data.data.Currency) +'</td></tr>';
  556.                         o += '<tr class="new-row"><td colspan="7"><button type="button" class="btn btn-medium waves-effect waves-light blue" onclick="newEmptyRow(this)">+ Nuova Riga</td></tr>';
  557.                         if(data.data.Shipping > 0) {
  558.                             var shippingPriceRefund = 0.00;
  559.                             var shippingQtyRefund = 0;
  560.                             if(typeof(shipping_notacredito['ShippingPriceRefund'])!== "undefined") {
  561.                                 shippingQtyRefund = 1;
  562.                                 shippingPriceRefund = parseFloat(getPrice(shipping_notacredito['ShippingPriceRefund'], 2));
  563.                             }
  564.                             o += '<tr class="credit-note-shipping">\
  565.                                 <td><b>RIMBORSO SPESE SPEDIZIONE:</b></td>\
  566.                                 <td></td>\
  567.                                 <td></td>\
  568.                                 <td><span class="creditnote-detail-shipping" data-value="'+data.data.Shipping+'">'+getPrice(data.data.Shipping,2)+'</span></td>\
  569.                                 <td><input class="creditnote-detail-refund-shipping-quantity" type="number" value="'+shippingQtyRefund+'" min="0" max="1" onclick="calcRefundShipping(this)" /></td>\
  570.                                 <td><input class="creditnote-detail-refund-shipping" type="text" value="'+shippingPriceRefund+'" onchange="calcTotal()" />' + getCurrencySymbol(data.data.Currency) +'</td>\
  571.                             </tr>';
  572.                         }
  573.                         
  574.                         o += '<tr><td colspan="7"><hr/></td></tr>';
  575.                         o += '<tr class="credit-note-total">\
  576.                                 <td colspan="4"></td>\
  577.                                 <td><b>Totale:</b> </td>\
  578.                                 <td><span value=""><input class="creditnote-detail-refund-total" type="text" value="0.00" onchange="calcTotal()" disabled></span> / <span class="credit-note-refund-amount" data-value="'+data.data.RefundAmount+'">'+getPrice(data.data.RefundAmount,2)+' '+ getCurrencySymbol(data.data.Currency) +'</span><td>\
  579.                             </tr>';
  580.                         o += '<tr><td colspan="7"><hr/></td></tr>';
  581.                         
  582.                         o += '<tr><td colspan="7" style="text-align:center">\
  583.                         <button id="credit-note-details-button-save" type="button" class="btn btn-medium waves-effect waves-light" onclick="saveNotaCreditoDetails('+id+')">Salva Dettagli Nota Credito</button>\
  584.                         <button id="credit-note-details-button-cancel" type="button" class="btn btn-medium waves-effect waves-light red">Annulla</button>\
  585.                         </td></tr>';
  586.                         o += '</tbody>\
  587.                             </table>\
  588.                             </td>';
  589.                         o += '</tr>';
  590.                         $('#notacredito-actions-'+id).parent().parent().after(o);
  591.                         calcTotal();
  592.                        }
  593.                });
  594.   }
  595.     function calcRefundPrice(el)
  596.     {
  597.         var row = $(el).parent().parent();
  598.         var qty = el.value;
  599.         var price = parseFloat(row.find('span.creditnote-detail-price').data('value'));
  600.         row.find('input.creditnote-detail-refund-price').val(price * qty).change();
  601.     }
  602.     function calcRefundShipping(el)
  603.     {
  604.         var row = $(el).parent().parent();
  605.         var qty = el.value;
  606.         var price = parseFloat(row.find('span.creditnote-detail-shipping').data('value'));
  607.         row.find('input.creditnote-detail-refund-shipping').val(price * qty).change();
  608.     }
  609.   
  610.     function calcTotal()
  611.     {
  612.         var sum = 0;
  613.         $('.creditnote-detail-refund-price').each(function(i,v){
  614.             //qty = parseInt($(this).parent().parent().find('input.creditnote-detail-refund-quantity').val());
  615.             sum += parseFloat(v.value);
  616.         });
  617.         $('.creditnote-detail-new-row-price').each(function(i,v){
  618.                 sum += parseFloat(v.value);
  619.         });
  620.         $('.creditnote-detail-refund-shipping').each(function(i,v){sum += parseFloat(v.value);});
  621.         $('.creditnote-detail-refund-total').val(Math.round(sum * 100,2)/100).data('value', sum);
  622.     };
  623.     function newEmptyRow(el) {
  624.         var new_row = $('tr.creditnote-detail-new-row').eq(0).clone();
  625.         console.log(new_row);
  626.         $(el).parent().parent().before(new_row.show());
  627.     }
  628.     function saveNotaCreditoDetails(id) {
  629.         var post_data = {'id': id, 'products': [], 'shipping': [], 'total': 0.00};
  630.         var upload = true;
  631.         $('tr.credit-note-product').each(function(i,v){
  632.             var _product_data = {};
  633.             var $el = $(v);
  634.             _product_data['Name'] = $el.find('span.creditnote-detail-name').html();
  635.             _product_data['SKU'] = $el.find('span.creditnote-detail-sku').html();
  636.             _product_data['RefundQuantity'] = parseFloat($el.find('input.creditnote-detail-refund-quantity').val());
  637.             _product_data['RefundPrice'] = parseFloat($el.find('input.creditnote-detail-refund-price').val());
  638.             post_data['products'].push(_product_data);
  639.         });
  640.         $('tr.creditnote-detail-new-row').each(function(i,v){
  641.             var _product_data = {};
  642.             var $el = $(v);
  643.             _product_data['Name'] = $el.find('input.creditnote-detail-name').val();
  644.             _product_data['SKU'] = '';
  645.             if(_product_data['Name'] == '')
  646.                 return true;
  647.             _product_data['RefundQuantity'] = parseFloat($el.find('input.creditnote-detail-new-row-quantity').val());
  648.             if(_product_data['RefundQuantity'] == 0) {
  649.                 alert('Attenzione! specifica la quantità della Nuova Riga: '+_product_data['Name']);
  650.                 upload = false;
  651.                 return false;
  652.             }
  653.             
  654.             _product_data['RefundPrice'] = parseFloat($el.find('input.creditnote-detail-new-row-price').val());
  655.             if(_product_data['RefundPrice'] == 0) {
  656.                 alert('Attenzione! specifica il prezzo della Nuova Riga: '+_product_data['Name']);
  657.                 upload = false;
  658.                 return false;
  659.             }
  660.             post_data['products'].push(_product_data);
  661.         });
  662.         if(!upload)
  663.             return;
  664.         $('tr.credit-note-shipping').each(function(i,v){
  665.             var _product_data = {};
  666.             var $el = $(v);
  667.             _product_data['RefundQuantity'] = parseFloat($el.find('input.creditnote-detail-refund-shipping-quantity').val());
  668.             _product_data['RefundPrice'] = parseFloat($el.find('input.creditnote-detail-refund-shipping').val());
  669.             post_data['shipping'].push(_product_data);
  670.         });
  671.         post_data['total'] = parseFloat($('tr.credit-note-total').find('input.creditnote-detail-refund-total').val());
  672.         var refundAmount = getPrice($('tr.credit-note-total').find('span.credit-note-refund-amount').data('value'),2);
  673.         
  674.         if( post_data['total'] != parseFloat(refundAmount) ) {
  675.             $('tr.credit-note-total').find('input.creditnote-detail-refund-total').addClass('error');
  676.             alert('Attenzione, il valore finale della nota credito non coincide con il totale rimborsato');
  677.             return;
  678.         }else{
  679.             $('tr.credit-note-total').find('input.creditnote-detail-refund-total').removeClass('error');
  680.         }
  681.          $.ajax({
  682.             url: '/admin/note-credito/', 
  683.             type: "POST",
  684.             dataType: "json",
  685.             data: post_data
  686.         }).then(function(data) {
  687.             alert(data.message);
  688.         });
  689.     }
  690. </script>
  691. {% endblock %}
  692. <style>
  693. td, th {
  694.     padding: 2px 5px;
  695.     font-size: 0.9rem;
  696. }
  697. th.sortable {
  698.     text-decoration: underline;
  699. }
  700. th.sortable.asc::after {
  701.     content: '\2b61';
  702. }
  703. th.sortable.desc::after {
  704.     content: '\2b63';
  705. }
  706. table.striped > thead > tr{
  707.     background-color: #e4e4e4;
  708.     border-bottom: 1px solid #CCC !important;
  709. }
  710. tbody > tr > td:first-child{
  711.     background-color: #e4e4e4;
  712. }
  713. tr.selectable:hover > td{
  714.     cursor: pointer;
  715.     background-color: #BBB;
  716. }
  717. .modal {
  718.    max-height: 100%;
  719. }
  720. .modal.modal-fixed-footer {
  721.    height: 90%;
  722. }
  723. .incassi-table-pagination {
  724.     text-align: center;
  725.     display: flex;
  726.     flex-wrap: wrap;
  727.     justify-content: center;
  728. }
  729. .incassi-table-pagination .page {
  730.     display: inline;
  731.     padding: 3px;
  732. }
  733. .incassi-table-pagination .page a {
  734.     color: #000;
  735. }
  736. .incassi-table-pagination .page.active a {
  737.     font-weight: bold;
  738.     padding: 5px;
  739.     text-decoration: underline;
  740. }
  741. div.select-wrapper{
  742.     display:inline-block;
  743. }
  744. #incassiSenzaOrdine thead td
  745. {
  746.     font-weight: bold;
  747.     color: #000;
  748. }
  749. #incassiSenzaOrdine td
  750. {
  751.     color: #000;
  752. }
  753. #NotaCreditoPreviewModal tbody tr.error td {
  754.     font-weight: bold;
  755.     color: #f00;
  756.     border: 2px solid #F00;
  757. }
  758. button.btn.btn-small.waves-effect.waves-light {
  759.     margin: 0px 15px 0px 15px;
  760. }
  761. i.arrot {
  762.     color: brown;
  763.     font-size: 10px;
  764.     text-align: right;
  765. }
  766. tr.credit-note-detail {
  767.     background-color: #FFF !important;
  768. }
  769. table.credit-note-detail-table th{
  770.     border-bottom: 1px solid #DDD !important;
  771.     text-align:center;
  772. }
  773. table.credit-note-detail-table td {
  774.     text-align:center;
  775. }
  776. table.credit-note-detail-table input{
  777.     background-color: #FFF !important;
  778.     border: 1px solid #DDD !important;
  779. }
  780. table.credit-note-detail-table input[type="number"],
  781. table.credit-note-detail-table input[type="text"]{
  782.     width: 30%;
  783.     text-align: center;
  784. }
  785. tbody > tr.credit-note-detail > td{
  786.     background-color: #EEE !important;
  787. }
  788. input.creditnote-detail-refund-total.error {
  789.     border: 1px solid #F00 !important;
  790. }
  791. </style>
  792. {% endblock %}