fQuery("SELECT cfg_erp_api_url, cfg_erp_api_token FROM tbl_config LIMIT 1", "config fetch error"); $url = isset($row['cfg_erp_api_url']) ? trim($row['cfg_erp_api_url']) : ''; $token = isset($row['cfg_erp_api_token']) ? trim($row['cfg_erp_api_token']) : ''; // URL 없으면 바로 예외 (서버 아직 준비 안됨) if ($url === '' || $url === null) { $this->enabled = false; $this->baseUrl = ''; $this->token = ''; return; } $this->enabled = true; $this->baseUrl = rtrim($url, '/'); $this->token = $token; } /** * 공통 HTTP 요청 처리 */ private function request($method, $endpoint, $data = null) { // ERP 비활성화면 아무것도 하지 않고 조용히 반환 if (!$this->enabled) { return [ "disabled" => true, "skipped" => true, "endpoint" => $endpoint, ]; } $url = $this->baseUrl . $endpoint; $headers = [ "Authorization: Bearer {$this->token}", "Content-Type: application/json" ]; $ch = curl_init($url); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); if ($data !== null) { curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); } $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($response === false) { $err = curl_error($ch); curl_close($ch); throw new Exception("cURL Error: $err"); } curl_close($ch); $result = json_decode($response, true); if ($result === null && json_last_error() !== JSON_ERROR_NONE) { throw new Exception("JSON Decode Error: " . json_last_error_msg() . " - Response: $response"); } if ($httpCode >= 400) { $msg = isset($result['message']) ? $result['message'] : $response; throw new Exception("HTTP $httpCode Error: $msg"); } return $result; } // ------------------------------------------------------- // 기본 Customer API // ------------------------------------------------------- public function createCustomer($data) { return $this->request("POST", "/customer", $data); } public function updateCustomer($cusNo, $data) { return $this->request("PATCH", "/customer/no/" . $cusNo, $data); } public function deleteCustomer($cusNo) { return $this->request("DELETE", "/customer/no/" . $cusNo); } // ------------------------------------------------------- // 공통 유틸 // ------------------------------------------------------- private function convertDate($dateStr) { if (!$dateStr || !is_string($dateStr)) { return null; } // YYYYMMDD (8) if (strlen($dateStr) === 8) { return substr($dateStr, 0, 4) . '-' . substr($dateStr, 4, 2) . '-' . substr($dateStr, 6, 2); } // YYYYMMDDHHIISS (14) if (strlen($dateStr) === 14) { return substr($dateStr,0,4)."-" . substr($dateStr,4,2)."-" . substr($dateStr,6,2)."T" . substr($dateStr,8,2).":" . substr($dateStr,10,2).":" . substr($dateStr,12,2); } // 지원하지 않는 포맷 return null; } private function normalizeValue($value) { if ($value === '' || $value === false) return null; if (is_string($value) && trim($value) === '') return null; return $value; } private function getValue($columns, $values, $col) { $idx = array_search($col, $columns); return $idx !== false ? $values[$idx] : null; } // ------------------------------------------------------- // MIS → ERP Customer Payload 빌드 (완전 자동 변환) // ------------------------------------------------------- public function buildCustomerPayload($columns, $values, $loginUser) { $payload = []; // MIS → ERP 매핑 규칙 $map = [ "cusNo" => "c_accountno", "cusName" => "c_name", "cusStatus" => "c_status", "cusAreaId" => "c_area", "cusAddress1" => "c_address", "cusAddress2" => "c_mailingaddr", "cusPostalCode" => "c_postal", "cusCity" => "c_city", "cusProvince" => "c_province", "cusEmail" => "c_email", "cusPhone" => "c_phone", "cusPhoneExt" => "c_phoneext", "cusRate" => "c_rate", "cusPayMethod" => "c_paymenttype", "cusContractDate" => "c_contractdate", "cusContractedBy" => "c_contractby", "cusInstallDate" => "c_installdate", // full cycle 필요하면 나중에 추가 2025-12-16 // "cusFullCycle" => "c_fullcycle", // "cusFullCycleFlag" => "c_fullcycleflag", // "cusFullCycleForced" => "c_fullcycleforced", // "cusFullCycleForcedDate"=> "c_forceddate", "cusSchedule" => "c_schedule", "cusScheduledays" => "c_scheduleday", "cusIsccDate" => "c_form_eu", "cusCorsiaDate" => "c_form_corsia", "cusHstNo" => "c_hstno", "cusComment" => "c_comment_ri", "cusContactComment" => "c_comment_ci", "cusGeoLat" => "c_geolat", "cusGeoLon" => "c_geolon", "cusInstallLocation" => "c_location", ]; // 날짜 변환 필드 목록 $dateCols = [ "c_contractdate", "c_installdate", "c_forceddate", "c_form_eu", "c_form_corsia" ]; // 기본 필드 채우기 foreach ($map as $erpKey => $misCol) { $value = $this->getValue($columns, $values, $misCol); if ($value && in_array($misCol, $dateCols)) { $value = $this->convertDate($value); } $payload[$erpKey] = $value; } // 로그인 사용자 $payload["cusLoginUser"] = $loginUser; return $payload; } // ------------------------------------------------------- // MIS → ERP Customer CREATE // ------------------------------------------------------- public function createCustomerFromMis($columns, $values, $loginUser) { // 비활성화면 로그도 남기지 말고 바로 종료 if (!$this->enabled) { return ["disabled" => true, "skipped" => true]; } $payload = $this->buildCustomerPayload($columns, $values, $loginUser); try { // 테스트용 // addLog("add" // , "/customer" // , "ERP - SUCCESS" // , $loginUser // , json_encode($payload, JSON_PRETTY_PRINT) // , '' // ); return $this->createCustomer($payload); } catch (Exception $e) { $logBody = "[EXCEPTION]\n" . $e->getMessage() . "\n\n" . "[PAYLOAD]\n" . json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); addLog("add" , "/customer" , "ERP - FAILED" , $loginUser , $logBody , '' ); // 사용자에게는 아무것도 안 알려줌 return [ "success" => false, "queued" => true ]; } } // ------------------------------------------------------- // MIS → ERP Customer UPDATE (cusNo 기준) // ------------------------------------------------------- public function updateCustomerFromMis($columns, $values, $loginUser) { // 비활성화면 로그도 남기지 말고 바로 종료 if (!$this->enabled) { return ["disabled" => true, "skipped" => true]; } // accountno 찾기 $cusNo = $this->getValue($columns, $values, "c_accountno"); if (!$cusNo) { throw new Exception("updateCustomerFromMis: Missing c_accountno"); } $payload = $this->buildCustomerPayload($columns, $values, $loginUser); try { // 테스트용 // addLog("add" // , "/customer/no/" . $cusNo // , "ERP - SUCCESS" // , $loginUser // , json_encode($payload, JSON_PRETTY_PRINT) // , $cusNo // ); return $this->updateCustomer($cusNo, $payload); } catch (Exception $e) { $logBody = "[EXCEPTION]\n" . $e->getMessage() . "\n\n" . "[PAYLOAD]\n" . json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); addLog("add" , "/customer/no/" . $cusNo , "ERP - FAILED" , $loginUser , $logBody , $cusNo ); // 사용자에게는 아무것도 안 알려줌 return [ "success" => false, "queued" => true ]; } } // ------------------------------------------------------- // MIS → ERP Customer 단일필드 업데이트 (update_column.php 용) // ------------------------------------------------------- public function updateCustomerFieldFromMis($cusNo, $field, $value, $loginUser) { if (!$this->enabled) { return ["disabled" => true, "skipped" => true]; } $payload = [ "cusLoginUser" => $loginUser, $field => $value ]; return $this->updateCustomer($cusNo, $payload); } // ------------------------------------------------------- // Customer Daily Order 관련 API (RAW 호출) // ------------------------------------------------------- /** * POST /customer-daily-order */ public function createOrder($data) { return $this->request("POST", "/customer-daily-order", $data); } /** * PATCH /customer-daily-order/customer/{customerNo}/{orderDate} * - customerNo : ERP customer.cus_no * - orderDate : yyyy-MM-dd */ public function updateOrder($customerNo, $orderDate, $data) { return $this->request( "PATCH", "/customer-daily-order/customer/" . $customerNo . "/" . $orderDate, $data ); } /** * DELETE /customer-daily-order/{uuid} */ public function deleteOrder($uuid) { return $this->request("DELETE", "/customer-daily-order/" . $uuid); } // ------------------------------------------------------- // Customer Daily Order - MIS 연동용 헬퍼 // (tbl_daily $columns / $values 기반으로 payload 생성) // ------------------------------------------------------- /** * MIS 의 tbl_daily ( $columns, $values ) 를 ERP CustomerDailyOrderRequestDto 로 변환 * * @param array $columns tbl_daily insert 시 사용한 컬럼명 배열 * @param array $values 각 컬럼에 대한 값 배열 * @param string $loginUser MIS 로그인 사용자 ID * @return array ERP에 보낼 payload */ public function buildDailyOrderPayload($columns, $values, $loginUser) { $payload = []; // MIS → ERP 매핑 규칙 // (필요에 따라 계속 보강 가능) $map = [ "cdoOrderDate" => "d_orderdate", "cdoOrderType" => "d_ordertype", "cdoRequestNote" => "d_requestnote", "cdoCustomerNo" => "d_accountno", "cdoCycle" => "d_cycle", "cdoPaymentType" => "d_paymenttype", "cdoRate" => "d_rate", "cdoStatus" => "d_status", "cdoEstimatedQty" => "d_estquantity", "cdoQuantity" => "d_quantity", "cdoSludge" => "d_sludge", "cdoPayStatus" => "d_paystatus", "cdoPayAmount" => "d_payamount", "cdoPayeeName" => "d_payeename", "cdoPayeeSign" => "d_payeesign", "cdoExternalDriverId" => "d_driveruid", "cdoVisitFlag" => "d_visit", "cdoPickupNote" => "d_pickupnote", "cdoPickupAt" => "d_inputdate", ]; // 날짜 변환이 필요한 컬럼들 $dateColumns = [ "d_orderdate", "d_inputdate", ]; // 로그인 사용자 $payload["cdoLoginUser"] = $loginUser; // map 에 따라 값 채우기 foreach ($map as $erpKey => $misCol) { $idx = array_search($misCol, $columns); $value = ($idx !== false) ? $values[$idx] : null; // 빈 문자열 → null if (is_string($value)) { $value = trim($value); if ($value === '') { $value = null; } } // 날짜 변환 if ($value !== null && in_array($misCol, $dateColumns, true)) { $value = $this->convertDate($value); } $payload[$erpKey] = $value; } /* Rule */ // 연결 key if (!$payload['cdoCustomerNo']) { throw new Exception("DailyOrder Error: Missing CustomerNo"); } if (!$payload['cdoOrderDate']) { throw new Exception("DailyOrder Error: Missing OrderDate"); } // quantity 있는데 sludge 없으면 sludge = 0 if ( array_key_exists('cdoQuantity', $payload) && $payload['cdoQuantity'] !== null && $payload['cdoSludge'] === null ) { $payload['cdoSludge'] = 0; } return $payload; } /** * MIS → ERP : Daily Order 신규 생성 편의 함수 * * user_process.php 에서: * $erp = new ErpApi(); * $payload = $erp->buildDailyOrderPayload($columns, $values, $lguserid); * $erp->createOrder($payload); * * 또는: * $erp->createDailyOrderFromMis($columns, $values, $lguserid); */ public function createDailyOrderFromMis($columns, $values, $loginUser) { if (!$this->enabled) { return ["disabled" => true, "skipped" => true]; } $payload = $this->buildDailyOrderPayload($columns, $values, $loginUser); try { // 테스트용 // addLog("add" // , "/customer-daily-order" // , "ERP - SUCCESS" // , $loginUser // , json_encode($payload, JSON_PRETTY_PRINT) // , '' // ); return $this->createOrder($payload); } catch (Exception $e) { $logBody = "[EXCEPTION]\n" . $e->getMessage() . "\n\n" . "[PAYLOAD]\n" . json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); addLog("add" , "/customer-daily-order" , "ERP - FAILED" , $loginUser , $logBody , '' ); // 사용자에게는 아무것도 안 알려줌 return [ "success" => false, "queued" => true ]; } } /** * MIS → ERP : Daily Order 업데이트 (customerNo + orderDate 기준) */ public function updateDailyOrderFromMis($columns, $values, $loginUser) { // 비활성화면 로그도 남기지 말고 바로 종료 if (!$this->enabled) { return ["disabled" => true, "skipped" => true]; } $payload = $this->buildDailyOrderPayload($columns, $values, $loginUser); // customerNo / orderDate 추출 $customerNo = $payload['cdoCustomerNo']; $orderDate = $payload['cdoOrderDate']; try { // 테스트용 // addLog("add" // , "/customer-daily-order/customer/" . $customerNo . "/" . $orderDate // , "ERP - SUCCESS" // , $loginUser // , json_encode($payload, JSON_PRETTY_PRINT) // , $customerNo // ); return $this->updateOrder($customerNo, $orderDate, $payload); } catch (Exception $e) { $logBody = "[EXCEPTION]\n" . $e->getMessage() . "\n\n" . "[PAYLOAD]\n" . json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); addLog("add" , "/customer-daily-order/customer/" . $customerNo . "/" . $orderDate , "ERP - FAILED" , $loginUser , $logBody , $customerNo ); // 사용자에게는 아무것도 안 알려줌 return [ "success" => false, "queued" => true ]; } } } ?>