'NL', 'belgiƫ' => 'BE', 'belgium' => 'BE', 'duitsland' => 'DE', 'germany' => 'DE', ]; function getColumnValue(array $columnValues, string $columnId): ?string { foreach ($columnValues as $column) { if ($column['id'] === $columnId) return $column['text']; } return null; } function updateMondayColumn(int $boardId, int $itemId, string $columnId, string $newValue, string $mondayToken) { $query = 'mutation ($itemId: ID!, $boardId: ID!, $columnId: String!, $newValue: String!) { change_simple_column_value(item_id: $itemId, board_id: $boardId, column_id: $columnId, value: $newValue) { id } }'; $variables = ['boardId' => $boardId, 'itemId' => $itemId, 'columnId' => $columnId, 'newValue' => $newValue]; $payload = json_encode(['query' => $query, 'variables' => $variables]); $ch = curl_init('https://api.monday.com/v2'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json', 'Authorization: ' . $mondayToken]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode >= 400) { error_log("Fout bij updaten Monday kolom {$columnId}: " . $response); } else { error_log("Monday kolom {$columnId} succesvol bijgewerkt voor item {$itemId}."); } } function getMondayItemData(int $itemId, string $mondayApiToken): ?array { $graphQLQuery = 'query($itemId: [ID!]) { items (ids: $itemId) { name column_values { id text } } }'; $mondayPayload = json_encode(['query' => $graphQLQuery, 'variables' => ['itemId' => $itemId]]); $ch_monday = curl_init('https://api.monday.com/v2'); curl_setopt($ch_monday, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch_monday, CURLOPT_POST, true); curl_setopt($ch_monday, CURLOPT_POSTFIELDS, $mondayPayload); curl_setopt($ch_monday, CURLOPT_HTTPHEADER, ['Content-Type: application/json', 'Authorization: ' . $mondayApiToken]); $mondayResponse = curl_exec($ch_monday); curl_close($ch_monday); $itemData = json_decode($mondayResponse, true)['data']['items'][0] ?? null; if (!$itemData) { error_log("Item met ID {$itemId} niet gevonden in Monday.com response."); } return $itemData; } // --- Functies voor Bedrijven en Vakkrachten (ongewijzigd) --- function handleBedrijven(array $itemData, int $itemId, WeFactAPI $wefactApi, string $mondayApiToken) { global $countryCodeMap, $bedrijvenBoardId; $columnValues = $itemData['column_values']; $wefactDebtorIdColumn = 'text_mksq79kz'; $wefactDebtorId = getColumnValue($columnValues, $wefactDebtorIdColumn); $debiteurData = array_filter([ 'CompanyName' => $itemData['name'], 'CompanyNumber' => getColumnValue($columnValues, 'kvk_mkmphj97'), 'TaxNumber' => getColumnValue($columnValues, 'text_mkpw2a77'), 'PhoneNumber' => getColumnValue($columnValues, 'telefoon_mkktmz4t'), 'EmailAddress' => getColumnValue($columnValues, 'e_mail_mkktxyr6'), 'Address' => getColumnValue($columnValues, 'text_mkpwgxkm'), 'ZipCode' => getColumnValue($columnValues, 'text_mkpwp7ps'), 'City' => getColumnValue($columnValues, 'text_mkpw5ek1'), 'Country' => getColumnValue($columnValues, 'text_mkpwb8q1') ? ($countryCodeMap[strtolower(getColumnValue($columnValues, 'text_mkpwb8q1'))] ?? getColumnValue($columnValues, 'text_mkpwb8q1')) : null, 'InvoiceEmail' => getColumnValue($columnValues, 'text_mkpw1nxd'), ], fn($value) => $value !== null && $value !== ''); if ($wefactDebtorId) { error_log("WeFact Debiteur ID {$wefactDebtorId} gevonden. Debiteur wordt bijgewerkt..."); $debiteurData['DebtorCode'] = $wefactDebtorId; $response = $wefactApi->sendRequest('debtor', 'edit', $debiteurData); } else { error_log("Geen WeFact Debiteur ID gevonden. Nieuwe debiteur wordt aangemaakt..."); $response = $wefactApi->sendRequest('debtor', 'add', $debiteurData); if ($response['status'] === 'success' && isset($response['debtor']['DebtorCode'])) { $newDebtorId = $response['debtor']['DebtorCode']; error_log("Debiteur succesvol aangemaakt met ID: {$newDebtorId}. Monday wordt bijgewerkt."); updateMondayColumn($bedrijvenBoardId, $itemId, $wefactDebtorIdColumn, $newDebtorId, $mondayApiToken); } } if ($response['status'] === 'error') { error_log("FOUT van WeFact (Debiteur): " . json_encode($response['errors'])); } else { error_log("SUCCES! Reactie van WeFact (Debiteur): " . json_encode($response)); } } function handleVakkrachten(array $itemData, int $itemId, WeFactAPI $wefactApi, string $mondayApiToken) { global $vakkrachtenBoardId; $columnValues = $itemData['column_values']; $wefactProductIdColumn = 'text_mksqgn4v'; $wefactProductId = getColumnValue($columnValues, $wefactProductIdColumn); $productData = array_filter([ 'ProductName' => $itemData['name'], 'ProductKeyPhrase' => getColumnValue($columnValues, 'text_mkrhy2ks'), ], fn($value) => $value !== null && $value !== ''); if (empty($productData['ProductName'])) { error_log("Geen productnaam gevonden voor item {$itemId}. Actie wordt gestopt."); return; } if ($wefactProductId) { error_log("WeFact Product ID {$wefactProductId} gevonden. Product wordt bijgewerkt..."); $productData['ProductCode'] = $wefactProductId; $response = $wefactApi->sendRequest('product', 'edit', $productData); } else { error_log("Geen WeFact Product ID gevonden. Nieuw product wordt aangemaakt..."); $response = $wefactApi->sendRequest('product', 'add', $productData); if ($response['status'] === 'success' && isset($response['product']['ProductCode'])) { $newProductId = $response['product']['ProductCode']; error_log("Product succesvol aangemaakt met ID: {$newProductId}. Monday wordt bijgewerkt."); updateMondayColumn($vakkrachtenBoardId, $itemId, $wefactProductIdColumn, $newProductId, $mondayApiToken); } } if ($response['status'] === 'error') { error_log("FOUT van WeFact (Product): " . json_encode($response['errors'])); } else { error_log("SUCCES! Reactie van WeFact (Product): " . json_encode($response)); } } // --- Webserver & Routing Logica --- $requestBody = file_get_contents('php://input'); $data = json_decode($requestBody, true); if (isset($data['challenge'])) { header('Content-Type: application/json'); echo json_encode(['challenge' => $data['challenge']]); exit; } if (isset($data['event'])) { $event = $data['event']; $boardId = (int)$event['boardId']; $itemId = (int)$event['pulseId']; // --- NIEUW: LOCK MECHANISME OM RACE CONDITIONS TE VOORKOMEN --- $lockFileDir = __DIR__ . '/locks'; if (!is_dir($lockFileDir)) { mkdir($lockFileDir, 0775, true); } $lockFilePath = $lockFileDir . '/' . $itemId . '.lock'; $lockFileHandle = fopen($lockFilePath, 'c'); if ($lockFileHandle === false) { error_log("Kon geen lock file handle aanmaken voor item {$itemId}."); exit; } // Probeer een exclusieve, niet-blokkerende lock te krijgen. if (!flock($lockFileHandle, LOCK_EX | LOCK_NB)) { // Als het niet lukt, is een ander proces al bezig met dit item. error_log("Process voor item {$itemId} is al bezig. Deze instantie wordt gestopt om duplicaten te voorkomen."); fclose($lockFileHandle); exit; } // Zorg ervoor dat de lock altijd wordt vrijgegeven, zelfs bij een fout. register_shutdown_function(function() use ($lockFileHandle, $lockFilePath) { flock($lockFileHandle, LOCK_UN); // Geef lock vrij fclose($lockFileHandle); unlink($lockFilePath); // Verwijder het lock-bestand }); // --- EINDE LOCK MECHANISME --- $itemData = getMondayItemData($itemId, $mondayApiToken); if ($itemData) { $wefactApi = new WeFactAPI($wefactApiKey); if ($boardId === $bedrijvenBoardId) { handleBedrijven($itemData, $itemId, $wefactApi, $mondayApiToken); } elseif ($boardId === $vakkrachtenBoardId) { handleVakkrachten($itemData, $itemId, $wefactApi, $mondayApiToken); } else { error_log("Webhook ontvangen van een niet-geconfigureerd bord: ID {$boardId}"); } } } http_response_code(200); echo json_encode(['message' => 'Event succesvol ontvangen.']); ?>