diff --git a/edit-mode/function/activityLocation.js b/edit-mode/function/activityLocation.js index cd8f394..77e9c90 100644 --- a/edit-mode/function/activityLocation.js +++ b/edit-mode/function/activityLocation.js @@ -5,36 +5,29 @@ let long = 106.559242; let zoom = 10; let currentIdAct = 0; let map = L.map('map_activity').setView([lat, long], zoom); +let drawnItems = new L.FeatureGroup().addTo(map); +let inter = 5; -let inter = 5; - -let circLat = "", -circLong = ""; +let circLat = "", + circLong = ""; L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }).addTo(map); -let drawnItem = L.featureGroup().addTo(map); - var drawControl = new L.Control.Draw({ draw: { circlemarker: false, - circle:false, + circle: false, polyline: false }, - edit:{ - featureGroup:drawnItem, - edit:false, - delete:false - } }); var drawnControlEdit = new L.Control.Draw({ draw: false, - edit:{ - featureGroup:drawnItem, - delete:true + edit: { + featureGroup: drawnItems, + delete: true } }); @@ -42,39 +35,72 @@ map.addControl(drawControl); // add searching location (nominatim) on map L.Control.geocoder().addTo(map); +function addDrawnLayer(layer) { + drawnItems.addLayer(layer); +} -function openActivityMap(id) -{ +function updateCurrentGeoJson() { + let shapes = []; + drawnItems.eachLayer(function (layer) { + let geojson = layer.toGeoJSON(); + if (layer instanceof L.Circle) { + geojson.properties.radius = layer.getRadius(); + } + shapes.push(geojson); + }); + currentGeoJson = { + type: 'FeatureCollection', + features: shapes + }; +} +function openActivityMap(id) { currentIdAct = id; map.invalidateSize(); $.ajax({ url: `${base_url}task/edit/${id}`, - type:"get", + type: "get", success: function (data) { let dataRes = data.data // console.log("cek data", data); - drawnItem.clearLayers(); - if(dataRes.geom){ + drawnItems.clearLayers(); + if (dataRes.geom) { let datageojson = JSON.parse(dataRes.geom); currentGeoJson = datageojson // console.log("cek data geojson", datageojson); - if(datageojson.properties.radius){ - let radius = datageojson.properties.radius - let lGeoJson = L.geoJson(datageojson); - let layers = lGeoJson.getLayers(); - let latlon = layers[0].getLatLng(); - let newCircle = L.circle([latlon.lat,latlon.lng], {radius: radius}); - drawnItem.addLayer(newCircle); - // console.log("cek layers", layers[0]); - }else{ - let lGeoJson = L.geoJson(datageojson); - let layers = lGeoJson.getLayers(); - drawnItem.addLayer(layers[0]); + if (datageojson.type === 'FeatureCollection') { + datageojson.features.forEach(feature => { + let lGeoJson = L.geoJSON(feature); + let layers = lGeoJson.getLayers(); + layers.forEach(layer => { + let radius = layer.feature.properties.radius; + if (radius) { + let latlon = layer.getLatLng(); + let circle = L.circle([latlon.lat, latlon.lng], { radius: radius }); + addDrawnLayer(circle); + } + else { + addDrawnLayer(layer) + } + }); + }); + } else { + if (datageojson.properties.radius) { + let radius = datageojson.properties.radius + let lGeoJson = L.geoJson(datageojson); + let layers = lGeoJson.getLayers(); + let latlon = layers[0].getLatLng(); + let newCircle = L.circle([latlon.lat, latlon.lng], { radius: radius }); + addDrawnLayer(newCircle) + // console.log("cek layers", layers[0]); + } else { + let lGeoJson = L.geoJson(datageojson); + let layers = lGeoJson.getLayers(); + addDrawnLayer(layers[0]) + } } actionLocationAc = "edit"; - drawControl.remove(); map.addControl(drawnControlEdit); - }else{ + } else { currentGeoJson = ""; actionLocationAc = "add"; drawnControlEdit.remove(); @@ -89,7 +115,7 @@ function openActivityMap(id) } $('#modal_activity_location').on('hide.bs.modal', function (event) { - currentGeoJson ="" + currentGeoJson = "" currentIdAct = 0; actionLocationAc = "add"; drawnControlEdit.remove(); @@ -100,7 +126,7 @@ $('#modal_activity_location').on('hide.bs.modal', function (event) { // map initialization $(document).ready(function () { let intervalMap = setInterval(function () { - if(inter=0){ + if (inter = 0) { clearInterval(intervalMap) } map.invalidateSize(); @@ -113,7 +139,7 @@ $(document).ready(function () { if (type === 'marker') { let latlong = layer.getLatLng(); // console.log("cek latlong", latlong); - circLat = latlong.lat + circLat = latlong.lat circLong = latlong.lng $("#modal_radius").modal("show"); // Do marker specific actions @@ -127,22 +153,22 @@ $(document).ready(function () { // console.log("cek layer", layer.toGeoJSON()); // layer.bindTooltip("cek"); // Do whatever else you need to. (save to db; add to map etc) - drawnItem.addLayer(layer); - drawControl.remove(); + addDrawnLayer(layer); + updateCurrentGeoJson(); map.addControl(drawnControlEdit); // map.addLayer(layer); }); map.on(L.Draw.Event.DELETED, function (e) { - var type = e.layerType, - layer = e.layer; - + var type = e.layerType; + let layers = e.layers.getLayers(); + layers.forEach(layer => { + drawnItems.removeLayer(layer); + }); + updateCurrentGeoJson() // console.log("cek layer", layer.toGeoJSON()); // Do whatever else you need to. (save to db; add to map etc) - currentGeoJson = ""; - drawnItem.removeLayer(layer); - drawnControlEdit.remove(); - map.addControl(drawControl); + // map.addLayer(layer); }); @@ -150,103 +176,132 @@ $(document).ready(function () { // var type = e.layerType, // layer = e.layer; let layers = e.layers.getLayers(); - let layer = layers[0] - let geoJson = layers[0].toGeoJSON(); - if(layer instanceof L.Circle){ - geoJson.properties.radius = layer.getRadius(); - currentGeoJson = geoJson - }else{ - currentGeoJson = geoJson - } + layers.forEach(layer => { + let geoJson = layer.toGeoJSON(); + if (layer instanceof L.Circle) { + geoJson.properties.radius = layer.getRadius(); + } + updateCurrentGeoJson(); + }); // console.log("cek layer", layers[0].toGeoJSON()); // console.log("cek layer", layer.toGeoJSON()); // Do whatever else you need to. (save to db; add to map etc) - // drawnItem.removeLayer(layer); // drawnControlEdit.remove(); // map.addControl(drawControl); // map.addLayer(layer); }); - $("#modal_activity_location").on("click", "#btn_save_location", function() { - if(currentGeoJson==""){ + $("#modal_activity_location").on("click", "#btn_save_location", function () { + if (currentGeoJson == "") { gantt.confirm({ text: "Lokasi belum ditentukan!, lanjutkan?", - ok:"Submit", - cancel:"Cancel", - callback: function(result){ - if(!result){ + ok: "Submit", + cancel: "Cancel", + callback: function (result) { + if (!result) { return false - }else{ - submitLocation(); + } else { + submitShapes(); } } }); - }else{ - submitLocation() + } else { + submitShapes(); } }); - function submitLocation() - { + function submitShapes() { + let payload + + if (currentGeoJson && currentGeoJson != "") { + payload = { + geom: JSON.stringify(currentGeoJson), + } + } else { + payload = { + geom: null, + } + } + + $.ajax({ + data: JSON.stringify(payload), + url: `${base_url}task/update-regular/${currentIdAct}`, + type: "PUT", + processData: false, + contentType: false, + success: function (data) { + $("#modal_activity_location").modal("hide"); + currentGeoJson = "" + currentIdAct = 0; + gantt.alert("Activity Location successfully updated!"); + }, + error: function (data) { + $("#modal_activity_location").modal("hide"); + currentGeoJson = "" + currentIdAct = 0; + gantt.alert("Activity Location failed updated!, try again later!"); + } + }); + } + + function submitLocation() { let payload - if(currentGeoJson && currentGeoJson!=""){ + if (currentGeoJson && currentGeoJson != "") { payload = { geom: JSON.stringify(currentGeoJson), } - }else{ + } else { payload = { geom: null, } } $.ajax({ - data: JSON.stringify(payload), + data: JSON.stringify(payload), url: `${base_url}task/update-regular/${currentIdAct}`, type: "PUT", processData: false, contentType: false, success: function (data) { $("#modal_activity_location").modal("hide"); - currentGeoJson ="" + currentGeoJson = "" currentIdAct = 0; gantt.alert("Activity Location successfully updated!"); }, error: function (data) { $("#modal_activity_location").modal("hide"); - currentGeoJson ="" + currentGeoJson = "" currentIdAct = 0; gantt.alert("Activity Location failed updated!, try again later!"); } }); } - $("#modal_radius").on("click", "#btn_save_radius", function() { + $("#modal_radius").on("click", "#btn_save_radius", function () { let radius = $("#buffer_radius").val(); - if(radius <= 0){ + if (radius <= 0) { gantt.alert("radius buffer tidak boleh kurang dari atau sama dengan 0!!"); - }else{ + } else { submitCircle(radius); } }); }); -function submitCircle(radius) -{ - let circle = L.circle([circLat,circLong], {radius: radius}); +function submitCircle(radius) { + let circle = L.circle([circLat, circLong], { radius: radius }); let geojsoncircle = circle.toGeoJSON(); geojsoncircle.properties.radius = radius currentGeoJson = geojsoncircle - // console.log("geojsoncircle", geojsoncircle); - drawnItem.addLayer(circle); - drawControl.remove(); + addDrawnLayer(circle); + updateCurrentGeoJson(); map.addControl(drawnControlEdit); $("#modal_radius").modal('hide'); } $('#modal_radius').on('hide.bs.modal', function (event) { - circLat = 0 + circLat = 0 circLong = 0 $("#buffer_radius").val(""); }); \ No newline at end of file diff --git a/edit-mode/function/expenseResource.js b/edit-mode/function/expenseResource.js index bd7f101..602ca20 100644 --- a/edit-mode/function/expenseResource.js +++ b/edit-mode/function/expenseResource.js @@ -4,6 +4,7 @@ function resetFormAssignexpense() { $('#select-expense').val(null).trigger("change"); $('#select-expense').find('option').remove(); $('#select-expense').val(""); + $('#uom-req-expense').val(null).trigger('change'); $('#form-assign-expense').trigger("reset"); $('#btn-assign-expense').html('Assign'); $('#btn-assign-expense').prop("disabled", false); @@ -59,6 +60,7 @@ $(document).ready(function () { }); function deleteexpenseAssign(id) { + searchReport(id); $.ajax({ url: `${base_url}assign-material/delete/${id}`, type: "DELETE", @@ -131,7 +133,15 @@ $(document).ready(function () { cache: false } }); - + // $('#required-date-req-expense').datepicker({ + // format: 'dd-mm-yyyy', // Set the desired format + // autoclose: true // Close the datepicker when a date is selected + // }); + // + // $('#required-date-plan-expense').datepicker({ + // format: 'dd-mm-yyyy', // Set the desired format + // autoclose: true // Close the datepicker when a date is selected + // }); $("#form-assign-expense").on('submit', function (e) { e.preventDefault(); diff --git a/edit-mode/function/function.js b/edit-mode/function/function.js index 2e7aa28..c91369b 100644 --- a/edit-mode/function/function.js +++ b/edit-mode/function/function.js @@ -14,6 +14,46 @@ function getUrlParameter(sParam) { return false; }; + function searchReport(id, updateActual = true) { + var payload = { + "columns": [ + { + "name": "assign_material_id", + "logic_operator": "=", + "value": id, + "operator": "AND" + } + ], + // "joins": [{ "name": "m_proyek", "column_join": "proyek_id", "column_results": ["kode_sortname", "nama"] }], + } + $.ajax({ + data: JSON.stringify(payload), + url: `${base_url}report-activity-material/search`, + type: "POST", + success: function (data) { + if (updateActual) { + data.data.forEach(element => { + let activityId = element.activity_id; + let task = gantt.getTask(activityId); + task.actual_start = null; + task.actual_end = null; + }); + } else { + if (data.data.length == 1) { + let activityId = data.data[0].activity_id; + let task = gantt.getTask(activityId); + task.actual_start = null; + task.actual_end = null; + } + } + actionHappen = true; + }, + error: function (data) { + // gantt.alert("Failed to get the data."); + } + }); + } + const formatNumber = (angka) => { var number_string = angka.replace(/[^,\d]/g, '').toString(), split = number_string.split(','), @@ -212,6 +252,7 @@ function updateActivity(id) { gantt.getTask(id).assign_hr = data.assign_hr; gantt.getTask(id).assign_material = data.assign_material; gantt.getTask(id).assign_tools = data.assign_tools; + gantt.getTask(id).assign_expense = data.assign_expense; gantt.getTask(id).bobot_planning = data.bobot_planning; gantt.getTask(id).rencana_biaya = data.rencana_biaya; gantt.getTask(id).biaya_actual = data.biaya_actual; @@ -339,7 +380,7 @@ function initializationColumn() { if (data.status == "not yet have") { addShowHideColumn(); } else if (data.status == "not have access") { - + gantt.config.columns = createColumnsConfig(columnShows); } else { setUpForShowHideColumn(data); } @@ -366,6 +407,36 @@ function setGanttOpen() { localStorage.setItem('ganttOpen', JSON.stringify(ganttOpen)); } +function compareData(data){ + expandTask(); + var allTasks = []; + var taskCount = gantt.getTaskCount(); + + for (var i = 0; i < taskCount; i++) { + var task = gantt.getTaskByIndex(i); + allTasks.push(task); + } + allTasks.forEach((task, index) => { + if (task.progress > 0 && task.progress < 1) { + // task.end_date = moment().format('YYYY-MM-DD HH:mm:ss'); + // task.end_date = new Date(); + } + if (task.start_date != data.data[index].start_date) { + gantt.getTask(task.id).start_date = task.start_date; + } + if (task.end_date != data.data[index].end_date) { + gantt.getTask(task.id).end_date = task.end_date; + } + if (task.planned_start != data.data[index].planned_start) { + gantt.getTask(task.id).planned_start = task.planned_start; + } + if (task.planned_end != data.data[index].planned_end) { + gantt.getTask(task.id).planned_end = task.planned_end; + } + gantt.updateTask(task.id); + }); +} + function getGanttOpen() { let ganttOpen = localStorage.getItem('ganttOpen'); if (ganttOpen) { @@ -513,7 +584,7 @@ function submitShowHideColumn(allColumn) { version_gantt_id: ganttId, columns: allColumn } - + gantt.config.columns = createColumnsConfig(allColumn); $.ajax({ data: JSON.stringify(payload), url: `${base_url}gantt-show-hide/add`, @@ -537,7 +608,12 @@ function setUpForShowHideColumn(data) { columns.map((val, index) => { configColumn[val.column_name] = val.show }); - + if (!isBaselineSet) { + // configColumn.planned_start = undefined; + // configColumn.planned_end = undefined; + // configColumn.planned_duration = undefined; + // configColumn.baseline_progress = undefined; + } gantt.config.columns = createColumnsConfig(configColumn); gantt.render(); @@ -555,10 +631,10 @@ function updateShowHideColumn(data) { processData: false, contentType: false, success: function (data) { - console.log(data); + // console.log(data); }, error: function (data) { - console.log(data); + // console.log(data); } }); } @@ -569,6 +645,8 @@ function colAjaxReq(type) { type: "GET", success: function (data) { let ganttColumnsByType = data.data; + // console.log("ini gantt field ", ganttColumnsByType); + // console.log("ini column ", gantt.config.columns); let isFound = false; x = gantt.config.columns.filter((val) => { isFound = ganttColumnsByType.find(obj => { @@ -576,6 +654,10 @@ function colAjaxReq(type) { }); if (isFound) return val; + if (isFound == false){ + // console.log("ini gantt field !isFound ", val); + } + }); gantt.config.columns = x.filter(item => item); allColumns = gantt.config.columns; @@ -633,7 +715,107 @@ function expandTask() { gantt.render(); } -function resetActivity() { - localStorage.setItem('batchEntity', ''); - gantt.alert("Actiivity Saved"); -} \ No newline at end of file +// Function to get the earliest planned start date among all tasks +function getEarliestTaskDate() { + var earliestDate = null; + gantt.eachTask(function (task) { + var taskStartDate = task.planned_start || task.start_date; + if (!earliestDate || task.planned_start < earliestDate) { + earliestDate = taskStartDate; + if (task.start_date < earliestDate) { + earliestDate = task.start_date; + } + } + }); + return earliestDate; +} + +// Function to get the latest planned end date among all tasks +function getLatestTaskDate() { + var latestDate = null; + gantt.eachTask(function (task) { + var taskEndDate = task.planned_end || task.end_date; + if (!latestDate || task.planned_end > latestDate) { + latestDate = taskEndDate; + if (task.end_date > latestDate) { + latestDate = task.end_date; + } + } + }); + return latestDate; +} + +function batchUpdate(){ + let data = localStorage.getItem('batchEntity'); + $("body").addClass("loading"); + return gantt.ajax.post({ + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${token}` + }, + url: base_url + "activity/batch-update/" + ganttId, + data: data + }).then(function (response) { + $("body").removeClass("loading"); + localStorage.setItem('batchEntity', ''); + $("#save-activity").hide(); + $("#save-separator").hide(); + sendStorage(); + refresData(); + }).catch(function (error) { + $("body").removeClass("loading") + + gantt.alert({ + title: "Peringatan", + type: "alert-error", + text: "Update activity gagal" + }); + }); +} + +$(window).on('beforeunload', function(event) { + let batchEntity = localStorage.getItem('batchEntity'); + sendStorage(); + if (batchEntity && batchEntity != '') { + event.preventDefault() + return event.returnValue = 'You have unsaved changes. Are you sure you want to leave this page?'; + } +}); + +function sendStorage(){ + const batchEntityData = localStorage.getItem('batchEntity'); + window.parent.postMessage({ batchEntity: batchEntityData }, '*'); +} + +function updateLinksLag(data) { + data.data.forEach(task => { + data.links.forEach(link => { + if (link.target == task.id && task.actual_start != null) { + let predecessor = data.data.find(item => item.id == link.source); + if (predecessor) { + let lag; + if (isBaselineSet) { + switch (link.type) { + case "0": // FS + lag = gantt.calculateDuration(new Date(predecessor.end_date), new Date(task.start_date)); + break; + case "1": // SS + lag = gantt.calculateDuration(new Date(predecessor.start_date), new Date(task.start_date)); + break; + case "2": // FF + lag = gantt.calculateDuration(new Date(predecessor.end_date), new Date(task.end_date)); + break; + case "3": // SF + lag = gantt.calculateDuration(new Date(predecessor.start_date), new Date(task.end_date)); + break; + default: + // Handle an unknown link type if needed + break; + } + link.lag = lag; + } + } + } + }); + }); +} diff --git a/edit-mode/function/ganttConfig.js b/edit-mode/function/ganttConfig.js index a22ca2d..0c07b6a 100644 --- a/edit-mode/function/ganttConfig.js +++ b/edit-mode/function/ganttConfig.js @@ -10,6 +10,8 @@ let userToVersionGanttId = 0 let activityId = 0; let actionHappen = false; let activityName = ""; +let activityEarlyStart; +let activityEarlyFinish; let token = getUrlParameter("token"); let forceDurationUpdateTriggered = false; let editEndDateDurationTriggered = false; @@ -22,7 +24,12 @@ const axiosInstance = axios.create({ "Content-type": "application/json" } }); - +const axiosInstanceMultipart = axios.create({ + headers: { + "Content-Type": "multipart/form-data", + "Authorization": `Bearer ${token}`, + } +}); axiosInstance.interceptors.request.use(async (config) => { try { $("body").addClass("loading"); @@ -172,6 +179,8 @@ const editor = { planned_start: { type: "date", map_to: "planned_start", min: new Date(2018, 0, 1) }, planned_end: { type: "end_date", map_to: "planned_end", min: new Date(2018, 0, 1) }, planned_duration: { type: "duration", map_to: "planned_duration", min: 0, max: 365, formatter: formatter }, + // early_start: { type: "date", map_to: "planned_start", min: new Date(2018, 0, 1) }, + // early_end: { type: "end_date", map_to: "planned_start", min: new Date(2018, 0, 1) }, duration: { type: "duration", map_to: "duration", min: 0, max: 365, formatter: formatter }, cost: { type: "number", map_to: "rencana_biaya", min: 0 }, costActual: { type: "number", map_to: "biaya_actual", min: 0 }, @@ -266,28 +275,48 @@ function createColumnsConfig(selectedColumns) { } var allColumns = [ + { name: "action", label: colHeader, align: "left", min_width: 115, template: colContent, resize: true }, { name: "kode_sortname", label: "Kode / Sortname", align: "center", min_width: 120, editor: editor.kode_sortname, resize: true }, { name: "text", label: "Activity", tree: true, min_width: 150, editor: editor.text, resize: true }, { name: "planned_start", label: "Baseline Start", align: "center", min_width: 80, editor: editor.planned_start, resize: true, template: function (text) { if (!text.planned_start) { - return text.start_date; + return moment(text.start_date).format("DD-MM-YYYY"); } - return text.planned_start; + return moment(text.planned_start).format("DD-MM-YYYY"); } - }, - { name: "start_date", label: "Actual Start", align: "center", min_width: 80, editor: editor.start_date, resize: true }, + }, { name: "planned_end", label: "Baseline Finish", align: "center", min_width: 80, editor: editor.planned_end, resize: true, template: function (text) { if (!text.planned_end) { - return text.end_date; + return moment(text.end_date).format("DD-MM-YYYY"); } - return text.planned_end; + return moment(text.planned_end).format("DD-MM-YYYY"); } }, - { name: "end_date", label: "Actual Finish", align: "center", min_width: 80, editor: editor.end_date, resize: true }, - + { name: "start_date", label: "Early Start", align: "center", min_width: 80, editor: editor.start_date, resize: true, template: function (text) { + return moment(text.start_date).format("DD-MM-YYYY"); + } + }, + { name: "end_date", label: "Early Finish", align: "center", min_width: 80, editor: editor.end_date, resize: true, template: function (text) { + return moment(text.end_date).format("DD-MM-YYYY"); + } + }, + { name: "actual_start", label: "Actual Start", align: "center", min_width: 80, resize: true, template: function (text) { + if (!text.actual_start) { + return ''; + } + return moment(text.actual_start).format("DD-MM-YYYY"); + } + }, + { name: "actual_end", label: "Actual Finish", align: "center", min_width: 80, resize: true, template: function (text) { + if (!text.actual_end) { + return ''; + } + return moment(text.actual_end).format("DD-MM-YYYY"); + } + }, { name: "bobot_planning", label: "Bobot (%)", align: "center", editor: editor.bobot_planning, resize: true, min_width: 115, template: function (text) { let bobot = parseFloat(text.bobot_planning); @@ -344,7 +373,7 @@ var allColumns = [ }) return plannedDuration; }}, - { name: "duration", label: "Actual Duration (Day)", align: "center", min_width: 50, resize: true, editor: editor.duration }, + { name: "duration", label: "Duration (Day)", align: "center", min_width: 50, resize: true, editor: editor.duration }, { name: "rencana_biaya", label: "Cost Planning", align: "right", min_width: 100, resize: true, template: function (text) { if (!text.rencana_biaya) { @@ -512,6 +541,8 @@ let columnShows = { planned_start: false, planned_end: false, planned_duration: false, + actual_start: false, + actual_end: false, duration: true, rencana_biaya: true, cost_actual: true, @@ -538,6 +569,8 @@ gantt.config.columns = createColumnsConfig({ planned_start: true, planned_end: true, planned_duration: true, + actual_start: true, + actual_end: true, duration: true, rencana_biaya: true, cost_actual: true, @@ -630,7 +663,7 @@ gantt.templates.rightside_text = function (start, end, task) { end_date: end, task: task }, 'day'); - var text = "Overdue: " + overdue + " days"; + var text = "Overdue: " + overdue + " days"; return text; } } diff --git a/edit-mode/function/ganttEvent.js b/edit-mode/function/ganttEvent.js index b58d96a..47c6247 100644 --- a/edit-mode/function/ganttEvent.js +++ b/edit-mode/function/ganttEvent.js @@ -10,12 +10,15 @@ gantt.attachEvent("onAfterTaskAdd", function (id, item) { gantt.updateTask(parentId); } } + updateRange(); }); gantt.attachEvent("onTaskRowClick", function (id, row) { activityId = id; var activity = gantt.getTaskBy("id", id); activityName = activity[0]?.name; + activityEarlyStart = new Date(activity[0]?.start_date); + activityEarlyFinish = new Date(activity[0]?.end_date); }); gantt.ext.inlineEditors.attachEvent("onBeforeEditStart", function (state) { @@ -40,7 +43,16 @@ gantt.ext.inlineEditors.attachEvent("onBeforeEditStart", function (state) { } return true }); - +function updateRange(){ + var range = gantt.getSubtaskDates(); + var chart = gantt.getState(); + if(range.start_date.valueOf() <= chart.min_date.valueOf() || range.end_date.valueOf() >= chart.max_date.valueOf()){ + gantt.config.start_date = gantt.date.add(range.start_date, -1, "day"); + gantt.config.end_date = gantt.date.add(range.end_date, 2, "day"); + gantt.render(); + } +} +gantt.attachEvent("onAfterTaskUpdate", updateRange); gantt.attachEvent("onBeforeTaskUpdate", function (id, new_item) { // format progress let progress = new_item.progress; @@ -168,11 +180,11 @@ gantt.attachEvent("onGanttScroll", function (left, top){ var max_allowed_date = gantt.date.add(gantt.config.end_date, -1, "day"); var repaint = false; - if (+left_date <= +min_allowed_date){ + if (earliest && +left_date <= +min_allowed_date && +left_date >= +earliest){ gantt.config.start_date = gantt.date.add(gantt.config.start_date, -1, "day"); repaint = true; } - if (+right_date >= +max_allowed_date){ + if (latest && +right_date >= +max_allowed_date && +right_date <= +latest){ gantt.config.end_date = gantt.date.add(gantt.config.end_date, 1, "day"); repaint = true; } @@ -183,4 +195,4 @@ gantt.attachEvent("onGanttScroll", function (left, top){ },20) } } -}); \ No newline at end of file +}); diff --git a/edit-mode/function/ganttSettings.js b/edit-mode/function/ganttSettings.js index 061bbc4..86cc8e9 100644 --- a/edit-mode/function/ganttSettings.js +++ b/edit-mode/function/ganttSettings.js @@ -136,13 +136,21 @@ $(document).ready(function () { }); $("#save-activity").on('click', function (event) { - resetActivity(); + batchUpdate(); }); $("#gantt-synchronize").on('click', function (event) { setSynchronize(); }); + $("#compare-data").on('click', function (event) { + compareData(ganttTask); + }); + + $("#update-schedule").on('click', function (event) { + updateSchedule(); + }); + initHolidays(); initGanttSettings(); }); @@ -350,7 +358,7 @@ function setBaseline() { }); } -async function setBaselineAPI() { +async function importUpdate() { expandTask(); var allTasks = []; var taskCount = gantt.getTaskCount(); @@ -381,6 +389,10 @@ async function setBaselineAPI() { text: "Update import gagal" }); }); +} + +async function setBaselineAPI() { + await importUpdate(); const res = await axiosInstance .get(ACTIVITY_SET_BASELINE_URL, HEADER) .then(res => res) @@ -435,6 +447,27 @@ function setSynchronize() { }); } +function updateSchedule() { + $("body").addClass("loading"); + return gantt.ajax.get({ + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${token}` + }, + url: base_url + "activity/update-schedule/" + ganttId + }).then(function (response) { + $("body").removeClass("loading"); + window.location.reload(); + }).catch(function (error) { + $("body").removeClass("loading") + gantt.alert({ + title: "Peringatan", + type: "alert-error", + text: "Update activity gagal" + }); + }); +} + async function setSynchronizeAPI() { const res = await axiosInstance .get(ACTIVITY_SYNCHRONIZE_REPORT_URL, HEADER) diff --git a/edit-mode/function/humanResource.js b/edit-mode/function/humanResource.js index 9a8708a..d297fb7 100644 --- a/edit-mode/function/humanResource.js +++ b/edit-mode/function/humanResource.js @@ -7,6 +7,8 @@ function resetFormAssign() { $('#select-hr').val(null).trigger("change"); $('#select-hr').find('option').remove(); $('#select-hr').val(""); + $("#hr-start-date").val(""); + $("#hr-end-date").val(""); $("#hr_role").val(""); // $("#hide-form-hr").hide(); // $("#show-form-hr").show(); @@ -29,6 +31,8 @@ $(document).ready(function () { "columns": [ { data: 'user_name', name: 'user_name' }, { data: 'role_name', name: 'role_name' }, + { data: 'start_date', name: 'start_date' }, + { data: 'end_date', name: 'end_date' }, { data: 'action', name: 'action', @@ -149,6 +153,21 @@ $(document).ready(function () { }); + $("#hr-start-date").on('change', (e) => { + let start_date = new Date($("#hr-start-date").val()); + if (start_date < activityEarlyStart || start_date > activityEarlyFinish) { + gantt.alert("Start date should be inside activity date range !"); + $("#hr-start-date").val(""); + } + }) + + $("#hr-end-date").on('change', (e) => { + let end_date = new Date($("#hr-end-date").val()); + if (end_date < activityEarlyStart || end_date > activityEarlyFinish) { + gantt.alert("End date should be inside activity date range !"); + $("#hr-end-date").val(""); + } + }) $("#form-assign-hr").on('submit', function (e) { e.preventDefault(); @@ -158,6 +177,8 @@ $(document).ready(function () { // var formData = new FormData(this); let users = $("#select-hr").val(); + let start_date = $("#hr-start-date").val(); + let end_date = $("#hr-end-date").val(); let user_id = []; let user_role = []; users.map((item)=>{ @@ -175,6 +196,8 @@ $(document).ready(function () { let payload = { user_id: user_id, + start_date: start_date, + end_date: end_date, role_proyek_id: user_role, version_gantt_id: ganttId, proyek_id: proyekId, diff --git a/edit-mode/function/materialResource.js b/edit-mode/function/materialResource.js index 1a01df7..c865919 100644 --- a/edit-mode/function/materialResource.js +++ b/edit-mode/function/materialResource.js @@ -4,6 +4,8 @@ function resetFormAssignMaterial() { $('#select-material').val(null).trigger("change"); $('#select-material').find('option').remove(); $('#select-material').val(""); + $('#uom-req-material').val(null).trigger('change'); + $('#select-material-integration').val(null).trigger('change'); $('#form-assign-material').trigger("reset"); $('#btn-assign-material').html('Assign'); $('#btn-assign-material').prop("disabled", false); @@ -59,6 +61,7 @@ $(document).ready(function () { }); function deleteMaterialAssign(id) { + searchReport(id); $.ajax({ url: `${base_url}assign-material/delete/${id}`, type: "DELETE", @@ -164,13 +167,24 @@ $(document).ready(function () { results: dataIntegrasiMaterial }; }, error: function (jqXHR, textStatus, errorThrown) { - gantt.alert(`Status: ${textStatus}`); - gantt.alert(`Error thrown: ${errorThrown}`); - gantt.alert(`Error accessing URL: ${adwIntegrationUrl}/request-material/get-material-integration`); + // console.log("textStatus ", textStatus); + if (textStatus != "abort") { + // gantt.alert(`Status: ${textStatus}`); + gantt.alert(`Data Not Found`); + // gantt.alert(`Error accessing URL: ${adwIntegrationUrl}/request-material/get-material-integration`); + } } } }); - + // $('#required-date-req-material').datepicker({ + // format: 'dd-mm-yyyy', // Set the desired format + // autoclose: true // Close the datepicker when a date is selected + // }); + // + // $('#required-date-plan-material').datepicker({ + // format: 'dd-mm-yyyy', // Set the desired format + // autoclose: true // Close the datepicker when a date is selected + // }); $("#form-assign-material").on('submit', function (e) { e.preventDefault(); diff --git a/edit-mode/function/milestone.js b/edit-mode/function/milestone.js index 1d67187..bfd7158 100644 --- a/edit-mode/function/milestone.js +++ b/edit-mode/function/milestone.js @@ -70,7 +70,16 @@ $(document).ready(function () { $("#name_milestone").val(data.text); }); + $('#due_milestone').datepicker({ + format: 'dd-mm-yyyy', // Set the desired format + autoclose: true // Close the datepicker when a date is selected + }); + $('#deadline_milestone').datepicker({ + format: 'dd-mm-yyyy', // Set the desired format + autoclose: true // Close the datepicker when a date is selected + }); + $('#modal-material').on('show.bs.modal', function (event) { }); @@ -88,8 +97,8 @@ $(document).ready(function () { console.log("cek data form", data); let parent = data.milestone_parent; var taskId = 0; - var start = moment(data.due_date, "YYYY-MM-DD"); - var end = moment(data.deadline, "YYYY-MM-DD"); + var start = moment(data.due_date, "DD-MM-YYYY"); + var end = moment(data.deadline, "DD-MM-YYYY"); let duration = moment.duration(start.diff(end)).asDays(); let nameMilestone = data.status!="" ? data.status : data.id_milestone // console.log("cek duration", Math.abs(duration)); @@ -97,8 +106,8 @@ $(document).ready(function () { taskId = gantt.addTask({ id: Math.floor(Math.random() * 1000) + 5000, text: nameMilestone, - start_date: data.due_date, - end_date: data.deadline, + start_date: start.format("YYYY-MM-DD"), + end_date: end.format("YYYY-MM-DD"), duration: Math.abs(duration), type: "milestone", type_activity:"milestone" @@ -107,8 +116,8 @@ $(document).ready(function () { taskId = gantt.addTask({ id: Math.floor(Math.random() * 1000) + 5000, text: nameMilestone, - start_date: data.due_date, - end_date: data.deadline, + start_date: start.format("YYYY-MM-DD"), + end_date: end.format("YYYY-MM-DD"), duration: Math.abs(duration), type: "milestone", type_activity:"milestone" @@ -124,4 +133,4 @@ $(document).ready(function () { gantt.alert("Add Milestone Failed!"); } }); -}); \ No newline at end of file +}); diff --git a/edit-mode/function/reportActivity.js b/edit-mode/function/reportActivity.js index 7c6d232..e9d58aa 100644 --- a/edit-mode/function/reportActivity.js +++ b/edit-mode/function/reportActivity.js @@ -62,7 +62,15 @@ $(document).ready(function () { $('#ra_date_end_activity').prop('disabled', true); } }); - + // $('#ra_date_start_activity').datepicker({ + // format: 'dd-mm-yyyy', // Set the desired format + // autoclose: true // Close the datepicker when a date is selected + // }); + // + // $('#ra_date_end_activity').datepicker({ + // format: 'dd-mm-yyyy', // Set the desired format + // autoclose: true // Close the datepicker when a date is selected + // }); $("#ra_date_end_activity").on("change", function () { let valEnd = $(this).val() let valStart = $('#ra_date_start_activity').val() @@ -166,6 +174,9 @@ $(document).ready(function () { d.idAct = activityId; d.materialName = materialName; d.type = 'actual'; + }, + "error": function (xhr, error, code) { + console.log(xhr, error, code); } }, "columns": [ @@ -180,6 +191,11 @@ $(document).ready(function () { return data ? formatRupiah(data) : '-' } }, + { + data: 'qty_planning', render: function (data, type) { + return data ? formatRupiah(data) : '-' + } + }, { data: 'description', name: 'description' }, { data: 'action', @@ -190,33 +206,32 @@ $(document).ready(function () { ], "order": [[1, 'asc']], }); - - var tableRaMaterialPlan = $("#table_activity_material_plan").DataTable({ - "processing": true, - "serverSide": true, - "ajax": { - "url": `${base_url}report-activity-material/datatables`, - "data": function (d) { - d.idAmi = assignMaterialId; - d.idAct = activityId; - d.type = 'plan'; - } - }, - "columns": [ - { data: 'material_name', name: 'material_name' }, - { - data: 'qty_planning', render: function (data, type) { - return data ? formatRupiah(parseInt(data)) : '-' - } - }, - { data: 'uom', name: 'uom' }, - { - data: 'plan_date', render: function (data, type) { - return data ? formatDate(data) : '-' - } - }, - ] - }); + // var tableRaMaterialPlan = $("#table_activity_material_plan").DataTable({ + // "processing": true, + // "serverSide": true, + // "ajax": { + // "url": `${base_url}report-activity-material/datatables`, + // "data": function (d) { + // d.idAmi = assignMaterialId; + // d.idAct = activityId; + // d.type = 'plan'; + // } + // }, + // "columns": [ + // { data: 'material_name', name: 'material_name' }, + // { + // data: 'qty_planning', render: function (data, type) { + // return data ? formatRupiah(parseInt(data)) : '-' + // } + // }, + // { data: 'uom', name: 'uom' }, + // { + // data: 'plan_date', render: function (data, type) { + // return data ? formatDate(data) : '-' + // } + // }, + // ] + // }); $('#select_ra_hr').select2({ @@ -341,10 +356,15 @@ $(document).ready(function () { }); - + $('#ra_date_material').datepicker({ + format: 'dd-mm-yyyy', // Set the desired format + autoclose: true // Close the datepicker when a date is selected + }); $("#form_report_activity_material").on("submit", function (e) { e.preventDefault(); var formData = new FormData(this); + let formattedDate = moment(formData.get("report_date"), "DD-MM-YYYY").format("YYYY-MM-DD"); + formData.set('report_date', formattedDate); formData.append("activity_id", activityId); formData.append("assign_material_id", assignMaterialId); let idRa = $("#id_ra_material").val(); @@ -362,6 +382,13 @@ $(document).ready(function () { }); async function submitStatus(formData) { + let activityId = formData.get("activity_id"); + let statusActivity = formData.get("status_activity"); + let task = gantt.getTask(activityId); + if (statusActivity != "done") { + task.actual_start = null; + task.actual_end = null; + } const result = await axiosInstance .post(`${base_url}report-activity-material/update-status`, formData) .then(res => res) @@ -417,24 +444,55 @@ $(document).ready(function () { } } - async function submitRaMaterial(formData, id) { - let qty_actual = $("#volume_pekerjaan_material").val(); - formData.set('qty', qty_actual); - const result = await axiosInstance - .post(`${base_url}report-activity-material/add`, formData) - .then(res => res) - .catch((error) => error.response); - - // console.log("cek result", result); + async function submitRaMaterial(formData, force) { + try { + if (force) { + formData.append("force", force); + } + const qty_actual = $("#volume_pekerjaan_material").val(); + formData.set('qty', qty_actual); + const result = await axiosInstance + .post(`${base_url}report-activity-material/add`, formData); + + const reportId = result.data.data.report_id; + try { + const image = formData.get("files"); + const imageFormData = new FormData(); + imageFormData.append("ref_id", reportId); + imageFormData.append("category", "report_activity"); + imageFormData.append("files", image, image.name); + + if (image.name && image.size) { + const resultImage = await axiosInstanceMultipart.post(`${base_url}image/upload`, imageFormData); + } - if (result && result.status == 200) { - gantt.alert("Add report activity material Success!"); - resetFormAddRaMaterial(); - tableRaMaterialActual.draw(); - } else { - resetFormAddRaMaterial(); + if (result.status === 200) { + gantt.alert("Add report activity material Success!"); + resetFormAddRaMaterial(); + tableRaMaterialActual.draw(); + } else { + throw new Error("Add report activity material failed."); + } + } catch (error) { + throw new Error("Image upload failed."); + } + } catch (error) { $("body").removeClass("loading"); - gantt.alert("Add report activity material failed, try again later!"); + if (error.response.status == 400) { + gantt.confirm({ + text: error.response.data.message, + ok: "Add", + cancel: "Cancel", + callback: function (result) { + if (result) { + submitRaMaterial(formData, true); + } + } + }); + } else { + resetFormAddRaMaterial(); + gantt.alert("Add report activity material failed."); + } } } @@ -503,7 +561,7 @@ $(document).ready(function () { // kalo gambarnya banyak belum di handle... }, error: function (data) { - gantt.alert({ type: "error", text: "Failed to get report image" }); + gantt.alert({ type: "error", text: "Image not found !" }); } }); }); @@ -596,6 +654,7 @@ $(document).ready(function () { } function deleteRaMaterial(id) { + searchReport(assignMaterialId, false); $.ajax({ url: `${base_url}report-activity-material/delete/${id}`, type: "DELETE", diff --git a/edit-mode/function/restActivityLink.js b/edit-mode/function/restActivityLink.js index bf23dc5..011b6b6 100644 --- a/edit-mode/function/restActivityLink.js +++ b/edit-mode/function/restActivityLink.js @@ -1,4 +1,7 @@ let geom = []; +let latest; +let earliest; +let ganttTask; $("body").addClass("loading"); gantt.ajax.get({ url: `${base_url}activity/${ganttId}/${proyekId}/get`, @@ -8,6 +11,14 @@ gantt.ajax.get({ } }).then(function (xhr) { $("body").removeClass("loading"); + let batchEntity = localStorage.getItem('batchEntity'); + if (!batchEntity || batchEntity == '') { + $("#save-activity").hide(); + $("#save-separator").hide(); + } else { + $("#save-activity").show(); + $("#save-separator").show(); + } let data = {}; let response = xhr.responseText; let obj = JSON.parse(response); @@ -30,9 +41,13 @@ gantt.ajax.get({ }) }); gantt.silent(function () { + // updateLinksLag(data); + ganttTask = data; gantt.parse(data); getGanttOpen(); gantt.parse(data); + earliest = getEarliestTaskDate(); + latest = getLatestTaskDate(); }); }).catch(function (error) { $("body").removeClass("loading"); @@ -60,6 +75,14 @@ function refresData(id) { } }).then(function (xhr) { $("body").removeClass("loading"); + let batchEntity = localStorage.getItem('batchEntity'); + if (!batchEntity || batchEntity == '') { + $("#save-activity").hide(); + $("#save-separator").hide(); + } else { + $("#save-activity").show(); + $("#save-separator").show(); + } gantt.clearAll(); let data = {}; let response = xhr.responseText; @@ -74,9 +97,13 @@ function refresData(id) { }) }); gantt.silent(function () { + // updateLinksLag(data); + ganttTask = data; gantt.parse(data); getGanttOpen(); gantt.parse(data); + earliest = getEarliestTaskDate(); + latest = getLatestTaskDate(); }); if (id) { if (gantt.isTaskExists(id)) { @@ -154,6 +181,11 @@ var dp = gantt.createDataProcessor(function (entity, action, data, id) { // data['start_date'] = startDate.format("YYYY-MM-DD")+" 00:00:00+07"; let endDate = moment(data.end_date, "YYYY-MM-DD"); + let configStart = moment(gantt.config.start_date); + let configEnd = moment(gantt.config.end_date); + if (startDate >= configEnd || startDate <= configStart || endDate >= configEnd || endDate <= configStart) { + // location.reload(); + } if (startDate > endDate) { gantt.alert({ title: "Peringatan", @@ -176,56 +208,59 @@ var dp = gantt.createDataProcessor(function (entity, action, data, id) { }); } data['geom'] = geom.find(obj => obj.activity_id == id)?.geom; - // let existingEntity = localStorage.getItem('batchEntity'); - // if (existingEntity) { - // existingEntity = JSON.parse(existingEntity); - // // Now batchEntity is an object containing your data, and you can access its properties like batchEntity.entity and batchEntity.data - // } - // let batchEntity = { - // entity: entity, - // data: data - // }; - // let toBeSet = [] - // if (existingEntity) { - // toBeSet = [...existingEntity, batchEntity] - // } else { - // toBeSet = [batchEntity] - // } - // localStorage.setItem('batchEntity', JSON.stringify(toBeSet)); - $("body").addClass("loading"); - return gantt.ajax.put({ - headers: { - "Content-Type": "application/json", - "Authorization": `Bearer ${token}` - }, - url: base_url + entity + "/" + id, - data: JSON.stringify(data) - }).then(function (response) { - $("body").removeClass("loading"); - if (entity == "task") { - let parent = data.parent; - let responseText = JSON.parse(response.responseText) - let resData = responseText - let updateBobot = resData.update_bobot || false - if (updateBobot) { - if (parent && parent > 0) { - updateActivity(parent); - } - } else if (parent && parent > 0) { - updateActivity(parent); - } - if (!parent) { - refresData(); - } - } - }).catch(function (error) { - $("body").removeClass("loading"); - gantt.alert({ - title: "Peringatan", - type: "alert-error", - text: "Update activity gagal" - }); - }); + let existingEntity = localStorage.getItem('batchEntity'); + if (existingEntity) { + existingEntity = JSON.parse(existingEntity); + // Now batchEntity is an object containing your data, and you can access its properties like batchEntity.entity and batchEntity.data + } + let batchEntity = { + entity: entity, + data: data + }; + let toBeSet = [] + if (existingEntity) { + toBeSet = [...existingEntity, batchEntity] + } else { + toBeSet = [batchEntity] + } + localStorage.setItem('batchEntity', JSON.stringify(toBeSet)); + $("#save-activity").show(); + $("#save-separator").show(); + sendStorage(); + // $("body").addClass("loading"); + // return gantt.ajax.put({ + // headers: { + // "Content-Type": "application/json", + // "Authorization": `Bearer ${token}` + // }, + // url: base_url + entity + "/" + id, + // data: JSON.stringify(data) + // }).then(function (response) { + // $("body").removeClass("loading"); + // if (entity == "task") { + // let parent = data.parent; + // let responseText = JSON.parse(response.responseText) + // let resData = responseText + // let updateBobot = resData.update_bobot || false + // if (updateBobot) { + // if (parent && parent > 0) { + // updateActivity(parent); + // } + // } else if (parent && parent > 0) { + // updateActivity(parent); + // } + // if (!parent) { + // refresData(); + // } + // } + // }).catch(function (error) { + // $("body").removeClass("loading"); + // gantt.alert({ + // title: "Peringatan", + // type: "alert-error", + // text: "Update activity gagal" + // }); + // }); break; case "delete": diff --git a/edit-mode/index.html b/edit-mode/index.html index a05549f..8f2aced 100644 --- a/edit-mode/index.html +++ b/edit-mode/index.html @@ -87,18 +87,24 @@ | - + | | + + | | | + + | | @@ -132,11 +138,19 @@