본문으로 건너뛰기

소스 변경 전체 보기

PHP 8 · GODO26
변경 파일 수: 24개
변경 파일 목록
총 24개
변경 파일 코드
추가삭제
부운영자 1:1 문의 기능 추가
Admin/base/_index_qna_layer.php+154
변경 전_index_qna_layer.php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
변경 후_index_qna_layer.php
<script src="<?= gd_set_browser_cache(PATH_ADMIN_GD_SHARE . 'ncds/script/common/aggregator-message-router.js') ?>"></script>
<div>
<input type="hidden" name="mode" value="grow_qna_register" />
<div class="layer_helper_write" style="display:none;">
<script>
$(document).ready(function() {
var qnaIframeOrigin = '';
var qnaClientInfo = null;
var qnaAjax = null;
 
// 공용 라우터(aggregator-message-router.js) 콜백 등록.
 
// 접속 정보 요청 -> 응답
IframeMessageRouter._config.onRequestClientInfo = function () {
sendClientInfo();
};
 
// 모달 닫기
IframeMessageRouter._config.onModalClose = function () {
modalClose();
};
 
// 상세 팝업(opener)이 relay 한 전송 메시지 처리
IframeMessageRouter._config.onSendToParent = function (message) {
var payload = (message && message.payload) || {};
 
// payload 에 따라 문의 목록 iframe 에 완료 알림
switch (payload.action) {
case 'delete' : notifyInquiryList({ category: 'INQUIRY', type: 'DELETE_COMPLETE' }); break;
case 'reinquiry' : notifyInquiryList({ category: 'INQUIRY', type: 'REINQUIRY_COMPLETE' }); break;
}
 
// payload 에 따라 어드민 개인정보 접근기록(es_adminLog) 작성
recordAccessLog(payload);
};
 
// 상세 페이지를 새 윈도우 팝업으로 연다.
function openInquiryDetail(query) {
var qnaNo = query && query.qnaNo;
if (!qnaNo) {
return;
}
var params = $.param({ endpoint: 'detail', qnaNo: qnaNo });
window.open('/member/layer_qna.php?' + params, '_blank', 'width=1000,height=550,scrollbars=yes,resizable=yes');
}
 
// 레이어팝업을 닫는다. (자식 iframe 의 MODAL_CLOSE 수신 시)
function modalClose() {
$('.layer_helper_write').hide();
$('body').removeAttr('style');
}
 
// endpoint 로 iframe URL/접속정보를 조회해 src 로 주입한다. (최초 로드/재로딩 공통)
function loadInquiryIframe(endpoint) {
if (qnaAjax) {
qnaAjax.abort();
}
var currentAjax = $.ajax({
url: '/member/layer_qna.php',
type: 'GET',
dataType: 'json',
data: { endpoint: endpoint }
});
qnaAjax = currentAjax;
currentAjax.done(function (res) {
if (!res || !res.success || !res.data || !res.data.url) {
return;
}
qnaClientInfo = res.data.postParameters || null;
 
var parsedUrl = null;
try {
parsedUrl = new URL(res.data.url, window.location.origin);
qnaIframeOrigin = parsedUrl.origin;
} catch (e) {
qnaIframeOrigin = '';
}
// http/https 스킴만 iframe 에 로드 (javascript: 등 위험 스킴 차단)
if (parsedUrl && (parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:')) {
$('.helper_write_iframe').attr('src', parsedUrl.href);
}
}).always(function () {
if (qnaAjax === currentAjax) {
qnaAjax = null;
}
});
}
 
// 완료 메시지(삭제/재문의완료)를 문의 목록 iframe 에 전달해 목록 API 를 재호출시킨다.
function notifyInquiryList(message) {
var inquiryIframe = $('.helper_write_iframe').get(0);
if (!inquiryIframe || !inquiryIframe.contentWindow || !qnaIframeOrigin) {
return;
}
inquiryIframe.contentWindow.postMessage(message, qnaIframeOrigin);
}
 
// 접속페이지 유형(list·detail:조회, search:검색, delete:삭제, inquiry·reinquiry:등록)을 접속기록 API 로 기록한다.
function recordAccessLog(payload) {
var accessLogActions = ['list', 'search', 'detail', 'delete', 'inquiry', 'reinquiry'];
if (!payload || accessLogActions.indexOf(payload.action) === -1) {
return;
}
$.ajax({
url: '/policy/access_log_ps.php',
type: 'POST',
dataType: 'json',
data: {
action: payload.action,
adminIds: payload.adminIds || [],
searchValue: payload.searchValue || ''
}
});
}
 
// 접속 정보(CLIENT_INFO)를 자식 iframe 에 응답한다. 서버 미응답 값은 fallback 처리.
function sendClientInfo() {
var inquiryIframe = $('.helper_write_iframe').get(0);
if (!inquiryIframe || !inquiryIframe.contentWindow || !qnaIframeOrigin) {
return;
}
var info = qnaClientInfo || {};
inquiryIframe.contentWindow.postMessage({
category: 'INQUIRY',
type: 'CLIENT_INFO',
payload: {
ip: info.ip || '',
device: info.device || 'PC',
userAgent: info.agent || navigator.userAgent,
isSubAdmin: !!info.isSubAdmin,
adminId: info.managerId,
hp: info.cellPhone || '',
email: info.email || '',
}
}, qnaIframeOrigin);
}
 
// 1:1문의 아이콘 클릭 시 레이어팝업 노출
$('.btn_adm_qna').on('click', function (){
var buttonId = this.id;
var layerWidth = (buttonId === 'inquiry') ? '760px' : '1000px';
$('.helper_write_wrap.helper_write_wrap_iframe').css('width', layerWidth);
$('.layer_helper_write').show();
// 1:1문의 iframe URL/접속정보를 조회해 src 로 주입
loadInquiryIframe(buttonId);
});
});
</script>
<div class="helper_write_wrap_dim"></div>
<div class="helper_write_wrap helper_write_wrap_iframe" style="padding:unset;">
<iframe class="helper_write_iframe" style="flex:none; height:100%"> </iframe>
</div>
</div>
</div>
 
Admin/base/index.php+5-4
변경 전index.php
<?php include($serviceState); ?>
<!-- 운영 필수 서비스 현황 내용 끝 -->
 
<!-- 그로우 상점 1:1문의 시작 -->
<?php include($growData);?>
<!-- 그로우 상점 1:1문의 끝 -->
 
<?php if(gd_is_provider() === false) { ?>
<div class="main-section">
<div class="table-title">
고객센터
<a class="btn btn-white btn-sm <?php if ($manager['isSuper'] == 'y') { ?>btn_grow<?php } else {?>btn_err<?php }?>" style="margin-left:5px;">1:1 문의</a>
 
<div id="panel_link_customerLink" class="pull-right"></div>
</div>
<!-- gorw 상점 유무에 따라 고객센터 번호 호출 -->
 
변경 후index.php
<?php include($serviceState); ?>
<!-- 운영 필수 서비스 현황 내용 끝 -->
 
<!-- 상점 1:1문의 시작 -->
<?php include($qnaPopup);?>
<!-- 상점 1:1문의 끝 -->
 
<?php if(gd_is_provider() === false) { ?>
<div class="main-section">
<div class="table-title">
고객센터
<a class="btn btn-white btn-sm btn_adm_qna" id="inquiry" style="margin-left:5px;">1:1 문의</a>
<a class="btn btn-white btn-sm btn_adm_qna" id="list" style="margin-left:5px;">문의 내역</a>
<div id="panel_link_customerLink" class="pull-right"></div>
</div>
<!-- gorw 상점 유무에 따라 고객센터 번호 호출 -->
 
Admin/base/popup_qna_detail_iframe.php+14
변경 전popup_qna_detail_iframe.php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
변경 후popup_qna_detail_iframe.php
<style>
/* 팝업 창이 iframe 높이(100%)의 기준이 되도록 body 를 뷰포트에 고정하고, 창 세로 스크롤은 막는다 (스크롤은 iframe 내부가 담당) */
body { overflow-y: hidden; height: 100vh; }
</style>
<script src="<?= gd_set_browser_cache(PATH_ADMIN_GD_SHARE . 'ncds/script/common/aggregator-message-router.js') ?>"></script>
<!-- 창 크기가 높이를 정하는 팝업이므로 RESIZE 높이 동기화 제외 -->
<iframe name="qnaDetailPopup" src="<?= htmlspecialchars($pageUrl, ENT_QUOTES, 'UTF-8') ?>" frameborder="0" marginwidth="0" marginheight="0" width="100%" style="height: 100%;" data-frame-height-sync="off"></iframe>
<script>
// 공용 라우터가 수신한 메시지를 처리할 콜백을 인라인으로 주입한다.
// 상세 닫기(MODAL_CLOSE): 팝업 창 종료
IframeMessageRouter._config.onModalClose = function () {
window.close();
};
</script>
 
Component/Admin/AdminLogDAO.php+15-5
변경 전AdminLogDAO.php
use Framework\Utility\ArrayUtils;
use Framework\Utility\DateTimeUtils;
use Framework\Utility\StringUtils;
 
use Component\Member\MemberMasking;
use Origin\Service\Member\ManagerEditPolicy;
 
// 기존 : 운영자정보 접속기록 탭에 관리자 노출, 공급사는 회원정보 접속기록에 노출
// 변경 : 관리자, 공급사 두개 다 운영자정보 접속기록에 노출되도록 작업
// 관리자에 추가된다면, 공급사도 기획측에 확인해서 추가 필요!
$adminListPage = ['/policy/manage_list.php', '/policy/manage_register.php', '/policy/manage_ps.php', '/policy/manage_permission.php', '/share/layer_manage.php'];
$providerListPage = ['/provider/policy/manage_list.php', '/provider/policy/manage_register.php', '/provider/policy/manage_ps.php', '/provider/policy/manage_permission.php', '/provider/share/layer_manage.php'];
 
$adminListPage = array_merge($adminListPage, $providerListPage);
 
if ($request['view'] == 'adminList') {
$where[] = 'a.baseUri IN (?,?,?,?,?,?,?,?,?,?)';
} else { //default
$where[] = 'a.baseUri NOT IN (?,?,?,?,?,?,?,?,?,?)';
}
foreach($adminListPage as $adminListPageVal) {
$this->_db->bind_param_push($arrBind, 's', $adminListPageVal);
case 'manage_ps.php':
case 'manage_list.php':
case 'layer_manage.php':
 
$lVal['data'] = json_decode($lVal['data'], true);
if ($lVal['page'] == 'adminInfo' || empty($lVal['data']['searchData']) === false) {
$data[$lKey]['displayDetailLogFl'] = 'y';
case 'layer_manage.php':
$result['searchTargetMsg'] = '처리 대상 : '. $result['searchData'];
break;
 
 
 
 
 
 
 
 
case 'manage_register.php':
$manager = \App::load('\\Component\\Member\\Manager');
$managerIdArr = $manager->getManagerId($data['data']['GET']['sno']);
// 기존 : 운영자정보 접속기록 탭에 관리자 노출, 공급사는 회원정보 접속기록에 노출
// 변경 : 관리자, 공급사 두개 다 운영자정보 접속기록에 노출되도록 작업
// 관리자에 추가된다면, 공급사도 기획측에 확인해서 추가 필요!
$adminListPage = ['/policy/manage_list.php', '/policy/manage_register.php', '/policy/manage_ps.php', '/policy/manage_permission.php', '/share/layer_manage.php'];
$providerListPage = ['/provider/policy/manage_list.php', '/provider/policy/manage_register.php', '/provider/policy/manage_ps.php', '/provider/policy/manage_permission.php', '/provider/share/layer_manage.php'];
 
$adminListPage = array_merge($adminListPage, $providerListPage);
 
$where[] = 'a.baseUri NOT IN (?,?,?,?,?,?,?,?,?,?)';
 
foreach($adminListPage as $adminListPageVal) {
$this->_db->bind_param_push($arrBind, 's', $adminListPageVal);
 
변경 후AdminLogDAO.php
use Framework\Utility\ArrayUtils;
use Framework\Utility\DateTimeUtils;
use Framework\Utility\StringUtils;
use Origin\Enum\Policy\AccessLogAction;
use Component\Member\MemberMasking;
use Origin\Service\Member\ManagerEditPolicy;
 
// 기존 : 운영자정보 접속기록 탭에 관리자 노출, 공급사는 회원정보 접속기록에 노출
// 변경 : 관리자, 공급사 두개 다 운영자정보 접속기록에 노출되도록 작업
// 관리자에 추가된다면, 공급사도 기획측에 확인해서 추가 필요!
$adminListPage = ['/policy/manage_list.php', '/policy/manage_register.php', '/policy/manage_ps.php', '/policy/manage_permission.php', '/share/layer_manage.php', '/policy/access_log_ps.php'];
$providerListPage = ['/provider/policy/manage_list.php', '/provider/policy/manage_register.php', '/provider/policy/manage_ps.php', '/provider/policy/manage_permission.php', '/provider/share/layer_manage.php'];
 
$adminListPage = array_merge($adminListPage, $providerListPage);
 
if ($request['view'] == 'adminList') {
$where[] = 'a.baseUri IN (?,?,?,?,?,?,?,?,?,?,?)';
} else { //default
$where[] = 'a.baseUri NOT IN (?,?,?,?,?,?,?,?,?,?,?)';
}
foreach($adminListPage as $adminListPageVal) {
$this->_db->bind_param_push($arrBind, 's', $adminListPageVal);
case 'manage_ps.php':
case 'manage_list.php':
case 'layer_manage.php':
case 'access_log_ps.php': // 1:1 문의 접속기록 (대상 관리자 아이디가 남은 경우)
$lVal['data'] = json_decode($lVal['data'], true);
if ($lVal['page'] == 'adminInfo' || empty($lVal['data']['searchData']) === false) {
$data[$lKey]['displayDetailLogFl'] = 'y';
case 'layer_manage.php':
$result['searchTargetMsg'] = '처리 대상 : '. $result['searchData'];
break;
case 'access_log_ps.php':
$result['searchTargetMsg'] = '처리 대상 : '. $result['searchData'];
// 검색어 유무와 관계없이 검색어(...) 형식으로 고정하고, 공통 처리의 ' (키워드)' 조립은 막음
if (($data['data']['POST']['action'] ?? '') === AccessLogAction::SEARCH->value) {
$result['searchConditionMsg'] = '처리조건 : 검색어(' . ($data['data']['GET']['keyword'] ?? '') . ')';
}
$keyword = '';
break;
case 'manage_register.php':
$manager = \App::load('\\Component\\Member\\Manager');
$managerIdArr = $manager->getManagerId($data['data']['GET']['sno']);
// 기존 : 운영자정보 접속기록 탭에 관리자 노출, 공급사는 회원정보 접속기록에 노출
// 변경 : 관리자, 공급사 두개 다 운영자정보 접속기록에 노출되도록 작업
// 관리자에 추가된다면, 공급사도 기획측에 확인해서 추가 필요!
$adminListPage = ['/policy/manage_list.php', '/policy/manage_register.php', '/policy/manage_ps.php', '/policy/manage_permission.php', '/share/layer_manage.php', '/policy/access_log_ps.php'];
$providerListPage = ['/provider/policy/manage_list.php', '/provider/policy/manage_register.php', '/provider/policy/manage_ps.php', '/provider/policy/manage_permission.php', '/provider/share/layer_manage.php'];
 
$adminListPage = array_merge($adminListPage, $providerListPage);
 
$where[] = 'a.baseUri NOT IN (?,?,?,?,?,?,?,?,?,?,?)';
 
foreach($adminListPage as $adminListPageVal) {
$this->_db->bind_param_push($arrBind, 's', $adminListPageVal);
 
Component/Admin/AdminMenu.php+27
변경 전AdminMenu.php
return $menuList[0]['adminMenuNo'];
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* getMainStatisticsAccessMenu
*
 
변경 후AdminMenu.php
return $menuList[0]['adminMenuNo'];
}
 
/**
* 1차 메뉴 코드를 통해 adminMenu 고유 코드를 반환
* getAdminMenuNo() 의 1차 메뉴(adminMenuDepth = 1) 전용 버전
*
* @param string $topMenu 1차 메뉴 코드
* @return string 1차 메뉴의 adminMenuNo
*/
public function getTopAdminMenuNo(string $topMenu): string
{
// 1차 메뉴 코드 및 뎁스 구분
$this->arrWhere[] = 'f.adminMenuCode = ?';
$this->db->bind_param_push($this->arrBind, 's', $topMenu);
$this->arrWhere[] = 'f.adminMenuDepth = ?';
$this->db->bind_param_push($this->arrBind, 'i', 1);
 
$this->db->strField = 'f.adminMenuNo';
$this->db->strWhere = implode(' AND ', $this->arrWhere);
$query = $this->db->query_complete();
$strSQL = 'SELECT ' . array_shift($query) . ' FROM ' . DB_ADMIN_MENU . ' as f ' . gd_implode(' ', $query);
$menuData = $this->db->query_fetch($strSQL, $this->arrBind, false);
unset($this->arrBind);
unset($this->arrWhere);
 
// 조회 결과가 없으면 빈 배열이 반환되므로 반환 타입(string) 보장을 위해 방어
return (string) ($menuData['adminMenuNo'] ?? '');
}
 
/**
* getMainStatisticsAccessMenu
*
 
Controller/Admin/Base/IndexController.php+1-1
변경 전IndexController.php
$this->getView()->setDefine('serviceCalendar', 'base/_index_service_calendar.php'); // 주요 일정
$this->getView()->setDefine('serviceState', 'base/_index_service_state.php'); // 운영 필수 서비스 현황
$this->getView()->setDefine('serviceBoard', 'base/_index_service_board.php'); // 문의 / 답변 관리
$this->getView()->setDefine('growData', 'base/_index_grow_qna.php'); // 그로우 상점 1:1문의
 
$this->setData('svcInfos', $svcInfos);
$this->setData('svcStates', $svcStates);
 
변경 후IndexController.php
$this->getView()->setDefine('serviceCalendar', 'base/_index_service_calendar.php'); // 주요 일정
$this->getView()->setDefine('serviceState', 'base/_index_service_state.php'); // 운영 필수 서비스 현황
$this->getView()->setDefine('serviceBoard', 'base/_index_service_board.php'); // 문의 / 답변 관리
$this->getView()->setDefine('qnaPopup', 'base/_index_qna_layer.php'); // 상점 1:1문의
 
$this->setData('svcInfos', $svcInfos);
$this->setData('svcStates', $svcStates);
 
쇼핑몰 정보 조회 기능 추가
Component/Policy/Policy.php+29
변경 전Policy.php
namespace Bundle\Component\Policy;
 
use App;
 
 
use Component\Display\DisplayConfigAdmin;
use Bundle\Component\Godo\GodoDwServerApi;
use Bundle\Component\PlusShop\Enum\PlusShopConfigs;
use Framework\Debug\Exception\AlertCloseException;
use Globals;
use Logger;
 
use Request;
use UserFilePath;
 
return $this->getStorage()->getDefaultValue($name);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 쇼핑몰명 저장
*
if ($this->setValue('basic.info', $getValue) != true) {
throw new \Exception(__('처리중에 오류가 발생하여 실패되었습니다.'));
}
 
 
}
 
/**
throw new \Exception(__('처리중에 오류가 발생하여 실패되었습니다.'));
}
 
 
 
 
 
 
// 기준몰 저장시 해외몰에 공통정보 저장
if ($mallSno == DEFAULT_MALL_NUMBER) {
$mall = new Mall();
 
변경 후Policy.php
namespace Bundle\Component\Policy;
 
use App;
use DateTime;
use DateTimeZone;
use Component\Display\DisplayConfigAdmin;
use Bundle\Component\Godo\GodoDwServerApi;
use Bundle\Component\PlusShop\Enum\PlusShopConfigs;
use Framework\Debug\Exception\AlertCloseException;
use Globals;
use Logger;
use Origin\Service\Policy\ShopInfoChangedTopicService;
use Request;
use UserFilePath;
 
return $this->getStorage()->getDefaultValue($name);
}
 
/**
* 상점 정보 변경 토픽 발행
*
* @param mixed $basicInfo 저장한 basic.info
* @return void
*/
protected function produceShopInfoChangedTopic(mixed $basicInfo): void
{
// 서비스 생성(ProducerUtils 등) 실패도 저장 실패로 번지지 않게 감싼다
try {
App::getInstance(ShopInfoChangedTopicService::class)->produce(
$basicInfo,
new DateTime('now', new DateTimeZone('Asia/Seoul'))
);
} catch (\Throwable $e) {
Logger::channel('kafka')->error('상점 정보 변경 토픽 발행 실패', ['exception' => $e]);
}
}
 
/**
* 쇼핑몰명 저장
*
if ($this->setValue('basic.info', $getValue) != true) {
throw new \Exception(__('처리중에 오류가 발생하여 실패되었습니다.'));
}
 
$this->produceShopInfoChangedTopic($getValue);
}
 
/**
throw new \Exception(__('처리중에 오류가 발생하여 실패되었습니다.'));
}
 
// 해외몰 정보는 발행 대상이 아니다
if ($mallSno == DEFAULT_MALL_NUMBER) {
$this->produceShopInfoChangedTopic($setValue);
}
 
// 기준몰 저장시 해외몰에 공통정보 저장
if ($mallSno == DEFAULT_MALL_NUMBER) {
$mall = new Mall();
 
토스페이 승인 요청 중복 유입 시 정상 결제가 PG확인요망으로 남는 문제 개선
Controller/Front/Order/OrderEndController.php+1-1
변경 전OrderEndController.php
 
// 결제 실패시의 모드에 따른 처리
$mode = Request::get()->get('mode');
if (in_array($mode, ['pgUserStop', 'pgTimeOver', 'pgDbError', 'pgWaitingCallback'])) {
/** @var OrderEndService $service */
$service = \App::getInstance(OrderEndService::class);
$pgFailReason = $service->failProcess($mode, $orderNo);
 
변경 후OrderEndController.php
 
// 결제 실패시의 모드에 따른 처리
$mode = Request::get()->get('mode');
if (in_array($mode, ['pgUserStop', 'pgTimeOver', 'pgDbError', 'pgWaitingCallback', 'pgPending'])) {
/** @var OrderEndService $service */
$service = \App::getInstance(OrderEndService::class);
$pgFailReason = $service->failProcess($mode, $orderNo);
 
Controller/Mobile/Order/OrderEndController.php+1-1
변경 전OrderEndController.php
 
// 결제 실패시의 모드에 따른 처리
$mode = Request::get()->get('mode');
if (in_array($mode, ['pgUserStop', 'pgTimeOver', 'pgDbError', 'pgWaitingCallback'])) {
/** @var OrderEndService $service */
$service = \App::getInstance(OrderEndService::class);
$pgFailReason = $service->failProcess($mode, $orderNo);
 
변경 후OrderEndController.php
 
// 결제 실패시의 모드에 따른 처리
$mode = Request::get()->get('mode');
if (in_array($mode, ['pgUserStop', 'pgTimeOver', 'pgDbError', 'pgWaitingCallback', 'pgPending'])) {
/** @var OrderEndService $service */
$service = \App::getInstance(OrderEndService::class);
$pgFailReason = $service->failProcess($mode, $orderNo);
 
Service/Order/OrderEndService.php+4
변경 전OrderEndService.php
$pgFailReason = __('결제가 정상적으로 완료되지 않았을 수 있습니다. 잠시 후 자동으로 확인되며, 결제 내역이 없다면 다시 시도해 주세요.');
$this->orderAdmin->setStatusChangePgWaitingCallback($orderNo);
break;
 
 
 
 
default :
$pgFailReason = '';
break;
 
변경 후OrderEndService.php
$pgFailReason = __('결제가 정상적으로 완료되지 않았을 수 있습니다. 잠시 후 자동으로 확인되며, 결제 내역이 없다면 다시 시도해 주세요.');
$this->orderAdmin->setStatusChangePgWaitingCallback($orderNo);
break;
case 'pgPending' :
// 다른 요청이 결제완료(f1→p1)를 선점할 수 있어 f1을 유지해야 하므로 상태를 기록하지 않는다
$pgFailReason = __('결제가 정상적으로 완료되지 않았을 수 있습니다. 잠시 후 자동으로 확인되며, 결제 내역이 없다면 다시 시도해 주세요.');
break;
default :
$pgFailReason = '';
break;
 
중화권 결제 운영사 변경 (올페이 → 선레이트)
Admin/order/order_view.php+4-4
변경 전order_view.php
<?php if ($data['mallSno'] > DEFAULT_MALL_NUMBER) { ?>
<span class="notice-danger" style="font-size:12px;">멀티상점 주문의 경우 PG부분 결제취소가 불가하므로 전체 반품/환불처리만 가능합니다.</span>
<?php } ?>
<?php if(($data['settleKind'] == 'oa' || $data['settleKind'] == 'ou') && empty($data['pgResultCode'])) {?>
<div class="notice-info">올페이 결제 결과를 받지 못한 주문은 1회에 한하여 주문상태 수동 동기화가 가능합니다. <a class="btn-link hand js-allPay-inquiry" href="javascript:;">[주문상태 수동 동기화]</a></div>
<?php } ?>
<?php if($data['orderChannelFl'] == 'naverpay') {?>
<?php if($data['statusMode'] == 'o') {?>
//$("textarea[name='consult[consultMemo]']").val('');
});
 
$('.js-allPay-inquiry').click(function () {
post_with_reload('../order/order_ps.php', {
mode: 'allPayInquiry',
orderNo: '<?=$data['orderNo']?>',
});
});
 
변경 후order_view.php
<?php if ($data['mallSno'] > DEFAULT_MALL_NUMBER) { ?>
<span class="notice-danger" style="font-size:12px;">멀티상점 주문의 경우 PG부분 결제취소가 불가하므로 전체 반품/환불처리만 가능합니다.</span>
<?php } ?>
<?php if(in_array($data['settleKind'], ['oa', 'ot', 'ou'], true) && empty($data['pgResultCode'])) {?>
<div class="notice-info">선레이트 결제 결과를 받지 못한 주문은 1회에 한하여 주문상태 수동 동기화가 가능합니다. <a class="btn-link hand js-sunrate-inquiry" href="javascript:;">[주문상태 수동 동기화]</a></div>
<?php } ?>
<?php if($data['orderChannelFl'] == 'naverpay') {?>
<?php if($data['statusMode'] == 'o') {?>
//$("textarea[name='consult[consultMemo]']").val('');
});
 
$('.js-sunrate-inquiry').click(function () {
post_with_reload('../order/order_ps.php', {
mode: 'sunrateInquiry',
orderNo: '<?=$data['orderNo']?>',
});
});
 
Component/Member/PageAccess.php+6-1
변경 전PageAccess.php
'guest' => 'x',
'intro' => 'x',
],
'allpay/pg_return.php' => [
 
 
 
 
 
'member' => 'x',
'guest' => 'x',
'intro' => 'x',
 
변경 후PageAccess.php
'guest' => 'x',
'intro' => 'x',
],
'sunrate/pg_return.php' => [
'member' => 'x',
'guest' => 'x',
'intro' => 'x',
],
'sunrate/pg_refund_return.php' => [
'member' => 'x',
'guest' => 'x',
'intro' => 'x',
 
Component/Order/OrderSalesStatistics.php+1-1
변경 전OrderSalesStatistics.php
'eb' => '에스크로<br/>(계좌이체)',
'ev' => '에스크로<br/>(가상계좌)',
'oa' => 'ALIPAY',
'ot' => 'TENPAY',
'ou' => 'UNIONPAY',
'mp' => 'PAYPAL',
'mc' => 'VISA / MASTER / JCB / AMEX',
 
변경 후OrderSalesStatistics.php
'eb' => '에스크로<br/>(계좌이체)',
'ev' => '에스크로<br/>(가상계좌)',
'oa' => 'ALIPAY',
'ot' => 'WECHAT PAY',
'ou' => 'UNIONPAY',
'mp' => 'PAYPAL',
'mc' => 'VISA / MASTER / JCB / AMEX',
 
Component/Order/ReOrderCalculation.php+38
변경 전ReOrderCalculation.php
use Framework\Utility\ArrayUtils;
use Framework\Utility\NumberUtils;
use Globals;
 
use Origin\Service\WebHook\OrderWebHookService;
use Origin\Enum\Statistics\Analytics\Order\ClaimType;
use Origin\Service\Statistics\Analytics\Order\ClaimCompleteAnalyticsCollectorService;
if ($orderInfo['settleKind'] === 'gb' && ((int)$getData['info']['completePgPrice'] > 0 || $getData['info']['refundMethod'] === 'PG환불')) {
throw new Exception(__('무통장입금 주문건은 PG환불 수단으로 환불을 진행할 수 없습니다.'));
}
 
 
 
 
 
 
 
 
 
// 환불할 주문상품을 가공하여 사용할 데이터 조합.
$orderRefundInfo = $this->getRefundInfoData($getData['orderNo'], $orderInfo, $getData);
if ($orderInfo['settleKind'] === 'gb' && ((int)$getData['info']['completePgPrice'] > 0 || $getData['info']['refundMethod'] === 'PG환불')) {
throw new Exception(__('무통장입금 주문건은 PG환불 수단으로 환불을 진행할 수 없습니다.'));
}
 
 
 
 
 
 
 
 
 
// *** 1. 데이터 백업
$backupReturn = $this->setBackupOrderOriginalData($getData['orderNo'], 'r');
$this->db->set_update_db_query(DB_MEMBER, $updateSet, $where);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* completeRefundPrice
* 환불 - 현금성 환불에 대한 처리
 
변경 후ReOrderCalculation.php
use Framework\Utility\ArrayUtils;
use Framework\Utility\NumberUtils;
use Globals;
use Origin\Enum\Payment\Sunrate\SunrateCommonCode;
use Origin\Service\WebHook\OrderWebHookService;
use Origin\Enum\Statistics\Analytics\Order\ClaimType;
use Origin\Service\Statistics\Analytics\Order\ClaimCompleteAnalyticsCollectorService;
if ($orderInfo['settleKind'] === 'gb' && ((int)$getData['info']['completePgPrice'] > 0 || $getData['info']['refundMethod'] === 'PG환불')) {
throw new Exception(__('무통장입금 주문건은 PG환불 수단으로 환불을 진행할 수 없습니다.'));
}
// 올페이 결제 주문은 선레이트로 PG 취소할 수 없다 (환불 처리 저장 전에 차단)
if ($orderInfo['pgName'] === SunrateCommonCode::PREV_PG_NAME && ((int)$getData['info']['completePgPrice'] > 0 || $getData['info']['refundMethod'] === 'PG환불')) {
throw new Exception(__(SunrateCommonCode::PREV_PG_REFUND_NOT_SUPPORTED_MESSAGE));
}
// 선레이트는 전체 취소만 지원하므로 부분 PG환불은 환불 처리 저장 전에 차단
if ($this->isSunratePartPgRefund($orderInfo, $getData)) {
throw new Exception(__(SunrateCommonCode::PART_CANCEL_NOT_SUPPORTED_MESSAGE));
}
 
// 환불할 주문상품을 가공하여 사용할 데이터 조합.
$orderRefundInfo = $this->getRefundInfoData($getData['orderNo'], $orderInfo, $getData);
if ($orderInfo['settleKind'] === 'gb' && ((int)$getData['info']['completePgPrice'] > 0 || $getData['info']['refundMethod'] === 'PG환불')) {
throw new Exception(__('무통장입금 주문건은 PG환불 수단으로 환불을 진행할 수 없습니다.'));
}
// 올페이 결제 주문은 선레이트로 PG 취소할 수 없다 (환불 처리 저장 전에 차단)
if ($orderInfo['pgName'] === SunrateCommonCode::PREV_PG_NAME && ((int)$getData['info']['completePgPrice'] > 0 || $getData['info']['refundMethod'] === 'PG환불')) {
throw new Exception(__(SunrateCommonCode::PREV_PG_REFUND_NOT_SUPPORTED_MESSAGE));
}
// 선레이트는 전체 취소만 지원하므로 부분 PG환불은 환불 처리 저장 전에 차단
if ($this->isSunratePartPgRefund($orderInfo, $getData)) {
throw new Exception(__(SunrateCommonCode::PART_CANCEL_NOT_SUPPORTED_MESSAGE));
}
 
// *** 1. 데이터 백업
$backupReturn = $this->setBackupOrderOriginalData($getData['orderNo'], 'r');
$this->db->set_update_db_query(DB_MEMBER, $updateSet, $where);
}
 
/**
* 선레이트 부분 PG환불 여부 (선레이트는 전체 취소만 지원)
*
* PG 취소 모듈(Cancel::sendPgCancel)과 같은 기준(결제 금액 = PG 환불 금액 + 해외배송 보험료)으로 판정한다.
* @param array $orderInfo 주문 정보 (pgName, settlePrice)
* @param array $getData 환불 요청 정보 (info.completePgPrice, info.refundDeliveryInsuranceFee)
* @return bool
*/
protected function isSunratePartPgRefund(array $orderInfo, array $getData): bool
{
if ($orderInfo['pgName'] !== SunrateCommonCode::PG_NAME || (int) $getData['info']['completePgPrice'] <= 0) {
return false;
}
 
$settlePrice = gd_money_format((float) $orderInfo['settlePrice'], false);
$cancelPrice = gd_money_format((float) $getData['info']['completePgPrice'], false);
$deliveryInsuranceFee = $getData['info']['refundDeliveryInsuranceFee'] ?? 0;
 
return intval($settlePrice) !== intval($cancelPrice + floatval($deliveryInsuranceFee));
}
 
/**
* completeRefundPrice
* 환불 - 현금성 환불에 대한 처리
 
Controller/Admin/Order/OrderPsController.php+5-4
변경 전OrderPsController.php
use Framework\Utility\ProducerUtils;
use Framework\Utility\StringUtils;
use Request;
 
 
/**
* 주문 상세 처리 페이지
}
exit();
break;
// 올페이 주문상태 수동 동기화
case 'allPayInquiry':
Request::get()->set('orderNo', Request::post()->get('orderNo'));
Request::get()->set('f4Fl', true);
$pgReturn = \App::load('\\Component\\Payment\\Allpay\\PgReturn');
$orderNo = $pgReturn->setPgResultRecheck();
$orderStatus = $order->getOrderData($orderNo);
if (substr($orderStatus['orderStatus'], 0, 1) == 'f' && $orderStatus['orderStatus'] != 'f3') {
$this->json(__('동기화에 실패하였습니다. 잠시 후 다시 시도하여 주세요. 해당 현상이 계속 되는 경우 고객센터에 문의 바랍니다.'));
 
변경 후OrderPsController.php
use Framework\Utility\ProducerUtils;
use Framework\Utility\StringUtils;
use Request;
use Origin\Service\Payment\Sunrate\PgResultRecheckService;
 
/**
* 주문 상세 처리 페이지
}
exit();
break;
// 선레이트 주문상태 수동 동기화
case 'sunrateInquiry':
Request::get()->set('orderNo', Request::post()->get('orderNo'));
Request::get()->set('f4Fl', true);
$pgResultRecheckService = \App::getInstance(PgResultRecheckService::class);
$orderNo = $pgResultRecheckService->setPgResultRecheck();
$orderStatus = $order->getOrderData($orderNo);
if (substr($orderStatus['orderStatus'], 0, 1) == 'f' && $orderStatus['orderStatus'] != 'f3') {
$this->json(__('동기화에 실패하였습니다. 잠시 후 다시 시도하여 주세요. 해당 현상이 계속 되는 경우 고객센터에 문의 바랍니다.'));
 
Controller/Admin/Policy/SettlePgOverseasConfigController.php+1-1
변경 전SettlePgOverseasConfigController.php
}
 
// 2017-09-29 사이렉스페이 VISA, AMEX 메뉴 숨김처리
if (!gd_in_array($cKey, ['vmcard', 'jacard', 'tenpay', 'paypal'])) {
$setDefaultPgDataOverseasList[$pgKey][$cKey] = $cVal;
}
}
 
변경 후SettlePgOverseasConfigController.php
}
 
// 2017-09-29 사이렉스페이 VISA, AMEX 메뉴 숨김처리
if (!gd_in_array($cKey, ['vmcard', 'jacard', 'wechatpay', 'paypal'])) {
$setDefaultPgDataOverseasList[$pgKey][$cKey] = $cVal;
}
}
 
Repository/Order/OrderHandleRepository.php+15
변경 전OrderHandleRepository.php
->map(fn ($model) => $model->toArray())
->all();
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
변경 후OrderHandleRepository.php
->map(fn ($model) => $model->toArray())
->all();
}
 
/**
* 주문의 처리건 (환불 상태 전환 판단에 필요한 항목만, 환불 계좌 등은 조회하지 않는다)
*
* @param string $orderNo 주문 번호
* @return array 처리건 목록
*/
public function findRefundHandlesByOrderNo(string $orderNo): array
{
return OrderHandle::query()
->select(['sno', 'handleMode', 'handleCompleteFl', 'refundGroupCd', 'refundPrice'])
->where('orderNo', $orderNo)
->get()
->toArray();
}
}
 
카카오 브랜드메시지 도입에 따른 요금제 변경 반영
Admin/crm/message_config.php+1-1
변경 전message_config.php
<ul class="ncua-accordion__content">
<li class="ncua-notice-info">'기본설정 > 기본 정보 설정'에 올바른 쇼핑몰 도메인이 등록되었는지 확인해 주세요.</li>
<li class="ncua-notice-info">발신 프로필키가 발급되고 1시간이 지난 후 발송하세요.</li>
<li class="ncua-notice-info">친구톡 1건당 1.4 포인트가 필요합니다. 메시지 포인트가 충분한지 확인해 주세요.</li>
</ul>
</details>
</section>
 
변경 후message_config.php
<ul class="ncua-accordion__content">
<li class="ncua-notice-info">'기본설정 > 기본 정보 설정'에 올바른 쇼핑몰 도메인이 등록되었는지 확인해 주세요.</li>
<li class="ncua-notice-info">발신 프로필키가 발급되고 1시간이 지난 후 발송하세요.</li>
<li class="ncua-notice-info">친구톡 1건당 <?= $kakaoFriendTalkPoint ?>포인트가 필요합니다. 메시지 포인트가 충분한지 확인해 주세요.</li>
</ul>
</details>
</section>
 
Admin/crm/mobile_send/layer_kakao_friendtalk_content_setting.php+1-1
변경 전layer_kakao_friendtalk_content_setting.php
<th><div>메시지 타입</div></th>
<td>
<div class="ncua-gap-4" id="campaignUnitPoint">
텍스트 (건당 <strong>1.4</strong> 포인트)
</div>
</td>
</tr>
 
변경 후layer_kakao_friendtalk_content_setting.php
<th><div>메시지 타입</div></th>
<td>
<div class="ncua-gap-4" id="campaignUnitPoint">
텍스트 (건당 <strong><?= $defaultCampaignUnitPoint ?></strong> 포인트)
</div>
</td>
</tr>
 
Admin/crm/popup_charge_message_points.php+2-2
변경 전popup_charge_message_points.php
<th><div>SMS<br/>(건당 1포인트)</div></th>
<th><div>LMS<br/>(건당 <?= $lmsPoint ?>포인트)</div></th>
<th><div>알림톡<br/>(건당 <?= $kakaoPoint ?>포인트)</div></th>
<th><div>친구톡<br/>(텍스트 기준 건당 <?= $kakaoFriendTalkPoint ?>포인트)</div></th>
</tr>
</thead>
<tbody>
<li class="ncua-notice-info">메시지 발송에는 메시지 포인트가 필요합니다. (앱푸시는 제외)</li>
<li class="ncua-notice-info">SMS (90byte 이하) 1 포인트 / LMS (90~2000byte) <?= $lmsPoint ?>포인트</li>
<li class="ncua-notice-info">카카오 알림톡 <?= $kakaoPoint ?> 포인트</li>
<li class="ncua-notice-info">카카오 친구톡: 텍스트 형 <?= $kakaoFriendTalkPoint ?> 포인트 / 이미지형·와이드 이미지형 <?= $kakaoFriendTalkImagePoint ?> 포인트 / 와이드 아이템 리스트형·캐러셀형 <?= $kakaoFriendTalkWideItemPoint ?> 포인트</li>
</ul>
</details>
</article>
 
변경 후popup_charge_message_points.php
<th><div>SMS<br/>(건당 1포인트)</div></th>
<th><div>LMS<br/>(건당 <?= $lmsPoint ?>포인트)</div></th>
<th><div>알림톡<br/>(건당 <?= $kakaoPoint ?>포인트)</div></th>
<th><div>친구톡<br/>(건당 <?= $kakaoFriendTalkPoint ?>포인트)</div></th>
</tr>
</thead>
<tbody>
<li class="ncua-notice-info">메시지 발송에는 메시지 포인트가 필요합니다. (앱푸시는 제외)</li>
<li class="ncua-notice-info">SMS (90byte 이하) 1 포인트 / LMS (90~2000byte) <?= $lmsPoint ?>포인트</li>
<li class="ncua-notice-info">카카오 알림톡 <?= $kakaoPoint ?> 포인트</li>
<li class="ncua-notice-info">카카오 친구톡 <?= $kakaoFriendTalkPoint ?> 포인트</li>
</ul>
</details>
</article>
 
Admin/member/sms_charge.php+1-1
변경 전sms_charge.php
<th class="text-center">SMS(건당 1포인트)</th>
<th class="text-center">LMS(건당 <?php echo $lmsPoint;?>포인트)</th>
<th class="text-center">알림톡(건당 <?php echo $kakaoPoint;?>포인트)</th>
<th class="text-center">친구톡(텍스트 기준 건당 <?php echo $kakaoFriendTalkPoint;?>포인트)</th>
</tr>
</thead>
<tbody>
 
변경 후sms_charge.php
<th class="text-center">SMS(건당 1포인트)</th>
<th class="text-center">LMS(건당 <?php echo $lmsPoint;?>포인트)</th>
<th class="text-center">알림톡(건당 <?php echo $kakaoPoint;?>포인트)</th>
<th class="text-center">친구톡(건당 <?php echo $kakaoFriendTalkPoint;?>포인트)</th>
</tr>
</thead>
<tbody>
 
네이버페이 개인통관고유부호 정책 대응
Admin/order/order_view.php+10-1
변경 전order_view.php
<div class="table-title gd-help-manual">추가 정보</div>
<table class="table table-cols">
<?php if($naverpayIndividualCustomUniqueCode) {?>
 
<tr>
<th>개인통관 고유번호(네이버)</th>
</tr>
<tr>
<td><?=$naverpayIndividualCustomUniqueCode?></td>
</tr>
 
 
 
 
 
 
 
 
<?php }?>
<?php if($paycoIndividualCustomUniqNo) {?>
<tr>
 
변경 후order_view.php
<div class="table-title gd-help-manual">추가 정보</div>
<table class="table table-cols">
<?php if($naverpayIndividualCustomUniqueCode) {?>
<?php if (empty($naverpayOneTimeCertificationNo)) { ?>
<tr>
<th>개인통관 고유번호(네이버)</th>
</tr>
<tr>
<td><?= gd_htmlspecialchars($naverpayIndividualCustomUniqueCode) ?></td>
</tr>
<?php } else { ?>
<tr>
<th>개인통관 고유번호/인증번호(네이버)</th>
</tr>
<tr>
<td><?= gd_htmlspecialchars($naverpayIndividualCustomUniqueCode) ?>/<?= gd_htmlspecialchars($naverpayOneTimeCertificationNo) ?></td>
</tr>
<?php } ?>
<?php }?>
<?php if($paycoIndividualCustomUniqNo) {?>
<tr>
 
Component/Excel/ExcelRequest.php+16-2
변경 전ExcelRequest.php
if ($val['orderChannelFl'] == 'naverpay') {
$checkoutData = json_decode($val['checkoutData'], true);
if (empty($checkoutData['orderGoodsData']['IndividualCustomUniqueCode']) === false) {
$excelAddField[] = "<td> 개인통관 고유번호(네이버) : " . $checkoutData['orderGoodsData']['IndividualCustomUniqueCode'] . "</td>";
 
 
 
 
 
 
 
}
}
if ($val['orderChannelFl'] == 'payco') {
if ($val['orderChannelFl'] == 'naverpay') {
$checkoutData = json_decode($val['checkoutData'], true);
if (empty($checkoutData['orderGoodsData']['IndividualCustomUniqueCode']) === false) {
$excelAddField[] = "<td> 개인통관 고유번호(네이버) : " . $checkoutData['orderGoodsData']['IndividualCustomUniqueCode'] . "</td>";
 
 
 
 
 
 
 
}
}
if ($val['orderChannelFl'] == 'payco') {
 
변경 후ExcelRequest.php
if ($val['orderChannelFl'] == 'naverpay') {
$checkoutData = json_decode($val['checkoutData'], true);
if (empty($checkoutData['orderGoodsData']['IndividualCustomUniqueCode']) === false) {
$oneTimeCertificationNo = isset($checkoutData['orderGoodsData']['OneTimeCertificationNo']) ? $checkoutData['orderGoodsData']['OneTimeCertificationNo'] : null;
$customsCodeLabel = '개인통관 고유번호';
$customsCodeValue = gd_htmlspecialchars($checkoutData['orderGoodsData']['IndividualCustomUniqueCode']);
if (!empty($oneTimeCertificationNo)) {
$customsCodeLabel .= '/인증번호';
$customsCodeValue .= '/' . gd_htmlspecialchars($oneTimeCertificationNo);
}
$excelAddField[] = "<td> {$customsCodeLabel}(네이버) : {$customsCodeValue}</td>";
}
}
if ($val['orderChannelFl'] == 'payco') {
if ($val['orderChannelFl'] == 'naverpay') {
$checkoutData = json_decode($val['checkoutData'], true);
if (empty($checkoutData['orderGoodsData']['IndividualCustomUniqueCode']) === false) {
$oneTimeCertificationNo = isset($checkoutData['orderGoodsData']['OneTimeCertificationNo']) ? $checkoutData['orderGoodsData']['OneTimeCertificationNo'] : null;
$customsCodeLabel = '개인통관 고유번호';
$customsCodeValue = gd_htmlspecialchars($checkoutData['orderGoodsData']['IndividualCustomUniqueCode']);
if (!empty($oneTimeCertificationNo)) {
$customsCodeLabel .= '/인증번호';
$customsCodeValue .= '/' . gd_htmlspecialchars($oneTimeCertificationNo);
}
$excelAddField[] = "<td> {$customsCodeLabel}(네이버) : {$customsCodeValue}</td>";
}
}
if ($val['orderChannelFl'] == 'payco') {
 
Controller/Admin/Order/OrderViewController.php+9-1
변경 전OrderViewController.php
$claimSort = ['cancel' => 1, 'exchange' => 2, 'back' => 3, 'refund' => 4, 'none' => 9];
//@formatter:on
$naverpayIndividualCustomUniqueCode = null; //네이버페이 개인통관 고유번호
 
 
$syncNaverpayApiOrderNo = false; //네이버페이 주문번호 동기화여부
if ($data['orderChannelFl'] == 'naverpay' && empty($data['apiOrderNo']) === false) {
foreach ($sVal as $dKey => $dVal) {
foreach ($dVal as $key => $val) {
if ($val['orderChannelFl'] == 'naverpay') {
$naverpayIndividualCustomUniqueCode = $naverpayIndividualCustomUniqueCode ? $naverpayIndividualCustomUniqueCode : $val['checkoutData']['orderGoodsData']['IndividualCustomUniqueCode'];
 
 
 
 
if (!empty($val['checkoutData']['orderGoodsData']['ShippingMemo'])) {
$naverPayMemo[] = [
'optionName'=>$val['checkoutData']['orderGoodsData']['ProductOption'],
 
if($naverpayIndividualCustomUniqueCode) {
$this->setData('naverpayIndividualCustomUniqueCode', $naverpayIndividualCustomUniqueCode);
 
 
 
}
 
$paycoData = empty($data['fintechData']) === false ? 'fintechData' : 'checkoutData';
 
변경 후OrderViewController.php
$claimSort = ['cancel' => 1, 'exchange' => 2, 'back' => 3, 'refund' => 4, 'none' => 9];
//@formatter:on
$naverpayIndividualCustomUniqueCode = null; //네이버페이 개인통관 고유번호
$naverpayOneTimeCertificationNo = null;
 
$syncNaverpayApiOrderNo = false; //네이버페이 주문번호 동기화여부
if ($data['orderChannelFl'] == 'naverpay' && empty($data['apiOrderNo']) === false) {
foreach ($sVal as $dKey => $dVal) {
foreach ($dVal as $key => $val) {
if ($val['orderChannelFl'] == 'naverpay') {
// 인증번호는 부호와 짝이므로 부호를 가져온 주문상품 행에서만 함께 가져온다
if (empty($naverpayIndividualCustomUniqueCode) && !empty($val['checkoutData']['orderGoodsData']['IndividualCustomUniqueCode'])) {
$naverpayIndividualCustomUniqueCode = $val['checkoutData']['orderGoodsData']['IndividualCustomUniqueCode'];
$naverpayOneTimeCertificationNo = isset($val['checkoutData']['orderGoodsData']['OneTimeCertificationNo']) ? $val['checkoutData']['orderGoodsData']['OneTimeCertificationNo'] : null;
}
if (!empty($val['checkoutData']['orderGoodsData']['ShippingMemo'])) {
$naverPayMemo[] = [
'optionName'=>$val['checkoutData']['orderGoodsData']['ProductOption'],
 
if($naverpayIndividualCustomUniqueCode) {
$this->setData('naverpayIndividualCustomUniqueCode', $naverpayIndividualCustomUniqueCode);
if (!empty($naverpayOneTimeCertificationNo)) {
$this->setData('naverpayOneTimeCertificationNo', $naverpayOneTimeCertificationNo);
}
}
 
$paycoData = empty($data['fintechData']) === false ? 'fintechData' : 'checkoutData';