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() ]); }