dolibarr 25.0.0-alpha
lib_dispatch.js.php
Go to the documentation of this file.
1<?php
2// Copyright (C) 2014 Cedric GROSS <c.gross@kreiz-it.fr>
3// Copyright (C) 2017 Francis Appels <francis.appels@z-application.com>
4//
5// This program is free software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation; either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <https://www.gnu.org/licenses/>.
17// or see https://www.gnu.org/
18
24if (!defined('NOREQUIRESOC')) {
25 define('NOREQUIRESOC', '1');
26}
27if (!defined('NOCSRFCHECK')) {
28 define('NOCSRFCHECK', 1);
29}
30if (!defined('NOTOKENRENEWAL')) {
31 define('NOTOKENRENEWAL', 1);
32}
33if (!defined('NOLOGIN')) {
34 define('NOLOGIN', 1);
35}
36if (!defined('NOREQUIREMENU')) {
37 define('NOREQUIREMENU', 1);
38}
39if (!defined('NOREQUIREHTML')) {
40 define('NOREQUIREHTML', 1);
41}
42if (!defined('NOREQUIREAJAX')) {
43 define('NOREQUIREAJAX', '1');
44}
45
46session_cache_limiter('public');
47
48require_once '../../main.inc.php';
53// Load translation files required by the page
54$langs->loadLangs(array("productbatch"));
55
56// Define javascript type
57top_httphead('text/javascript; charset=UTF-8');
58// Important: Following code is to avoid page request by browser and PHP CPU at each Dolibarr page access.
59header('Cache-Control: max-age=10800, public, must-revalidate');
60
61?>
71function addDispatchLine(index, type, mode, lotnumber) {
72 mode = mode || 'qtymissing'
73 lotnumber = lotnumber || ''
74
75 console.log("fourn/js/lib_dispatch.js.php addDispatchLine Split line type="+type+" index="+index+" mode="+mode);
76
77 var $row0 = $("tr[name='"+type+'_0_'+index+"']");
78 var $dpopt = $row0.find('.hasDatepicker').first().datepicker('option', 'all'); // get current datepicker options to apply the same to the cloned datepickers
79 var $row = $row0.clone(true); // clone first batch line to jQuery object
80 var nbrTrs = $("tr[name^='"+type+"_'][name$='_"+index+"']").length; // count nb of tr line with attribute name that starts with 'batch_' or 'dispatch_', and end with _index
81 var qtyOrdered = parseFloat($("#qty_ordered_0_"+index).val()); // Qty ordered is same for all rows
82
83 var qty = parseFloat($("#qty_"+(nbrTrs - 1)+"_"+index).val());
84 if (isNaN(qty)) {
85 qty = '';
86 }
87
88 console.log("fourn/js/lib_dispatch.js.php addDispatchLine Split line nbrTrs="+nbrTrs+" qtyOrdered="+qtyOrdered+" qty="+qty);
89
90 var qtyDispatched;
91
92 if (mode === 'lessone') {
93 qtyDispatched = parseFloat($("#qty_dispatched_0_" + index).val()) + 1;
94 }
95 else {
96 qtyDispatched = parseFloat($("#qty_dispatched_0_" + index).val()) + qty;
97 // If user did not reduced the qty to dispatch on old line, we keep only 1 on old line and the rest on new line
98 if (lotnumber === '' && qtyDispatched == qtyOrdered && qtyDispatched > 1) {
99 qtyDispatched = parseFloat($("#qty_dispatched_0_" + index).val()) + 1;
100 mode = 'lessone';
101 }
102 }
103 console.log("qtyDispatched=" + qtyDispatched + " qtyOrdered=" + qtyOrdered+ " qty=" + qty);
104
105 if (qty <= 1 && lotnumber === '') {
106 window.alert("Remain quantity to dispatch is too low to be split");
107 } else {
108 var oldlineqty = qtyDispatched;
109 var newlineqty = qtyOrdered - qtyDispatched;
110 if (lotnumber !== '') {
111 newlineqty = 1; // One serial number = one unit, previous line is kept unchanged
112 } else if (newlineqty <= 0) {
113 newlineqty = qty - 1;
114 oldlineqty = 1;
115 $("#qty_"+(nbrTrs - 1)+"_"+index).val(oldlineqty);
116 }
117
118 //replace tr suffix nbr
119 $row.html($row.html().replace(/_0_/g, "_" + nbrTrs + "_"));
120
121 // jquery's deep clone is incompatible with date pickers (the clone shares data with the original)
122 // so we destroy and rebuild the new date pickers
123 setTimeout(() => {
124 $row.find('.hasDatepicker').each((i, dp) => {
125 $(dp).removeData()
126 .removeClass('hasDatepicker');
127 $(dp).next('img.ui-datepicker-trigger').remove();
128 $(dp).datepicker($dpopt);
129 });
130 }, 0);
131
132 //create new select2 to avoid duplicate id of cloned one
133 $row.find("select[name='" + 'entrepot_' + nbrTrs + '_' + index + "']").select2();
134 // Copy selected option to new select
135 let $prevRow = $("tr[name^='" + type + "_'][name$='_" + index + "']:last")
136 let $prevEntr = Number($prevRow.find("select[name='" + 'entrepot_' + (nbrTrs-1) + '_' + index + "']").val())
137 $row.find("select[name='" + 'entrepot_' + nbrTrs + '_' + index + "']").val($prevEntr)
138 // TODO find solution to keep new tr's after page refresh
139 //clear value
140 $row.find("input[name^='qty']").val('');
141 //change name of new row
142 $row.attr('name', type + '_' + nbrTrs + '_' + index);
143 //insert new row before last row
144 $("tr[name^='" + type + "_'][name$='_" + index + "']:last").after($row);
145
146 //remove cloned select2 with duplicate id.
147 $("#s2id_entrepot_" + nbrTrs + '_' + index).detach(); // old way to find duplicated select2 component
148 $(".csswarehouse_" + nbrTrs + "_" + index + ":first-child").parent("span.selection").parent(".select2").detach();
149
150 /* Suffix of lines are: _ trs.length _ index */
151 $("#qty_"+nbrTrs+"_"+index).focus();
152 $("#qty_dispatched_0_"+index).val(oldlineqty);
153
154 //hide all buttons then show only the last one
155 $("tr[name^='" + type + "_'][name$='_" + index + "'] .splitbutton").hide();
156 $("tr[name^='" + type + "_'][name$='_" + index + "']:last .splitbutton").show();
157
158 $("#reset_" + (nbrTrs) + "_" + index).click(function (event) {
159 event.preventDefault();
160 id = $(this).attr("id");
161 id = id.split("reset_");
162 idrow = id[1];
163 idlast = $("tr[name^='" + type + "_'][name$='_" + index + "']:last .qtydispatchinput").attr("id");
164 if (idlast == $("#qty_" + idrow).attr("id")) {
165 console.log("Remove trigger for tr name = " + type + "_" + idrow);
166 $('tr[name="' + type + '_' + idrow + '"').remove();
167 $("tr[name^='" + type + "_'][name$='_" + index + "']:last .splitbutton").show();
168 } else {
169 console.log("fourn/js/lib_dispatch.js.php Reset trigger for id = qty_" + idrow);
170 $("#qty_" + idrow).val("");
171 }
172 });
173
174 if (mode === 'lessone')
175 {
176 qty = 1; // keep 1 in old line
177 $("#qty_"+(nbrTrs-1)+"_"+index).val(qty);
178 }
179 $("#qty_"+nbrTrs+"_"+index).val(newlineqty);
180 // Store arbitrary data for dispatch qty input field change event
181 $("#qty_" + (nbrTrs - 1) + "_" + index).data('qty', qty);
182 $("#qty_" + (nbrTrs - 1) + "_" + index).data('type', type);
183 $("#qty_" + (nbrTrs - 1) + "_" + index).data('index', index);
184 // Update dispatched qty when value dispatch qty input field changed
185 //$("#qty_" + (nbrTrs - 1) + "_" + index).change(this.onChangeDispatchLineQty);
186 //set focus on lot of new line (if it exists)
187 $("#lot_number_" + (nbrTrs) + "_" + index).focus();
188 //Clean bad values
189 $("tr[name^='" + type + "_'][name$='_" + index + "']:last").data("remove", "remove");
190 $("#lot_number_" + (nbrTrs) + "_" + index).val(lotnumber)
191 $("#idline_" + (nbrTrs) + "_" + index).val("-1")
192 $("#qty_" + (nbrTrs) + "_" + index).data('expected', "0");
193 $("#lot_number_" + (nbrTrs) + "_" + index).removeAttr("disabled");
194 }
195}
196
206function addDispatchLinesFromSerialList(index, type) {
207 console.log("fourn/js/lib_dispatch.js.php addDispatchLinesFromSerialList type="+type+" index="+index);
208
209 var $dialog = jQuery("#dialogforpopup");
210 var html = '<textarea id="seriallist" class="centpercent" rows="10" placeholder="<?php echo dol_escape_js(dol_escape_htmltag($langs->transnoentitiesnoconv("EnterOneSerialNumberPerLine"))); ?>"></textarea>';
211 html += '<div id="seriallistmessage" class="opacitymedium paddingtop"></div>';
212 $dialog.html(html);
213
214 // Return the list of non empty trimmed lines
215 var getSerialList = function() {
216 return jQuery("#seriallist").val().split(/\r\n|\r|\n/).map(function(s) { return s.trim(); }).filter(function(s) { return s !== ''; });
217 };
218
219 jQuery("#seriallist").on("input", function() {
220 jQuery("#seriallistmessage").removeClass("error").text('<?php echo dol_escape_js($langs->transnoentitiesnoconv("NbOfSerialNumbersDetected", "%s")); ?>'.replace('%s', getSerialList().length));
221 });
222
223 $dialog.dialog({
224 title: '<?php echo dol_escape_js($langs->transnoentitiesnoconv("EnterMultipleSerialNumbers")); ?>',
225 modal: true,
226 resizable: false,
227 width: 'auto',
228 buttons: [
229 {
230 text: '<?php echo dol_escape_js($langs->transnoentitiesnoconv("Apply")); ?>',
231 click: function() {
232 var serials = getSerialList();
233 if (serials.length == 0) {
234 return;
235 }
236 // Cheap early check of duplicates inside the list. Uniqueness in stock is still checked by MouvementStock.
237 var seen = {};
238 for (var n = 0; n < serials.length; n++) {
239 if (seen[serials[n]]) {
240 jQuery("#seriallistmessage").addClass("error").text('<?php echo dol_escape_js($langs->transnoentitiesnoconv("ErrorDuplicateSerialNumberInList", "%s")); ?>'.replace('%s', serials[n]));
241 return;
242 }
243 seen[serials[n]] = true;
244 }
245
246 var nbrTrs = $("tr[name^='"+type+"_'][name$='_"+index+"']").length;
247 var $lastlot = $("#lot_number_"+(nbrTrs - 1)+"_"+index);
248 var k = 0;
249 // Reuse the last line if it is still empty (not a saved line and no lot/serial entered yet)
250 if (!$lastlot.prop('disabled') && $lastlot.val().trim() === '') {
251 $lastlot.val(serials[0]);
252 $("#qty_"+(nbrTrs - 1)+"_"+index).val(1);
253 k = 1;
254 }
255 for (; k < serials.length; k++) {
256 addDispatchLine(index, type, 'qtymissing', serials[k]);
257 }
258
259 jQuery(this).dialog("close");
260 }
261 },
262 {
263 text: '<?php echo dol_escape_js($langs->transnoentitiesnoconv("Cancel")); ?>',
264 click: function() {
265 jQuery(this).dialog("close");
266 }
267 }
268 ]
269 });
270 jQuery("#seriallist").focus();
271}
272
282function onChangeDispatchLineQty(element) {
283 var type = $(element).data('type'),
284 qty = parseFloat($(element).data('expected')),
285 changedQty, nbrTrs, dispatchingQty, qtyOrdered, qtyDispatched;
286 id = $(element).attr("id");
287 id = id.split("_");
288 index = id[2];
289
290 if (index >= 0 && type && qty >= 0) {
291 nbrTrs = $("tr[name^='" + type + "_'][name$='_" + index + "']").length;
292 qtyChanged = parseFloat($(element).val()) - qty; // qty changed
293 qtyDispatching = parseFloat($(element).val()); // qty currently being dispatched
294 qtyOrdered = parseFloat($("#qty_ordered_0_" + index).val()); // qty ordered
295 qtyDispatched = parseFloat($("#qty_dispatched_0_" + index).val()); // qty already dispatched
296
297 console.log("onChangeDispatchLineQty qtyChanged: " + qtyChanged + " qtyDispatching: " + qtyDispatching + " qtyOrdered: " + qtyOrdered + " qtyDispatched: " + qtyDispatched);
298
299 if ((qtyChanged) <= (qtyOrdered - (qtyDispatched + qtyDispatching))) {
300 $("#qty_dispatched_0_" + index).val(qtyDispatched + qtyChanged);
301 } else {
302 /*console.log("eee");
303 $(element).val($(element).data('expected'));*/
304 }
305 $(element).data('expected', $(element).val());
306 }
307}
if(!defined( 'NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
Definition repair.php:130
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:133