Compare commits
No commits in common. "a15ab08576c1a6a792df4451ebbf09d8e598a89f" and "cb38bfb75a9ed29c144779e80f9418cf14b81039" have entirely different histories.
a15ab08576
...
cb38bfb75a
@ -1,131 +0,0 @@
|
|||||||
<?php
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
include('include/headscript.php');
|
|
||||||
|
|
||||||
$dbHandler = DBHandlerSelect::getInstance();
|
|
||||||
$pdo = $dbHandler->getConnection();
|
|
||||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
||||||
|
|
||||||
$data = json_decode(file_get_contents('php://input'), true);
|
|
||||||
|
|
||||||
$sourceIddatadb = isset($data['source_iddatadb']) ? (int)$data['source_iddatadb'] : 0;
|
|
||||||
$targetList = $data['target_iddatadb_list'] ?? [];
|
|
||||||
|
|
||||||
$targetIds = array_values(array_unique(array_filter(array_map('intval', (array)$targetList), function ($v) use ($sourceIddatadb) {
|
|
||||||
return $v > 0 && $v !== $sourceIddatadb;
|
|
||||||
})));
|
|
||||||
|
|
||||||
if ($sourceIddatadb <= 0 || empty($targetIds)) {
|
|
||||||
echo json_encode([
|
|
||||||
'success' => false,
|
|
||||||
'message' => 'Missing source or target records'
|
|
||||||
]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$pdo->beginTransaction();
|
|
||||||
|
|
||||||
// 1. Load source parts
|
|
||||||
$stmtParts = $pdo->prepare("
|
|
||||||
SELECT id, part_number, part_description, mix, idmatrice, note, dateexpiry
|
|
||||||
FROM identification_parts
|
|
||||||
WHERE iddatadb = ?
|
|
||||||
ORDER BY part_number ASC, id ASC
|
|
||||||
");
|
|
||||||
$stmtParts->execute([$sourceIddatadb]);
|
|
||||||
$sourceParts = $stmtParts->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
if (empty($sourceParts)) {
|
|
||||||
$pdo->rollBack();
|
|
||||||
echo json_encode([
|
|
||||||
'success' => false,
|
|
||||||
'message' => 'No parts found for source record'
|
|
||||||
]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Prepare statements
|
|
||||||
$stmtInsertPart = $pdo->prepare("
|
|
||||||
INSERT INTO identification_parts
|
|
||||||
(iddatadb, part_number, part_description, mix, idmatrice, note, dateexpiry, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
(:iddatadb, :part_number, :part_description, :mix, :idmatrice, :note, :dateexpiry, NOW(), NOW())
|
|
||||||
");
|
|
||||||
|
|
||||||
$stmtLoadCF = $pdo->prepare("
|
|
||||||
SELECT field_id, value_id, value_text
|
|
||||||
FROM identification_parts_customfields
|
|
||||||
WHERE part_id = ?
|
|
||||||
ORDER BY id ASC
|
|
||||||
");
|
|
||||||
|
|
||||||
$stmtInsertCF = $pdo->prepare("
|
|
||||||
INSERT INTO identification_parts_customfields
|
|
||||||
(part_id, field_id, value_id, value_text, created_at, updated_at)
|
|
||||||
VALUES
|
|
||||||
(:part_id, :field_id, :value_id, :value_text, NOW(), NOW())
|
|
||||||
");
|
|
||||||
|
|
||||||
$details = [];
|
|
||||||
$totalClonedParts = 0;
|
|
||||||
|
|
||||||
// 3. Clone source parts to each target record
|
|
||||||
foreach ($targetIds as $targetIddatadb) {
|
|
||||||
$clonedCountForTarget = 0;
|
|
||||||
|
|
||||||
foreach ($sourceParts as $part) {
|
|
||||||
$stmtInsertPart->execute([
|
|
||||||
':iddatadb' => $targetIddatadb,
|
|
||||||
':part_number' => $part['part_number'],
|
|
||||||
':part_description' => $part['part_description'],
|
|
||||||
':mix' => $part['mix'] ?? 'N',
|
|
||||||
':idmatrice' => $part['idmatrice'] !== '' ? $part['idmatrice'] : null,
|
|
||||||
':note' => $part['note'] ?? null,
|
|
||||||
':dateexpiry' => $part['dateexpiry'] ?? null,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$newPartId = (int)$pdo->lastInsertId();
|
|
||||||
|
|
||||||
// Load source custom fields for this part
|
|
||||||
$stmtLoadCF->execute([(int)$part['id']]);
|
|
||||||
$customFields = $stmtLoadCF->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
foreach ($customFields as $cf) {
|
|
||||||
$stmtInsertCF->execute([
|
|
||||||
':part_id' => $newPartId,
|
|
||||||
':field_id' => (int)$cf['field_id'],
|
|
||||||
':value_id' => ($cf['value_id'] !== null && $cf['value_id'] !== '') ? (int)$cf['value_id'] : null,
|
|
||||||
':value_text' => $cf['value_text'] !== '' ? $cf['value_text'] : null,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$clonedCountForTarget++;
|
|
||||||
$totalClonedParts++;
|
|
||||||
}
|
|
||||||
|
|
||||||
$details[] = [
|
|
||||||
'target_iddatadb' => $targetIddatadb,
|
|
||||||
'cloned_parts' => $clonedCountForTarget
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$pdo->commit();
|
|
||||||
|
|
||||||
echo json_encode([
|
|
||||||
'success' => true,
|
|
||||||
'source_iddatadb' => $sourceIddatadb,
|
|
||||||
'cloned_targets' => count($targetIds),
|
|
||||||
'total_cloned_parts' => $totalClonedParts,
|
|
||||||
'details' => $details
|
|
||||||
]);
|
|
||||||
} catch (Throwable $e) {
|
|
||||||
if ($pdo->inTransaction()) {
|
|
||||||
$pdo->rollBack();
|
|
||||||
}
|
|
||||||
|
|
||||||
echo json_encode([
|
|
||||||
'success' => false,
|
|
||||||
'message' => 'Clone failed: ' . $e->getMessage()
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
@ -26,9 +26,7 @@
|
|||||||
<button type="button" class="btn btn-info btn-sm" id="renumberPartsBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">
|
<button type="button" class="btn btn-info btn-sm" id="renumberPartsBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">
|
||||||
Rinumera Parti
|
Rinumera Parti
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-primary btn-sm" id="clonePartsBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">
|
|
||||||
<i class="fas fa-clone"></i> Clona Parti
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-secondary btn-sm ms-2" id="toggleVoiceBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">
|
<button type="button" class="btn btn-secondary btn-sm ms-2" id="toggleVoiceBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem;">
|
||||||
<i class="fas fa-microphone"></i> Voce
|
<i class="fas fa-microphone"></i> Voce
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -2,111 +2,93 @@
|
|||||||
* modals_gridData.js — Photos, Parts, Tested Component handlers for gridData pages
|
* modals_gridData.js — Photos, Parts, Tested Component handlers for gridData pages
|
||||||
*/
|
*/
|
||||||
(function () {
|
(function () {
|
||||||
"use strict";
|
'use strict';
|
||||||
|
|
||||||
// ── Photos — use photos.js loadPopupContent (exported to window) ──
|
// ── Photos — use photos.js loadPopupContent (exported to window) ──
|
||||||
$(document).on("click", ".photos-btn", function () {
|
$(document).on('click', '.photos-btn', function () {
|
||||||
const iddatadb = $(this).data("iddatadb") || null;
|
const iddatadb = $(this).data('iddatadb') || null;
|
||||||
const idquotations = $(this).data("idquotations") || null;
|
const idquotations = $(this).data('idquotations') || null;
|
||||||
const modal = document.getElementById("photosModal");
|
const modal = document.getElementById('photosModal');
|
||||||
if (!modal) return;
|
if (!modal) return;
|
||||||
|
|
||||||
modal.style.display = "block";
|
modal.style.display = 'block';
|
||||||
|
|
||||||
if (typeof window.loadPopupContent === "function") {
|
if (typeof window.loadPopupContent === 'function') {
|
||||||
window.loadPopupContent(iddatadb, idquotations);
|
window.loadPopupContent(iddatadb, idquotations);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Close photos modal
|
// Close photos modal
|
||||||
$(document).on("click", ".close-btn", function () {
|
$(document).on('click', '.close-btn', function () {
|
||||||
const modal = document.getElementById("photosModal");
|
const modal = document.getElementById('photosModal');
|
||||||
if (modal) modal.style.display = "none";
|
if (modal) modal.style.display = 'none';
|
||||||
});
|
});
|
||||||
|
|
||||||
// Close on backdrop click
|
// Close on backdrop click
|
||||||
$(document).on("click", "#photosModal", function (e) {
|
$(document).on('click', '#photosModal', function (e) {
|
||||||
if (e.target === this) {
|
if (e.target === this) {
|
||||||
this.style.display = "none";
|
this.style.display = 'none';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Parts (matching import_edit2.php behavior) ─────────────────────
|
// ── Parts (matching import_edit2.php behavior) ─────────────────────
|
||||||
$(document).on("click", ".parts-btn", function () {
|
$(document).on('click', '.parts-btn', function () {
|
||||||
const iddatadb = $(this).data("iddatadb") || null;
|
const iddatadb = $(this).data('iddatadb') || null;
|
||||||
const idquotations = $(this).data("idquotations") || null;
|
const idquotations = $(this).data('idquotations') || null;
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "modal_partsTable.php",
|
url: 'modal_partsTable.php',
|
||||||
method: "GET",
|
method: 'GET',
|
||||||
data: { iddatadb: iddatadb },
|
data: { iddatadb: iddatadb },
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
$("#partsModalContainer").html(response);
|
$('#partsModalContainer').html(response);
|
||||||
const modalElement = document.getElementById("partsModal");
|
const modalElement = document.getElementById('partsModal');
|
||||||
if (!modalElement) return;
|
if (!modalElement) return;
|
||||||
|
|
||||||
$("#trfHeader").text(iddatadb || idquotations || "");
|
$("#trfHeader").text(iddatadb || idquotations || '');
|
||||||
|
$("#partsModal").data("iddatadb", iddatadb).data("idquotations", idquotations);
|
||||||
const visibleIddatadbList = Array.isArray(window.gridData)
|
|
||||||
? window.gridData
|
|
||||||
.map((r) => parseInt(r.iddatadb, 10))
|
|
||||||
.filter((v) => !isNaN(v) && v > 0)
|
|
||||||
: [];
|
|
||||||
|
|
||||||
$("#partsModal")
|
|
||||||
.data("iddatadb", iddatadb)
|
|
||||||
.data("idquotations", idquotations)
|
|
||||||
.data("visible-iddatadb-list", visibleIddatadbList);
|
|
||||||
|
|
||||||
let modal = bootstrap.Modal.getInstance(modalElement);
|
let modal = bootstrap.Modal.getInstance(modalElement);
|
||||||
if (!modal)
|
if (!modal) modal = new bootstrap.Modal(modalElement, { backdrop: true, keyboard: true, focus: true });
|
||||||
modal = new bootstrap.Modal(modalElement, {
|
|
||||||
backdrop: true,
|
|
||||||
keyboard: true,
|
|
||||||
focus: true,
|
|
||||||
});
|
|
||||||
modal.show();
|
modal.show();
|
||||||
|
|
||||||
if (typeof window.loadParts === "function") {
|
if (typeof window.loadParts === 'function') {
|
||||||
window.loadParts(iddatadb, idquotations);
|
window.loadParts(iddatadb, idquotations);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function (xhr, status, error) {
|
error: function (xhr, status, error) {
|
||||||
console.error("Error loading parts:", error);
|
console.error('Error loading parts:', error);
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on("hidden.bs.modal", "#partsModal", function () {
|
$(document).on('hidden.bs.modal', '#partsModal', function () {
|
||||||
const modalElement = document.getElementById("partsModal");
|
const modalElement = document.getElementById('partsModal');
|
||||||
if (modalElement) {
|
if (modalElement) {
|
||||||
const modal = bootstrap.Modal.getInstance(modalElement);
|
const modal = bootstrap.Modal.getInstance(modalElement);
|
||||||
if (modal) modal.dispose();
|
if (modal) modal.dispose();
|
||||||
}
|
}
|
||||||
$("#partsModalContainer").empty();
|
$('#partsModalContainer').empty();
|
||||||
$(".modal-backdrop").remove();
|
$('.modal-backdrop').remove();
|
||||||
$("body").removeClass("modal-open").css("padding-right", "");
|
$('body').removeClass('modal-open').css('padding-right', '');
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Tested Component quick add ───────────────────────────────────────
|
// ── Tested Component quick add ───────────────────────────────────────
|
||||||
$(document).on("click", ".add-part-btn", async function () {
|
$(document).on('click', '.add-part-btn', async function () {
|
||||||
const iddatadb = $(this).data("iddatadb") || null;
|
const iddatadb = $(this).data('iddatadb') || null;
|
||||||
const rowIndex = parseInt($(this).data("row"));
|
const rowIndex = parseInt($(this).data('row'));
|
||||||
const row = window.gridData?.[rowIndex];
|
const row = window.gridData?.[rowIndex];
|
||||||
const id = iddatadb || (row ? row.iddatadb : null);
|
const id = iddatadb || (row ? row.iddatadb : null);
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
|
|
||||||
const $cell = $(this).closest(".grid-cell, div");
|
const $cell = $(this).closest('.grid-cell, div');
|
||||||
const $input = $cell.find("input");
|
const $input = $cell.find('input');
|
||||||
const raw = ($input.val() || "").trim();
|
const raw = ($input.val() || '').trim();
|
||||||
const parts = raw
|
const parts = raw.split('|').map(s => s.trim()).filter(s => s.length > 0);
|
||||||
.split("|")
|
|
||||||
.map((s) => s.trim())
|
|
||||||
.filter((s) => s.length > 0);
|
|
||||||
const uniqueParts = [...new Set(parts)];
|
const uniqueParts = [...new Set(parts)];
|
||||||
|
|
||||||
if (!uniqueParts.length) {
|
if (!uniqueParts.length) {
|
||||||
alert("Insert a description first.");
|
alert('Insert a description first.');
|
||||||
$input.focus();
|
$input.focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -114,17 +96,14 @@
|
|||||||
try {
|
try {
|
||||||
for (const p of uniqueParts) {
|
for (const p of uniqueParts) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("iddatadb", id);
|
formData.append('iddatadb', id);
|
||||||
formData.append("part_description", p);
|
formData.append('part_description', p);
|
||||||
await fetch("add_part_quick.php", {
|
await fetch('add_part_quick.php', { method: 'POST', body: formData });
|
||||||
method: "POST",
|
|
||||||
body: formData,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
alert(`Added ${uniqueParts.length} part(s).`);
|
alert(`Added ${uniqueParts.length} part(s).`);
|
||||||
$input.val("");
|
$input.val('');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
alert("Error: " + e.message);
|
alert('Error: ' + e.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -132,47 +111,44 @@
|
|||||||
let deleteIddatadb = null;
|
let deleteIddatadb = null;
|
||||||
let deleteRowIndex = null;
|
let deleteRowIndex = null;
|
||||||
|
|
||||||
$(document).on("click", ".delete-btn", function () {
|
$(document).on('click', '.delete-btn', function () {
|
||||||
deleteIddatadb = $(this).data("iddatadb");
|
deleteIddatadb = $(this).data('iddatadb');
|
||||||
deleteRowIndex = parseInt($(this).data("row"));
|
deleteRowIndex = parseInt($(this).data('row'));
|
||||||
const modalEl = document.getElementById("deleteConfirmModal");
|
const modalEl = document.getElementById('deleteConfirmModal');
|
||||||
if (modalEl) {
|
if (modalEl) {
|
||||||
document.getElementById("deleteIddatadbText").textContent =
|
document.getElementById('deleteIddatadbText').textContent = deleteIddatadb;
|
||||||
deleteIddatadb;
|
|
||||||
new bootstrap.Modal(modalEl).show();
|
new bootstrap.Modal(modalEl).show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on("click", "#deleteConfirmBtn", async function () {
|
$(document).on('click', '#deleteConfirmBtn', async function () {
|
||||||
const modalEl = document.getElementById("deleteConfirmModal");
|
const modalEl = document.getElementById('deleteConfirmModal');
|
||||||
const modal = bootstrap.Modal.getInstance(modalEl);
|
const modal = bootstrap.Modal.getInstance(modalEl);
|
||||||
if (modal) modal.hide();
|
if (modal) modal.hide();
|
||||||
|
|
||||||
if (!deleteIddatadb) return;
|
if (!deleteIddatadb) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const resp = await fetch("delete_record.php", {
|
const resp = await fetch('delete_record.php', {
|
||||||
method: "POST",
|
method: 'POST',
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ id: deleteIddatadb }),
|
body: JSON.stringify({ id: deleteIddatadb })
|
||||||
});
|
});
|
||||||
const result = await resp.json();
|
const result = await resp.json();
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
// Remove from gridData
|
// Remove from gridData
|
||||||
const idx = window.gridData.findIndex(
|
const idx = window.gridData.findIndex(r => r.iddatadb === deleteIddatadb);
|
||||||
(r) => r.iddatadb === deleteIddatadb,
|
|
||||||
);
|
|
||||||
if (idx >= 0) window.gridData.splice(idx, 1);
|
if (idx >= 0) window.gridData.splice(idx, 1);
|
||||||
|
|
||||||
// Re-render
|
// Re-render
|
||||||
const gr = window.gridRenderer;
|
const gr = window.gridRenderer;
|
||||||
if (gr) gr.renderVisibleRows();
|
if (gr) gr.renderVisibleRows();
|
||||||
} else {
|
} else {
|
||||||
alert("Error: " + result.message);
|
alert('Error: ' + result.message);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
alert("Error: " + e.message);
|
alert('Error: ' + e.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteIddatadb = null;
|
deleteIddatadb = null;
|
||||||
@ -180,26 +156,20 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ── Add new row ──────────────────────────────────────────────────────
|
// ── Add new row ──────────────────────────────────────────────────────
|
||||||
$(document).on("click", "#addRowBtn", async function () {
|
$(document).on('click', '#addRowBtn', async function () {
|
||||||
const btn = this;
|
const btn = this;
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const templateId = window.gridMeta?.templateId;
|
const templateId = window.gridMeta?.templateId;
|
||||||
if (!templateId) {
|
if (!templateId) { alert('Template ID missing'); return; }
|
||||||
alert("Template ID missing");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
const importref = urlParams.get("importref") || "";
|
const importref = urlParams.get('importref') || '';
|
||||||
const resp = await fetch("add_record.php", {
|
const resp = await fetch('add_record.php', {
|
||||||
method: "POST",
|
method: 'POST',
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({ template_id: templateId, importreferencecode: importref })
|
||||||
template_id: templateId,
|
|
||||||
importreferencecode: importref,
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
const result = await resp.json();
|
const result = await resp.json();
|
||||||
|
|
||||||
@ -207,20 +177,17 @@
|
|||||||
// Build new row object
|
// Build new row object
|
||||||
const newRow = {
|
const newRow = {
|
||||||
iddatadb: result.iddatadb,
|
iddatadb: result.iddatadb,
|
||||||
status: "i",
|
status: 'i',
|
||||||
idclient: window.gridMeta?.defaultIdclient || "",
|
idclient: window.gridMeta?.defaultIdclient || '',
|
||||||
cliente_fornitore_id: null,
|
cliente_fornitore_id: null,
|
||||||
commessaweb: null,
|
commessaweb: null,
|
||||||
user_name: result.user_name || "",
|
user_name: result.user_name || '',
|
||||||
importreferencecode: result.importreferencecode || "",
|
importreferencecode: result.importreferencecode || '',
|
||||||
filename_import: "",
|
filename_import: '',
|
||||||
importdate: new Date()
|
importdate: new Date().toISOString().slice(0, 19).replace('T', ' '),
|
||||||
.toISOString()
|
|
||||||
.slice(0, 19)
|
|
||||||
.replace("T", " "),
|
|
||||||
fixedFields: {},
|
fixedFields: {},
|
||||||
details: {},
|
details: {},
|
||||||
mainFieldValue: "",
|
mainFieldValue: '',
|
||||||
_dirty: false,
|
_dirty: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -232,27 +199,20 @@
|
|||||||
if (gr) gr.renderVisibleRows();
|
if (gr) gr.renderVisibleRows();
|
||||||
|
|
||||||
// Highlight new row briefly
|
// Highlight new row briefly
|
||||||
const newGridRow = document.querySelector(
|
const newGridRow = document.querySelector(`.grid-row[data-id="${result.iddatadb}"]`);
|
||||||
`.grid-row[data-id="${result.iddatadb}"]`,
|
|
||||||
);
|
|
||||||
if (newGridRow) {
|
if (newGridRow) {
|
||||||
newGridRow.classList.add("row-just-created");
|
newGridRow.classList.add('row-just-created');
|
||||||
newGridRow.scrollIntoView({
|
newGridRow.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
behavior: "smooth",
|
setTimeout(() => newGridRow.classList.remove('row-just-created'), 4000);
|
||||||
block: "center",
|
|
||||||
});
|
|
||||||
setTimeout(
|
|
||||||
() => newGridRow.classList.remove("row-just-created"),
|
|
||||||
4000,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
alert("Error: " + (result.message || "Unknown error"));
|
alert('Error: ' + (result.message || 'Unknown error'));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
alert("Error: " + e.message);
|
alert('Error: ' + e.message);
|
||||||
} finally {
|
} finally {
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@ -1595,11 +1595,7 @@ $(document).ready(function () {
|
|||||||
dataType: "json",
|
dataType: "json",
|
||||||
delay: 150,
|
delay: 150,
|
||||||
data: function (params) {
|
data: function (params) {
|
||||||
return {
|
return { q: params.term || "", limit: 20, macro: selectedMacro || "" };
|
||||||
q: params.term || "",
|
|
||||||
limit: 20,
|
|
||||||
macro: selectedMacro || "",
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
processResults: function (data) {
|
processResults: function (data) {
|
||||||
return { results: data.results || [] };
|
return { results: data.results || [] };
|
||||||
@ -1658,11 +1654,7 @@ $(document).ready(function () {
|
|||||||
dataType: "json",
|
dataType: "json",
|
||||||
delay: 150,
|
delay: 150,
|
||||||
data: function (params) {
|
data: function (params) {
|
||||||
return {
|
return { q: params.term || "", limit: 20, macro: selectedMacro || "" };
|
||||||
q: params.term || "",
|
|
||||||
limit: 20,
|
|
||||||
macro: selectedMacro || "",
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
processResults: function (data) {
|
processResults: function (data) {
|
||||||
return { results: data.results || [] };
|
return { results: data.results || [] };
|
||||||
@ -1808,9 +1800,7 @@ $(document).ready(function () {
|
|||||||
$("#partsTableBody .part-matrice").each(function () {
|
$("#partsTableBody .part-matrice").each(function () {
|
||||||
const $target = $(this);
|
const $target = $(this);
|
||||||
if (!$target.find(`option[value="${globalVal}"]`).length) {
|
if (!$target.find(`option[value="${globalVal}"]`).length) {
|
||||||
$target.append(
|
$target.append(new Option(globalText, globalVal, true, true));
|
||||||
new Option(globalText, globalVal, true, true),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
$target.val(globalVal).trigger("change");
|
$target.val(globalVal).trigger("change");
|
||||||
});
|
});
|
||||||
@ -1979,109 +1969,7 @@ $(document).ready(function () {
|
|||||||
".add-row-global, .add-mix-global, .add-mix-row, .remove-row, .propagate-matrice-btn, .propagate-all-btn, .note-btn",
|
".add-row-global, .add-mix-global, .add-mix-row, .remove-row, .propagate-matrice-btn, .propagate-all-btn, .note-btn",
|
||||||
markUnsaved,
|
markUnsaved,
|
||||||
);
|
);
|
||||||
$(document).on("click", "#clonePartsBtn", function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const sourceIddatadb =
|
|
||||||
parseInt($("#partsModal").data("iddatadb"), 10) || null;
|
|
||||||
const visibleListRaw =
|
|
||||||
$("#partsModal").data("visible-iddatadb-list") || [];
|
|
||||||
|
|
||||||
if (!sourceIddatadb) {
|
|
||||||
const errorMsg = $(
|
|
||||||
'<div class="alert alert-danger temp-alert" role="alert">Source record not found.</div>',
|
|
||||||
);
|
|
||||||
$("#partsModal .modal-body").prepend(errorMsg);
|
|
||||||
setTimeout(() => {
|
|
||||||
errorMsg.fadeOut(500, function () {
|
|
||||||
$(this).remove();
|
|
||||||
});
|
|
||||||
}, 5000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetIds = (Array.isArray(visibleListRaw) ? visibleListRaw : [])
|
|
||||||
.map((v) => parseInt(v, 10))
|
|
||||||
.filter((v) => !isNaN(v) && v > 0 && v !== sourceIddatadb);
|
|
||||||
|
|
||||||
if (!targetIds.length) {
|
|
||||||
const errorMsg = $(
|
|
||||||
'<div class="alert alert-warning temp-alert" role="alert">No other visible records available for clone.</div>',
|
|
||||||
);
|
|
||||||
$("#partsModal .modal-body").prepend(errorMsg);
|
|
||||||
setTimeout(() => {
|
|
||||||
errorMsg.fadeOut(500, function () {
|
|
||||||
$(this).remove();
|
|
||||||
});
|
|
||||||
}, 5000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!confirm(
|
|
||||||
`Confermi il clone delle parti del record ${sourceIddatadb} negli altri ${targetIds.length} record visibili?`,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const $btn = $(this);
|
|
||||||
const originalHtml = $btn.html();
|
|
||||||
$btn.prop("disabled", true).html(
|
|
||||||
'<i class="fas fa-spinner fa-spin"></i> Clonazione...',
|
|
||||||
);
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: "clone_parts_to_visible.php",
|
|
||||||
method: "POST",
|
|
||||||
contentType: "application/json",
|
|
||||||
dataType: "json",
|
|
||||||
data: JSON.stringify({
|
|
||||||
source_iddatadb: sourceIddatadb,
|
|
||||||
target_iddatadb_list: targetIds,
|
|
||||||
}),
|
|
||||||
success: function (response) {
|
|
||||||
$btn.prop("disabled", false).html(originalHtml);
|
|
||||||
|
|
||||||
if (response.success) {
|
|
||||||
const successMsg = $(
|
|
||||||
`<div class="alert alert-success temp-alert" role="alert">
|
|
||||||
Clone completed. Source parts copied to ${response.cloned_targets || 0} record(s), total cloned parts: ${response.total_cloned_parts || 0}.
|
|
||||||
</div>`,
|
|
||||||
);
|
|
||||||
$("#partsModal .modal-body").prepend(successMsg);
|
|
||||||
setTimeout(() => {
|
|
||||||
successMsg.fadeOut(500, function () {
|
|
||||||
$(this).remove();
|
|
||||||
});
|
|
||||||
}, 5000);
|
|
||||||
} else {
|
|
||||||
const errorMsg = $(
|
|
||||||
`<div class="alert alert-danger temp-alert" role="alert">Clone error: ${response.message || "Unknown error"}</div>`,
|
|
||||||
);
|
|
||||||
$("#partsModal .modal-body").prepend(errorMsg);
|
|
||||||
setTimeout(() => {
|
|
||||||
errorMsg.fadeOut(500, function () {
|
|
||||||
$(this).remove();
|
|
||||||
});
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: function (xhr, status, error) {
|
|
||||||
$btn.prop("disabled", false).html(originalHtml);
|
|
||||||
|
|
||||||
const errorMsg = $(
|
|
||||||
`<div class="alert alert-danger temp-alert" role="alert">Clone error: ${error} (${xhr.status})</div>`,
|
|
||||||
);
|
|
||||||
$("#partsModal .modal-body").prepend(errorMsg);
|
|
||||||
setTimeout(() => {
|
|
||||||
errorMsg.fadeOut(500, function () {
|
|
||||||
$(this).remove();
|
|
||||||
});
|
|
||||||
}, 5000);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// Esporta la funzione loadParts per essere usata da import_Edit2.php
|
// Esporta la funzione loadParts per essere usata da import_Edit2.php
|
||||||
window.loadParts = loadParts;
|
window.loadParts = loadParts;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user