본문으로 건너뛰기

소스 변경 전체 보기

PHP 8 · GODO25
변경 파일 수: 67개
변경 파일 목록
67
개발소스관리 스테이징 환경 개선 및 배포 검증 강화
header_myapp.phpAdmin/header.phpAdmin/head.phpAdmin/layout_dev_source.phpAdmin/
사업자 회원의 사업자등록증 추가서류 등록 기능이 개선되었어요.
layer_company_certification_setting.phpAdmin/member/member_joinitem.phpAdmin/member/_member_view_business.phpAdmin/member/CompanyCertification.phpComponent/Member/Company/MemberAdmin.phpComponent/Member/MemberDAO.phpComponent/Member/Member.phpComponent/Member/MemberVO.phpComponent/Member/MyPage.phpComponent/Member/JoinItemPolicy.phpComponent/Policy/CompanyCertificationPsController.phpController/Admin/Member/LayerCompanyCertificationSettingController.phpController/Admin/Member/MemberJoinitemController.phpController/Admin/Member/MemberModifyController.phpController/Admin/Member/MemberRegisterController.phpController/Admin/Member/MemberCrmDetailController.phpController/Admin/Share/JoinController.phpController/Front/Member/MyPageController.phpController/Front/Mypage/JoinController.phpController/Mobile/Member/CompanyCertificationInsertDTO.phpDTO/Member/DocumentType.phpEnum/Member/Company/CompanyCertificationRepository.phpRepository/Member/gd_member2.jsdata/skin/front/moment/js/_join_view_business.htmldata/skin/front/moment/member/gd_member2.jsdata/skin/front/mygreek/js/_join_view_business.htmldata/skin/front/mygreek/member/member.cssdata/skin/mobile/moment/css/member/gd_member2.jsdata/skin/mobile/moment/js/_join_view_business.htmldata/skin/mobile/moment/member/my_page.htmldata/skin/mobile/moment/mypage/member.cssdata/skin/mobile/mygreek/css/member/gd_member2.jsdata/skin/mobile/mygreek/js/_join_view_business.htmldata/skin/mobile/mygreek/member/my_page.htmldata/skin/mobile/mygreek/mypage/
관리자 내 마케팅 콘텐츠 노출 영역 신설
index.phpAdmin/base/AdminPanelApiController.phpController/Admin/Share/
상품 리스트, 기획전, 플러스리뷰 페이지 보안 강화
Goods.phpComponent/Goods/EventSaleConfigController.phpController/Admin/Promotion/
Payco ID 로그인 사용 시 회원가입 항목 설정의 부가정보가 정상적으로 표시되도록 개선되었어요.
PaycoLoginConfigController.phpController/Admin/Member/
공통 헤더 스크롤 동작 안정화
scm_regist.phpAdmin/scm/
CRM 반복그룹 이메일 발송이 개선되었어요.
mail_send.phpAdmin/member/MailAdmin.phpComponent/Mail/
사은품 지급 수량 최대값 확대 (127 → 10,000개)
gift_present_register.phpAdmin/goods/
주문 카운트 토픽 발행 안정성 강화
OrderNew.phpComponent/Order/Order.phpComponent/Order/
SMS 발송 관련 로그 처리 최적화
SmsAuto.phpComponent/Sms/
외부 저장소 게시판에서 파일 미첨부 시 글 등록 개선
BoardUtil.phpComponent/Board/
바로구매 후 로그인 과정의 구매 진행 안내 개선
PageAccess.phpComponent/Member/
결제 취소 시 결제 진행 상태 안정적으로 정리
OrderAdminNew.phpComponent/Order/OrderNew.phpComponent/Order/
취소복원 시 재고 부족으로 복원이 보류되면 마일리지도 함께 보류되도록 개선
ReOrderCalculation.phpComponent/Order/
주문 다운로드 엑셀에 '배송번호' 항목 추가 및 '배송비코드' 명칭 변경
ExcelForm.phpComponent/Excel/ExcelRequest.phpComponent/Excel/OrderAdminGrid.phpComponent/Order/
변경 파일 코드
추가삭제
개발소스관리 스테이징 환경 개선 및 배포 검증 강화
Admin/header_myapp.php+2-2
변경 전header_myapp.php
if (Session::get('manager.workPermissionFl') == 'y') {
?>
<li class="devide"></li>
<li class="admin"><a href="javascript:dev_source_manager();" class="font dev-source-gnb-highlight">개발소스관리</a></li>
<?php
} else if (Globals::get('gLicense.shopWorkLimited') === true) {
?>
if (Session::get('manager.workPermissionFl') == 'y') {
?>
<li class="devide"></li>
<li class="admin"><a href="javascript:dev_source_manager();" class="font dev-source-gnb-highlight">개발소스관리</a></li>
<?php
} else if (Globals::get('gLicense.shopWorkLimited') === true) {
?>
 
변경 후header_myapp.php
if (Session::get('manager.workPermissionFl') == 'y') {
?>
<li class="devide"></li>
<li class="admin"><a href="javascript:dev_source_manager();" class="font" style="!important; font-weight:bold;">개발소스관리</a></li>
<?php
} else if (Globals::get('gLicense.shopWorkLimited') === true) {
?>
if (Session::get('manager.workPermissionFl') == 'y') {
?>
<li class="devide"></li>
<li class="admin"><a href="javascript:dev_source_manager();" class="font" style="!important; font-weight:bold;">개발소스관리</a></li>
<?php
} else if (Globals::get('gLicense.shopWorkLimited') === true) {
?>
 
Admin/header.php+2-4
변경 전header.php
* @author Shin Donggyu <artherot@godo.co.kr>
*/
?>
<link rel="stylesheet" href="<?= PATH_ADMIN_GD_SHARE ?>css/dev_source.css">
<nav class="navbar">
<div class="container">
<div class="navbar-inner">
if (Session::get('manager.workPermissionFl') == 'y') {
?>
<li class="devide"></li>
<li class="admin"><a href="javascript:dev_source_manager('customizingInfo.php');" class="font dev-source-gnb-highlight"><img src="<?= PATH_ADMIN_GD_SHARE ?>img/icon_new.png" width="14" style="margin-right:3px;">개발소스관리</a></li>
<li class="devide"></li>
<li class="admin"><a href="javascript:cache_manager();" class="font">속도개선관리</a></li>
<?php
* @author Shin Donggyu <artherot@godo.co.kr>
*/
?>
<link rel="stylesheet" href="<?= PATH_ADMIN_GD_SHARE ?>css/dev_source.css">
<nav class="navbar">
<div class="container">
<div class="navbar-inner">
if (Session::get('manager.workPermissionFl') == 'y') {
?>
<li class="devide"></li>
<li class="admin"><a href="javascript:dev_source_manager('customizingInfo.php');" class="font dev-source-gnb-highlight"><img src="<?= PATH_ADMIN_GD_SHARE ?>img/icon_new.png" width="14" style="margin-right:3px;">개발소스관리</a></li>
<li class="devide"></li>
<li class="admin"><a href="javascript:cache_manager();" class="font">속도개선관리</a></li>
<?php
 
변경 후header.php
* @author Shin Donggyu <artherot@godo.co.kr>
*/
?>
 
<nav class="navbar">
<div class="container">
<div class="navbar-inner">
if (Session::get('manager.workPermissionFl') == 'y') {
?>
<li class="devide"></li>
<li class="admin"><a href="javascript:dev_source_manager('customizingInfo.php');" class="font" style="!important; font-weight:bold;"><img src="<?= PATH_ADMIN_GD_SHARE ?>img/icon_new.png" width="14" style="margin-right:3px;">개발소스관리</a></li>
<li class="devide"></li>
<li class="admin"><a href="javascript:cache_manager();" class="font">속도개선관리</a></li>
<?php
* @author Shin Donggyu <artherot@godo.co.kr>
*/
?>
 
<nav class="navbar">
<div class="container">
<div class="navbar-inner">
if (Session::get('manager.workPermissionFl') == 'y') {
?>
<li class="devide"></li>
<li class="admin"><a href="javascript:dev_source_manager('customizingInfo.php');" class="font" style="!important; font-weight:bold;"><img src="<?= PATH_ADMIN_GD_SHARE ?>img/icon_new.png" width="14" style="margin-right:3px;">개발소스관리</a></li>
<li class="devide"></li>
<li class="admin"><a href="javascript:cache_manager();" class="font">속도개선관리</a></li>
<?php
 
Admin/head.php-10
변경 전head.php
} ?>
<link type="text/css" href="<?=gd_set_browser_cache(PATH_ADMIN_GD_SHARE . 'css/gd5-style.css')?>" rel="stylesheet"/>
<link type="text/css" href="<?=gd_set_browser_cache(PATH_ADMIN_SKIN . 'css/admin-custom.css')?>" rel="stylesheet"/>
<!-- 컴포넌트 업데이트 되면 버전 변경이 있을 수 있습니다. -->
<link type="text/css" href="https://fe-sdk.cdn-nhncommerce.com/@ncds/ui-admin/1.5/main.min.css" rel="stylesheet"/>
<link type="text/css" href="<?=gd_set_browser_cache(PATH_ADMIN_GD_SHARE . 'ncds/css/style.css')?>" rel="stylesheet"/>
 
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
}
} ?>
<script type="text/javascript" src="<?=gd_set_browser_cache(PATH_ADMIN_SKIN . 'script/admin-custom.js')?>"></script>
<script type="text/javascript" src="https://fe-sdk.cdn-nhncommerce.com/@ncds/ui-admin/1.5/main.min.js"></script>
 
<script type="text/javascript">
<!--
} ?>
<link type="text/css" href="<?=gd_set_browser_cache(PATH_ADMIN_GD_SHARE . 'css/gd5-style.css')?>" rel="stylesheet"/>
<link type="text/css" href="<?=gd_set_browser_cache(PATH_ADMIN_SKIN . 'css/admin-custom.css')?>" rel="stylesheet"/>
<!-- 컴포넌트 업데이트 되면 버전 변경이 있을 수 있습니다. -->
<link type="text/css" href="https://fe-sdk.cdn-nhncommerce.com/@ncds/ui-admin/1.5/main.min.css" rel="stylesheet"/>
<link type="text/css" href="<?=gd_set_browser_cache(PATH_ADMIN_GD_SHARE . 'ncds/css/style.css')?>" rel="stylesheet"/>
 
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
}
} ?>
<script type="text/javascript" src="<?=gd_set_browser_cache(PATH_ADMIN_SKIN . 'script/admin-custom.js')?>"></script>
<script type="text/javascript" src="https://fe-sdk.cdn-nhncommerce.com/@ncds/ui-admin/1.5/main.min.js"></script>
 
<script type="text/javascript">
<!--
 
변경 후head.php
} ?>
<link type="text/css" href="<?=gd_set_browser_cache(PATH_ADMIN_GD_SHARE . 'css/gd5-style.css')?>" rel="stylesheet"/>
<link type="text/css" href="<?=gd_set_browser_cache(PATH_ADMIN_SKIN . 'css/admin-custom.css')?>" rel="stylesheet"/>
 
 
 
 
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
}
} ?>
<script type="text/javascript" src="<?=gd_set_browser_cache(PATH_ADMIN_SKIN . 'script/admin-custom.js')?>"></script>
 
 
<script type="text/javascript">
<!--
} ?>
<link type="text/css" href="<?=gd_set_browser_cache(PATH_ADMIN_GD_SHARE . 'css/gd5-style.css')?>" rel="stylesheet"/>
<link type="text/css" href="<?=gd_set_browser_cache(PATH_ADMIN_SKIN . 'css/admin-custom.css')?>" rel="stylesheet"/>
 
 
 
 
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
}
} ?>
<script type="text/javascript" src="<?=gd_set_browser_cache(PATH_ADMIN_SKIN . 'script/admin-custom.js')?>"></script>
 
 
<script type="text/javascript">
<!--
 
Admin/layout_dev_source.php+10
변경 전layout_dev_source.php
 
include UserFilePath::adminSkin('head.php');
?>
 
 
 
 
 
<style type="text/css">
.staging-top-banner {
background: var(--orange-50, #fefaf5);
 
include UserFilePath::adminSkin('head.php');
?>
 
 
 
 
 
<style type="text/css">
.staging-top-banner {
background: var(--orange-50, #fefaf5);
 
변경 후layout_dev_source.php
 
include UserFilePath::adminSkin('head.php');
?>
<!-- 컴포넌트 업데이트 되면 버전 변경이 있을 수 있습니다. -->
<link type="text/css" href="https://fe-sdk.cdn-nhncommerce.com/@ncds/ui-admin/1.5/main.min.css" rel="stylesheet"/>
<link type="text/css" href="<?=gd_set_browser_cache(PATH_ADMIN_GD_SHARE . 'ncds/css/style.css')?>" rel="stylesheet"/>
<!-- 개발소스관리 전용 공통 스타일(디자인 QA §1) — 이 레이아웃에서만 로드하여 다른 관리자 페이지(GNB/LNB)에 영향을 주지 않도록 스코핑 -->
<link type="text/css" href="<?=gd_set_browser_cache(PATH_ADMIN_GD_SHARE . 'ncds/css/development/dev-source-common.css')?>" rel="stylesheet"/>
<style type="text/css">
.staging-top-banner {
background: var(--orange-50, #fefaf5);
 
include UserFilePath::adminSkin('head.php');
?>
<!-- 컴포넌트 업데이트 되면 버전 변경이 있을 수 있습니다. -->
<link type="text/css" href="https://fe-sdk.cdn-nhncommerce.com/@ncds/ui-admin/1.5/main.min.css" rel="stylesheet"/>
<link type="text/css" href="<?=gd_set_browser_cache(PATH_ADMIN_GD_SHARE . 'ncds/css/style.css')?>" rel="stylesheet"/>
<!-- 개발소스관리 전용 공통 스타일(디자인 QA §1) — 이 레이아웃에서만 로드하여 다른 관리자 페이지(GNB/LNB)에 영향을 주지 않도록 스코핑 -->
<link type="text/css" href="<?=gd_set_browser_cache(PATH_ADMIN_GD_SHARE . 'ncds/css/development/dev-source-common.css')?>" rel="stylesheet"/>
<style type="text/css">
.staging-top-banner {
background: var(--orange-50, #fefaf5);
 
사업자 회원의 사업자등록증 추가서류 등록 기능이 개선되었어요.
Admin/member/layer_company_certification_setting.php+30-4
변경 전layer_company_certification_setting.php
}
 
// 부모 폼의 certificationFileSize 값 입력
window.parent.$('#certificationFileSize').val(inputSize);
 
 
 
 
 
 
 
 
 
 
$.ajax({
url: '../member/company_certification_ps.php',
type: 'POST',
data: { mode: 'setting', fileSize: inputSize },
 
 
 
 
success: function(res) {
if(res.result) {
dialog_alert('설정이 저장되었습니다.');
}
 
// 부모 폼의 certificationFileSize 값 입력
window.parent.$('#certificationFileSize').val(inputSize);
 
 
 
 
 
 
 
 
 
 
$.ajax({
url: '../member/company_certification_ps.php',
type: 'POST',
data: { mode: 'setting', fileSize: inputSize },
 
 
 
 
success: function(res) {
if(res.result) {
dialog_alert('설정이 저장되었습니다.');
 
변경 후layer_company_certification_setting.php
}
 
// 부모 폼의 certificationFileSize 값 입력
var key = '<?= $key ?>';
var matched = key.match(/^comAddiCert(\d+)$/);
if (matched) {
// 추가 첨부 항목인 경우: comAddiCert[index][certificationFileSize] 변경
var index = matched[1];
$('input[name="comAddiCert[' + index + '][certificationFileSize]"]', window.parent.document).val(inputSize);
} else {
// 사업자등록증인 경우
$('#certificationFileSize', window.parent.document).val(inputSize);
}
 
$.ajax({
url: '../member/company_certification_ps.php',
type: 'POST',
data: {
mode: 'setting',
fileSize: inputSize,
key : '<?= $key ?>'
},
success: function(res) {
if(res.result) {
dialog_alert('설정이 저장되었습니다.');
}
 
// 부모 폼의 certificationFileSize 값 입력
var key = '<?= $key ?>';
var matched = key.match(/^comAddiCert(\d+)$/);
if (matched) {
// 추가 첨부 항목인 경우: comAddiCert[index][certificationFileSize] 변경
var index = matched[1];
$('input[name="comAddiCert[' + index + '][certificationFileSize]"]', window.parent.document).val(inputSize);
} else {
// 사업자등록증인 경우
$('#certificationFileSize', window.parent.document).val(inputSize);
}
 
$.ajax({
url: '../member/company_certification_ps.php',
type: 'POST',
data: {
mode: 'setting',
fileSize: inputSize,
key : '<?= $key ?>'
},
success: function(res) {
if(res.result) {
dialog_alert('설정이 저장되었습니다.');
 
Admin/member/member_joinitem.php+308-8
변경 전member_joinitem.php
<table class="table table-cols div-business">
<colgroup>
<col class="width-md"/>
<col class="width-xl"/>
<col/>
<col class="width-xs center"/>
</colgroup>
<tr>
<th rowspan="7">사업자회원</th>
<td class="business">
<label class="checkbox-inline" title="사용여부를 선택해주세요!">
<input type="checkbox" name="company[use]" class="defaultBusinessInfoUse" value="y"/>
필수
</label>
)
<input type="hidden" name="certificationFileSize" id="certificationFileSize" value="<?= $data['comCertification']['maxSize']?>"/>
<button type="button" class="comCertificationSetting btn btn-gray btn-sm">설정</button>
</td>
<td></td>
</tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</table>
<?php } ?>
 
return pass;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$(document).ready(function () {
// 아이디 자리수 체크
$('input[name*="memId"]:text').on('blur', function() {
able_rquire.call(this);
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// 사업자회원 활성화
var $businessinfo = $('input[name=\'businessinfo[use]\']');
var $defaultBusinessInfoUse = $('.defaultBusinessInfoUse');
// 가입항목추가 버튼
$('.addfield').on('click', add_field);
 
 
 
 
 
 
// 가입항목추가필드 삭제
$('.delfield').one('click', function () {
$(this).parents('tr').remove();
});
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$('#frmSetup').validate({
submitHandler: function (form) {
if (minMaxRangeValidation('memId') && minMaxRangeValidation('nickNm') && extraValidation()) {
form.submit();
}
return false;
$('.setup_field', obj).on('click', call_setup_field);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 가입항목추가필드 설정창 호출
*/
}
}
 
 
 
 
 
 
 
 
 
 
 
/**
* 사업자회원 활성화
*/
<table class="table table-cols div-business">
<colgroup>
<col class="width-md"/>
<col class="width-xl"/>
<col/>
<col class="width-xs center"/>
</colgroup>
<tr>
<th rowspan="7">사업자회원</th>
<td class="business">
<label class="checkbox-inline" title="사용여부를 선택해주세요!">
<input type="checkbox" name="company[use]" class="defaultBusinessInfoUse" value="y"/>
필수
</label>
)
<input type="hidden" name="certificationFileSize" id="certificationFileSize" value="<?= $data['comCertification']['maxSize']?>"/>
<button type="button" class="comCertificationSetting btn btn-gray btn-sm">설정</button>
</td>
<td></td>
</tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</table>
<?php } ?>
 
return pass;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$(document).ready(function () {
// 아이디 자리수 체크
$('input[name*="memId"]:text').on('blur', function() {
able_rquire.call(this);
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// 사업자회원 활성화
var $businessinfo = $('input[name=\'businessinfo[use]\']');
var $defaultBusinessInfoUse = $('.defaultBusinessInfoUse');
// 가입항목추가 버튼
$('.addfield').on('click', add_field);
 
 
 
 
 
 
// 가입항목추가필드 삭제
$('.delfield').one('click', function () {
$(this).parents('tr').remove();
});
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$('#frmSetup').validate({
submitHandler: function (form) {
if (minMaxRangeValidation('memId') && minMaxRangeValidation('nickNm') && extraValidation()) {
form.submit();
}
return false;
$('.setup_field', obj).on('click', call_setup_field);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 가입항목추가필드 설정창 호출
*/
}
}
 
 
 
 
 
 
 
 
 
 
 
/**
* 사업자회원 활성화
*/
 
변경 후member_joinitem.php
<table class="table table-cols div-business">
<colgroup>
<col class="width-md"/>
<col class="width-h2xl"/>
<col/>
<col class="width-xs center"/>
</colgroup>
<tr>
<th rowspan="12">사업자회원</th>
<td class="business">
<label class="checkbox-inline" title="사용여부를 선택해주세요!">
<input type="checkbox" name="company[use]" class="defaultBusinessInfoUse" value="y"/>
필수
</label>
)
<input type="hidden" name="certificationFileSize" id="certificationFileSize" value="<?= $data['comCertification']['maxSize'] ?>"/>
<button type="button" class="comCertificationSetting btn btn-gray btn-sm">설정</button>
</td>
<td></td>
</tr>
<?php
for ($i = 0; $i < $certificationAdditionalFileCount; $i++) {
// 초기값이 없는 경우에도 첫 번째 row(추가 버튼 보유)는 강제 렌더링
if ($i !== 0 && !isset($data["comAddiCert$i"])) {
continue;
}
$additionalData = $data["comAddiCert$i"] ?? [];
?>
<tr>
<td class="business">
<label class="checkbox-inline" title="사용여부를 선택해주세요!">
<input type="checkbox" name="comAddiCert[<?= $i ?>][use]" value="y" <?= (($additionalData['use'] ?? '') == 'y') ? 'checked' : '' ?>/>
</label>
<span class="checkbox-inline width40p">
<input type="text" name="comAddiCert[<?= $i ?>][name]" placeholder="추가 첨부 항목명" class="form-control width100p" value="<?= $additionalData['name'] ?? '' ?>" data-initial-value="<?= $additionalData['name'] ?? '' ?>"/>
</span>
(
<label class="checkbox-inline" title="필수 사용여부를 선택해주세요!">
<input value="y" name="comAddiCert[<?= $i ?>][require]" type="checkbox" <?= !empty($additionalData['require']) ? 'checked' : '' ?> />
필수
</label>
)
<input type="hidden" name="comAddiCert[<?= $i ?>][certificationFileSize]" value="<?= $additionalData['certificationFileSize'] ?? $defaultCertificationFileSize ?>">
<button type="button" class="comAddfieldSetting btn btn-gray btn-sm">설정</button>
</td>
<td></td>
<td>
<?php if ($i === 0) { ?>
<a class="businessAddfiled btn btn-white btn-icon-plus btn-sm">추가</a>
<?php } else { ?>
<a class="businessDelField btn btn-white btn-icon-minus btn-sm">삭제</a>
<?php } ?>
</td>
</tr>
<?php
} ?>
</table>
<?php } ?>
 
return pass;
}
 
/**
* 추가 첨부 항목 use 체크 시 항목명 입력 여부 검증
*/
function comAddiCertValidation() {
var pass = true;
$('input[name^="comAddiCert"][name$="[use]"]').each(function () {
if ($(this).prop('checked') !== true) {
return true;
}
var $tr = $(this).closest('tr');
var $nameInput = $tr.find('input[name^="comAddiCert"][name$="[name]"]');
var nameValue = ($nameInput.val() || '').replace(/^\s+|\s+$/g, '');
if (nameValue === '') {
BootstrapDialog.alert({
title: "경고",
message: "추가 첨부의 항목명을 입력해주세요."
});
$nameInput.focus();
pass = false;
return false;
}
});
return pass;
}
 
$(document).ready(function () {
// 아이디 자리수 체크
$('input[name*="memId"]:text').on('blur', function() {
able_rquire.call(this);
});
 
// 추가 첨부 항목: comAddiCert[N][use]에 따라 같은 row의 comAddiCert[N][require] 활성/비활성
$('#frmSetup').on('click', 'input[name^="comAddiCert"][name$="[use]"]', able_com_add_file_require);
$('#frmSetup input[name^="comAddiCert"][name$="[use]"]').each(able_com_add_file_require);
 
// 추가 첨부 항목명 변경 시 확인 모달 (기존 등록값이 있을 때만)
$('#frmSetup').on('change', 'input[name^="comAddiCert"][name$="[name]"]', function () {
var $target = $(this);
var initialValue = $target.attr('data-initial-value') || '';
var currentValue = $target.val();
 
if (initialValue !== '' && initialValue !== currentValue) {
BootstrapDialog.confirm({
title: "확인",
message: "이미 사용중인 추가 첨부 항목을 변경하시겠습니까? 사용중인 항목이 변경될 경우, 기존 등록된 회원정보 내 항목도 변경됩니다.",
btnCancelLabel: "취소",
btnOkLabel: "변경",
callback: function (result) {
if (!result) {
$target.val(initialValue);
}
}
});
}
});
 
// 사업자회원 활성화
var $businessinfo = $('input[name=\'businessinfo[use]\']');
var $defaultBusinessInfoUse = $('.defaultBusinessInfoUse');
// 가입항목추가 버튼
$('.addfield').on('click', add_field);
 
$('.businessAddfiled').on('click', business_add_field)
$('.businessDelField').one('click', function () {
$(this).parents('tr').remove();
});
 
// 가입항목추가필드 삭제
$('.delfield').one('click', function () {
$(this).parents('tr').remove();
});
});
 
// 추가 첨부 항목 설정 버튼 (동적으로 추가된 row까지 처리되도록 이벤트 위임 사용)
$('#frmSetup').on('click', '.comAddfieldSetting', function () {
var $tr = $(this).closest('tr');
var nameValue = $tr.find('input[name^="comAddiCert"][name$="[name]"]').val();
var title = (nameValue ? nameValue + ' ' : '') + '추가 설정';
// 부모 row의 comAddiCert[N][use] name에서 인덱스 추출
var useName = $tr.find('input[name^="comAddiCert"][name$="[use]"]').attr('name') || '';
var matched = useName.match(/comAddiCert\[(\d+)\]/);
var rowIndex = matched ? matched[1] : 0;
$.get('layer_company_certification_setting.php?type=comAddiCert&index=' + rowIndex, function (data) {
layer_popup(data, title, 'normal');
});
});
 
$('#frmSetup').validate({
submitHandler: function (form) {
if (minMaxRangeValidation('memId') && minMaxRangeValidation('nickNm') && extraValidation() && comAddiCertValidation()) {
form.submit();
}
return false;
$('.setup_field', obj).on('click', call_setup_field);
}
 
function business_add_field(e) {
if ($('.businessDelField').length >= <?= $certificationAdditionalFileCount - 1 ?>) {
alert('사업자회원 추가 항목은 5개까지만 추가할 수 있습니다.');
return;
}
 
// 클론 전 시점의 comAddiCert[N][use] 개수가 새 row의 인덱스
var addFileLength = $('input[name^="comAddiCert"][name$="[use]"]').length;
var obj = $(this).parents('tr').clone();
obj.find('.businessAddfiled').parents('td').html('<a class="businessDelField btn btn-white btn-icon-minus btn-sm">삭제</a>');
obj.find('input[name^="comAddiCert"]').each(function () {
this.name = this.name.replace(/comAddiCert\[\d+\]/, 'comAddiCert[' + addFileLength + ']');
});
obj.find('input').each(function () {
if (this.type == 'text' || this.type == 'hidden') {
this.value = '';
} else if (this.type == 'checkbox') {
this.checked = false;
}
});
// 추가 첨부 최대 용량 hidden 은 빈값으로 두지 않고 기본값으로 초기화
obj.find('input[name^="comAddiCert"][name$="[certificationFileSize]"]').val('<?= $defaultCertificationFileSize ?>');
// 신규 row이므로 항목명 input의 기존값 attribute 비움 (변경 모달 미발생 처리)
obj.find('input[name^="comAddiCert"][name$="[name]"]').attr('data-initial-value', '');
obj.appendTo($(this).parents('table'));
 
// event element
$('label input[name*=\'[use]\']', obj).click(able_rquire).each(able_rquire);
// 클론된 row의 comAddiCert[N][require] disabled 상태 초기화
$('input[name^="comAddiCert"][name$="[use]"]', obj).each(able_com_add_file_require);
$('.businessDelField', obj).one('click', function () {
$(this).parents('tr').remove();
});
}
 
/**
* 가입항목추가필드 설정창 호출
*/
}
}
 
/**
* 추가 첨부 항목 row의 comAddiCert[N][use]에 따라 같은 row의 comAddiCert[N][require] 활성/비활성
* 텍스트 input(ex[name][])은 영향받지 않음
*/
function able_com_add_file_require() {
var $tr = $(this).closest('tr');
var $require = $tr.find('input[name^="comAddiCert"][name$="[require]"]');
$require.prop('disabled', !$(this).prop('checked'));
}
 
/**
* 사업자회원 활성화
*/
<table class="table table-cols div-business">
<colgroup>
<col class="width-md"/>
<col class="width-h2xl"/>
<col/>
<col class="width-xs center"/>
</colgroup>
<tr>
<th rowspan="12">사업자회원</th>
<td class="business">
<label class="checkbox-inline" title="사용여부를 선택해주세요!">
<input type="checkbox" name="company[use]" class="defaultBusinessInfoUse" value="y"/>
필수
</label>
)
<input type="hidden" name="certificationFileSize" id="certificationFileSize" value="<?= $data['comCertification']['maxSize'] ?>"/>
<button type="button" class="comCertificationSetting btn btn-gray btn-sm">설정</button>
</td>
<td></td>
</tr>
<?php
for ($i = 0; $i < $certificationAdditionalFileCount; $i++) {
// 초기값이 없는 경우에도 첫 번째 row(추가 버튼 보유)는 강제 렌더링
if ($i !== 0 && !isset($data["comAddiCert$i"])) {
continue;
}
$additionalData = $data["comAddiCert$i"] ?? [];
?>
<tr>
<td class="business">
<label class="checkbox-inline" title="사용여부를 선택해주세요!">
<input type="checkbox" name="comAddiCert[<?= $i ?>][use]" value="y" <?= (($additionalData['use'] ?? '') == 'y') ? 'checked' : '' ?>/>
</label>
<span class="checkbox-inline width40p">
<input type="text" name="comAddiCert[<?= $i ?>][name]" placeholder="추가 첨부 항목명" class="form-control width100p" value="<?= $additionalData['name'] ?? '' ?>" data-initial-value="<?= $additionalData['name'] ?? '' ?>"/>
</span>
(
<label class="checkbox-inline" title="필수 사용여부를 선택해주세요!">
<input value="y" name="comAddiCert[<?= $i ?>][require]" type="checkbox" <?= !empty($additionalData['require']) ? 'checked' : '' ?> />
필수
</label>
)
<input type="hidden" name="comAddiCert[<?= $i ?>][certificationFileSize]" value="<?= $additionalData['certificationFileSize'] ?? $defaultCertificationFileSize ?>">
<button type="button" class="comAddfieldSetting btn btn-gray btn-sm">설정</button>
</td>
<td></td>
<td>
<?php if ($i === 0) { ?>
<a class="businessAddfiled btn btn-white btn-icon-plus btn-sm">추가</a>
<?php } else { ?>
<a class="businessDelField btn btn-white btn-icon-minus btn-sm">삭제</a>
<?php } ?>
</td>
</tr>
<?php
} ?>
</table>
<?php } ?>
 
return pass;
}
 
/**
* 추가 첨부 항목 use 체크 시 항목명 입력 여부 검증
*/
function comAddiCertValidation() {
var pass = true;
$('input[name^="comAddiCert"][name$="[use]"]').each(function () {
if ($(this).prop('checked') !== true) {
return true;
}
var $tr = $(this).closest('tr');
var $nameInput = $tr.find('input[name^="comAddiCert"][name$="[name]"]');
var nameValue = ($nameInput.val() || '').replace(/^\s+|\s+$/g, '');
if (nameValue === '') {
BootstrapDialog.alert({
title: "경고",
message: "추가 첨부의 항목명을 입력해주세요."
});
$nameInput.focus();
pass = false;
return false;
}
});
return pass;
}
 
$(document).ready(function () {
// 아이디 자리수 체크
$('input[name*="memId"]:text').on('blur', function() {
able_rquire.call(this);
});
 
// 추가 첨부 항목: comAddiCert[N][use]에 따라 같은 row의 comAddiCert[N][require] 활성/비활성
$('#frmSetup').on('click', 'input[name^="comAddiCert"][name$="[use]"]', able_com_add_file_require);
$('#frmSetup input[name^="comAddiCert"][name$="[use]"]').each(able_com_add_file_require);
 
// 추가 첨부 항목명 변경 시 확인 모달 (기존 등록값이 있을 때만)
$('#frmSetup').on('change', 'input[name^="comAddiCert"][name$="[name]"]', function () {
var $target = $(this);
var initialValue = $target.attr('data-initial-value') || '';
var currentValue = $target.val();
 
if (initialValue !== '' && initialValue !== currentValue) {
BootstrapDialog.confirm({
title: "확인",
message: "이미 사용중인 추가 첨부 항목을 변경하시겠습니까? 사용중인 항목이 변경될 경우, 기존 등록된 회원정보 내 항목도 변경됩니다.",
btnCancelLabel: "취소",
btnOkLabel: "변경",
callback: function (result) {
if (!result) {
$target.val(initialValue);
}
}
});
}
});
 
// 사업자회원 활성화
var $businessinfo = $('input[name=\'businessinfo[use]\']');
var $defaultBusinessInfoUse = $('.defaultBusinessInfoUse');
// 가입항목추가 버튼
$('.addfield').on('click', add_field);
 
$('.businessAddfiled').on('click', business_add_field)
$('.businessDelField').one('click', function () {
$(this).parents('tr').remove();
});
 
// 가입항목추가필드 삭제
$('.delfield').one('click', function () {
$(this).parents('tr').remove();
});
});
 
// 추가 첨부 항목 설정 버튼 (동적으로 추가된 row까지 처리되도록 이벤트 위임 사용)
$('#frmSetup').on('click', '.comAddfieldSetting', function () {
var $tr = $(this).closest('tr');
var nameValue = $tr.find('input[name^="comAddiCert"][name$="[name]"]').val();
var title = (nameValue ? nameValue + ' ' : '') + '추가 설정';
// 부모 row의 comAddiCert[N][use] name에서 인덱스 추출
var useName = $tr.find('input[name^="comAddiCert"][name$="[use]"]').attr('name') || '';
var matched = useName.match(/comAddiCert\[(\d+)\]/);
var rowIndex = matched ? matched[1] : 0;
$.get('layer_company_certification_setting.php?type=comAddiCert&index=' + rowIndex, function (data) {
layer_popup(data, title, 'normal');
});
});
 
$('#frmSetup').validate({
submitHandler: function (form) {
if (minMaxRangeValidation('memId') && minMaxRangeValidation('nickNm') && extraValidation() && comAddiCertValidation()) {
form.submit();
}
return false;
$('.setup_field', obj).on('click', call_setup_field);
}
 
function business_add_field(e) {
if ($('.businessDelField').length >= <?= $certificationAdditionalFileCount - 1 ?>) {
alert('사업자회원 추가 항목은 5개까지만 추가할 수 있습니다.');
return;
}
 
// 클론 전 시점의 comAddiCert[N][use] 개수가 새 row의 인덱스
var addFileLength = $('input[name^="comAddiCert"][name$="[use]"]').length;
var obj = $(this).parents('tr').clone();
obj.find('.businessAddfiled').parents('td').html('<a class="businessDelField btn btn-white btn-icon-minus btn-sm">삭제</a>');
obj.find('input[name^="comAddiCert"]').each(function () {
this.name = this.name.replace(/comAddiCert\[\d+\]/, 'comAddiCert[' + addFileLength + ']');
});
obj.find('input').each(function () {
if (this.type == 'text' || this.type == 'hidden') {
this.value = '';
} else if (this.type == 'checkbox') {
this.checked = false;
}
});
// 추가 첨부 최대 용량 hidden 은 빈값으로 두지 않고 기본값으로 초기화
obj.find('input[name^="comAddiCert"][name$="[certificationFileSize]"]').val('<?= $defaultCertificationFileSize ?>');
// 신규 row이므로 항목명 input의 기존값 attribute 비움 (변경 모달 미발생 처리)
obj.find('input[name^="comAddiCert"][name$="[name]"]').attr('data-initial-value', '');
obj.appendTo($(this).parents('table'));
 
// event element
$('label input[name*=\'[use]\']', obj).click(able_rquire).each(able_rquire);
// 클론된 row의 comAddiCert[N][require] disabled 상태 초기화
$('input[name^="comAddiCert"][name$="[use]"]', obj).each(able_com_add_file_require);
$('.businessDelField', obj).one('click', function () {
$(this).parents('tr').remove();
});
}
 
/**
* 가입항목추가필드 설정창 호출
*/
}
}
 
/**
* 추가 첨부 항목 row의 comAddiCert[N][use]에 따라 같은 row의 comAddiCert[N][require] 활성/비활성
* 텍스트 input(ex[name][])은 영향받지 않음
*/
function able_com_add_file_require() {
var $tr = $(this).closest('tr');
var $require = $tr.find('input[name^="comAddiCert"][name$="[require]"]');
$require.prop('disabled', !$(this).prop('checked'));
}
 
/**
* 사업자회원 활성화
*/
 
Admin/member/_member_view_business.php+152-40
변경 전_member_view_business.php
<br>
<?php endif; ?>
<div class="form-inline">
<input type="file" id="companyCertification" name="companyCertification" class="form-control" accept="image/*, application/pdf"/>
 
 
 
</div>
<div class="notice-info mgt10">
파일 업로드 최대 사이즈는 <?= $certificationMaxFileSize ?>MB 입니다.<br>
<?php if (!empty($certification)): ?>
<span>
<input type="checkbox" name="certificationDeleteSno" class="js-certification-checkbox" value="<?= $certification['sno'] ?>" />
Delete Uploaded File .. <?= $certification['imageFileNm'] ?>
<br>
</span>
<?php endif; ?>
</td>
</tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</table>
</div>
<iframe id="downloadFrame" style="display:none;"></iframe>
$(document).on('change', '.js-certification-checkbox', function(e) {
var checkbox = this;
if (checkbox.checked) {
dialog_confirm('등록된 사업자등록증을 삭제하시겠습니까? 회원정보 최종 저장 시 삭제되며, 복구가 불가합니다.', function(result) {
 
 
 
 
if (!result) {
checkbox.checked = false;
}
}
});
 
$('#companyCertification').change(function (e) {
const $fileInput = $('input[name="companyCertification"]');
const file = $fileInput[0].files[0];
const fileMaxSize = certificationMaxFileSize || 2; // MB
const allowedExt = ['pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
 
// 확장자 검사
const ext = file.name.split('.').pop().toLowerCase();
if (!allowedExt.includes(ext)) {
e.target.value = '';
dialog_alert('등록이 불가한 파일 형식입니다. 이미지(jpg, jpeg, png, gif, bmp, webp, svg) 및 pdf 파일만 업로드 가능합니다.');
return;
}
 
 
// 파일 크기 검사
const fileSizeMB = file.size / (1024 * 1024);
if (fileSizeMB > fileMaxSize) {
e.target.value = '';
dialog_alert('파일은 최대 ' + fileMaxSize.toString() + 'MB 이하로만 등록 가능합니다.');
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
 
 
 
 
 
 
});
</script>
<br>
<?php endif; ?>
<div class="form-inline">
<input type="file" id="companyCertification" name="companyCertification" class="form-control" accept="image/*, application/pdf"/>
 
 
 
</div>
<div class="notice-info mgt10">
파일 업로드 최대 사이즈는 <?= $certificationMaxFileSize ?>MB 입니다.<br>
<?php if (!empty($certification)): ?>
<span>
<input type="checkbox" name="certificationDeleteSno" class="js-certification-checkbox" value="<?= $certification['sno'] ?>" />
Delete Uploaded File .. <?= $certification['imageFileNm'] ?>
<br>
</span>
<?php endif; ?>
</td>
</tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</table>
</div>
<iframe id="downloadFrame" style="display:none;"></iframe>
$(document).on('change', '.js-certification-checkbox', function(e) {
var checkbox = this;
if (checkbox.checked) {
dialog_confirm('등록된 사업자등록증을 삭제하시겠습니까? 회원정보 최종 저장 시 삭제되며, 복구가 불가합니다.', function(result) {
 
 
 
 
if (!result) {
checkbox.checked = false;
}
}
});
 
$('#companyCertification').change(function (e) {
const $fileInput = $('input[name="companyCertification"]');
const file = $fileInput[0].files[0];
const fileMaxSize = certificationMaxFileSize || 2; // MB
const allowedExt = ['pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
 
// 확장자 검사
const ext = file.name.split('.').pop().toLowerCase();
if (!allowedExt.includes(ext)) {
e.target.value = '';
dialog_alert('등록이 불가한 파일 형식입니다. 이미지(jpg, jpeg, png, gif, bmp, webp, svg) 및 pdf 파일만 업로드 가능합니다.');
return;
}
 
 
// 파일 크기 검사
const fileSizeMB = file.size / (1024 * 1024);
if (fileSizeMB > fileMaxSize) {
e.target.value = '';
dialog_alert('파일은 최대 ' + fileMaxSize.toString() + 'MB 이하로만 등록 가능합니다.');
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
 
 
 
 
 
 
});
</script>
 
변경 후_member_view_business.php
<br>
<?php endif; ?>
<div class="form-inline">
<input type="file" id="companyCertification" name="companyCertification" class="form-control js-cert-file" accept="image/*, application/pdf" data-max-size="<?= $certificationMaxFileSize ?>"/>
<?php if ($mode === 'register'): // 등록 시에만 첨부 취소 버튼 노출 (수정 시 미노출) ?>
<button type="button" class="btn btn-white btn-sm js-cert-file-clear" style="display:none;">- 삭제</button>
<?php endif; ?>
</div>
<div class="notice-info mgt10">
파일 업로드 최대 사이즈는 <?= $certificationMaxFileSize ?>MB 입니다.<br>
<?php if (!empty($certification)): ?>
<span>
<input type="checkbox" name="certificationDeleteSno" class="js-certification-checkbox" value="<?= $certification['sno'] ?>" />
업로드된 파일 삭제 .. <?= $certification['imageFileNm'] ?>
<br>
</span>
<?php endif; ?>
</td>
</tr>
<?php
for ($i = 0; $i < $certificationAdditionalFileCount ; $i++) {
$additional = $additionalCertification["comAddiCert$i"] ?? null;
if($additional && $additional['use'] === 'y') { ?>
<tr>
<th><?= $additional['name'] ?></th>
<td class="input_area" colspan="3">
<?php if (!empty($additional['file'])): ?>
<a href="#" class="js-certification-download" data-url="../member/company_certification.php?mode=download&sno=<?= $additional['file']['sno'] ?>">
<?= $additional['file']['imageFileNm'] ?>
</a>
<br>
<?php endif; ?>
<div class="form-inline">
<input type="file" id="comAddiCert[<?= $i ?>][file]" name="comAddiCert[<?= $i ?>][file]" class="form-control js-cert-file" accept="image/*, application/pdf" data-max-size="<?= $additional['certificationFileSize'] ?>"/>
<?php if ($mode === 'register'): // 등록 시에만 첨부 취소 버튼 노출 (수정 시 미노출) ?>
<button type="button" class="btn btn-white btn-sm js-cert-file-clear" style="display:none;">- 삭제</button>
<?php endif; ?>
</div>
<div class="notice-info mgt10">
파일 업로드 최대 사이즈는 <?= $additional['certificationFileSize'] ?>MB 입니다.<br>
</div>
<?php if (!empty($additional['file'])): ?>
<span>
<input type="checkbox" name="comAddiCert[<?= $i ?>][DeleteSno]" class="js-certification-checkbox" value="<?= $additional['file']['sno'] ?>" />
업로드된 파일 삭제 .. <?= $additional['file']['imageFileNm'] ?>
<br>
</span>
<?php endif; ?>
</td>
</tr>
<?php
}
} ?>
</table>
</div>
<iframe id="downloadFrame" style="display:none;"></iframe>
$(document).on('change', '.js-certification-checkbox', function(e) {
var checkbox = this;
if (checkbox.checked) {
// 추가서류(comAddiCert[N][DeleteSno])와 사업자등록증(certificationDeleteSno) 문구 구분
var message = checkbox.name.indexOf('comAddiCert') === 0
? '등록된 첨부파일을 삭제하시겠습니까? 회원정보 최종 저장 시 삭제되며, 복구가 불가능 합니다.'
: '등록된 사업자등록증을 삭제하시겠습니까? 회원정보 최종 저장 시 삭제되며, 복구가 불가합니다.';
dialog_confirm(message, function(result) {
if (!result) {
checkbox.checked = false;
}
}
});
 
// 선택 파일 비우기: bootstrap-filestyle 위젯이 적용된 경우 표시 텍스트박스까지 함께 비운다
function clearCertFile($input) {
if ($input.data('filestyle')) {
$input.filestyle('clear');
} else {
$input.val('');
 
 
 
 
 
 
}
}
 
// 찾아보기로 파일 선택 시 확장자·용량 검사 후 '- 삭제' 버튼 노출, 클릭 시 선택 취소(첨부 제거)
$(document).on('change', '.js-cert-file', function () {
const file = this.files[0];
 
if (file) {
const allowedExt = ['pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
const ext = file.name.split('.').pop().toLowerCase();
if (!allowedExt.includes(ext)) {
clearCertFile($(this));
dialog_alert('등록이 불가한 파일 형식입니다. 이미지(jpg, jpeg, png, gif, bmp, webp, svg) 및 pdf 파일만 업로드 가능합니다.');
} else {
const fileMaxSize = parseFloat($(this).data('max-size')) || 2; // MB
const fileSizeMB = file.size / (1024 * 1024);
if (fileSizeMB > fileMaxSize) {
clearCertFile($(this));
dialog_alert('파일은 최대 ' + fileMaxSize.toString() + 'MB 이하로만 등록 가능합니다.');
}
}
}
 
$(this).closest('.form-inline').find('.js-cert-file-clear').toggle(this.files.length > 0);
});
 
$(document).on('click', '.js-cert-file-clear', function () {
clearCertFile($(this).closest('.form-inline').find('.js-cert-file'));
$(this).hide();
});
</script>
<br>
<?php endif; ?>
<div class="form-inline">
<input type="file" id="companyCertification" name="companyCertification" class="form-control js-cert-file" accept="image/*, application/pdf" data-max-size="<?= $certificationMaxFileSize ?>"/>
<?php if ($mode === 'register'): // 등록 시에만 첨부 취소 버튼 노출 (수정 시 미노출) ?>
<button type="button" class="btn btn-white btn-sm js-cert-file-clear" style="display:none;">- 삭제</button>
<?php endif; ?>
</div>
<div class="notice-info mgt10">
파일 업로드 최대 사이즈는 <?= $certificationMaxFileSize ?>MB 입니다.<br>
<?php if (!empty($certification)): ?>
<span>
<input type="checkbox" name="certificationDeleteSno" class="js-certification-checkbox" value="<?= $certification['sno'] ?>" />
업로드된 파일 삭제 .. <?= $certification['imageFileNm'] ?>
<br>
</span>
<?php endif; ?>
</td>
</tr>
<?php
for ($i = 0; $i < $certificationAdditionalFileCount ; $i++) {
$additional = $additionalCertification["comAddiCert$i"] ?? null;
if($additional && $additional['use'] === 'y') { ?>
<tr>
<th><?= $additional['name'] ?></th>
<td class="input_area" colspan="3">
<?php if (!empty($additional['file'])): ?>
<a href="#" class="js-certification-download" data-url="../member/company_certification.php?mode=download&sno=<?= $additional['file']['sno'] ?>">
<?= $additional['file']['imageFileNm'] ?>
</a>
<br>
<?php endif; ?>
<div class="form-inline">
<input type="file" id="comAddiCert[<?= $i ?>][file]" name="comAddiCert[<?= $i ?>][file]" class="form-control js-cert-file" accept="image/*, application/pdf" data-max-size="<?= $additional['certificationFileSize'] ?>"/>
<?php if ($mode === 'register'): // 등록 시에만 첨부 취소 버튼 노출 (수정 시 미노출) ?>
<button type="button" class="btn btn-white btn-sm js-cert-file-clear" style="display:none;">- 삭제</button>
<?php endif; ?>
</div>
<div class="notice-info mgt10">
파일 업로드 최대 사이즈는 <?= $additional['certificationFileSize'] ?>MB 입니다.<br>
</div>
<?php if (!empty($additional['file'])): ?>
<span>
<input type="checkbox" name="comAddiCert[<?= $i ?>][DeleteSno]" class="js-certification-checkbox" value="<?= $additional['file']['sno'] ?>" />
업로드된 파일 삭제 .. <?= $additional['file']['imageFileNm'] ?>
<br>
</span>
<?php endif; ?>
</td>
</tr>
<?php
}
} ?>
</table>
</div>
<iframe id="downloadFrame" style="display:none;"></iframe>
$(document).on('change', '.js-certification-checkbox', function(e) {
var checkbox = this;
if (checkbox.checked) {
// 추가서류(comAddiCert[N][DeleteSno])와 사업자등록증(certificationDeleteSno) 문구 구분
var message = checkbox.name.indexOf('comAddiCert') === 0
? '등록된 첨부파일을 삭제하시겠습니까? 회원정보 최종 저장 시 삭제되며, 복구가 불가능 합니다.'
: '등록된 사업자등록증을 삭제하시겠습니까? 회원정보 최종 저장 시 삭제되며, 복구가 불가합니다.';
dialog_confirm(message, function(result) {
if (!result) {
checkbox.checked = false;
}
}
});
 
// 선택 파일 비우기: bootstrap-filestyle 위젯이 적용된 경우 표시 텍스트박스까지 함께 비운다
function clearCertFile($input) {
if ($input.data('filestyle')) {
$input.filestyle('clear');
} else {
$input.val('');
 
 
 
 
 
 
}
}
 
// 찾아보기로 파일 선택 시 확장자·용량 검사 후 '- 삭제' 버튼 노출, 클릭 시 선택 취소(첨부 제거)
$(document).on('change', '.js-cert-file', function () {
const file = this.files[0];
 
if (file) {
const allowedExt = ['pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
const ext = file.name.split('.').pop().toLowerCase();
if (!allowedExt.includes(ext)) {
clearCertFile($(this));
dialog_alert('등록이 불가한 파일 형식입니다. 이미지(jpg, jpeg, png, gif, bmp, webp, svg) 및 pdf 파일만 업로드 가능합니다.');
} else {
const fileMaxSize = parseFloat($(this).data('max-size')) || 2; // MB
const fileSizeMB = file.size / (1024 * 1024);
if (fileSizeMB > fileMaxSize) {
clearCertFile($(this));
dialog_alert('파일은 최대 ' + fileMaxSize.toString() + 'MB 이하로만 등록 가능합니다.');
}
}
}
 
$(this).closest('.form-inline').find('.js-cert-file-clear').toggle(this.files.length > 0);
});
 
$(document).on('click', '.js-cert-file-clear', function () {
clearCertFile($(this).closest('.form-inline').find('.js-cert-file'));
$(this).hide();
});
</script>
 
Component/Member/Company/CompanyCertification.php+346-38
변경 전CompanyCertification.php
 
namespace Bundle\Component\Member\Company;
 
 
use DTO\Member\CompanyCertificationInsertDTO;
use Exception;
use Framework\Debug\Exception\AlertBackException;
{
const DEFAULT_COMPANY_CERTIFICATION_FILE_SIZE = '2'; // MB
const CERTIFICATION_IMAGE_UPLOAD_PATH = '/member/company/certification/%s';
 
 
const ALLOW_MIME_TYPES = [
'application/pdf',
'image/jpeg',
}
 
/**
* 사업자 등록증 파일 크기 설정
* @param int $size
 
 
* @return bool
*/
public function setCompanyCertificationFileSize(int $size): bool
{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$joinItem = $this->policy->getValue('member.joinitem');
$joinItem['comCertification']['maxSize'] = $size;
 
return $this->policy->setValue('member.joinitem', $joinItem);
}
 
/**
* 사업자 등록증 파일 크기
 
 
*
* @return int
*/
public function getCompanyCertificationFileSize(): int
{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$joinItem = $this->policy->getValue('member.joinitem');
 
 
 
return $joinItem['comCertification']['maxSize'] ?? self::DEFAULT_COMPANY_CERTIFICATION_FILE_SIZE;
 
 
 
 
 
 
 
}
 
/**
* 사업자 등록증 이미지 OBS 업로드
 
*
* @param array $certificationFiles
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
* @param int $memNo
* @return void
* @throws Exception|\Throwable
*/
public function upload(array $certificationFiles, int $memNo): void
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
{
$fileCount = count($certificationFiles['tmp_name']);
if ($fileCount !== 1) {
throw new \Exception('사업자 등록증 파일은 1개만 업로드 가능합니다.');
 
 
 
 
 
 
 
}
 
// 기존파일이 있으면 삭제부터 진행.
$certificationInfo = $this->companyCertificationRepository->findCertificationInfoByMemNo($memNo);
if (!empty($certificationInfo)) {
$deleteResult = $this->imageUploadService->deleteImage($certificationInfo['imageFilePath']);
if ($deleteResult === false) {
throw new \Exception('기존 사업자 등록증 이미지 삭제에 실패했습니다.');
}
$this->companyCertificationRepository->deleteCertificationInfo($certificationInfo['sno']);
}
 
// 파일 업로드 최대 사이즈
$maxFileSize = $this->getCompanyCertificationFileSize();
 
$result = $this->uploadToObs($maxFileSize, $certificationFiles, $memNo);
$this->logger->channel('adminLog')->info('OBS IMAGE UPLOAD RESULT : ', $result);
 
// 업로드 결과 처리
if ($result['result']) {
$this->insertCertificationInfo($memNo, $result); // 성공시 insert
} else {
throw new \Exception('사업자 등록증 이미지 업로드에 실패했습니다.');
}
}
* 결과 정보 저장
* @param int $memNo
* @param array $result
 
* @return void
* @throws \Throwable
*/
private function insertCertificationInfo(int $memNo, array $result): void
{
// DB 저장
try {
$dto = new CompanyCertificationInsertDTO($memNo, [
'filePath' => $result['saveFileNm'], // img full url
'fileName' => $result['uploadFileNm'], // file name
]);
 
 
 
 
$this->companyCertificationRepository->insertCertificationInfo($dto);
} catch (\Throwable $e) {
// DB 저장 실패 시 OBS에서 파일 삭제
return $this->companyCertificationRepository->findCertificationInfoByMemNo($memNo);
}
 
 
 
 
 
 
/**
* 사업자 등록증 다운로드
* @param int $sno
}
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 사업자등록증을 OBS에 업로드하는 함수
* @param int $maxFileSize
 
namespace Bundle\Component\Member\Company;
 
 
use DTO\Member\CompanyCertificationInsertDTO;
use Exception;
use Framework\Debug\Exception\AlertBackException;
{
const DEFAULT_COMPANY_CERTIFICATION_FILE_SIZE = '2'; // MB
const CERTIFICATION_IMAGE_UPLOAD_PATH = '/member/company/certification/%s';
 
 
const ALLOW_MIME_TYPES = [
'application/pdf',
'image/jpeg',
}
 
/**
* 사업자 등록증 파일 크기 설정
* @param int $size
 
 
* @return bool
*/
public function setCompanyCertificationFileSize(int $size): bool
{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$joinItem = $this->policy->getValue('member.joinitem');
$joinItem['comCertification']['maxSize'] = $size;
 
return $this->policy->setValue('member.joinitem', $joinItem);
}
 
/**
* 사업자 등록증 파일 크기
 
 
*
* @return int
*/
public function getCompanyCertificationFileSize(): int
{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$joinItem = $this->policy->getValue('member.joinitem');
 
 
 
return $joinItem['comCertification']['maxSize'] ?? self::DEFAULT_COMPANY_CERTIFICATION_FILE_SIZE;
 
 
 
 
 
 
 
}
 
/**
* 사업자 등록증 이미지 OBS 업로드
 
*
* @param array $certificationFiles
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
* @param int $memNo
* @return void
* @throws Exception|\Throwable
*/
public function upload(array $certificationFiles, int $memNo): void
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
{
$fileCount = count($certificationFiles['tmp_name']);
if ($fileCount !== 1) {
throw new \Exception('사업자 등록증 파일은 1개만 업로드 가능합니다.');
 
 
 
 
 
 
 
}
 
// 기존파일이 있으면 삭제부터 진행.
$certificationInfo = $this->companyCertificationRepository->findCertificationInfoByMemNo($memNo);
if (!empty($certificationInfo)) {
$deleteResult = $this->imageUploadService->deleteImage($certificationInfo['imageFilePath']);
if ($deleteResult === false) {
throw new \Exception('기존 사업자 등록증 이미지 삭제에 실패했습니다.');
}
$this->companyCertificationRepository->deleteCertificationInfo($certificationInfo['sno']);
}
 
// 파일 업로드 최대 사이즈
$maxFileSize = $this->getCompanyCertificationFileSize();
 
$result = $this->uploadToObs($maxFileSize, $certificationFiles, $memNo);
$this->logger->channel('adminLog')->info('OBS IMAGE UPLOAD RESULT : ', $result);
 
// 업로드 결과 처리
if ($result['result']) {
$this->insertCertificationInfo($memNo, $result); // 성공시 insert
} else {
throw new \Exception('사업자 등록증 이미지 업로드에 실패했습니다.');
}
}
* 결과 정보 저장
* @param int $memNo
* @param array $result
 
* @return void
* @throws \Throwable
*/
private function insertCertificationInfo(int $memNo, array $result): void
{
// DB 저장
try {
$dto = new CompanyCertificationInsertDTO($memNo, [
'filePath' => $result['saveFileNm'], // img full url
'fileName' => $result['uploadFileNm'], // file name
]);
 
 
 
 
$this->companyCertificationRepository->insertCertificationInfo($dto);
} catch (\Throwable $e) {
// DB 저장 실패 시 OBS에서 파일 삭제
return $this->companyCertificationRepository->findCertificationInfoByMemNo($memNo);
}
 
 
 
 
 
 
/**
* 사업자 등록증 다운로드
* @param int $sno
}
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 사업자등록증을 OBS에 업로드하는 함수
* @param int $maxFileSize
 
변경 후CompanyCertification.php
 
namespace Bundle\Component\Member\Company;
 
use Bundle\Enum\Member\Company\DocumentType;
use DTO\Member\CompanyCertificationInsertDTO;
use Exception;
use Framework\Debug\Exception\AlertBackException;
{
const DEFAULT_COMPANY_CERTIFICATION_FILE_SIZE = '2'; // MB
const CERTIFICATION_IMAGE_UPLOAD_PATH = '/member/company/certification/%s';
/** 주 사업자등록증의 정책(member.joinitem) file key (DB documentType=registration 과 표현이 다름) */
const REGISTRATION_FILE_KEY = 'comCertification';
const ALLOW_MIME_TYPES = [
'application/pdf',
'image/jpeg',
}
 
/**
* 사업자 등록증(주 서류) 파일 크기 설정
* 주 사업자등록증(comCertification) 기준으로 최대 파일 크기를 설정한다.
*
* @param int $size 최대 파일 크기 (MB)
* @return bool
*/
public function setCompanyCertificationFileSize(int $size): bool
{
return $this->setCompanyCertificationFileSizeByKey($size, $this->toFileKey(DocumentType::REGISTRATION));
}
 
/**
* 사업자 등록증 / 추가서류 파일 크기 설정
* key 에 해당하는 서류의 최대 파일 크기를 설정한다.
*
* @param int $size 최대 파일 크기 (MB)
* @param string $key 정책 file key (comCertification / comAddiCert{n})
* @exception \Exception 허용되지 않은 key 인 경우
* @return bool
*/
public function setCompanyCertificationFileSizeByKey(int $size, string $key): bool
{
if ($this->tryFromFileKey($key) === null) {
throw new \Exception("허용되지 않은 key Type : $key");
}
 
$joinItem = $this->policy->getValue('member.joinitem');
$joinItem[$key][$this->fileSizeField($key)] = $size;
 
return $this->policy->setValue('member.joinitem', $joinItem);
}
 
/**
* 사업자 등록증(주 서류) 파일 크기 조회
* 주 사업자등록증(comCertification) 기준 최대 파일 크기를 반환한다.
* 튜닝 메소드 시그니처 호환용
*
* @return int
*/
public function getCompanyCertificationFileSize(): int
{
return $this->getCompanyCertificationFileSizeByKey($this->toFileKey(DocumentType::REGISTRATION));
}
 
/**
* 사업자 등록증 / 추가서류 파일 크기 조회
* key 에 해당하는 서류의 최대 파일 크기를 반환한다. 미설정 시 기본값.
*
* @param string $key 정책 file key (comCertification / comAddiCert{n})
* @exception \Exception 허용되지 않은 key 인 경우
* @return int
*/
public function getCompanyCertificationFileSizeByKey(string $key): int
{
if ($this->tryFromFileKey($key) === null) {
throw new \Exception("허용되지 않은 key Type : $key");
}
 
$joinItem = $this->policy->getValue('member.joinitem');
return $joinItem[$key][$this->fileSizeField($key)] ?? self::DEFAULT_COMPANY_CERTIFICATION_FILE_SIZE;
}
 
/**
* 사업자 추가 제출 서류 최대 개수
* @return int
*/
public function getCompanyAddiCertificationFileCount(): int
{
// 사업자등록증(주 서류) 제외한 추가 제출 서류 개수
return count(DocumentType::cases()) - 1;
}
 
/**
* 서류 종류별 정책(member.joinitem)에 보관된 파일 크기 하위 키를 반환한다.
* 사업자등록증(comCertification)은 maxSize, 추가서류(comAddiCert{n})는 certificationFileSize 로 보관된다.
*
* @param string $key 정책 file key
* @return string 파일 크기 하위 키
*/
private function fileSizeField(string $key): string
{
return $key === self::REGISTRATION_FILE_KEY ? 'maxSize' : 'certificationFileSize';
}
 
/**
* 서류 종류(DB documentType)로부터 정책(member.joinitem) file key 로 변환한다.
* 주 사업자등록증만 'comCertification'(REGISTRATION_FILE_KEY) 으로 표현이 다르고,
* 추가서류는 documentType backing value 와 동일하다.
*
* @param DocumentType $type
* @return string 정책 file key
*/
private function toFileKey(DocumentType $type): string
{
return match ($type) {
DocumentType::REGISTRATION => self::REGISTRATION_FILE_KEY,
default => $type->value,
};
}
 
/**
* 정책(member.joinitem) file key 로부터 서류 종류를 조회한다. 허용되지 않은 key 면 null.
*
* @param string $fileKey 정책 file key
* @return DocumentType|null
*/
private function tryFromFileKey(string $fileKey): ?DocumentType
{
return match ($fileKey) {
self::REGISTRATION_FILE_KEY => DocumentType::REGISTRATION,
// 'registration'(DB documentType)은 정책 file key 가 아니므로 제외한다
DocumentType::REGISTRATION->value => null,
default => DocumentType::tryFrom($fileKey),
};
}
 
/**
* 사업자 등록증(주 서류) 이미지 OBS 업로드
*
* @param array $certificationFiles 업로드 파일 정보 (tmp_name, name, size 등)
* @param int $memNo
* @return void
* @throws Exception|\Throwable
*/
public function upload(array $certificationFiles, int $memNo): void
{
$this->uploadCertificationFile($certificationFiles, $memNo, null);
}
 
/**
* 사업자 추가 제출 서류 이미지 OBS 업로드
*
* @param array $certificationFiles 업로드 파일 정보 (tmp_name, name, size 등)
* @param int $memNo
* @param int $index 추가서류 인덱스 (comAddiCert{index} 타입으로 저장)
* @return void
* @throws Exception|\Throwable
*/
public function uploadAdditional(array $certificationFiles, int $memNo, int $index): void
{
$this->uploadCertificationFile($certificationFiles, $memNo, "comAddiCert$index");
}
 
/**
* 사업자 등록증 / 추가서류 공통 업로드 처리
*
* @param array $certificationFiles 업로드 파일 정보 (tmp_name, name, size 등)
* @param int $memNo
* @param string|null $certType null이면 주 사업자등록증(comCertification), 값이 있으면 추가서류 타입(comAddiCert{index})
* @return void
* @throws Exception|\Throwable
*/
private function uploadCertificationFile(array $certificationFiles, int $memNo, ?string $certType): void
{
$fileCount = count($certificationFiles['tmp_name']);
if ($fileCount !== 1) {
throw new \Exception('파일은 1개만 업로드 가능합니다.');
}
 
// certType이 있으면 추가서류, 없으면 주 사업자등록증 기준으로 기존 정보 조회
if ($certType !== null) {
$certificationInfo = $this->companyCertificationRepository->findCertificationInfoByMemNoAndType($memNo, $certType);
} else {
$certificationInfo = $this->companyCertificationRepository->findCertificationInfoByMemNo($memNo);
}
 
// 기존파일이 있으면 삭제부터 진행.
 
if (!empty($certificationInfo)) {
$deleteResult = $this->imageUploadService->deleteImage($certificationInfo['imageFilePath']);
if ($deleteResult === false) {
\Logger::channel('member')->error("기존 사업자 등록 서류 삭제에 실패했습니다. memNo : {$memNo}");
}
$this->companyCertificationRepository->deleteCertificationInfo($certificationInfo['sno']);
}
 
// 파일 업로드 최대 사이즈 (주 사업자등록증 / 추가서류 각 서류별 설정값 사용)
$fileKey = $certType ?? $this->toFileKey(DocumentType::REGISTRATION);
$maxFileSize = $this->getCompanyCertificationFileSizeByKey($fileKey);
$result = $this->uploadToObs($maxFileSize, $certificationFiles, $memNo);
$this->logger->channel('adminLog')->info('OBS IMAGE UPLOAD RESULT : ', $result);
 
// 업로드 결과 처리
if ($result['result']) {
$this->insertCertificationInfo($memNo, $result, $certType); // 성공시 insert
} else {
throw new \Exception('사업자 등록증 이미지 업로드에 실패했습니다.');
}
}
* 결과 정보 저장
* @param int $memNo
* @param array $result
* @param string|null $certType 추가서류 타입(comAddiCert{index}), null이면 주 사업자등록증
* @return void
* @throws \Throwable
*/
private function insertCertificationInfo(int $memNo, array $result, ?string $certType = null): void
{
// DB 저장
try {
$dto = new CompanyCertificationInsertDTO(
$memNo,
[
'filePath' => $result['saveFileNm'], // img full url
'fileName' => $result['uploadFileNm'] // file name
],
$certType
);
$this->companyCertificationRepository->insertCertificationInfo($dto);
} catch (\Throwable $e) {
// DB 저장 실패 시 OBS에서 파일 삭제
return $this->companyCertificationRepository->findCertificationInfoByMemNo($memNo);
}
 
public function getCertificationByMemNoAndType(int $memNo, string $type): array
{
return $this->companyCertificationRepository->findCertificationInfoByMemNoAndType($memNo, $type);
}
 
/**
* 사업자 등록증 다운로드
* @param int $sno
}
}
 
public function getAdditionalData(): array
{
$joinItem = $this->policy->getValue('member.joinitem');
$additionalData = [];
 
foreach ($joinItem as $key => $value) {
if (str_contains($key, 'comAddiCert')) {
$additionalData[$key] = $value;
}
}
 
return $additionalData;
}
 
/**
* 사업자등록증을 OBS에 업로드하는 함수
* @param int $maxFileSize
 
namespace Bundle\Component\Member\Company;
 
use Bundle\Enum\Member\Company\DocumentType;
use DTO\Member\CompanyCertificationInsertDTO;
use Exception;
use Framework\Debug\Exception\AlertBackException;
{
const DEFAULT_COMPANY_CERTIFICATION_FILE_SIZE = '2'; // MB
const CERTIFICATION_IMAGE_UPLOAD_PATH = '/member/company/certification/%s';
/** 주 사업자등록증의 정책(member.joinitem) file key (DB documentType=registration 과 표현이 다름) */
const REGISTRATION_FILE_KEY = 'comCertification';
const ALLOW_MIME_TYPES = [
'application/pdf',
'image/jpeg',
}
 
/**
* 사업자 등록증(주 서류) 파일 크기 설정
* 주 사업자등록증(comCertification) 기준으로 최대 파일 크기를 설정한다.
*
* @param int $size 최대 파일 크기 (MB)
* @return bool
*/
public function setCompanyCertificationFileSize(int $size): bool
{
return $this->setCompanyCertificationFileSizeByKey($size, $this->toFileKey(DocumentType::REGISTRATION));
}
 
/**
* 사업자 등록증 / 추가서류 파일 크기 설정
* key 에 해당하는 서류의 최대 파일 크기를 설정한다.
*
* @param int $size 최대 파일 크기 (MB)
* @param string $key 정책 file key (comCertification / comAddiCert{n})
* @exception \Exception 허용되지 않은 key 인 경우
* @return bool
*/
public function setCompanyCertificationFileSizeByKey(int $size, string $key): bool
{
if ($this->tryFromFileKey($key) === null) {
throw new \Exception("허용되지 않은 key Type : $key");
}
 
$joinItem = $this->policy->getValue('member.joinitem');
$joinItem[$key][$this->fileSizeField($key)] = $size;
 
return $this->policy->setValue('member.joinitem', $joinItem);
}
 
/**
* 사업자 등록증(주 서류) 파일 크기 조회
* 주 사업자등록증(comCertification) 기준 최대 파일 크기를 반환한다.
* 튜닝 메소드 시그니처 호환용
*
* @return int
*/
public function getCompanyCertificationFileSize(): int
{
return $this->getCompanyCertificationFileSizeByKey($this->toFileKey(DocumentType::REGISTRATION));
}
 
/**
* 사업자 등록증 / 추가서류 파일 크기 조회
* key 에 해당하는 서류의 최대 파일 크기를 반환한다. 미설정 시 기본값.
*
* @param string $key 정책 file key (comCertification / comAddiCert{n})
* @exception \Exception 허용되지 않은 key 인 경우
* @return int
*/
public function getCompanyCertificationFileSizeByKey(string $key): int
{
if ($this->tryFromFileKey($key) === null) {
throw new \Exception("허용되지 않은 key Type : $key");
}
 
$joinItem = $this->policy->getValue('member.joinitem');
return $joinItem[$key][$this->fileSizeField($key)] ?? self::DEFAULT_COMPANY_CERTIFICATION_FILE_SIZE;
}
 
/**
* 사업자 추가 제출 서류 최대 개수
* @return int
*/
public function getCompanyAddiCertificationFileCount(): int
{
// 사업자등록증(주 서류) 제외한 추가 제출 서류 개수
return count(DocumentType::cases()) - 1;
}
 
/**
* 서류 종류별 정책(member.joinitem)에 보관된 파일 크기 하위 키를 반환한다.
* 사업자등록증(comCertification)은 maxSize, 추가서류(comAddiCert{n})는 certificationFileSize 로 보관된다.
*
* @param string $key 정책 file key
* @return string 파일 크기 하위 키
*/
private function fileSizeField(string $key): string
{
return $key === self::REGISTRATION_FILE_KEY ? 'maxSize' : 'certificationFileSize';
}
 
/**
* 서류 종류(DB documentType)로부터 정책(member.joinitem) file key 로 변환한다.
* 주 사업자등록증만 'comCertification'(REGISTRATION_FILE_KEY) 으로 표현이 다르고,
* 추가서류는 documentType backing value 와 동일하다.
*
* @param DocumentType $type
* @return string 정책 file key
*/
private function toFileKey(DocumentType $type): string
{
return match ($type) {
DocumentType::REGISTRATION => self::REGISTRATION_FILE_KEY,
default => $type->value,
};
}
 
/**
* 정책(member.joinitem) file key 로부터 서류 종류를 조회한다. 허용되지 않은 key 면 null.
*
* @param string $fileKey 정책 file key
* @return DocumentType|null
*/
private function tryFromFileKey(string $fileKey): ?DocumentType
{
return match ($fileKey) {
self::REGISTRATION_FILE_KEY => DocumentType::REGISTRATION,
// 'registration'(DB documentType)은 정책 file key 가 아니므로 제외한다
DocumentType::REGISTRATION->value => null,
default => DocumentType::tryFrom($fileKey),
};
}
 
/**
* 사업자 등록증(주 서류) 이미지 OBS 업로드
*
* @param array $certificationFiles 업로드 파일 정보 (tmp_name, name, size 등)
* @param int $memNo
* @return void
* @throws Exception|\Throwable
*/
public function upload(array $certificationFiles, int $memNo): void
{
$this->uploadCertificationFile($certificationFiles, $memNo, null);
}
 
/**
* 사업자 추가 제출 서류 이미지 OBS 업로드
*
* @param array $certificationFiles 업로드 파일 정보 (tmp_name, name, size 등)
* @param int $memNo
* @param int $index 추가서류 인덱스 (comAddiCert{index} 타입으로 저장)
* @return void
* @throws Exception|\Throwable
*/
public function uploadAdditional(array $certificationFiles, int $memNo, int $index): void
{
$this->uploadCertificationFile($certificationFiles, $memNo, "comAddiCert$index");
}
 
/**
* 사업자 등록증 / 추가서류 공통 업로드 처리
*
* @param array $certificationFiles 업로드 파일 정보 (tmp_name, name, size 등)
* @param int $memNo
* @param string|null $certType null이면 주 사업자등록증(comCertification), 값이 있으면 추가서류 타입(comAddiCert{index})
* @return void
* @throws Exception|\Throwable
*/
private function uploadCertificationFile(array $certificationFiles, int $memNo, ?string $certType): void
{
$fileCount = count($certificationFiles['tmp_name']);
if ($fileCount !== 1) {
throw new \Exception('파일은 1개만 업로드 가능합니다.');
}
 
// certType이 있으면 추가서류, 없으면 주 사업자등록증 기준으로 기존 정보 조회
if ($certType !== null) {
$certificationInfo = $this->companyCertificationRepository->findCertificationInfoByMemNoAndType($memNo, $certType);
} else {
$certificationInfo = $this->companyCertificationRepository->findCertificationInfoByMemNo($memNo);
}
 
// 기존파일이 있으면 삭제부터 진행.
 
if (!empty($certificationInfo)) {
$deleteResult = $this->imageUploadService->deleteImage($certificationInfo['imageFilePath']);
if ($deleteResult === false) {
\Logger::channel('member')->error("기존 사업자 등록 서류 삭제에 실패했습니다. memNo : {$memNo}");
}
$this->companyCertificationRepository->deleteCertificationInfo($certificationInfo['sno']);
}
 
// 파일 업로드 최대 사이즈 (주 사업자등록증 / 추가서류 각 서류별 설정값 사용)
$fileKey = $certType ?? $this->toFileKey(DocumentType::REGISTRATION);
$maxFileSize = $this->getCompanyCertificationFileSizeByKey($fileKey);
$result = $this->uploadToObs($maxFileSize, $certificationFiles, $memNo);
$this->logger->channel('adminLog')->info('OBS IMAGE UPLOAD RESULT : ', $result);
 
// 업로드 결과 처리
if ($result['result']) {
$this->insertCertificationInfo($memNo, $result, $certType); // 성공시 insert
} else {
throw new \Exception('사업자 등록증 이미지 업로드에 실패했습니다.');
}
}
* 결과 정보 저장
* @param int $memNo
* @param array $result
* @param string|null $certType 추가서류 타입(comAddiCert{index}), null이면 주 사업자등록증
* @return void
* @throws \Throwable
*/
private function insertCertificationInfo(int $memNo, array $result, ?string $certType = null): void
{
// DB 저장
try {
$dto = new CompanyCertificationInsertDTO(
$memNo,
[
'filePath' => $result['saveFileNm'], // img full url
'fileName' => $result['uploadFileNm'] // file name
],
$certType
);
$this->companyCertificationRepository->insertCertificationInfo($dto);
} catch (\Throwable $e) {
// DB 저장 실패 시 OBS에서 파일 삭제
return $this->companyCertificationRepository->findCertificationInfoByMemNo($memNo);
}
 
public function getCertificationByMemNoAndType(int $memNo, string $type): array
{
return $this->companyCertificationRepository->findCertificationInfoByMemNoAndType($memNo, $type);
}
 
/**
* 사업자 등록증 다운로드
* @param int $sno
}
}
 
public function getAdditionalData(): array
{
$joinItem = $this->policy->getValue('member.joinitem');
$additionalData = [];
 
foreach ($joinItem as $key => $value) {
if (str_contains($key, 'comAddiCert')) {
$additionalData[$key] = $value;
}
}
 
return $additionalData;
}
 
/**
* 사업자등록증을 OBS에 업로드하는 함수
* @param int $maxFileSize
 
Component/Member/MemberAdmin.php+74-4
변경 전MemberAdmin.php
namespace Bundle\Component\Member;
 
use App;
 
 
use Component\Database\DBTableField;
use Component\Mail\MailUtil;
use Component\Member\Group\Util as GroupUtil;
 
use Component\Member\Util\MemberUtil;
use Component\Mileage\Mileage;
use Component\Mileage\MileageDAO;
use Origin\Service\WebHook\MemberWebHookService;
use Request;
use Session;
 
 
/**
* Class 관리자에서 사용하는 회원 관리
/**
* 회원 목록
*
* @author sunny
*
* @param $arrData
*
* @return array data
 
 
* @deprecated
*/
public function getMemberPageList($arrData)
StringUtils::strIsSet($arrData['maillingFl'], 'n');
StringUtils::strIsSet($arrData['smsFl'], 'n');
 
 
 
 
 
 
 
 
 
 
$arrData = $this->validateMemberByAdminModification($arrData);
 
 
 
 
//@formatter:off
$arrBind = $db->get_binding(DBTableField::tableMember(), $arrData, 'update', gd_array_keys($arrData), ['memNo', 'memId', 'memPw',]);
//@formatter:on
$companyCertificationService->delete($arrData['certificationDeleteSno']);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
if ($before === null) {
throw new \Exception(__('수정 전 회원정보가 없습니다.'));
}
'rc_groupNm' => $groupInfo[$after['groupSno']],
'name' => $after['memNm'],
'memNm' => $after['memNm'],
 
'memId' => $after['memId'],
'mileage' => $after['mileage'],
'deposit' => $after['deposit'],
'groupNm' => $groupInfo[$member['groupSno']],
'name' => $member['memNm'],
'memNm' => $member['memNm'],
 
'memId' => $member['memId'],
'mileage' => $member['mileage'],
'deposit' => $member['deposit'],
namespace Bundle\Component\Member;
 
use App;
 
 
use Component\Database\DBTableField;
use Component\Mail\MailUtil;
use Component\Member\Group\Util as GroupUtil;
 
use Component\Member\Util\MemberUtil;
use Component\Mileage\Mileage;
use Component\Mileage\MileageDAO;
use Origin\Service\WebHook\MemberWebHookService;
use Request;
use Session;
 
 
/**
* Class 관리자에서 사용하는 회원 관리
/**
* 회원 목록
*
* @author sunny
*
* @param $arrData
*
* @return array data
 
 
* @deprecated
*/
public function getMemberPageList($arrData)
StringUtils::strIsSet($arrData['maillingFl'], 'n');
StringUtils::strIsSet($arrData['smsFl'], 'n');
 
 
 
 
 
 
 
 
 
 
$arrData = $this->validateMemberByAdminModification($arrData);
 
 
 
 
//@formatter:off
$arrBind = $db->get_binding(DBTableField::tableMember(), $arrData, 'update', gd_array_keys($arrData), ['memNo', 'memId', 'memPw',]);
//@formatter:on
$companyCertificationService->delete($arrData['certificationDeleteSno']);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
if ($before === null) {
throw new \Exception(__('수정 전 회원정보가 없습니다.'));
}
'rc_groupNm' => $groupInfo[$after['groupSno']],
'name' => $after['memNm'],
'memNm' => $after['memNm'],
 
'memId' => $after['memId'],
'mileage' => $after['mileage'],
'deposit' => $after['deposit'],
'groupNm' => $groupInfo[$member['groupSno']],
'name' => $member['memNm'],
'memNm' => $member['memNm'],
 
'memId' => $member['memId'],
'mileage' => $member['mileage'],
'deposit' => $member['deposit'],
 
변경 후MemberAdmin.php
namespace Bundle\Component\Member;
 
use App;
 
use Carbon\Carbon;
use Component\Database\DBTableField;
use Component\Mail\MailUtil;
use Component\Member\Group\Util as GroupUtil;
use Component\Member\Sleep\SleepService;
use Component\Member\Util\MemberUtil;
use Component\Mileage\Mileage;
use Component\Mileage\MileageDAO;
use Origin\Service\WebHook\MemberWebHookService;
use Request;
use Session;
use Origin\Model\Member\Member as MemberModel;
 
/**
* Class 관리자에서 사용하는 회원 관리
/**
* 회원 목록
*
 
 
* @param $arrData
*
* @return array data
* @author sunny
*
* @deprecated
*/
public function getMemberPageList($arrData)
StringUtils::strIsSet($arrData['maillingFl'], 'n');
StringUtils::strIsSet($arrData['smsFl'], 'n');
 
// validateMemberByAdminModification이 화이트리스트 필터링으로 file 관련 키들을 제거하므로
// validate 전 백업 후 validate 직후 복원
$preservedFileKeys = [];
foreach (['comAddiCert', 'companyCertification', 'certificationDeleteSno'] as $fileKey) {
if (array_key_exists($fileKey, $arrData)) {
$preservedFileKeys[$fileKey] = $arrData[$fileKey];
}
}
 
$arrData = $this->validateMemberByAdminModification($arrData);
 
foreach ($preservedFileKeys as $fileKey => $fileVal) {
$arrData[$fileKey] = $fileVal;
}
//@formatter:off
$arrBind = $db->get_binding(DBTableField::tableMember(), $arrData, 'update', gd_array_keys($arrData), ['memNo', 'memId', 'memPw',]);
//@formatter:on
$companyCertificationService->delete($arrData['certificationDeleteSno']);
}
 
// 추가 첨부 파일 업로드 (수정 흐름)
if ($arrData['memberFl'] == 'business' && !empty($arrData['comAddiCert'])) {
$companyCertificationService = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$arrComAddiCert = \Component\Member\MemberVO::reArrangeComAddiCertFiles($arrData['comAddiCert']);
foreach ($arrComAddiCert as $index => $value) {
// 신규 업로드 파일이 있으면 업로드, 업로드 없이 삭제 식별자만 있으면 기존 추가서류 삭제
if (!empty($value['tmp_name'])) {
$companyCertificationService->uploadAdditional($value, $arrData['memNo'], $index);
continue;
}
if (!empty($value['DeleteSno'])) {
$companyCertificationService->delete((int)$value['DeleteSno']);
}
}
}
 
if ($before === null) {
throw new \Exception(__('수정 전 회원정보가 없습니다.'));
}
'rc_groupNm' => $groupInfo[$after['groupSno']],
'name' => $after['memNm'],
'memNm' => $after['memNm'],
'memNo' => $after['memNo'],
'memId' => $after['memId'],
'mileage' => $after['mileage'],
'deposit' => $after['deposit'],
'groupNm' => $groupInfo[$member['groupSno']],
'name' => $member['memNm'],
'memNm' => $member['memNm'],
'memNo' => $member['memNo'],
'memId' => $member['memId'],
'mileage' => $member['mileage'],
'deposit' => $member['deposit'],
namespace Bundle\Component\Member;
 
use App;
 
use Carbon\Carbon;
use Component\Database\DBTableField;
use Component\Mail\MailUtil;
use Component\Member\Group\Util as GroupUtil;
use Component\Member\Sleep\SleepService;
use Component\Member\Util\MemberUtil;
use Component\Mileage\Mileage;
use Component\Mileage\MileageDAO;
use Origin\Service\WebHook\MemberWebHookService;
use Request;
use Session;
use Origin\Model\Member\Member as MemberModel;
 
/**
* Class 관리자에서 사용하는 회원 관리
/**
* 회원 목록
*
 
 
* @param $arrData
*
* @return array data
* @author sunny
*
* @deprecated
*/
public function getMemberPageList($arrData)
StringUtils::strIsSet($arrData['maillingFl'], 'n');
StringUtils::strIsSet($arrData['smsFl'], 'n');
 
// validateMemberByAdminModification이 화이트리스트 필터링으로 file 관련 키들을 제거하므로
// validate 전 백업 후 validate 직후 복원
$preservedFileKeys = [];
foreach (['comAddiCert', 'companyCertification', 'certificationDeleteSno'] as $fileKey) {
if (array_key_exists($fileKey, $arrData)) {
$preservedFileKeys[$fileKey] = $arrData[$fileKey];
}
}
 
$arrData = $this->validateMemberByAdminModification($arrData);
 
foreach ($preservedFileKeys as $fileKey => $fileVal) {
$arrData[$fileKey] = $fileVal;
}
//@formatter:off
$arrBind = $db->get_binding(DBTableField::tableMember(), $arrData, 'update', gd_array_keys($arrData), ['memNo', 'memId', 'memPw',]);
//@formatter:on
$companyCertificationService->delete($arrData['certificationDeleteSno']);
}
 
// 추가 첨부 파일 업로드 (수정 흐름)
if ($arrData['memberFl'] == 'business' && !empty($arrData['comAddiCert'])) {
$companyCertificationService = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$arrComAddiCert = \Component\Member\MemberVO::reArrangeComAddiCertFiles($arrData['comAddiCert']);
foreach ($arrComAddiCert as $index => $value) {
// 신규 업로드 파일이 있으면 업로드, 업로드 없이 삭제 식별자만 있으면 기존 추가서류 삭제
if (!empty($value['tmp_name'])) {
$companyCertificationService->uploadAdditional($value, $arrData['memNo'], $index);
continue;
}
if (!empty($value['DeleteSno'])) {
$companyCertificationService->delete((int)$value['DeleteSno']);
}
}
}
 
if ($before === null) {
throw new \Exception(__('수정 전 회원정보가 없습니다.'));
}
'rc_groupNm' => $groupInfo[$after['groupSno']],
'name' => $after['memNm'],
'memNm' => $after['memNm'],
'memNo' => $after['memNo'],
'memId' => $after['memId'],
'mileage' => $after['mileage'],
'deposit' => $after['deposit'],
'groupNm' => $groupInfo[$member['groupSno']],
'name' => $member['memNm'],
'memNm' => $member['memNm'],
'memNo' => $member['memNo'],
'memId' => $member['memId'],
'mileage' => $member['mileage'],
'deposit' => $member['deposit'],
 
Component/Member/MemberDAO.php+2-2
변경 전MemberDAO.php
{
$this->db->strField = 'm.*, ms.snsJoinFl, IF(ms.connectFl=\'y\', ms.snsTypeFl, \'\') AS snsTypeFl, ms.connectFl, mcc.imageFileNm as companyCertification';
$this->db->strJoin = ' LEFT JOIN ' . DB_MEMBER_SNS . ' AS ms ON m.memNo = ms.memNo';
$this->db->strJoin .= ' LEFT JOIN ' . DB_MEMBER_COMPANY_CERTIFICATION . ' AS mcc ON m.memNo = mcc.memNo';
$this->db->strWhere = 'm.memNo=?';
$this->db->bind_param_push($bind, $this->fields['memNo'], $memberNo);
$query = $this->db->query_complete();
{
$this->db->strField = 'm.*, ms.snsJoinFl, IF(ms.connectFl=\'y\', ms.snsTypeFl, \'\') AS snsTypeFl, ms.connectFl, mcc.imageFileNm as companyCertification';
$this->db->strJoin = ' LEFT JOIN ' . DB_MEMBER_SNS . ' AS ms ON m.memNo = ms.memNo';
$this->db->strJoin .= ' LEFT JOIN ' . DB_MEMBER_COMPANY_CERTIFICATION . ' AS mcc ON m.memNo = mcc.memNo';
$this->db->strWhere = 'm.memNo=?';
$this->db->bind_param_push($bind, $this->fields['memNo'], $memberNo);
$query = $this->db->query_complete();
 
변경 후MemberDAO.php
{
$this->db->strField = 'm.*, ms.snsJoinFl, IF(ms.connectFl=\'y\', ms.snsTypeFl, \'\') AS snsTypeFl, ms.connectFl, mcc.imageFileNm as companyCertification';
$this->db->strJoin = ' LEFT JOIN ' . DB_MEMBER_SNS . ' AS ms ON m.memNo = ms.memNo';
$this->db->strJoin .= ' LEFT JOIN ' . DB_MEMBER_COMPANY_CERTIFICATION . ' AS mcc ON m.memNo = mcc.memNo AND mcc.documentType = \'registration\'';
$this->db->strWhere = 'm.memNo=?';
$this->db->bind_param_push($bind, $this->fields['memNo'], $memberNo);
$query = $this->db->query_complete();
{
$this->db->strField = 'm.*, ms.snsJoinFl, IF(ms.connectFl=\'y\', ms.snsTypeFl, \'\') AS snsTypeFl, ms.connectFl, mcc.imageFileNm as companyCertification';
$this->db->strJoin = ' LEFT JOIN ' . DB_MEMBER_SNS . ' AS ms ON m.memNo = ms.memNo';
$this->db->strJoin .= ' LEFT JOIN ' . DB_MEMBER_COMPANY_CERTIFICATION . ' AS mcc ON m.memNo = mcc.memNo AND mcc.documentType = \'registration\'';
$this->db->strWhere = 'm.memNo=?';
$this->db->bind_param_push($bind, $this->fields['memNo'], $memberNo);
$query = $this->db->query_complete();
 
Component/Member/Member.php+43-9
변경 전Member.php
use Bundle\Component\Godo\GodoKakaoServerApi;
use Bundle\Component\Policy\KakaoLoginPolicy;
use Component\Database\DBTableField;
 
use Component\Member\Exception\LoginException;
use Component\Facebook\Facebook;
use Component\Godo\GodoNaverServerApi;
$cartWebHookService = \App::getInstance(CartWebHookService::class);
$migratedCartSnos = $cartWebHookService->findGuestCartSnos(Session::get('siteKey'));
$this->refreshBasket($encryptMember['memNo']);
 
if ($encryptMember['loginLimit']['loginFailCount'] ?? 0 > 0) {
$initLimitLoginLog = $this->initLimitLoginLog($encryptMember);
$encryptMember = $initLimitLoginLog['member'];
$goodsStatistics->setCartMemberUpdateStatistics($cartStatistics);
}
 
 
/**
* 아이디찾기
*
 
// 사업자등록증 등록
if ($params['memberFl'] == 'business' && !empty($params['comCertification']['name'][0])) {
$companyCertificationService = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$companyCertificationService->upload($params['comCertification'], $member['memNo']);
}
 
 
 
 
 
 
 
 
 
 
 
$session->del(Member::SESSION_JOIN_INFO);
 
if ($member['mallSno'] == DEFAULT_MALL_NUMBER) {
$this->benefitJoin($vo);
 
// 사업자등록증 업로드
 
if ($vo->getMemberFl() === 'business' && !empty($vo->getCompanyCertification())) {
$companyCertificationService = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$companyCertificationService->upload($vo->getCompanyCertification(), $memberNo);
}
 
 
 
 
 
 
 
}
);
 
'mileage' => 0,
'deposit' => 0,
'memNm' => $member['memNm'],
 
'memId' => $member['memId'],
]
);
use Bundle\Component\Godo\GodoKakaoServerApi;
use Bundle\Component\Policy\KakaoLoginPolicy;
use Component\Database\DBTableField;
 
use Component\Member\Exception\LoginException;
use Component\Facebook\Facebook;
use Component\Godo\GodoNaverServerApi;
$cartWebHookService = \App::getInstance(CartWebHookService::class);
$migratedCartSnos = $cartWebHookService->findGuestCartSnos(Session::get('siteKey'));
$this->refreshBasket($encryptMember['memNo']);
 
if ($encryptMember['loginLimit']['loginFailCount'] ?? 0 > 0) {
$initLimitLoginLog = $this->initLimitLoginLog($encryptMember);
$encryptMember = $initLimitLoginLog['member'];
$goodsStatistics->setCartMemberUpdateStatistics($cartStatistics);
}
 
 
/**
* 아이디찾기
*
 
// 사업자등록증 등록
if ($params['memberFl'] == 'business' && !empty($params['comCertification']['name'][0])) {
$companyCertificationService = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$companyCertificationService->upload($params['comCertification'], $member['memNo']);
}
 
 
 
 
 
 
 
 
 
 
 
$session->del(Member::SESSION_JOIN_INFO);
 
if ($member['mallSno'] == DEFAULT_MALL_NUMBER) {
*
* @return int|string
*/
public function register(\Component\Member\MemberVO $vo)
{
$vo->databaseFormat();
$vo->setEntryDt(date('Y-m-d H:i:s'));
$this->benefitJoin($vo);
 
// 사업자등록증 업로드
 
if ($vo->getMemberFl() === 'business' && !empty($vo->getCompanyCertification())) {
$companyCertificationService = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$companyCertificationService->upload($vo->getCompanyCertification(), $memberNo);
}
 
 
 
 
 
 
 
}
);
 
'mileage' => 0,
'deposit' => 0,
'memNm' => $member['memNm'],
 
'memId' => $member['memId'],
]
);
 
변경 후Member.php
use Bundle\Component\Godo\GodoKakaoServerApi;
use Bundle\Component\Policy\KakaoLoginPolicy;
use Component\Database\DBTableField;
use Component\Member\Company\CompanyCertification;
use Component\Member\Exception\LoginException;
use Component\Facebook\Facebook;
use Component\Godo\GodoNaverServerApi;
$cartWebHookService = \App::getInstance(CartWebHookService::class);
$migratedCartSnos = $cartWebHookService->findGuestCartSnos(Session::get('siteKey'));
$this->refreshBasket($encryptMember['memNo']);
 
if ($encryptMember['loginLimit']['loginFailCount'] ?? 0 > 0) {
$initLimitLoginLog = $this->initLimitLoginLog($encryptMember);
$encryptMember = $initLimitLoginLog['member'];
$goodsStatistics->setCartMemberUpdateStatistics($cartStatistics);
}
 
 
/**
* 아이디찾기
*
 
// 사업자등록증 등록
if ($params['memberFl'] == 'business' && !empty($params['comCertification']['name'][0])) {
$companyCertificationService = \App::getInstance(CompanyCertification::class);
$companyCertificationService->upload($params['comCertification'], $member['memNo']);
}
 
// 추가 첨부 등록 (comAddiCert)
if ($params['memberFl'] == 'business' && !empty($vo->getComAddiCert())) {
if (!isset($companyCertificationService)) {
$companyCertificationService = \App::getInstance(CompanyCertification::class);
}
foreach ($vo->getComAddiCert() as $index => $value) {
$companyCertificationService->uploadAdditional($value, $member['memNo'], $index);
}
}
 
$session->del(Member::SESSION_JOIN_INFO);
 
if ($member['mallSno'] == DEFAULT_MALL_NUMBER) {
$this->benefitJoin($vo);
 
// 사업자등록증 업로드
$companyCertificationService = \App::getInstance(CompanyCertification::class);
if ($vo->getMemberFl() === 'business' && !empty($vo->getCompanyCertification())) {
 
$companyCertificationService->upload($vo->getCompanyCertification(), $memberNo);
}
 
//추가 서류 업로드
if ($vo->getMemberFl() === 'business' && !empty($vo->getComAddiCert())) {
foreach ($vo->getComAddiCert() as $index => $value) {
$companyCertificationService->uploadAdditional($value, $memberNo, $index);
}
}
}
);
 
'mileage' => 0,
'deposit' => 0,
'memNm' => $member['memNm'],
'memNo' => $member['memNo'],
'memId' => $member['memId'],
]
);
use Bundle\Component\Godo\GodoKakaoServerApi;
use Bundle\Component\Policy\KakaoLoginPolicy;
use Component\Database\DBTableField;
use Component\Member\Company\CompanyCertification;
use Component\Member\Exception\LoginException;
use Component\Facebook\Facebook;
use Component\Godo\GodoNaverServerApi;
$cartWebHookService = \App::getInstance(CartWebHookService::class);
$migratedCartSnos = $cartWebHookService->findGuestCartSnos(Session::get('siteKey'));
$this->refreshBasket($encryptMember['memNo']);
 
if ($encryptMember['loginLimit']['loginFailCount'] ?? 0 > 0) {
$initLimitLoginLog = $this->initLimitLoginLog($encryptMember);
$encryptMember = $initLimitLoginLog['member'];
$goodsStatistics->setCartMemberUpdateStatistics($cartStatistics);
}
 
 
/**
* 아이디찾기
*
 
// 사업자등록증 등록
if ($params['memberFl'] == 'business' && !empty($params['comCertification']['name'][0])) {
$companyCertificationService = \App::getInstance(CompanyCertification::class);
$companyCertificationService->upload($params['comCertification'], $member['memNo']);
}
 
// 추가 첨부 등록 (comAddiCert)
if ($params['memberFl'] == 'business' && !empty($vo->getComAddiCert())) {
if (!isset($companyCertificationService)) {
$companyCertificationService = \App::getInstance(CompanyCertification::class);
}
foreach ($vo->getComAddiCert() as $index => $value) {
$companyCertificationService->uploadAdditional($value, $member['memNo'], $index);
}
}
 
$session->del(Member::SESSION_JOIN_INFO);
 
if ($member['mallSno'] == DEFAULT_MALL_NUMBER) {
*
* @return int|string
*/
public function register(MemberVO $vo)
{
$vo->databaseFormat();
$vo->setEntryDt(date('Y-m-d H:i:s'));
$this->benefitJoin($vo);
 
// 사업자등록증 업로드
$companyCertificationService = \App::getInstance(CompanyCertification::class);
if ($vo->getMemberFl() === 'business' && !empty($vo->getCompanyCertification())) {
 
$companyCertificationService->upload($vo->getCompanyCertification(), $memberNo);
}
 
//추가 서류 업로드
if ($vo->getMemberFl() === 'business' && !empty($vo->getComAddiCert())) {
foreach ($vo->getComAddiCert() as $index => $value) {
$companyCertificationService->uploadAdditional($value, $memberNo, $index);
}
}
}
);
 
'mileage' => 0,
'deposit' => 0,
'memNm' => $member['memNm'],
'memNo' => $member['memNo'],
'memId' => $member['memId'],
]
);
 
Component/Member/MemberVO.php+116-2
변경 전MemberVO.php
protected $under14ConsentFl;
protected $companyCertification;
protected $certificationDeleteSno;
 
 
function __construct(array $arr = null)
{
if (is_null($arr) === false) {
foreach ($arr as $key => $value) {
 
 
 
 
 
$this->$key = $value;
}
}
}
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public function toChecked()
{
$array = $this->toArray();
public function adminViewFormat()
{
// 사업자 번호가 DB에 저장될 때 - 가 없이 들어간 경우를 위한 체크
if (strpos($this->busiNo, '-') == false) {
$this->busiNo = StringUtils::numberToBusiness($this->busiNo);
}
$arrData = $this->toArray();
if ($index === 'lastNotificationDt') {
continue;
}
 
 
 
 
if ($index === 'busiNo' && strpos($item, '-') > -1) {
$this->$index = explode('-', $item);
} elseif ($index === 'email' && strpos($item, '@') > -1) {
}
 
}
 
 
 
 
 
 
 
 
}
protected $under14ConsentFl;
protected $companyCertification;
protected $certificationDeleteSno;
 
 
function __construct(array $arr = null)
{
if (is_null($arr) === false) {
foreach ($arr as $key => $value) {
 
 
 
 
 
$this->$key = $value;
}
}
}
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public function toChecked()
{
$array = $this->toArray();
public function adminViewFormat()
{
// 사업자 번호가 DB에 저장될 때 - 가 없이 들어간 경우를 위한 체크
if (strpos($this->busiNo, '-') == false) {
$this->busiNo = StringUtils::numberToBusiness($this->busiNo);
}
$arrData = $this->toArray();
if ($index === 'lastNotificationDt') {
continue;
}
 
 
 
 
if ($index === 'busiNo' && strpos($item, '-') > -1) {
$this->$index = explode('-', $item);
} elseif ($index === 'email' && strpos($item, '@') > -1) {
}
 
}
 
 
 
 
 
 
 
 
}
 
변경 후MemberVO.php
protected $under14ConsentFl;
protected $companyCertification;
protected $certificationDeleteSno;
protected $comAddiCert;
 
function __construct(array $arr = null)
{
if (is_null($arr) === false) {
foreach ($arr as $key => $value) {
 
// 추가 첨부 파일은 PHP $_FILES의 transposed nested 구조를 정상 nested 구조로 변환
if ($key === 'comAddiCert' && is_array($value)) {
$value = self::reArrangeComAddiCertFiles($value);
}
$this->$key = $value;
}
}
}
}
 
/**
* 추가 첨부 파일($_FILES['comAddiCert'])의 transposed 구조를 정상 file array로 변환
*
* @param array $files
* @return array
*/
public static function reArrangeComAddiCertFiles(array $files): array
{
if (!isset($files['name']) || !is_array($files['name'])) {
return $files;
}
 
$keys = array_keys($files);
$result = [];
 
foreach ($files['name'] as $index => $fields) {
if (!is_array($fields) || !isset($fields['file'])) {
continue;
}
 
$fileData = [];
foreach ($keys as $k) {
$value = $files[$k][$index]['file'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
$fileData[$k] = [$value];
}
 
if ((int)($fileData['error'][0] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) {
continue;
}
 
$result[$index] = $fileData;
}
 
return $result;
}
 
public function toChecked()
{
$array = $this->toArray();
public function adminViewFormat()
{
// 사업자 번호가 DB에 저장될 때 - 가 없이 들어간 경우를 위한 체크
if (is_string($this->busiNo) && strpos($this->busiNo, '-') == false) {
$this->busiNo = StringUtils::numberToBusiness($this->busiNo);
}
$arrData = $this->toArray();
if ($index === 'lastNotificationDt') {
continue;
}
// PHP 8: strpos는 string만 허용. 이미 array로 변환된 필드(busiNo, email 등 재진입 케이스) 보호
if (!is_string($item)) {
continue;
}
if ($index === 'busiNo' && strpos($item, '-') > -1) {
$this->$index = explode('-', $item);
} elseif ($index === 'email' && strpos($item, '@') > -1) {
}
 
}
 
/**
* @return mixed
*/
public function getComAddiCert()
{
return $this->comAddiCert;
}
}
protected $under14ConsentFl;
protected $companyCertification;
protected $certificationDeleteSno;
protected $comAddiCert;
 
function __construct(array $arr = null)
{
if (is_null($arr) === false) {
foreach ($arr as $key => $value) {
 
// 추가 첨부 파일은 PHP $_FILES의 transposed nested 구조를 정상 nested 구조로 변환
if ($key === 'comAddiCert' && is_array($value)) {
$value = self::reArrangeComAddiCertFiles($value);
}
$this->$key = $value;
}
}
}
}
 
/**
* 추가 첨부 파일($_FILES['comAddiCert'])의 transposed 구조를 정상 file array로 변환
*
* @param array $files
* @return array
*/
public static function reArrangeComAddiCertFiles(array $files): array
{
if (!isset($files['name']) || !is_array($files['name'])) {
return $files;
}
 
$keys = array_keys($files);
$result = [];
 
foreach ($files['name'] as $index => $fields) {
if (!is_array($fields) || !isset($fields['file'])) {
continue;
}
 
$fileData = [];
foreach ($keys as $k) {
$value = $files[$k][$index]['file'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
$fileData[$k] = [$value];
}
 
if ((int)($fileData['error'][0] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) {
continue;
}
 
$result[$index] = $fileData;
}
 
return $result;
}
 
public function toChecked()
{
$array = $this->toArray();
public function adminViewFormat()
{
// 사업자 번호가 DB에 저장될 때 - 가 없이 들어간 경우를 위한 체크
if (is_string($this->busiNo) && strpos($this->busiNo, '-') == false) {
$this->busiNo = StringUtils::numberToBusiness($this->busiNo);
}
$arrData = $this->toArray();
if ($index === 'lastNotificationDt') {
continue;
}
// PHP 8: strpos는 string만 허용. 이미 array로 변환된 필드(busiNo, email 등 재진입 케이스) 보호
if (!is_string($item)) {
continue;
}
if ($index === 'busiNo' && strpos($item, '-') > -1) {
$this->$index = explode('-', $item);
} elseif ($index === 'email' && strpos($item, '@') > -1) {
}
 
}
 
/**
* @return mixed
*/
public function getComAddiCert()
{
return $this->comAddiCert;
}
}
 
Component/Member/MyPage.php+68-4
변경 전MyPage.php
 
 
use App;
 
use Component\Database\DBTableField;
use Component\Mail\MailMimeAuto;
 
use Component\Member\Util\MemberUtil;
use Component\Validator\Validator;
use Component\Agreement\BuyerInform;
if ($result == 1) {
// 사업자등록증 등록/삭제
if ($requestParams['memberFl'] == 'business' && !empty($requestParams['comCertification']['name'][0])) {
$companyCertificationService = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$companyCertificationService->upload($requestParams['comCertification'], $requestParams['memNo']);
}
 
// 사업자등록증 삭제
if ($requestParams['memberFl'] == 'business' && !empty($requestParams['certificationDeleteSno'])) {
$companyCertificationService = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$companyCertificationService->delete($requestParams['certificationDeleteSno']);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
$memberWithGroup = $this->memberDao->selectMemberWithGroup($requestParams['memNo'], 'memNo');
if ($requestParams['comCertification'] != '') {
$v->add('comCertification', '');
}
 
 
 
if ($v->act($requestParams, true) === false) {
if (gd_array_key_exists('memPw', $v->errors) && gd_array_key_exists('memPwRe', $v->errors)) {
unset($v->errors['memPwRe']);
 
 
use App;
 
use Component\Database\DBTableField;
use Component\Mail\MailMimeAuto;
 
use Component\Member\Util\MemberUtil;
use Component\Validator\Validator;
use Component\Agreement\BuyerInform;
if ($result == 1) {
// 사업자등록증 등록/삭제
if ($requestParams['memberFl'] == 'business' && !empty($requestParams['comCertification']['name'][0])) {
$companyCertificationService = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$companyCertificationService->upload($requestParams['comCertification'], $requestParams['memNo']);
}
 
// 사업자등록증 삭제
if ($requestParams['memberFl'] == 'business' && !empty($requestParams['certificationDeleteSno'])) {
$companyCertificationService = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$companyCertificationService->delete($requestParams['certificationDeleteSno']);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
$memberWithGroup = $this->memberDao->selectMemberWithGroup($requestParams['memNo'], 'memNo');
if ($requestParams['comCertification'] != '') {
$v->add('comCertification', '');
}
 
 
 
if ($v->act($requestParams, true) === false) {
if (gd_array_key_exists('memPw', $v->errors) && gd_array_key_exists('memPwRe', $v->errors)) {
unset($v->errors['memPwRe']);
 
변경 후MyPage.php
 
 
use App;
use Component\Member\MemberVO;
use Component\Database\DBTableField;
use Component\Mail\MailMimeAuto;
use Component\Member\Company\CompanyCertification;
use Component\Member\Util\MemberUtil;
use Component\Validator\Validator;
use Component\Agreement\BuyerInform;
if ($result == 1) {
// 사업자등록증 등록/삭제
if ($requestParams['memberFl'] == 'business' && !empty($requestParams['comCertification']['name'][0])) {
$companyCertificationService = \App::getInstance(CompanyCertification::class);
$companyCertificationService->upload($requestParams['comCertification'], $requestParams['memNo']);
}
 
// 사업자등록증 삭제
if ($requestParams['memberFl'] == 'business' && !empty($requestParams['certificationDeleteSno'])) {
$companyCertificationService = \App::getInstance(CompanyCertification::class);
$companyCertificationService->delete($requestParams['certificationDeleteSno']);
}
 
// 추가 첨부 등록 (comAddiCert)
// $requestParams['comAddiCert'] 는 컨트롤러에서 array_merge(POST, FILES) 시 FILES 가 덮어써서 transposed 구조로 들어옴
if ($requestParams['memberFl'] == 'business' && !empty($requestParams['comAddiCert'])) {
if (!isset($companyCertificationService)) {
$companyCertificationService = \App::getInstance(CompanyCertification::class);
}
$arrComAddiCert = MemberVO::reArrangeComAddiCertFiles($requestParams['comAddiCert']);
foreach ($arrComAddiCert as $index => $value) {
$companyCertificationService->uploadAdditional($value, $requestParams['memNo'], $index);
}
}
 
// 추가 첨부 삭제 (comAddiCert[N][DeleteSno])
// POST 는 array_merge 시 FILES 에 덮여 손실되므로, Request 에서 POST 만 따로 읽는다
if ($requestParams['memberFl'] == 'business') {
$postComAddiCert = \App::getInstance('request')->post()->all()['comAddiCert'] ?? [];
if (!empty($postComAddiCert) && is_array($postComAddiCert)) {
if (!isset($companyCertificationService)) {
$companyCertificationService = \App::getInstance(CompanyCertification::class);
}
foreach ($postComAddiCert as $item) {
if (!empty($item['DeleteSno'])) {
$companyCertificationService->delete((int)$item['DeleteSno']);
}
}
}
}
}
 
$memberWithGroup = $this->memberDao->selectMemberWithGroup($requestParams['memNo'], 'memNo');
if ($requestParams['comCertification'] != '') {
$v->add('comCertification', '');
}
if (!empty($requestParams['comAddiCert'])) {
$v->add('comAddiCert', '');
}
if ($v->act($requestParams, true) === false) {
if (gd_array_key_exists('memPw', $v->errors) && gd_array_key_exists('memPwRe', $v->errors)) {
unset($v->errors['memPwRe']);
 
 
use App;
use Component\Member\MemberVO;
use Component\Database\DBTableField;
use Component\Mail\MailMimeAuto;
use Component\Member\Company\CompanyCertification;
use Component\Member\Util\MemberUtil;
use Component\Validator\Validator;
use Component\Agreement\BuyerInform;
if ($result == 1) {
// 사업자등록증 등록/삭제
if ($requestParams['memberFl'] == 'business' && !empty($requestParams['comCertification']['name'][0])) {
$companyCertificationService = \App::getInstance(CompanyCertification::class);
$companyCertificationService->upload($requestParams['comCertification'], $requestParams['memNo']);
}
 
// 사업자등록증 삭제
if ($requestParams['memberFl'] == 'business' && !empty($requestParams['certificationDeleteSno'])) {
$companyCertificationService = \App::getInstance(CompanyCertification::class);
$companyCertificationService->delete($requestParams['certificationDeleteSno']);
}
 
// 추가 첨부 등록 (comAddiCert)
// $requestParams['comAddiCert'] 는 컨트롤러에서 array_merge(POST, FILES) 시 FILES 가 덮어써서 transposed 구조로 들어옴
if ($requestParams['memberFl'] == 'business' && !empty($requestParams['comAddiCert'])) {
if (!isset($companyCertificationService)) {
$companyCertificationService = \App::getInstance(CompanyCertification::class);
}
$arrComAddiCert = MemberVO::reArrangeComAddiCertFiles($requestParams['comAddiCert']);
foreach ($arrComAddiCert as $index => $value) {
$companyCertificationService->uploadAdditional($value, $requestParams['memNo'], $index);
}
}
 
// 추가 첨부 삭제 (comAddiCert[N][DeleteSno])
// POST 는 array_merge 시 FILES 에 덮여 손실되므로, Request 에서 POST 만 따로 읽는다
if ($requestParams['memberFl'] == 'business') {
$postComAddiCert = \App::getInstance('request')->post()->all()['comAddiCert'] ?? [];
if (!empty($postComAddiCert) && is_array($postComAddiCert)) {
if (!isset($companyCertificationService)) {
$companyCertificationService = \App::getInstance(CompanyCertification::class);
}
foreach ($postComAddiCert as $item) {
if (!empty($item['DeleteSno'])) {
$companyCertificationService->delete((int)$item['DeleteSno']);
}
}
}
}
}
 
$memberWithGroup = $this->memberDao->selectMemberWithGroup($requestParams['memNo'], 'memNo');
if ($requestParams['comCertification'] != '') {
$v->add('comCertification', '');
}
if (!empty($requestParams['comAddiCert'])) {
$v->add('comAddiCert', '');
}
if ($v->act($requestParams, true) === false) {
if (gd_array_key_exists('memPw', $v->errors) && gd_array_key_exists('memPwRe', $v->errors)) {
unset($v->errors['memPwRe']);
 
Component/Policy/JoinItemPolicy.php+42-6
변경 전JoinItemPolicy.php
throw new \Exception(__('회원정보 변경 시 추천인아이디 등록 불가는 추천인아이디 항목을 사용하여야 합니다'));
}
if (isset($getValue['certificationFileSize']) && $getValue['certificationFileSize'] !== '') {
if (!is_int((int)$getValue['certificationFileSize']) || $getValue['certificationFileSize'] < self::MIN_COMPANY_CERTIFICATION_FILE_SIZE || $getValue['certificationFileSize'] > self::MAX_COMPANY_CERTIFICATION_FILE_SIZE) {
throw new \Exception(sprintf(__('업로드 용량은 최소 %dMB 부터 %dMB 까지 정수로 설정할 수 있습니다.'), self::MIN_COMPANY_CERTIFICATION_FILE_SIZE, self::MAX_COMPANY_CERTIFICATION_FILE_SIZE));
}
$getValue['comCertification']['maxSize'] = $getValue['certificationFileSize'];
}
 
 
 
 
 
 
 
 
 
unset($getValue['certificationFileSize']);
 
$getValue['memPw']['minlen'] = 10;
 
return $totalInfo;
}
 
 
 
 
 
 
 
 
 
 
 
}
throw new \Exception(__('회원정보 변경 시 추천인아이디 등록 불가는 추천인아이디 항목을 사용하여야 합니다'));
}
if (isset($getValue['certificationFileSize']) && $getValue['certificationFileSize'] !== '') {
if (!is_int((int)$getValue['certificationFileSize']) || $getValue['certificationFileSize'] < self::MIN_COMPANY_CERTIFICATION_FILE_SIZE || $getValue['certificationFileSize'] > self::MAX_COMPANY_CERTIFICATION_FILE_SIZE) {
throw new \Exception(sprintf(__('업로드 용량은 최소 %dMB 부터 %dMB 까지 정수로 설정할 수 있습니다.'), self::MIN_COMPANY_CERTIFICATION_FILE_SIZE, self::MAX_COMPANY_CERTIFICATION_FILE_SIZE));
}
$getValue['comCertification']['maxSize'] = $getValue['certificationFileSize'];
}
 
 
 
 
 
 
 
 
 
unset($getValue['certificationFileSize']);
 
$getValue['memPw']['minlen'] = 10;
 
return $totalInfo;
}
 
 
 
 
 
 
 
 
 
 
 
}
 
변경 후JoinItemPolicy.php
throw new \Exception(__('회원정보 변경 시 추천인아이디 등록 불가는 추천인아이디 항목을 사용하여야 합니다'));
}
if (isset($getValue['certificationFileSize']) && $getValue['certificationFileSize'] !== '') {
$this->validUploadFileSize($getValue);
 
 
$getValue['comCertification']['maxSize'] = $getValue['certificationFileSize'];
}
 
foreach ($getValue['comAddiCert'] as $index => $value) {
if (isset($value['certificationFileSize']) && $value['certificationFileSize'] !== '') {
$this->validUploadFileSize($value);
$getValue["comAddiCert$index"] = $value;
}
}
 
unset($getValue['comAddiCert']);
unset($getValue['certificationFileSize']);
 
$getValue['memPw']['minlen'] = 10;
 
return $totalInfo;
}
 
private function validUploadFileSize(array $value)
{
if (
!is_int((int)$value['certificationFileSize']) ||
$value['certificationFileSize'] < self::MIN_COMPANY_CERTIFICATION_FILE_SIZE ||
$value['certificationFileSize'] > self::MAX_COMPANY_CERTIFICATION_FILE_SIZE
) {
throw new \Exception(sprintf(__('업로드 용량은 최소 %dMB 부터 %dMB 까지 정수로 설정할 수 있습니다.'), self::MIN_COMPANY_CERTIFICATION_FILE_SIZE, self::MAX_COMPANY_CERTIFICATION_FILE_SIZE));
}
}
}
throw new \Exception(__('회원정보 변경 시 추천인아이디 등록 불가는 추천인아이디 항목을 사용하여야 합니다'));
}
if (isset($getValue['certificationFileSize']) && $getValue['certificationFileSize'] !== '') {
$this->validUploadFileSize($getValue);
 
 
$getValue['comCertification']['maxSize'] = $getValue['certificationFileSize'];
}
 
foreach ($getValue['comAddiCert'] as $index => $value) {
if (isset($value['certificationFileSize']) && $value['certificationFileSize'] !== '') {
$this->validUploadFileSize($value);
$getValue["comAddiCert$index"] = $value;
}
}
 
unset($getValue['comAddiCert']);
unset($getValue['certificationFileSize']);
 
$getValue['memPw']['minlen'] = 10;
 
return $totalInfo;
}
 
private function validUploadFileSize(array $value)
{
if (
!is_int((int)$value['certificationFileSize']) ||
$value['certificationFileSize'] < self::MIN_COMPANY_CERTIFICATION_FILE_SIZE ||
$value['certificationFileSize'] > self::MAX_COMPANY_CERTIFICATION_FILE_SIZE
) {
throw new \Exception(sprintf(__('업로드 용량은 최소 %dMB 부터 %dMB 까지 정수로 설정할 수 있습니다.'), self::MIN_COMPANY_CERTIFICATION_FILE_SIZE, self::MAX_COMPANY_CERTIFICATION_FILE_SIZE));
}
}
}
 
Controller/Admin/Member/CompanyCertificationPsController.php+8-4
변경 전CompanyCertificationPsController.php
 
namespace Bundle\Controller\Admin\Member;
 
 
use Bundle\Controller\Admin\Controller;
use Framework\Debug\Exception\AlertOnlyException;
 
$request = \App::getInstance('request');
$postData = $request->post()->toArray();
 
$service = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
 
try {
switch ($postData['mode']) {
case 'setting':
$result = $service->setCompanyCertificationFileSize($postData['fileSize']);
$this->json(['result' => $result]);
default:
break;
 
namespace Bundle\Controller\Admin\Member;
 
 
use Bundle\Controller\Admin\Controller;
use Framework\Debug\Exception\AlertOnlyException;
 
$request = \App::getInstance('request');
$postData = $request->post()->toArray();
 
$service = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
 
try {
switch ($postData['mode']) {
case 'setting':
$result = $service->setCompanyCertificationFileSize($postData['fileSize']);
$this->json(['result' => $result]);
default:
break;
 
변경 후CompanyCertificationPsController.php
 
namespace Bundle\Controller\Admin\Member;
 
use Component\Member\Company\CompanyCertification;
use Bundle\Controller\Admin\Controller;
use Framework\Debug\Exception\AlertOnlyException;
 
$request = \App::getInstance('request');
$postData = $request->post()->toArray();
 
/** @var \Bundle\Component\Member\Company\CompanyCertification $service */
$service = \App::getInstance(CompanyCertification::class);
try {
switch ($postData['mode']) {
case 'setting':
$result = $service->setCompanyCertificationFileSizeByKey($postData['fileSize'], $postData['key']);
$this->json(['result' => $result]);
default:
break;
 
namespace Bundle\Controller\Admin\Member;
 
use Component\Member\Company\CompanyCertification;
use Bundle\Controller\Admin\Controller;
use Framework\Debug\Exception\AlertOnlyException;
 
$request = \App::getInstance('request');
$postData = $request->post()->toArray();
 
/** @var \Bundle\Component\Member\Company\CompanyCertification $service */
$service = \App::getInstance(CompanyCertification::class);
try {
switch ($postData['mode']) {
case 'setting':
$result = $service->setCompanyCertificationFileSizeByKey($postData['fileSize'], $postData['key']);
$this->json(['result' => $result]);
default:
break;
 
Controller/Admin/Member/LayerCompanyCertificationSettingController.php+26-6
변경 전LayerCompanyCertificationSettingController.php
 
namespace Bundle\Controller\Admin\Member;
 
 
use Bundle\Controller\Admin\Controller;
 
 
/**
* 사업자 등록증 설정 관련 컨트롤러
public function index()
{
try {
$companyCertification = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$fileSize = $companyCertification->getCompanyCertificationFileSize();
 
 
 
 
 
 
 
 
$this->setData('fileSize', $fileSize);
 
 
$this->getView()->setDefine('layout', 'layout_layer.php');
$this->getView()->setPageName('member/layer_company_certification_setting.php');
 
} catch (\Throwable $e) {
\Logger::warning('사업자 등록증 설정 페이지 로딩 중 오류 발생: ' . $e->getMessage());
throw $e;
}
}
 
namespace Bundle\Controller\Admin\Member;
 
 
use Bundle\Controller\Admin\Controller;
 
 
/**
* 사업자 등록증 설정 관련 컨트롤러
public function index()
{
try {
$companyCertification = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$fileSize = $companyCertification->getCompanyCertificationFileSize();
 
 
 
 
 
 
 
 
$this->setData('fileSize', $fileSize);
 
 
$this->getView()->setDefine('layout', 'layout_layer.php');
$this->getView()->setPageName('member/layer_company_certification_setting.php');
 
} catch (\Throwable $e) {
\Logger::warning('사업자 등록증 설정 페이지 로딩 중 오류 발생: ' . $e->getMessage());
throw $e;
}
}
 
변경 후LayerCompanyCertificationSettingController.php
 
namespace Bundle\Controller\Admin\Member;
 
use Component\Member\Company\CompanyCertification;
use Bundle\Controller\Admin\Controller;
use Framework\Http\Request;
 
/**
* 사업자 등록증 설정 관련 컨트롤러
public function index()
{
try {
 
/** @var Request $request */
$request = \App::getInstance('request');
/** @var \Bundle\Component\Member\Company\CompanyCertification $companyCertification */
$companyCertification = \App::getInstance(CompanyCertification::class);
 
$key = $request->get()->get('type') ?? "comCertification";
$index = $request->get()->get('index') ?? "";
$fileSize = $companyCertification->getCompanyCertificationFileSizeByKey($key.$index);
 
$this->setData('fileSize', $fileSize);
$this->setData('key', $key.$index);
 
$this->getView()->setDefine('layout', 'layout_layer.php');
$this->getView()->setPageName('member/layer_company_certification_setting.php');
 
} catch (\Throwable $e) {
\Logger::warning('사업자 회원 파일등록 페이지 로딩중 오류 발생 : ' . $e->getMessage());
throw $e;
}
}
 
namespace Bundle\Controller\Admin\Member;
 
use Component\Member\Company\CompanyCertification;
use Bundle\Controller\Admin\Controller;
use Framework\Http\Request;
 
/**
* 사업자 등록증 설정 관련 컨트롤러
public function index()
{
try {
 
/** @var Request $request */
$request = \App::getInstance('request');
/** @var \Bundle\Component\Member\Company\CompanyCertification $companyCertification */
$companyCertification = \App::getInstance(CompanyCertification::class);
 
$key = $request->get()->get('type') ?? "comCertification";
$index = $request->get()->get('index') ?? "";
$fileSize = $companyCertification->getCompanyCertificationFileSizeByKey($key.$index);
 
$this->setData('fileSize', $fileSize);
$this->setData('key', $key.$index);
 
$this->getView()->setDefine('layout', 'layout_layer.php');
$this->getView()->setPageName('member/layer_company_certification_setting.php');
 
} catch (\Throwable $e) {
\Logger::warning('사업자 회원 파일등록 페이지 로딩중 오류 발생 : ' . $e->getMessage());
throw $e;
}
}
 
Controller/Admin/Member/MemberJoinitemController.php+14
변경 전MemberJoinitemController.php
*/
namespace Bundle\Controller\Admin\Member;
 
 
 
/**
* Class 회원가입항목설정
* @package Controller\Admin\Policy
$policy['interestCnt'] = $code->codeFetch('getCodeCount', '01001');
$policy['jobCnt'] = $code->codeFetch('getCodeCount', '01002');
 
 
 
 
/** set view data */
$this->setData('data', $policy);
$this->setData('mall', ['mallSno' => $mallSno]);
 
 
}
}
*/
namespace Bundle\Controller\Admin\Member;
 
 
 
/**
* Class 회원가입항목설정
* @package Controller\Admin\Policy
$policy['interestCnt'] = $code->codeFetch('getCodeCount', '01001');
$policy['jobCnt'] = $code->codeFetch('getCodeCount', '01002');
 
 
 
 
/** set view data */
$this->setData('data', $policy);
$this->setData('mall', ['mallSno' => $mallSno]);
 
 
}
}
 
변경 후MemberJoinitemController.php
*/
namespace Bundle\Controller\Admin\Member;
 
use Component\Member\Company\CompanyCertification;
 
/**
* Class 회원가입항목설정
* @package Controller\Admin\Policy
$policy['interestCnt'] = $code->codeFetch('getCodeCount', '01001');
$policy['jobCnt'] = $code->codeFetch('getCodeCount', '01002');
 
// 사업자 추가 제출 서류 최대 개수
$companyCertification = \App::getInstance(CompanyCertification::class);
 
/** set view data */
$this->setData('data', $policy);
$this->setData('mall', ['mallSno' => $mallSno]);
$this->setData('certificationAdditionalFileCount', $companyCertification->getCompanyAddiCertificationFileCount());
$this->setData('defaultCertificationFileSize', CompanyCertification::DEFAULT_COMPANY_CERTIFICATION_FILE_SIZE);
}
}
*/
namespace Bundle\Controller\Admin\Member;
 
use Component\Member\Company\CompanyCertification;
 
/**
* Class 회원가입항목설정
* @package Controller\Admin\Policy
$policy['interestCnt'] = $code->codeFetch('getCodeCount', '01001');
$policy['jobCnt'] = $code->codeFetch('getCodeCount', '01002');
 
// 사업자 추가 제출 서류 최대 개수
$companyCertification = \App::getInstance(CompanyCertification::class);
 
/** set view data */
$this->setData('data', $policy);
$this->setData('mall', ['mallSno' => $mallSno]);
$this->setData('certificationAdditionalFileCount', $companyCertification->getCompanyAddiCertificationFileCount());
$this->setData('defaultCertificationFileSize', CompanyCertification::DEFAULT_COMPANY_CERTIFICATION_FILE_SIZE);
}
}
 
Controller/Admin/Member/MemberModifyController.php+16
변경 전MemberModifyController.php
$certification = $companyCertification->getCertification($memNo);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
 
 
 
 
 
 
$this->setData('mode', 'modify');
$this->setData('joinField', \Component\Member\Util\MemberUtil::getJoinField($memberData['mallSno']));
$this->setData('htmlExtra', \Component\Member\Util\MemberUtil::makeExtraField($memberData));
$this->setData('hidePasswordBlock', $hidePasswordBlock);
$this->setData('certification', $certification);
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
 
 
} catch (\Exception $e) {
$logger = \App::getInstance('logger');
$logger->error($e->getTraceAsString());
$certification = $companyCertification->getCertification($memNo);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
 
 
 
 
 
 
$this->setData('mode', 'modify');
$this->setData('joinField', \Component\Member\Util\MemberUtil::getJoinField($memberData['mallSno']));
$this->setData('htmlExtra', \Component\Member\Util\MemberUtil::makeExtraField($memberData));
$this->setData('hidePasswordBlock', $hidePasswordBlock);
$this->setData('certification', $certification);
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
 
 
} catch (\Exception $e) {
$logger = \App::getInstance('logger');
$logger->error($e->getTraceAsString());
 
변경 후MemberModifyController.php
$certification = $companyCertification->getCertification($memNo);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
 
$additionalCertification = $companyCertification->getAdditionalData();
foreach ($additionalCertification as $key => $value) {
$additionalCertification[$key]['file'] = $companyCertification->getCertificationByMemNoAndType($memNo, $key);
}
 
$this->setData('mode', 'modify');
$this->setData('joinField', \Component\Member\Util\MemberUtil::getJoinField($memberData['mallSno']));
$this->setData('htmlExtra', \Component\Member\Util\MemberUtil::makeExtraField($memberData));
$this->setData('hidePasswordBlock', $hidePasswordBlock);
$this->setData('certification', $certification);
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
$this->setData('additionalCertification',$additionalCertification);
$this->setData('certificationAdditionalFileCount', $companyCertification->getCompanyAddiCertificationFileCount());
 
} catch (\Exception $e) {
$logger = \App::getInstance('logger');
$logger->error($e->getTraceAsString());
$certification = $companyCertification->getCertification($memNo);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
 
$additionalCertification = $companyCertification->getAdditionalData();
foreach ($additionalCertification as $key => $value) {
$additionalCertification[$key]['file'] = $companyCertification->getCertificationByMemNoAndType($memNo, $key);
}
 
$this->setData('mode', 'modify');
$this->setData('joinField', \Component\Member\Util\MemberUtil::getJoinField($memberData['mallSno']));
$this->setData('htmlExtra', \Component\Member\Util\MemberUtil::makeExtraField($memberData));
$this->setData('hidePasswordBlock', $hidePasswordBlock);
$this->setData('certification', $certification);
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
$this->setData('additionalCertification',$additionalCertification);
$this->setData('certificationAdditionalFileCount', $companyCertification->getCompanyAddiCertificationFileCount());
 
} catch (\Exception $e) {
$logger = \App::getInstance('logger');
$logger->error($e->getTraceAsString());
 
Controller/Admin/Member/MemberRegisterController.php+4
변경 전MemberRegisterController.php
$this->setData('data', $member);
$this->setData('checked', $vo->toChecked());
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
 
}
}
$this->setData('data', $member);
$this->setData('checked', $vo->toChecked());
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
 
}
}
 
변경 후MemberRegisterController.php
$this->setData('data', $member);
$this->setData('checked', $vo->toChecked());
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
$this->setData('additionalCertification',$companyCertification->getAdditionalData());
$this->setData('certificationAdditionalFileCount', $companyCertification->getCompanyAddiCertificationFileCount());
}
}
$this->setData('data', $member);
$this->setData('checked', $vo->toChecked());
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
$this->setData('additionalCertification',$companyCertification->getAdditionalData());
$this->setData('certificationAdditionalFileCount', $companyCertification->getCompanyAddiCertificationFileCount());
}
}
 
Controller/Admin/Share/MemberCrmDetailController.php+14
변경 전MemberCrmDetailController.php
$certification = $companyCertification->getCertification($memberNo);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
 
 
 
 
 
 
// 설치앱 디바이스 정보 및 설치 혜택 여부
$this->setMyAppDeviceInfo($memberNo);
 
$this->setData('hidePasswordBlock', $hidePasswordBlock);
$this->setData('certification', $certification);
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
 
}
}
$certification = $companyCertification->getCertification($memberNo);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
 
 
 
 
 
 
// 설치앱 디바이스 정보 및 설치 혜택 여부
$this->setMyAppDeviceInfo($memberNo);
 
$this->setData('hidePasswordBlock', $hidePasswordBlock);
$this->setData('certification', $certification);
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
 
}
}
 
변경 후MemberCrmDetailController.php
$certification = $companyCertification->getCertification($memberNo);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
 
$additionalCertification = $companyCertification->getAdditionalData();
foreach ($additionalCertification as $key => $value) {
$additionalCertification[$key]['file'] = $companyCertification->getCertificationByMemNoAndType($memberNo, $key);
}
 
// 설치앱 디바이스 정보 및 설치 혜택 여부
$this->setMyAppDeviceInfo($memberNo);
 
$this->setData('hidePasswordBlock', $hidePasswordBlock);
$this->setData('certification', $certification);
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
$this->setData('additionalCertification', $additionalCertification);
$this->setData('certificationAdditionalFileCount', $companyCertification->getCompanyAddiCertificationFileCount());
}
}
$certification = $companyCertification->getCertification($memberNo);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
 
$additionalCertification = $companyCertification->getAdditionalData();
foreach ($additionalCertification as $key => $value) {
$additionalCertification[$key]['file'] = $companyCertification->getCertificationByMemNoAndType($memberNo, $key);
}
 
// 설치앱 디바이스 정보 및 설치 혜택 여부
$this->setMyAppDeviceInfo($memberNo);
 
$this->setData('hidePasswordBlock', $hidePasswordBlock);
$this->setData('certification', $certification);
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
$this->setData('additionalCertification', $additionalCertification);
$this->setData('certificationAdditionalFileCount', $companyCertification->getCompanyAddiCertificationFileCount());
}
}
 
Controller/Front/Member/JoinController.php+2
변경 전JoinController.php
$companyCertification = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
 
$this->addScript($scripts);
$this->addCss($styles);
$companyCertification = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
 
$this->addScript($scripts);
$this->addCss($styles);
 
변경 후JoinController.php
$companyCertification = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
$this->setData('comAddiCerts', $companyCertification->getAdditionalData());
 
$this->addScript($scripts);
$this->addCss($styles);
$companyCertification = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
$this->setData('comAddiCerts', $companyCertification->getAdditionalData());
 
$this->addScript($scripts);
$this->addCss($styles);
 
Controller/Front/Mypage/MyPageController.php+14
변경 전MyPageController.php
$this->setData('comCertification', $certification);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
 
 
 
 
 
 
} catch (Exception $e) {
throw new AlertBackException($e->getMessage(), $e->getCode(), $e);
}
$this->setData('comCertification', $certification);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
 
 
 
 
 
 
} catch (Exception $e) {
throw new AlertBackException($e->getMessage(), $e->getCode(), $e);
}
 
변경 후MyPageController.php
$this->setData('comCertification', $certification);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
// 추가 첨부 항목 조회 (정책 + 회원별 등록 파일 정보)
$comAddiCerts = $companyCertification->getAdditionalData();
foreach ($comAddiCerts as $key => $value) {
$comAddiCerts[$key]['file'] = $companyCertification->getCertificationByMemNoAndType($memberData['memNo'], $key);
}
$this->setData('comAddiCerts', $comAddiCerts);
} catch (Exception $e) {
throw new AlertBackException($e->getMessage(), $e->getCode(), $e);
}
$this->setData('comCertification', $certification);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
// 추가 첨부 항목 조회 (정책 + 회원별 등록 파일 정보)
$comAddiCerts = $companyCertification->getAdditionalData();
foreach ($comAddiCerts as $key => $value) {
$comAddiCerts[$key]['file'] = $companyCertification->getCertificationByMemNoAndType($memberData['memNo'], $key);
}
$this->setData('comAddiCerts', $comAddiCerts);
} catch (Exception $e) {
throw new AlertBackException($e->getMessage(), $e->getCode(), $e);
}
 
Controller/Mobile/Member/JoinController.php+2
변경 전JoinController.php
$companyCertification = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
 
$this->addScript($scripts);
}
$companyCertification = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
 
$this->addScript($scripts);
}
 
변경 후JoinController.php
$companyCertification = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
$this->setData('comAddiCerts', $companyCertification->getAdditionalData());
 
$this->addScript($scripts);
}
$companyCertification = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
$this->setData('comAddiCerts', $companyCertification->getAdditionalData());
 
$this->addScript($scripts);
}
 
DTO/Member/CompanyCertificationInsertDTO.php+56-20
변경 전CompanyCertificationInsertDTO.php
*/
namespace Bundle\DTO\Member;
 
 
 
/**
* 사업자 등록증 DB 저장 DTO
*/
class CompanyCertificationInsertDTO extends \Origin\DTO\AbstractDTO
{
private $memNo;
private $imageFileNm;
private $imageFilePath;
private $regDt;
 
/**
* @param int $memNo
* @param array $result
 
*/
public function __construct(int $memNo, array $result)
 
 
 
 
{
$this->memNo = $memNo;
$this->imageFileNm = $result['fileName'] ?? '';
$this->imageFilePath = $result['filePath'] ?? '';
$this->regDt = date('Y-m-d H:i:s');
 
 
}
 
/**
}
 
/**
* @return string
 
 
 
 
 
 
 
 
 
*/
public function getRegDt(): string
{
return $this->regDt;
}
}
*/
namespace Bundle\DTO\Member;
 
 
 
/**
* 사업자 등록증 DB 저장 DTO
*/
class CompanyCertificationInsertDTO extends \Origin\DTO\AbstractDTO
{
private $memNo;
private $imageFileNm;
private $imageFilePath;
private $regDt;
 
/**
* @param int $memNo
* @param array $result
 
*/
public function __construct(int $memNo, array $result)
 
 
 
 
{
$this->memNo = $memNo;
$this->imageFileNm = $result['fileName'] ?? '';
$this->imageFilePath = $result['filePath'] ?? '';
$this->regDt = date('Y-m-d H:i:s');
 
 
}
 
/**
}
 
/**
* @return string
 
 
 
 
 
 
 
 
 
*/
public function getRegDt(): string
{
return $this->regDt;
}
}
 
변경 후CompanyCertificationInsertDTO.php
*/
namespace Bundle\DTO\Member;
 
use Bundle\Enum\Member\Company\DocumentType;
 
/**
* 사업자 등록증 DB 저장 DTO
*/
class CompanyCertificationInsertDTO extends \Origin\DTO\AbstractDTO
{
private int $memNo;
private string $imageFileNm;
private string $imageFilePath;
private DocumentType $documentType;
 
/**
* @param int $memNo
* @param array $result fileName, filePath 포함
* @param string|null $documentType 인증 서류 종류(DocumentType value). null 이면 주 사업자등록증
*/
public function __construct(
int $memNo,
array $result,
?string $documentType
)
{
$this->memNo = $memNo;
$this->imageFileNm = $result['fileName'] ?? '';
$this->imageFilePath = $result['filePath'] ?? '';
$this->documentType = $documentType !== null
? DocumentType::from($documentType)
: DocumentType::REGISTRATION;
}
 
/**
}
 
/**
* @return DocumentType
*/
public function getDocumentType(): DocumentType
{
return $this->documentType;
}
 
/**
* @param DocumentType $documentType
* @return void
*/
public function setDocumentType(DocumentType $documentType): void
{
$this->documentType = $documentType;
}
}
*/
namespace Bundle\DTO\Member;
 
use Bundle\Enum\Member\Company\DocumentType;
 
/**
* 사업자 등록증 DB 저장 DTO
*/
class CompanyCertificationInsertDTO extends \Origin\DTO\AbstractDTO
{
private int $memNo;
private string $imageFileNm;
private string $imageFilePath;
private DocumentType $documentType;
 
/**
* @param int $memNo
* @param array $result fileName, filePath 포함
* @param string|null $documentType 인증 서류 종류(DocumentType value). null 이면 주 사업자등록증
*/
public function __construct(
int $memNo,
array $result,
?string $documentType
)
{
$this->memNo = $memNo;
$this->imageFileNm = $result['fileName'] ?? '';
$this->imageFilePath = $result['filePath'] ?? '';
$this->documentType = $documentType !== null
? DocumentType::from($documentType)
: DocumentType::REGISTRATION;
}
 
/**
}
 
/**
* @return DocumentType
*/
public function getDocumentType(): DocumentType
{
return $this->documentType;
}
 
/**
* @param DocumentType $documentType
* @return void
*/
public function setDocumentType(DocumentType $documentType): void
{
$this->documentType = $documentType;
}
}
 
Enum/Member/Company/DocumentType.php+48
변경 전DocumentType.php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
변경 후DocumentType.php
<?php
/*
* Copyright (C) 2025 NHN COMMERCE. - All Rights Reserved
*
* Unauthorized copying or redistribution of this file in source and binary forms via any medium
* is strictly prohibited.
*/
 
namespace Bundle\Enum\Member\Company;
 
/**
* 사업자 등록증 인증 서류 종류
* - backing value : DB(es_memberCompanyCertification.documentType) 저장값
*
*/
enum DocumentType: string
{
case REGISTRATION = 'registration';
case ADDITIONAL_CERT_0 = 'comAddiCert0';
case ADDITIONAL_CERT_1 = 'comAddiCert1';
case ADDITIONAL_CERT_2 = 'comAddiCert2';
case ADDITIONAL_CERT_3 = 'comAddiCert3';
case ADDITIONAL_CERT_4 = 'comAddiCert4';
}
<?php
/*
* Copyright (C) 2025 NHN COMMERCE. - All Rights Reserved
*
* Unauthorized copying or redistribution of this file in source and binary forms via any medium
* is strictly prohibited.
*/
 
namespace Bundle\Enum\Member\Company;
 
/**
* 사업자 등록증 인증 서류 종류
* - backing value : DB(es_memberCompanyCertification.documentType) 저장값
*
*/
enum DocumentType: string
{
case REGISTRATION = 'registration';
case ADDITIONAL_CERT_0 = 'comAddiCert0';
case ADDITIONAL_CERT_1 = 'comAddiCert1';
case ADDITIONAL_CERT_2 = 'comAddiCert2';
case ADDITIONAL_CERT_3 = 'comAddiCert3';
case ADDITIONAL_CERT_4 = 'comAddiCert4';
}
 
Repository/Member/CompanyCertificationRepository.php+38-28
변경 전CompanyCertificationRepository.php
{
public function insertCertificationInfo(CompanyCertificationInsertDTO $dto)
{
CompanyCertification::query()
->insert([
'memNo' => $dto->getMemNo(),
'imageFileNm' => $dto->getImageFileNm(),
'imageFilePath' => $dto->getImageFilePath(),
'regDt' => $dto->getRegDt(),
]);
}
 
/**
* 사업자 등록증 정보를 memNo로 조회
 
*
* @param int $memNo
* @return array
*/
public function findCertificationInfoByMemNo(int $memNo): array
 
 
 
 
 
 
 
 
 
 
 
 
{
$certification = CompanyCertification::query()
->where('memNo', $memNo)
 
->first();
 
return $certification ? $certification->toArray() : [];
*/
public function findCertificationInfoBySno(int $sno): array
{
$certification = CompanyCertification::query()
->where('sno', $sno)
->first();
 
return $certification ? $certification->toArray() : [];
}
*/
public function deleteCertificationInfo(int $sno): void
{
CompanyCertification::query()
->where('sno', $sno)
->delete();
}
}
{
public function insertCertificationInfo(CompanyCertificationInsertDTO $dto)
{
CompanyCertification::query()
->insert([
'memNo' => $dto->getMemNo(),
'imageFileNm' => $dto->getImageFileNm(),
'imageFilePath' => $dto->getImageFilePath(),
'regDt' => $dto->getRegDt(),
]);
}
 
/**
* 사업자 등록증 정보를 memNo로 조회
 
*
* @param int $memNo
* @return array
*/
public function findCertificationInfoByMemNo(int $memNo): array
 
 
 
 
 
 
 
 
 
 
 
 
{
$certification = CompanyCertification::query()
->where('memNo', $memNo)
 
->first();
 
return $certification ? $certification->toArray() : [];
*/
public function findCertificationInfoBySno(int $sno): array
{
$certification = CompanyCertification::query()
->where('sno', $sno)
->first();
 
return $certification ? $certification->toArray() : [];
}
*/
public function deleteCertificationInfo(int $sno): void
{
CompanyCertification::query()
->where('sno', $sno)
->delete();
}
}
 
변경 후CompanyCertificationRepository.php
{
public function insertCertificationInfo(CompanyCertificationInsertDTO $dto)
{
// DB 컬럼에는 enum 의 backing value(예: documentType='registration')가 저장되어야 하므로 useEnumName=false 로 직렬화한다.
CompanyCertification::create($dto->toRecursiveArray(false));
 
 
 
 
 
}
 
/**
* 사업자 등록증(기본 서류) 정보를 memNo 로 조회
* 기본 인증 서류 종류(registration) 기준으로 조회한다.
*
* @param int $memNo
* @return array
*/
public function findCertificationInfoByMemNo(int $memNo): array
{
return $this->findCertificationInfoByMemNoAndType($memNo, 'registration');
}
 
/**
* 사업자 등록증 정보를 memNo 와 인증 서류 종류로 조회
*
* @param int $memNo
* @param string $type 인증 서류 종류
* @return array
*/
public function findCertificationInfoByMemNoAndType(int $memNo, string $type): array
{
$certification = CompanyCertification::query()
->where('memNo', $memNo)
->where('documentType', $type)
->first();
 
return $certification ? $certification->toArray() : [];
*/
public function findCertificationInfoBySno(int $sno): array
{
$certification = CompanyCertification::find($sno);
 
 
 
return $certification ? $certification->toArray() : [];
}
*/
public function deleteCertificationInfo(int $sno): void
{
CompanyCertification::find($sno)->delete();
 
 
}
}
{
public function insertCertificationInfo(CompanyCertificationInsertDTO $dto)
{
// DB 컬럼에는 enum 의 backing value(예: documentType='registration')가 저장되어야 하므로 useEnumName=false 로 직렬화한다.
CompanyCertification::create($dto->toRecursiveArray(false));
 
 
 
 
 
}
 
/**
* 사업자 등록증(기본 서류) 정보를 memNo 로 조회
* 기본 인증 서류 종류(registration) 기준으로 조회한다.
*
* @param int $memNo
* @return array
*/
public function findCertificationInfoByMemNo(int $memNo): array
{
return $this->findCertificationInfoByMemNoAndType($memNo, 'registration');
}
 
/**
* 사업자 등록증 정보를 memNo 와 인증 서류 종류로 조회
*
* @param int $memNo
* @param string $type 인증 서류 종류
* @return array
*/
public function findCertificationInfoByMemNoAndType(int $memNo, string $type): array
{
$certification = CompanyCertification::query()
->where('memNo', $memNo)
->where('documentType', $type)
->first();
 
return $certification ? $certification->toArray() : [];
*/
public function findCertificationInfoBySno(int $sno): array
{
$certification = CompanyCertification::find($sno);
 
 
 
return $certification ? $certification->toArray() : [];
}
*/
public function deleteCertificationInfo(int $sno): void
{
CompanyCertification::find($sno)->delete();
 
 
}
}
 
data/skin/front/moment/js/gd_member2.js+114-42
변경 전gd_member2.js
errorPlacement: function (error, element) {
try {
var elementId = $(error).attr('id');
 
 
 
 
var $error = $('#' + elementId);
if ($error.length === 0) {
if (elementId == 'calendarFl-error') {
},
highlight: function (element) {
this.errorList[0].element.focus();
 
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
},
unhighlight: function (element) {
if ($(element).prop('type') != 'checkbox' && $(element).prop('type') != 'radio') {
 
 
 
 
$(element).closest('div.member_warning').removeClass('prior_wrong').removeClass('prior_half_pass');
}
},
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
 
 
 
 
 
 
 
 
 
}
$markTarget.closest('td').prev('th').children('span').addClass('important');
}
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
 
 
 
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
$(form).find('select').prop('disabled',false);
validate.settings.submitHandler = func;
errorPlacement: function (error, element) {
try {
var elementId = $(error).attr('id');
 
 
 
 
var $error = $('#' + elementId);
if ($error.length === 0) {
if (elementId == 'calendarFl-error') {
highlight: function (element) {
this.errorList[0].element.focus();
var elemId = $(element).get(0).id || '';
if (/^comAddiCert\d+$/.test(elemId)) {
// 추가 첨부 항목: 같은 row 의 .file_text 만 빨갛게
$(element).closest('.file_upload_sec, .certification_box').find('.file_text').css('border', '3px solid #fa2828');
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
} else {
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
}
},
unhighlight: function (element) {
var elemId = $(element).get(0).id || '';
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
 
 
 
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
},
highlight: function (element) {
this.errorList[0].element.focus();
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
 
 
 
 
 
 
 
},
unhighlight: function (element) {
if ($(element).prop('type') != 'checkbox' && $(element).prop('type') != 'radio') {
 
 
 
 
$(element).closest('div.member_warning').removeClass('prior_wrong').removeClass('prior_half_pass');
}
},
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
 
 
 
 
 
 
 
 
 
}
$markTarget.closest('td').prev('th').children('span').addClass('important');
}
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
$(form).find('select').prop('disabled',false);
validate.settings.submitHandler = func;
 
변경 후gd_member2.js
errorPlacement: function (error, element) {
try {
var elementId = $(error).attr('id');
// 추가 첨부(comAddiCertN) 에러 메시지는 폭을 9em 으로 고정
if (/^comAddiCert\d+-error$/.test(elementId)) {
error.css('width', '9em');
}
var $error = $('#' + elementId);
if ($error.length === 0) {
if (elementId == 'calendarFl-error') {
},
highlight: function (element) {
this.errorList[0].element.focus();
var elemId = $(element).get(0).id || '';
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
},
unhighlight: function (element) {
var elemId = $(element).get(0).id || '';
if (/^comAddiCert\d+$/.test(elemId)) {
$(element).closest('.file_upload_sec, .certification_box').find('.file_text').css('border', '');
$(element).closest('div.member_warning').removeClass('prior_wrong').removeClass('prior_half_pass');
} else if ($(element).prop('type') != 'checkbox' && $(element).prop('type') != 'radio') {
$(element).closest('div.member_warning').removeClass('prior_wrong').removeClass('prior_half_pass');
}
},
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget;
// 추가 첨부 (comAddiCertN) 정책 키는 실제 input name 이 comAddiCert[N][file] 형태이므로 별도 매칭
var addiCertMatch = idx.match(/^comAddiCert(\d+)$/);
if (addiCertMatch) {
var addiCertRuleKey = 'comAddiCert[' + addiCertMatch[1] + '][file]';
$markTarget = $('input[name="' + addiCertRuleKey + '"]');
settings.rules[addiCertRuleKey] = {required: true};
} else {
$markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
}
}
$markTarget.closest('td').prev('th').children('span').addClass('important');
}
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
// 사업자등록증 입력 항목이 없으면 빈 selection 에 .rules() 가 호출돼 터지므로 가드
if ($comCertification.length > 0) {
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
var $addiInput = $(this);
var matched = ($addiInput.attr('name') || '').match(/^comAddiCert\[(\d+)\]\[file\]$/);
if (!matched) return;
var $addiDelBox = $('input[name="comAddiCert[' + matched[1] + '][DeleteSno]"]');
var rules = $addiInput.rules();
var addiRequired = !!(rules && rules.required);
var addiFileEmpty = !$addiInput.val();
var addiDeleteChecked = $addiDelBox.is(':checked');
var addiHasDeleteSno = !!$addiDelBox.val();
if (addiRequired && addiHasDeleteSno && addiFileEmpty && !addiDeleteChecked) {
$addiInput.rules("remove");
}
});
}
$(form).find('select').prop('disabled',false);
validate.settings.submitHandler = func;
errorPlacement: function (error, element) {
try {
var elementId = $(error).attr('id');
// 추가 첨부(comAddiCertN) 에러 메시지는 폭을 9em 으로 고정
if (/^comAddiCert\d+-error$/.test(elementId)) {
error.css('width', '9em');
}
var $error = $('#' + elementId);
if ($error.length === 0) {
if (elementId == 'calendarFl-error') {
highlight: function (element) {
this.errorList[0].element.focus();
var elemId = $(element).get(0).id || '';
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
 
 
 
 
 
 
},
unhighlight: function (element) {
var elemId = $(element).get(0).id || '';
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
// 사업자등록증 입력 항목이 없으면 빈 selection 에 .rules() 가 호출돼 터지므로 가드
if ($comCertification.length > 0) {
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
},
highlight: function (element) {
this.errorList[0].element.focus();
var elemId = $(element).get(0).id || '';
if (/^comAddiCert\d+$/.test(elemId)) {
// 추가 첨부 항목: 같은 row 의 .file_text 만 빨갛게
$(element).closest('.file_upload_sec, .certification_box').find('.file_text').css('border', '3px solid #fa2828');
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
} else {
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
}
},
unhighlight: function (element) {
var elemId = $(element).get(0).id || '';
if (/^comAddiCert\d+$/.test(elemId)) {
$(element).closest('.file_upload_sec, .certification_box').find('.file_text').css('border', '');
$(element).closest('div.member_warning').removeClass('prior_wrong').removeClass('prior_half_pass');
} else if ($(element).prop('type') != 'checkbox' && $(element).prop('type') != 'radio') {
$(element).closest('div.member_warning').removeClass('prior_wrong').removeClass('prior_half_pass');
}
},
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget;
// 추가 첨부 (comAddiCertN) 정책 키는 실제 input name 이 comAddiCert[N][file] 형태이므로 별도 매칭
var addiCertMatch = idx.match(/^comAddiCert(\d+)$/);
if (addiCertMatch) {
var addiCertRuleKey = 'comAddiCert[' + addiCertMatch[1] + '][file]';
$markTarget = $('input[name="' + addiCertRuleKey + '"]');
settings.rules[addiCertRuleKey] = {required: true};
} else {
$markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
}
}
$markTarget.closest('td').prev('th').children('span').addClass('important');
}
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
var $addiInput = $(this);
var matched = ($addiInput.attr('name') || '').match(/^comAddiCert\[(\d+)\]\[file\]$/);
if (!matched) return;
var $addiDelBox = $('input[name="comAddiCert[' + matched[1] + '][DeleteSno]"]');
var rules = $addiInput.rules();
var addiRequired = !!(rules && rules.required);
var addiFileEmpty = !$addiInput.val();
var addiDeleteChecked = $addiDelBox.is(':checked');
var addiHasDeleteSno = !!$addiDelBox.val();
if (addiRequired && addiHasDeleteSno && addiFileEmpty && !addiDeleteChecked) {
$addiInput.rules("remove");
}
});
}
$(form).find('select').prop('disabled',false);
validate.settings.submitHandler = func;
 
data/skin/front/moment/member/_join_view_business.html+196-2
변경 전_join_view_business.html
</label>
<div class="btn_upload_box">
<button type="button" class="btn_upload" title="{=__('찾아보기')}"><em>{=__('찾아보기')}</em></button>
<input type="file" id="comCertification" name="comCertification[]" class="file" />
</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</div>
</td>
</tr>
<!--{/}-->
 
</tbody>
</table>
</div>
}
});
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</script>
</label>
<div class="btn_upload_box">
<button type="button" class="btn_upload" title="{=__('찾아보기')}"><em>{=__('찾아보기')}</em></button>
<input type="file" id="comCertification" name="comCertification[]" class="file" />
</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</div>
</td>
</tr>
<!--{/}-->
 
</tbody>
</table>
</div>
}
});
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</script>
 
변경 후_join_view_business.html
</label>
<div class="btn_upload_box">
<button type="button" class="btn_upload" title="{=__('찾아보기')}"><em>{=__('찾아보기')}</em></button>
<input type="file" id="comCertification" name="comCertification[]" class="file js_cert_file" />
</div>
<!--{? !isMyPage}--><!-- 가입 시에만 첨부 취소 버튼 노출 (정보수정 시 미노출) -->
<button type="button" class="js_cert_clear" data-for="comCertification" style="display:none; float:left; margin-left:6px; padding:4px 10px; background:#fff; border:1px solid #ccc; cursor:pointer;">- {=__('삭제')}</button>
<!--{/}-->
</div>
</td>
</tr>
<!--{/}-->
<!--{ @ comAddiCerts }-->
<!--{? .value_.use == 'y'}-->
<tr>
<th><span><label for="comAddiCert{=substr(.key_, 11)}">{=.value_.name}</label></span></th>
<td>
<div class="file_upload_sec certification_box member_warning">
<!--{? .value_.file.imageFileNm}-->
<div>
<a href="../member/company_certification.php?mode=download&sno={.value_.file.sno}" class="link_file_down">{=.value_.file.imageFileNm}</a>
<input type="checkbox" id="comAddiCertDeleteSno{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][DeleteSno]" class="js_addi_cert_delete" value="{.value_.file.sno}" />
<label for="comAddiCertDeleteSno{=substr(.key_, 11)}" class="check_s">{=__('삭제')}</label>
</div>
<!--{/}-->
<label for="comAddiCert{=substr(.key_, 11)}">
<input type="text" class="file_text" title="{=__('파일 첨부하기')}" readonly="readonly"/>
</label>
<div class="btn_upload_box">
<button type="button" class="btn_upload" title="{=__('찾아보기')}"><em>{=__('찾아보기')}</em></button>
<input type="file" id="comAddiCert{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][file]" class="file js_cert_file js_addi_cert_file" data-max-size="{.value_.certificationFileSize}"/>
</div>
<!--{? !isMyPage}--><!-- 가입 시에만 첨부 취소 버튼 노출 (정보수정 시 미노출) -->
<button type="button" class="js_cert_clear" data-for="comAddiCert{=substr(.key_, 11)}" style="display:none; float:right; margin-left:6px; padding:4px 10px; background:#fff; border:1px solid #ccc; cursor:pointer;">- {=__('삭제')}</button>
<!--{/}-->
</div>
</td>
</tr>
<!--{/}-->
<!--{ / }-->
</tbody>
</table>
</div>
}
});
<!--{/}-->
 
// 추가 첨부 파일 변경 시 확장자/용량 검사
$(document).on('change', '.js_addi_cert_file', function (e) {
const $input = $(this);
const file = this.files[0];
if (!file) return;
const maxSize = parseInt($input.data('max-size'), 10) || 2;
const allowedExt = ['pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
 
// 확장자 검사
const ext = file.name.split('.').pop().toLowerCase();
if (!allowedExt.includes(ext)) {
e.target.value = '';
alert(__('등록이 불가한 파일 형식입니다.'));
return;
}
 
// 파일 크기 검사
const fileSizeMB = file.size / (1024 * 1024);
if (fileSizeMB > maxSize) {
e.target.value = '';
alert(__('파일은 최대 %1$sMB 이하로만 등록 가능합니다.', maxSize.toString()));
}
});
 
// 추가 첨부 삭제 체크 시 confirm
$(document).on('change', '.js_addi_cert_delete', function (e) {
const $box = $(this);
const $label = $('label[for="' + $box.attr('id') + '"]');
if ($box.is(':checked')) {
const confirmDelete = confirm('등록된 첨부파일을 삭제하시겠습니까?\n회원정보 최종 저장 시 삭제되며, 복구가 불가합니다.');
if (!confirmDelete) {
$label.removeClass('on');
$box.prop('checked', false);
}
}
});
 
// 사업자등록증/추가첨부: 찾아보기로 파일 선택 시 파일명 표시 + '- 삭제' 버튼 노출
$(document).on('change', '.js_cert_file', function () {
var $textbox = $('label[for="' + this.id + '"]').find('input[type="text"]');
var $clearBtn = $('.js_cert_clear[data-for="' + this.id + '"]');
if (this.files.length > 0) {
$textbox.val(this.files[0].name);
$clearBtn.show();
// '- 삭제' 버튼 폭만큼 텍스트박스를 줄여 같은 줄에 유지 (버튼 밀림 방지)
$textbox.css({ 'width': '', 'box-sizing': '' });
var freeWidth = $textbox.outerWidth() - $clearBtn.outerWidth(true);
if (freeWidth > 0) {
$textbox.css({ 'box-sizing': 'border-box', 'width': freeWidth + 'px' });
}
} else {
$textbox.val('');
$clearBtn.hide();
$textbox.css({ 'width': '', 'box-sizing': '' });
}
});
 
// '- 삭제' 클릭 시 첨부 취소 + 텍스트박스 내용 제거 + 폭 원복
$(document).on('click', '.js_cert_clear', function () {
var id = $(this).data('for');
$(document.getElementById(id)).val('');
$('label[for="' + id + '"]').find('input[type="text"]')
.val('').css({ 'width': '', 'box-sizing': '' });
$(this).hide();
});
</script>
</label>
<div class="btn_upload_box">
<button type="button" class="btn_upload" title="{=__('찾아보기')}"><em>{=__('찾아보기')}</em></button>
<input type="file" id="comCertification" name="comCertification[]" class="file js_cert_file" />
</div>
<!--{? !isMyPage}--><!-- 가입 시에만 첨부 취소 버튼 노출 (정보수정 시 미노출) -->
<button type="button" class="js_cert_clear" data-for="comCertification" style="display:none; float:left; margin-left:6px; padding:4px 10px; background:#fff; border:1px solid #ccc; cursor:pointer;">- {=__('삭제')}</button>
<!--{/}-->
</div>
</td>
</tr>
<!--{/}-->
<!--{ @ comAddiCerts }-->
<!--{? .value_.use == 'y'}-->
<tr>
<th><span><label for="comAddiCert{=substr(.key_, 11)}">{=.value_.name}</label></span></th>
<td>
<div class="file_upload_sec certification_box member_warning">
<!--{? .value_.file.imageFileNm}-->
<div>
<a href="../member/company_certification.php?mode=download&sno={.value_.file.sno}" class="link_file_down">{=.value_.file.imageFileNm}</a>
<input type="checkbox" id="comAddiCertDeleteSno{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][DeleteSno]" class="js_addi_cert_delete" value="{.value_.file.sno}" />
<label for="comAddiCertDeleteSno{=substr(.key_, 11)}" class="check_s">{=__('삭제')}</label>
</div>
<!--{/}-->
<label for="comAddiCert{=substr(.key_, 11)}">
<input type="text" class="file_text" title="{=__('파일 첨부하기')}" readonly="readonly"/>
</label>
<div class="btn_upload_box">
<button type="button" class="btn_upload" title="{=__('찾아보기')}"><em>{=__('찾아보기')}</em></button>
<input type="file" id="comAddiCert{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][file]" class="file js_cert_file js_addi_cert_file" data-max-size="{.value_.certificationFileSize}"/>
</div>
<!--{? !isMyPage}--><!-- 가입 시에만 첨부 취소 버튼 노출 (정보수정 시 미노출) -->
<button type="button" class="js_cert_clear" data-for="comAddiCert{=substr(.key_, 11)}" style="display:none; float:right; margin-left:6px; padding:4px 10px; background:#fff; border:1px solid #ccc; cursor:pointer;">- {=__('삭제')}</button>
<!--{/}-->
</div>
</td>
</tr>
<!--{/}-->
<!--{ / }-->
</tbody>
</table>
</div>
}
});
<!--{/}-->
 
// 추가 첨부 파일 변경 시 확장자/용량 검사
$(document).on('change', '.js_addi_cert_file', function (e) {
const $input = $(this);
const file = this.files[0];
if (!file) return;
const maxSize = parseInt($input.data('max-size'), 10) || 2;
const allowedExt = ['pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
 
// 확장자 검사
const ext = file.name.split('.').pop().toLowerCase();
if (!allowedExt.includes(ext)) {
e.target.value = '';
alert(__('등록이 불가한 파일 형식입니다.'));
return;
}
 
// 파일 크기 검사
const fileSizeMB = file.size / (1024 * 1024);
if (fileSizeMB > maxSize) {
e.target.value = '';
alert(__('파일은 최대 %1$sMB 이하로만 등록 가능합니다.', maxSize.toString()));
}
});
 
// 추가 첨부 삭제 체크 시 confirm
$(document).on('change', '.js_addi_cert_delete', function (e) {
const $box = $(this);
const $label = $('label[for="' + $box.attr('id') + '"]');
if ($box.is(':checked')) {
const confirmDelete = confirm('등록된 첨부파일을 삭제하시겠습니까?\n회원정보 최종 저장 시 삭제되며, 복구가 불가합니다.');
if (!confirmDelete) {
$label.removeClass('on');
$box.prop('checked', false);
}
}
});
 
// 사업자등록증/추가첨부: 찾아보기로 파일 선택 시 파일명 표시 + '- 삭제' 버튼 노출
$(document).on('change', '.js_cert_file', function () {
var $textbox = $('label[for="' + this.id + '"]').find('input[type="text"]');
var $clearBtn = $('.js_cert_clear[data-for="' + this.id + '"]');
if (this.files.length > 0) {
$textbox.val(this.files[0].name);
$clearBtn.show();
// '- 삭제' 버튼 폭만큼 텍스트박스를 줄여 같은 줄에 유지 (버튼 밀림 방지)
$textbox.css({ 'width': '', 'box-sizing': '' });
var freeWidth = $textbox.outerWidth() - $clearBtn.outerWidth(true);
if (freeWidth > 0) {
$textbox.css({ 'box-sizing': 'border-box', 'width': freeWidth + 'px' });
}
} else {
$textbox.val('');
$clearBtn.hide();
$textbox.css({ 'width': '', 'box-sizing': '' });
}
});
 
// '- 삭제' 클릭 시 첨부 취소 + 텍스트박스 내용 제거 + 폭 원복
$(document).on('click', '.js_cert_clear', function () {
var id = $(this).data('for');
$(document.getElementById(id)).val('');
$('label[for="' + id + '"]').find('input[type="text"]')
.val('').css({ 'width': '', 'box-sizing': '' });
$(this).hide();
});
</script>
 
data/skin/front/mygreek/js/gd_member2.js+113-43
변경 전gd_member2.js
errorPlacement: function (error, element) {
try {
var elementId = $(error).attr('id');
 
 
 
 
var $error = $('#' + elementId);
if ($error.length === 0) {
if (elementId == 'calendarFl-error') {
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
},
unhighlight: function (element) {
if ($(element).prop('type') != 'checkbox' && $(element).prop('type') != 'radio') {
 
 
 
 
$(element).closest('div.member_warning').removeClass('prior_wrong').removeClass('prior_half_pass');
}
},
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
 
 
 
 
 
 
 
 
 
}
$markTarget.closest('td').prev('th').children('span').addClass('important');
}
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
 
 
 
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
$(form).find('select').prop('disabled',false);
validate.settings.submitHandler = func;
errorPlacement: function (error, element) {
try {
var elementId = $(error).attr('id');
 
 
 
 
var $error = $('#' + elementId);
if ($error.length === 0) {
if (elementId == 'calendarFl-error') {
},
highlight: function (element) {
this.errorList[0].element.focus();
var elemId = $(element).get(0).id || '';
if (/^comAddiCert\d+$/.test(elemId)) {
// 추가 첨부 항목: 같은 row 의 .file_text 만 빨갛게
$(element).closest('.file_upload_sec, .certification_box').find('.file_text').css('border', '3px solid #fa2828');
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
} else {
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
}
},
unhighlight: function (element) {
var elemId = $(element).get(0).id || '';
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
 
 
 
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
},
highlight: function (element) {
this.errorList[0].element.focus();
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
 
 
 
 
 
 
 
},
unhighlight: function (element) {
if ($(element).prop('type') != 'checkbox' && $(element).prop('type') != 'radio') {
 
 
 
 
$(element).closest('div.member_warning').removeClass('prior_wrong').removeClass('prior_half_pass');
}
},
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
 
 
 
 
 
 
 
 
 
}
$markTarget.closest('td').prev('th').children('span').addClass('important');
}
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
$(form).find('select').prop('disabled',false);
validate.settings.submitHandler = func;
 
변경 후gd_member2.js
errorPlacement: function (error, element) {
try {
var elementId = $(error).attr('id');
// 추가 첨부(comAddiCertN) 에러 메시지는 폭을 9em 으로 고정
if (/^comAddiCert\d+-error$/.test(elementId)) {
error.css('width', '9em');
}
var $error = $('#' + elementId);
if ($error.length === 0) {
if (elementId == 'calendarFl-error') {
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
},
unhighlight: function (element) {
var elemId = $(element).get(0).id || '';
if (/^comAddiCert\d+$/.test(elemId)) {
$(element).closest('.file_upload_sec, .certification_box').find('.file_text').css('border', '');
$(element).closest('div.member_warning').removeClass('prior_wrong').removeClass('prior_half_pass');
} else if ($(element).prop('type') != 'checkbox' && $(element).prop('type') != 'radio') {
$(element).closest('div.member_warning').removeClass('prior_wrong').removeClass('prior_half_pass');
}
},
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget;
// 추가 첨부 (comAddiCertN) 정책 키는 실제 input name 이 comAddiCert[N][file] 형태이므로 별도 매칭
var addiCertMatch = idx.match(/^comAddiCert(\d+)$/);
if (addiCertMatch) {
var addiCertRuleKey = 'comAddiCert[' + addiCertMatch[1] + '][file]';
$markTarget = $('input[name="' + addiCertRuleKey + '"]');
settings.rules[addiCertRuleKey] = {required: true};
} else {
$markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
}
}
$markTarget.closest('td').prev('th').children('span').addClass('important');
}
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
// 사업자등록증 입력 항목이 없으면 빈 selection 에 .rules() 가 호출돼 터지므로 가드
if ($comCertification.length > 0) {
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
var $addiInput = $(this);
var matched = ($addiInput.attr('name') || '').match(/^comAddiCert\[(\d+)\]\[file\]$/);
if (!matched) return;
var $addiDelBox = $('input[name="comAddiCert[' + matched[1] + '][DeleteSno]"]');
var rules = $addiInput.rules();
var addiRequired = !!(rules && rules.required);
var addiFileEmpty = !$addiInput.val();
var addiDeleteChecked = $addiDelBox.is(':checked');
var addiHasDeleteSno = !!$addiDelBox.val();
if (addiRequired && addiHasDeleteSno && addiFileEmpty && !addiDeleteChecked) {
$addiInput.rules("remove");
}
});
}
$(form).find('select').prop('disabled',false);
validate.settings.submitHandler = func;
errorPlacement: function (error, element) {
try {
var elementId = $(error).attr('id');
// 추가 첨부(comAddiCertN) 에러 메시지는 폭을 9em 으로 고정
if (/^comAddiCert\d+-error$/.test(elementId)) {
error.css('width', '9em');
}
var $error = $('#' + elementId);
if ($error.length === 0) {
if (elementId == 'calendarFl-error') {
},
highlight: function (element) {
this.errorList[0].element.focus();
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
 
 
 
 
 
 
 
},
unhighlight: function (element) {
var elemId = $(element).get(0).id || '';
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
// 사업자등록증 입력 항목이 없으면 빈 selection 에 .rules() 가 호출돼 터지므로 가드
if ($comCertification.length > 0) {
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
},
highlight: function (element) {
this.errorList[0].element.focus();
var elemId = $(element).get(0).id || '';
if (/^comAddiCert\d+$/.test(elemId)) {
// 추가 첨부 항목: 같은 row 의 .file_text 만 빨갛게
$(element).closest('.file_upload_sec, .certification_box').find('.file_text').css('border', '3px solid #fa2828');
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
} else {
$(element).closest('div.member_warning').addClass('prior_wrong').removeClass('prior_half_pass');
}
},
unhighlight: function (element) {
var elemId = $(element).get(0).id || '';
if (/^comAddiCert\d+$/.test(elemId)) {
$(element).closest('.file_upload_sec, .certification_box').find('.file_text').css('border', '');
$(element).closest('div.member_warning').removeClass('prior_wrong').removeClass('prior_half_pass');
} else if ($(element).prop('type') != 'checkbox' && $(element).prop('type') != 'radio') {
$(element).closest('div.member_warning').removeClass('prior_wrong').removeClass('prior_half_pass');
}
},
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget;
// 추가 첨부 (comAddiCertN) 정책 키는 실제 input name 이 comAddiCert[N][file] 형태이므로 별도 매칭
var addiCertMatch = idx.match(/^comAddiCert(\d+)$/);
if (addiCertMatch) {
var addiCertRuleKey = 'comAddiCert[' + addiCertMatch[1] + '][file]';
$markTarget = $('input[name="' + addiCertRuleKey + '"]');
settings.rules[addiCertRuleKey] = {required: true};
} else {
$markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
}
}
$markTarget.closest('td').prev('th').children('span').addClass('important');
}
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
var $addiInput = $(this);
var matched = ($addiInput.attr('name') || '').match(/^comAddiCert\[(\d+)\]\[file\]$/);
if (!matched) return;
var $addiDelBox = $('input[name="comAddiCert[' + matched[1] + '][DeleteSno]"]');
var rules = $addiInput.rules();
var addiRequired = !!(rules && rules.required);
var addiFileEmpty = !$addiInput.val();
var addiDeleteChecked = $addiDelBox.is(':checked');
var addiHasDeleteSno = !!$addiDelBox.val();
if (addiRequired && addiHasDeleteSno && addiFileEmpty && !addiDeleteChecked) {
$addiInput.rules("remove");
}
});
}
$(form).find('select').prop('disabled',false);
validate.settings.submitHandler = func;
 
data/skin/front/mygreek/member/_join_view_business.html+202-4
변경 전_join_view_business.html
</label>
<div class="btn_upload_box comCertification_upload_box">
<button type="button" class="btn_upload" title="{=__('찾아보기')}"><em>{=__('찾아보기')}</em></button>
<input type="file" id="comCertification" name="comCertification[]" class="file" />
</div>
 
 
 
</div>
</td>
</tr>
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</tbody>
</table>
</div>
}
});
 
 
 
 
$(document).on('click', '.comCertification_upload_box .btn_upload', function (e) {
const $box = $(this).closest('.comCertification_upload_box');
const $file = $box.find('input[type="file"]');
$file.val(null);
$file.trigger('click');
});
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</script>
</label>
<div class="btn_upload_box comCertification_upload_box">
<button type="button" class="btn_upload" title="{=__('찾아보기')}"><em>{=__('찾아보기')}</em></button>
<input type="file" id="comCertification" name="comCertification[]" class="file" />
</div>
 
 
 
</div>
</td>
</tr>
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</tbody>
</table>
</div>
}
});
 
 
 
 
$(document).on('click', '.comCertification_upload_box .btn_upload', function (e) {
const $box = $(this).closest('.comCertification_upload_box');
const $file = $box.find('input[type="file"]');
$file.val(null);
$file.trigger('click');
});
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</script>
 
변경 후_join_view_business.html
</label>
<div class="btn_upload_box comCertification_upload_box">
<button type="button" class="btn_upload" title="{=__('찾아보기')}"><em>{=__('찾아보기')}</em></button>
<input type="file" id="comCertification" name="comCertification[]" class="file js_cert_file" />
</div>
<!--{? !isMyPage}--><!-- 가입 시에만 첨부 취소 버튼 노출 (정보수정 시 미노출) -->
<button type="button" class="js_cert_clear" data-for="comCertification" style="display:none; float:left; margin-left:6px; padding:4px 10px; background:#fff; border:1px solid #ccc; cursor:pointer;">- {=__('삭제')}</button>
<!--{/}-->
</div>
</td>
</tr>
<!--{/}-->
<!--{ @ comAddiCerts }-->
<!--{? .value_.use == 'y'}-->
<tr>
<th><span><label for="comAddiCert{=substr(.key_, 11)}">{=.value_.name}</label></span></th>
<td>
<div class="file_upload_sec certification_box member_warning">
<!--{? .value_.file.imageFileNm}-->
<div>
<a href="../member/company_certification.php?mode=download&sno={.value_.file.sno}" class="link_file_down">{=.value_.file.imageFileNm}</a>
<input type="checkbox" id="comAddiCertDeleteSno{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][DeleteSno]" class="js_addi_cert_delete" value="{.value_.file.sno}" />
<label for="comAddiCertDeleteSno{=substr(.key_, 11)}" class="check_s">{=__('삭제')}</label>
</div>
<!--{/}-->
<label for="comAddiCert{=substr(.key_, 11)}">
<input type="text" class="file_text" title="{=__('파일 첨부하기')}" readonly="readonly"/>
</label>
<div class="btn_upload_box comCertification_upload_box">
<button type="button" class="btn_upload" title="{=__('찾아보기')}"><em>{=__('찾아보기')}</em></button>
<input type="file" id="comAddiCert{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][file]" class="file js_cert_file js_addi_cert_file" data-max-size="{.value_.certificationFileSize}"/>
</div>
<!--{? !isMyPage}--><!-- 가입 시에만 첨부 취소 버튼 노출 (정보수정 시 미노출) -->
<button type="button" class="js_cert_clear" data-for="comAddiCert{=substr(.key_, 11)}" style="display:none; float:left; margin-left:6px; padding:4px 10px; background:#fff; border:1px solid #ccc; cursor:pointer;">- {=__('삭제')}</button>
<!--{/}-->
</div>
</td>
</tr>
<!--{/}-->
<!--{ / }-->
</tbody>
</table>
</div>
}
});
 
<!--{/}-->
 
// 찾아보기 버튼 클릭 시 파일 선택창 열기 (사업자등록증 + 추가첨부 공용 — 동일 .comCertification_upload_box 클래스 사용)
$(document).on('click', '.comCertification_upload_box .btn_upload', function (e) {
const $box = $(this).closest('.comCertification_upload_box');
const $file = $box.find('input[type="file"]');
$file.val(null);
$file.trigger('click');
});
 
// 추가 첨부 파일 변경 시 파일명 표시 + 확장자/용량 검사
$(document).on('change', '.js_addi_cert_file', function (e) {
const $input = $(this);
const file = this.files[0];
if (!file) return;
const maxSize = parseInt($input.data('max-size'), 10) || 2;
const allowedExt = ['pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
 
// 확장자 검사
const ext = file.name.split('.').pop().toLowerCase();
if (!allowedExt.includes(ext)) {
e.target.value = '';
alert(__('등록이 불가한 파일 형식입니다.'));
return;
}
 
// 파일 크기 검사
const fileSizeMB = file.size / (1024 * 1024);
if (fileSizeMB > maxSize) {
e.target.value = '';
alert(__('파일은 최대 %1$sMB 이하로만 등록 가능합니다.', maxSize.toString()));
}
});
 
// 추가 첨부 삭제 체크 시 confirm
$(document).on('change', '.js_addi_cert_delete', function (e) {
const $box = $(this);
const $label = $('label[for="' + $box.attr('id') + '"]');
if ($box.is(':checked')) {
const confirmDelete = confirm('등록된 첨부파일을 삭제하시겠습니까?\n회원정보 최종 저장 시 삭제되며, 복구가 불가합니다.');
if (!confirmDelete) {
$label.removeClass('on');
$box.prop('checked', false);
}
}
});
 
// 사업자등록증/추가첨부: 찾아보기로 파일 선택 시 파일명 표시 + '- 삭제' 버튼 노출
$(document).on('change', '.js_cert_file', function () {
var $textbox = $('label[for="' + this.id + '"]').find('input[type="text"]');
var $clearBtn = $('.js_cert_clear[data-for="' + this.id + '"]');
if (this.files.length > 0) {
$textbox.val(this.files[0].name);
$clearBtn.show();
// '- 삭제' 버튼 폭만큼 텍스트박스를 줄여 같은 줄에 유지 (버튼 밀림 방지)
$textbox.css({ 'width': '', 'box-sizing': '' });
var freeWidth = $textbox.outerWidth() - $clearBtn.outerWidth(true);
if (freeWidth > 0) {
$textbox.css({ 'box-sizing': 'border-box', 'width': freeWidth + 'px' });
}
} else {
$textbox.val('');
$clearBtn.hide();
$textbox.css({ 'width': '', 'box-sizing': '' });
}
});
 
// '- 삭제' 클릭 시 첨부 취소 + 텍스트박스 내용 제거 + 폭 원복
$(document).on('click', '.js_cert_clear', function () {
var id = $(this).data('for');
$(document.getElementById(id)).val('');
$('label[for="' + id + '"]').find('input[type="text"]')
.val('').css({ 'width': '', 'box-sizing': '' });
$(this).hide();
});
</script>
</label>
<div class="btn_upload_box comCertification_upload_box">
<button type="button" class="btn_upload" title="{=__('찾아보기')}"><em>{=__('찾아보기')}</em></button>
<input type="file" id="comCertification" name="comCertification[]" class="file js_cert_file" />
</div>
<!--{? !isMyPage}--><!-- 가입 시에만 첨부 취소 버튼 노출 (정보수정 시 미노출) -->
<button type="button" class="js_cert_clear" data-for="comCertification" style="display:none; float:left; margin-left:6px; padding:4px 10px; background:#fff; border:1px solid #ccc; cursor:pointer;">- {=__('삭제')}</button>
<!--{/}-->
</div>
</td>
</tr>
<!--{/}-->
<!--{ @ comAddiCerts }-->
<!--{? .value_.use == 'y'}-->
<tr>
<th><span><label for="comAddiCert{=substr(.key_, 11)}">{=.value_.name}</label></span></th>
<td>
<div class="file_upload_sec certification_box member_warning">
<!--{? .value_.file.imageFileNm}-->
<div>
<a href="../member/company_certification.php?mode=download&sno={.value_.file.sno}" class="link_file_down">{=.value_.file.imageFileNm}</a>
<input type="checkbox" id="comAddiCertDeleteSno{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][DeleteSno]" class="js_addi_cert_delete" value="{.value_.file.sno}" />
<label for="comAddiCertDeleteSno{=substr(.key_, 11)}" class="check_s">{=__('삭제')}</label>
</div>
<!--{/}-->
<label for="comAddiCert{=substr(.key_, 11)}">
<input type="text" class="file_text" title="{=__('파일 첨부하기')}" readonly="readonly"/>
</label>
<div class="btn_upload_box comCertification_upload_box">
<button type="button" class="btn_upload" title="{=__('찾아보기')}"><em>{=__('찾아보기')}</em></button>
<input type="file" id="comAddiCert{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][file]" class="file js_cert_file js_addi_cert_file" data-max-size="{.value_.certificationFileSize}"/>
</div>
<!--{? !isMyPage}--><!-- 가입 시에만 첨부 취소 버튼 노출 (정보수정 시 미노출) -->
<button type="button" class="js_cert_clear" data-for="comAddiCert{=substr(.key_, 11)}" style="display:none; float:left; margin-left:6px; padding:4px 10px; background:#fff; border:1px solid #ccc; cursor:pointer;">- {=__('삭제')}</button>
<!--{/}-->
</div>
</td>
</tr>
<!--{/}-->
<!--{ / }-->
</tbody>
</table>
</div>
}
});
 
<!--{/}-->
 
// 찾아보기 버튼 클릭 시 파일 선택창 열기 (사업자등록증 + 추가첨부 공용 — 동일 .comCertification_upload_box 클래스 사용)
$(document).on('click', '.comCertification_upload_box .btn_upload', function (e) {
const $box = $(this).closest('.comCertification_upload_box');
const $file = $box.find('input[type="file"]');
$file.val(null);
$file.trigger('click');
});
 
// 추가 첨부 파일 변경 시 파일명 표시 + 확장자/용량 검사
$(document).on('change', '.js_addi_cert_file', function (e) {
const $input = $(this);
const file = this.files[0];
if (!file) return;
const maxSize = parseInt($input.data('max-size'), 10) || 2;
const allowedExt = ['pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
 
// 확장자 검사
const ext = file.name.split('.').pop().toLowerCase();
if (!allowedExt.includes(ext)) {
e.target.value = '';
alert(__('등록이 불가한 파일 형식입니다.'));
return;
}
 
// 파일 크기 검사
const fileSizeMB = file.size / (1024 * 1024);
if (fileSizeMB > maxSize) {
e.target.value = '';
alert(__('파일은 최대 %1$sMB 이하로만 등록 가능합니다.', maxSize.toString()));
}
});
 
// 추가 첨부 삭제 체크 시 confirm
$(document).on('change', '.js_addi_cert_delete', function (e) {
const $box = $(this);
const $label = $('label[for="' + $box.attr('id') + '"]');
if ($box.is(':checked')) {
const confirmDelete = confirm('등록된 첨부파일을 삭제하시겠습니까?\n회원정보 최종 저장 시 삭제되며, 복구가 불가합니다.');
if (!confirmDelete) {
$label.removeClass('on');
$box.prop('checked', false);
}
}
});
 
// 사업자등록증/추가첨부: 찾아보기로 파일 선택 시 파일명 표시 + '- 삭제' 버튼 노출
$(document).on('change', '.js_cert_file', function () {
var $textbox = $('label[for="' + this.id + '"]').find('input[type="text"]');
var $clearBtn = $('.js_cert_clear[data-for="' + this.id + '"]');
if (this.files.length > 0) {
$textbox.val(this.files[0].name);
$clearBtn.show();
// '- 삭제' 버튼 폭만큼 텍스트박스를 줄여 같은 줄에 유지 (버튼 밀림 방지)
$textbox.css({ 'width': '', 'box-sizing': '' });
var freeWidth = $textbox.outerWidth() - $clearBtn.outerWidth(true);
if (freeWidth > 0) {
$textbox.css({ 'box-sizing': 'border-box', 'width': freeWidth + 'px' });
}
} else {
$textbox.val('');
$clearBtn.hide();
$textbox.css({ 'width': '', 'box-sizing': '' });
}
});
 
// '- 삭제' 클릭 시 첨부 취소 + 텍스트박스 내용 제거 + 폭 원복
$(document).on('click', '.js_cert_clear', function () {
var id = $(this).data('for');
$(document.getElementById(id)).val('');
$('label[for="' + id + '"]').find('input[type="text"]')
.val('').css({ 'width': '', 'box-sizing': '' });
$(this).hide();
});
</script>
 
data/skin/mobile/moment/css/member/member.css+4-2
변경 전member.css
.certification_box {position:relative; padding-right:70px;}
.upload_btn_box {position: relative; display: inline-block;}
.upload_btn_box .file {position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer;}
label.check_s[for="certificationDeleteSno"]{ min-height: 23px; line-height: 23px;}
 
 
/*** 회원가입 기타 정보 | member/_join_view_other.html ***/
/* SNS */
.certification_box {position:relative; padding-right:70px;}
.upload_btn_box {position: relative; display: inline-block;}
.upload_btn_box .file {position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer;}
label.check_s[for="certificationDeleteSno"]{ min-height: 23px; line-height: 23px;}
 
 
/*** 회원가입 기타 정보 | member/_join_view_other.html ***/
/* SNS */
 
변경 후member.css
.certification_box {position:relative; padding-right:70px;}
.upload_btn_box {position: relative; display: inline-block;}
.upload_btn_box .file {position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer;}
label.check_s[for="certificationDeleteSno"],
label.check_s[for^="comAddiCertDeleteSno"]{ min-height: 23px; line-height: 23px;}
 
/*** 회원가입 기타 정보 | member/_join_view_other.html ***/
/* SNS */
.certification_box {position:relative; padding-right:70px;}
.upload_btn_box {position: relative; display: inline-block;}
.upload_btn_box .file {position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer;}
label.check_s[for="certificationDeleteSno"],
label.check_s[for^="comAddiCertDeleteSno"]{ min-height: 23px; line-height: 23px;}
 
/*** 회원가입 기타 정보 | member/_join_view_other.html ***/
/* SNS */
 
data/skin/mobile/moment/js/gd_member2.js+120-48
변경 전gd_member2.js
},
highlight: function (element) {
this.errorList[0].element.focus();
 
if(element.type == 'radio') {
$(element).parent().css('border', '3px solid #fa2828');
} else if ('comCertification' == $(element).get(0).id) {
// 사업자등록증 별도 하이라이트 처리
$(`.file_text`).css('border', '3px solid #fa2828');
 
 
 
} else {
$(element).css('border', '3px solid #fa2828');
}
},
unhighlight: function (element) {
 
if(element.type == 'radio') {
$(element).parent().css('border', '0');
} else if ('comCertification' == $(element).get(0).id) {
// 사업자등록증 별도 하이라이트 처리
$(`.file_text`).css('border', '0');
 
 
} else {
$(element).css('border', '1px solid #d0d0d0');
}
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
 
 
 
 
 
 
 
 
 
}
$markTarget.removeClass('ignore');
$markTarget.closest('div.input_content').prev('div').addClass('required');
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
 
 
 
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
if (validate.form()) {
$(form).find('select').prop('disabled', false);
validate.settings.submitHandler = func;
 
$('.join_ok_btn').attr("disabled", true);
 
 
form.submit();
} else {
go_to_by_scroll($('div.c_red:first', form));
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
 
 
 
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
},
highlight: function (element) {
this.errorList[0].element.focus();
 
if(element.type == 'radio') {
$(element).parent().css('border', '3px solid #fa2828');
} else if ('comCertification' == $(element).get(0).id) {
// 사업자등록증 별도 하이라이트 처리
$(`.file_text`).css('border', '3px solid #fa2828');
 
 
 
} else {
$(element).css('border', '3px solid #fa2828');
}
},
unhighlight: function (element) {
 
if(element.type == 'radio') {
$(element).parent().css('border', '0');
} else if ('comCertification' == $(element).get(0).id) {
// 사업자등록증 별도 하이라이트 처리
$(`.file_text`).css('border', '0');
 
 
} else {
$(element).css('border', '1px solid #d0d0d0');
}
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
 
 
 
 
 
 
 
 
 
}
$markTarget.removeClass('ignore');
$markTarget.closest('div.input_content').prev('div').addClass('required');
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
if (validate.form()) {
$(form).find('select').prop('disabled', false);
validate.settings.submitHandler = func;
 
$('.join_ok_btn').attr("disabled", true);
 
 
form.submit();
} else {
go_to_by_scroll($('div.c_red:first', form));
 
변경 후gd_member2.js
},
highlight: function (element) {
this.errorList[0].element.focus();
var elemId = $(element).get(0).id || '';
if(element.type == 'radio') {
$(element).parent().css('border', '3px solid #fa2828');
} else if ('comCertification' == elemId) {
// 사업자등록증: 같은 row 의 .file_text 만 빨갛게 (전역 .file_text 사용 시 다른 항목 강조를 덮어써 사라짐)
$(element).closest('.certification_box').find('.file_text').css('border', '3px solid #fa2828');
} else if (/^comAddiCert\d+$/.test(elemId)) {
// 추가 첨부 항목: 같은 row 의 .file_text 만 빨갛게
$(element).closest('.certification_box').find('.file_text').css('border', '3px solid #fa2828');
} else {
$(element).css('border', '3px solid #fa2828');
}
},
unhighlight: function (element) {
var elemId = $(element).get(0).id || '';
if(element.type == 'radio') {
$(element).parent().css('border', '0');
} else if ('comCertification' == elemId) {
// 사업자등록증: 같은 row 의 .file_text 만 복귀 (전역 .file_text 복원 시 다른 항목 강조를 덮어씀)
$(element).closest('.certification_box').find('.file_text').css('border', '');
} else if (/^comAddiCert\d+$/.test(elemId)) {
$(element).closest('.certification_box').find('.file_text').css('border', '');
} else {
$(element).css('border', '1px solid #d0d0d0');
}
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget;
// 추가 첨부 (comAddiCertN) 정책 키는 실제 input name 이 comAddiCert[N][file] 형태이므로 별도 매칭
var addiCertMatch = idx.match(/^comAddiCert(\d+)$/);
if (addiCertMatch) {
var addiCertRuleKey = 'comAddiCert[' + addiCertMatch[1] + '][file]';
$markTarget = $('input[name="' + addiCertRuleKey + '"]');
settings.rules[addiCertRuleKey] = {required: true};
} else {
$markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
}
}
$markTarget.removeClass('ignore');
$markTarget.closest('div.input_content').prev('div').addClass('required');
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
// 사업자등록증 입력 항목이 없으면 빈 selection 에 .rules() 가 호출돼 터지므로 가드
if ($comCertification.length > 0) {
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
var $addiInput = $(this);
var matched = ($addiInput.attr('name') || '').match(/^comAddiCert\[(\d+)\]\[file\]$/);
if (!matched) return;
var $addiDelBox = $('input[name="comAddiCert[' + matched[1] + '][DeleteSno]"]');
var rules = $addiInput.rules();
var addiRequired = !!(rules && rules.required);
var addiFileEmpty = !$addiInput.val();
var addiDeleteChecked = $addiDelBox.is(':checked');
var addiHasDeleteSno = !!$addiDelBox.val();
if (addiRequired && addiHasDeleteSno && addiFileEmpty && !addiDeleteChecked) {
$addiInput.rules("remove");
}
});
$(form).find('select').prop('disabled', false);
validate.settings.submitHandler = func;
}
if (validate.form()) {
$(form).find('select').prop('disabled', false);
 
 
$('.join_ok_btn').attr("disabled", true);
 
validate.settings.submitHandler = func;
form.submit();
} else {
go_to_by_scroll($('div.c_red:first', form));
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
// 사업자등록증 입력 항목이 없으면 빈 selection 에 .rules() 가 호출돼 터지므로 가드
if ($comCertification.length > 0) {
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
},
highlight: function (element) {
this.errorList[0].element.focus();
var elemId = $(element).get(0).id || '';
if(element.type == 'radio') {
$(element).parent().css('border', '3px solid #fa2828');
} else if ('comCertification' == elemId) {
// 사업자등록증: 같은 row 의 .file_text 만 빨갛게 (전역 .file_text 사용 시 다른 항목 강조를 덮어써 사라짐)
$(element).closest('.certification_box').find('.file_text').css('border', '3px solid #fa2828');
} else if (/^comAddiCert\d+$/.test(elemId)) {
// 추가 첨부 항목: 같은 row 의 .file_text 만 빨갛게
$(element).closest('.certification_box').find('.file_text').css('border', '3px solid #fa2828');
} else {
$(element).css('border', '3px solid #fa2828');
}
},
unhighlight: function (element) {
var elemId = $(element).get(0).id || '';
if(element.type == 'radio') {
$(element).parent().css('border', '0');
} else if ('comCertification' == elemId) {
// 사업자등록증: 같은 row 의 .file_text 만 복귀 (전역 .file_text 복원 시 다른 항목 강조를 덮어씀)
$(element).closest('.certification_box').find('.file_text').css('border', '');
} else if (/^comAddiCert\d+$/.test(elemId)) {
$(element).closest('.certification_box').find('.file_text').css('border', '');
} else {
$(element).css('border', '1px solid #d0d0d0');
}
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget;
// 추가 첨부 (comAddiCertN) 정책 키는 실제 input name 이 comAddiCert[N][file] 형태이므로 별도 매칭
var addiCertMatch = idx.match(/^comAddiCert(\d+)$/);
if (addiCertMatch) {
var addiCertRuleKey = 'comAddiCert[' + addiCertMatch[1] + '][file]';
$markTarget = $('input[name="' + addiCertRuleKey + '"]');
settings.rules[addiCertRuleKey] = {required: true};
} else {
$markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
}
}
$markTarget.removeClass('ignore');
$markTarget.closest('div.input_content').prev('div').addClass('required');
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
var $addiInput = $(this);
var matched = ($addiInput.attr('name') || '').match(/^comAddiCert\[(\d+)\]\[file\]$/);
if (!matched) return;
var $addiDelBox = $('input[name="comAddiCert[' + matched[1] + '][DeleteSno]"]');
var rules = $addiInput.rules();
var addiRequired = !!(rules && rules.required);
var addiFileEmpty = !$addiInput.val();
var addiDeleteChecked = $addiDelBox.is(':checked');
var addiHasDeleteSno = !!$addiDelBox.val();
if (addiRequired && addiHasDeleteSno && addiFileEmpty && !addiDeleteChecked) {
$addiInput.rules("remove");
}
});
$(form).find('select').prop('disabled', false);
validate.settings.submitHandler = func;
}
if (validate.form()) {
$(form).find('select').prop('disabled', false);
 
 
$('.join_ok_btn').attr("disabled", true);
 
validate.settings.submitHandler = func;
form.submit();
} else {
go_to_by_scroll($('div.c_red:first', form));
 
data/skin/mobile/moment/member/_join_view_business.html+160
변경 전_join_view_business.html
</div>
</div>
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</div>
<!--{/}-->
<script type="text/javascript">
}
}
});
 
 
 
$(document).on('change', '.upload_btn_box .file', function(){
var i = $(this).val();
$('label[for=' + $(this).attr('id') + ']').find('.file_text').val(i);
});
 
 
 
 
 
 
 
 
 
 
 
 
 
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</script>
</div>
</div>
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</div>
<!--{/}-->
<script type="text/javascript">
}
}
});
 
 
 
$(document).on('change', '.upload_btn_box .file', function(){
var i = $(this).val();
$('label[for=' + $(this).attr('id') + ']').find('.file_text').val(i);
});
 
 
 
 
 
 
 
 
 
 
 
 
 
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</script>
 
변경 후_join_view_business.html
</div>
</div>
<!--{/}-->
<!--{ @ comAddiCerts }-->
<!--{? .value_.use == 'y'}-->
<div class="input_wrap">
<div class="input_title"><label for="comAddiCert{=substr(.key_, 11)}">{=.value_.name}</label></div>
<div class="input_content">
<!--{? .value_.file.imageFileNm}-->
<div class="form_element">
<a href="../member/company_certification.php?mode=download&sno={.value_.file.sno}" class="link_file_down">{=.value_.file.imageFileNm}</a>
<input type="checkbox" id="comAddiCertDeleteSno{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][DeleteSno]" class="js_addi_cert_delete" value="{.value_.file.sno}" />
<label for="comAddiCertDeleteSno{=substr(.key_, 11)}" class="check_s">{=__('삭제')}</label>
</div>
<!--{/}-->
<div class="certification_box">
<label for="comAddiCert{=substr(.key_, 11)}">
<input type="text" class="file_text" title="{=__('파일 첨부하기')}" readonly="readonly"/>
</label>
<div class="upload_btn_box">
<button type="button" class="zipcode_btn" title="{=__('찾아보기')}">{=__('찾아보기')}</button>
<input type="file" id="comAddiCert{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][file]" class="file js_addi_cert_file" accept="image/*, application/pdf" data-max-size="{.value_.certificationFileSize}"/>
</div>
</div>
</div>
</div>
<!--{/}-->
<!--{ / }-->
</div>
<!--{/}-->
<script type="text/javascript">
}
}
});
<!--{/}-->
 
// 파일 선택시 파일명 표시 (사업자등록증/추가첨부 공용 — comCertification if 영향 받지 않도록 밖에 둠)
$(document).on('change', '.upload_btn_box .file', function(){
var i = $(this).val();
$('label[for=' + $(this).attr('id') + ']').find('.file_text').val(i);
});
 
<!--{? !isMyPage}-->
// 가입 시: 첨부된 파일의 텍스트박스 클릭 → 삭제 확인 후 첨부/텍스트박스 비움
$(document).on('click', '.file_text', function (e) {
if (!$(this).val()) { return; } // 미첨부: 기본 동작(찾아보기) 허용
e.preventDefault(); // 첨부됨: 재선택(파일창) 차단 후 삭제 확인
if (confirm('첨부 파일을 삭제하시겠습니까?')) {
var forId = $(this).closest('label').attr('for');
var fileInput = forId ? document.getElementById(forId) : null;
if (fileInput) { fileInput.value = ''; }
$(this).val('');
}
});
<!--{/}-->
 
 
$(document).on('change', '.js_addi_cert_file', function (e) {
const $input = $(this);
const file = this.files[0];
if (!file) return;
const maxSize = parseInt($input.data('max-size'), 10) || 2;
const allowedExt = ['pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
// 표시 핸들러가 먼저 채운 파일명을 검증 실패 시 함께 비우기 위해 textbox 참조
const $fileText = $('label[for="' + this.id + '"]').find('.file_text');
 
// 확장자 검사
const ext = file.name.split('.').pop().toLowerCase();
if (!allowedExt.includes(ext)) {
e.target.value = '';
$fileText.val('');
alert(__('등록이 불가한 파일 형식입니다.'));
return;
}
 
// 파일 크기 검사
const fileSizeMB = file.size / (1024 * 1024);
if (fileSizeMB > maxSize) {
e.target.value = '';
$fileText.val('');
alert(__('파일은 최대 %1$sMB 이하로만 등록 가능합니다.', maxSize.toString()));
}
});
 
$(document).on('change', '.js_addi_cert_delete', function (e) {
const $box = $(this);
const $label = $('label[for="' + $box.attr('id') + '"]');
if ($box.is(':checked')) {
const confirmDelete = confirm('등록된 첨부파일을 삭제하시겠습니까?\n회원정보 최종 저장 시 삭제되며, 복구가 불가합니다.');
if (!confirmDelete) {
$label.removeClass('on');
$box.prop('checked', false);
}
}
});
</script>
</div>
</div>
<!--{/}-->
<!--{ @ comAddiCerts }-->
<!--{? .value_.use == 'y'}-->
<div class="input_wrap">
<div class="input_title"><label for="comAddiCert{=substr(.key_, 11)}">{=.value_.name}</label></div>
<div class="input_content">
<!--{? .value_.file.imageFileNm}-->
<div class="form_element">
<a href="../member/company_certification.php?mode=download&sno={.value_.file.sno}" class="link_file_down">{=.value_.file.imageFileNm}</a>
<input type="checkbox" id="comAddiCertDeleteSno{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][DeleteSno]" class="js_addi_cert_delete" value="{.value_.file.sno}" />
<label for="comAddiCertDeleteSno{=substr(.key_, 11)}" class="check_s">{=__('삭제')}</label>
</div>
<!--{/}-->
<div class="certification_box">
<label for="comAddiCert{=substr(.key_, 11)}">
<input type="text" class="file_text" title="{=__('파일 첨부하기')}" readonly="readonly"/>
</label>
<div class="upload_btn_box">
<button type="button" class="zipcode_btn" title="{=__('찾아보기')}">{=__('찾아보기')}</button>
<input type="file" id="comAddiCert{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][file]" class="file js_addi_cert_file" accept="image/*, application/pdf" data-max-size="{.value_.certificationFileSize}"/>
</div>
</div>
</div>
</div>
<!--{/}-->
<!--{ / }-->
</div>
<!--{/}-->
<script type="text/javascript">
}
}
});
<!--{/}-->
 
// 파일 선택시 파일명 표시 (사업자등록증/추가첨부 공용 — comCertification if 영향 받지 않도록 밖에 둠)
$(document).on('change', '.upload_btn_box .file', function(){
var i = $(this).val();
$('label[for=' + $(this).attr('id') + ']').find('.file_text').val(i);
});
 
<!--{? !isMyPage}-->
// 가입 시: 첨부된 파일의 텍스트박스 클릭 → 삭제 확인 후 첨부/텍스트박스 비움
$(document).on('click', '.file_text', function (e) {
if (!$(this).val()) { return; } // 미첨부: 기본 동작(찾아보기) 허용
e.preventDefault(); // 첨부됨: 재선택(파일창) 차단 후 삭제 확인
if (confirm('첨부 파일을 삭제하시겠습니까?')) {
var forId = $(this).closest('label').attr('for');
var fileInput = forId ? document.getElementById(forId) : null;
if (fileInput) { fileInput.value = ''; }
$(this).val('');
}
});
<!--{/}-->
 
 
$(document).on('change', '.js_addi_cert_file', function (e) {
const $input = $(this);
const file = this.files[0];
if (!file) return;
const maxSize = parseInt($input.data('max-size'), 10) || 2;
const allowedExt = ['pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
// 표시 핸들러가 먼저 채운 파일명을 검증 실패 시 함께 비우기 위해 textbox 참조
const $fileText = $('label[for="' + this.id + '"]').find('.file_text');
 
// 확장자 검사
const ext = file.name.split('.').pop().toLowerCase();
if (!allowedExt.includes(ext)) {
e.target.value = '';
$fileText.val('');
alert(__('등록이 불가한 파일 형식입니다.'));
return;
}
 
// 파일 크기 검사
const fileSizeMB = file.size / (1024 * 1024);
if (fileSizeMB > maxSize) {
e.target.value = '';
$fileText.val('');
alert(__('파일은 최대 %1$sMB 이하로만 등록 가능합니다.', maxSize.toString()));
}
});
 
$(document).on('change', '.js_addi_cert_delete', function (e) {
const $box = $(this);
const $label = $('label[for="' + $box.attr('id') + '"]');
if ($box.is(':checked')) {
const confirmDelete = confirm('등록된 첨부파일을 삭제하시겠습니까?\n회원정보 최종 저장 시 삭제되며, 복구가 불가합니다.');
if (!confirmDelete) {
$label.removeClass('on');
$box.prop('checked', false);
}
}
});
</script>
 
data/skin/mobile/moment/mypage/my_page.html+2-2
변경 전my_page.html
{*** 회원정보 변경 | mypage/my_page.php ***}
{ # header }
<div class="my_page" id="memberjoin">
<form id="formJoin" name="formJoin" action="{mypageActionUrl}" method="post" enctype="multipart/form-data">
<input type="hidden" name="memNo" value="{data.memNo}"/>
<input type="hidden" name="memberFl" value="{data.memberFl}"/>
{*** 회원정보 변경 | mypage/my_page.php ***}
{ # header }
<div class="my_page" id="memberjoin">
<form id="formJoin" name="formJoin" action="{mypageActionUrl}" method="post" enctype="multipart/form-data">
<input type="hidden" name="memNo" value="{data.memNo}"/>
<input type="hidden" name="memberFl" value="{data.memberFl}"/>
 
변경 후my_page.html
{*** 회원정보 변경 | mypage/my_page.php ***}
{ # header }
<div class="my_page join" id="memberjoin">
<form id="formJoin" name="formJoin" action="{mypageActionUrl}" method="post" enctype="multipart/form-data">
<input type="hidden" name="memNo" value="{data.memNo}"/>
<input type="hidden" name="memberFl" value="{data.memberFl}"/>
{*** 회원정보 변경 | mypage/my_page.php ***}
{ # header }
<div class="my_page join" id="memberjoin">
<form id="formJoin" name="formJoin" action="{mypageActionUrl}" method="post" enctype="multipart/form-data">
<input type="hidden" name="memNo" value="{data.memNo}"/>
<input type="hidden" name="memberFl" value="{data.memberFl}"/>
 
data/skin/mobile/mygreek/css/member/member.css+4-2
변경 전member.css
opacity: 0;
cursor: pointer;
}
label.check_s[for="certificationDeleteSno"]{
 
min-height: 23px;
line-height: 23px;
}
opacity: 0;
cursor: pointer;
}
label.check_s[for="certificationDeleteSno"]{
 
min-height: 23px;
line-height: 23px;
}
 
변경 후member.css
opacity: 0;
cursor: pointer;
}
label.check_s[for="certificationDeleteSno"],
label.check_s[for^="comAddiCertDeleteSno"]{
min-height: 23px;
line-height: 23px;
}
opacity: 0;
cursor: pointer;
}
label.check_s[for="certificationDeleteSno"],
label.check_s[for^="comAddiCertDeleteSno"]{
min-height: 23px;
line-height: 23px;
}
 
data/skin/mobile/mygreek/js/gd_member2.js+116-46
변경 전gd_member2.js
},
highlight: function (element) {
this.errorList[0].element.focus();
 
if(element.type == 'radio') {
$(element).parent().css('border', '3px solid #fa2828');
} else if ('comCertification' == $(element).get(0).id) {
// 사업자등록증 별도 하이라이트 처리
$('.file_text').css('border', '3px solid #fa2828');
 
 
 
} else {
$(element).css('border', '3px solid #fa2828');
}
},
unhighlight: function (element) {
 
if(element.type == 'radio') {
$(element).parent().css('border', '0');
} else if ('comCertification' == $(element).get(0).id) {
// 사업자등록증 별도 하이라이트 처리
$(`.file_text`).css('border', '1px solid #d0d0d0');
 
 
} else {
$(element).css('border', '1px solid #d0d0d0');
}
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
 
 
 
 
 
 
 
 
 
}
$markTarget.removeClass('ignore');
$markTarget.closest('div.input_content').prev('div').addClass('required');
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
 
 
 
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
if (validate.form()) {
$(form).find('select').prop('disabled',false);
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
 
 
 
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
},
highlight: function (element) {
this.errorList[0].element.focus();
 
if(element.type == 'radio') {
$(element).parent().css('border', '3px solid #fa2828');
} else if ('comCertification' == $(element).get(0).id) {
// 사업자등록증 별도 하이라이트 처리
$('.file_text').css('border', '3px solid #fa2828');
 
 
 
} else {
$(element).css('border', '3px solid #fa2828');
}
},
unhighlight: function (element) {
 
if(element.type == 'radio') {
$(element).parent().css('border', '0');
} else if ('comCertification' == $(element).get(0).id) {
// 사업자등록증 별도 하이라이트 처리
$(`.file_text`).css('border', '1px solid #d0d0d0');
 
 
} else {
$(element).css('border', '1px solid #d0d0d0');
}
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
 
 
 
 
 
 
 
 
 
}
$markTarget.removeClass('ignore');
$markTarget.closest('div.input_content').prev('div').addClass('required');
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
if (validate.form()) {
$(form).find('select').prop('disabled',false);
 
변경 후gd_member2.js
},
highlight: function (element) {
this.errorList[0].element.focus();
var elemId = $(element).get(0).id || '';
if(element.type == 'radio') {
$(element).parent().css('border', '3px solid #fa2828');
} else if ('comCertification' == elemId) {
// 사업자등록증: 같은 row 의 .file_text 만 빨갛게 (전역 .file_text 사용 시 다른 항목 강조를 덮어써 사라짐)
$(element).closest('.certification_box').find('.file_text').css('border', '3px solid #fa2828');
} else if (/^comAddiCert\d+$/.test(elemId)) {
// 추가 첨부 항목: 같은 row 의 .file_text 만 빨갛게
$(element).closest('.certification_box').find('.file_text').css('border', '3px solid #fa2828');
} else {
$(element).css('border', '3px solid #fa2828');
}
},
unhighlight: function (element) {
var elemId = $(element).get(0).id || '';
if(element.type == 'radio') {
$(element).parent().css('border', '0');
} else if ('comCertification' == elemId) {
// 사업자등록증: 같은 row 의 .file_text 만 복귀 (전역 .file_text 복원 시 다른 항목 강조를 덮어씀)
$(element).closest('.certification_box').find('.file_text').css('border', '1px solid #d0d0d0');
} else if (/^comAddiCert\d+$/.test(elemId)) {
$(element).closest('.certification_box').find('.file_text').css('border', '1px solid #d0d0d0');
} else {
$(element).css('border', '1px solid #d0d0d0');
}
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget;
// 추가 첨부 (comAddiCertN) 정책 키는 실제 input name 이 comAddiCert[N][file] 형태이므로 별도 매칭
var addiCertMatch = idx.match(/^comAddiCert(\d+)$/);
if (addiCertMatch) {
var addiCertRuleKey = 'comAddiCert[' + addiCertMatch[1] + '][file]';
$markTarget = $('input[name="' + addiCertRuleKey + '"]');
settings.rules[addiCertRuleKey] = {required: true};
} else {
$markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
}
}
$markTarget.removeClass('ignore');
$markTarget.closest('div.input_content').prev('div').addClass('required');
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
// 사업자등록증 입력 항목이 없으면 빈 selection 에 .rules() 가 호출돼 터지므로 가드
if ($comCertification.length > 0) {
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
var $addiInput = $(this);
var matched = ($addiInput.attr('name') || '').match(/^comAddiCert\[(\d+)\]\[file\]$/);
if (!matched) return;
var $addiDelBox = $('input[name="comAddiCert[' + matched[1] + '][DeleteSno]"]');
var rules = $addiInput.rules();
var addiRequired = !!(rules && rules.required);
var addiFileEmpty = !$addiInput.val();
var addiDeleteChecked = $addiDelBox.is(':checked');
var addiHasDeleteSno = !!$addiDelBox.val();
if (addiRequired && addiHasDeleteSno && addiFileEmpty && !addiDeleteChecked) {
$addiInput.rules("remove");
}
});
$(form).find('select').prop('disabled',false);
validate.settings.submitHandler = func;
}
if (validate.form()) {
$(form).find('select').prop('disabled',false);
if(is_my_page && isBusiness) {
var $certificationDeleteSno = $('input[name="certificationDeleteSno"]');
var $comCertification = $('input[name="comCertification[]"]');
// 사업자등록증 입력 항목이 없으면 빈 selection 에 .rules() 가 호출돼 터지므로 가드
if ($comCertification.length > 0) {
var isComCertificationRequired = $comCertification.rules().required;
var isFileEmpty = !$comCertification.val();
var isDeleteChecked = $certificationDeleteSno.is(':checked');
var hasDeleteSno = !!$certificationDeleteSno.val();
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
},
highlight: function (element) {
this.errorList[0].element.focus();
var elemId = $(element).get(0).id || '';
if(element.type == 'radio') {
$(element).parent().css('border', '3px solid #fa2828');
} else if ('comCertification' == elemId) {
// 사업자등록증: 같은 row 의 .file_text 만 빨갛게 (전역 .file_text 사용 시 다른 항목 강조를 덮어써 사라짐)
$(element).closest('.certification_box').find('.file_text').css('border', '3px solid #fa2828');
} else if (/^comAddiCert\d+$/.test(elemId)) {
// 추가 첨부 항목: 같은 row 의 .file_text 만 빨갛게
$(element).closest('.certification_box').find('.file_text').css('border', '3px solid #fa2828');
} else {
$(element).css('border', '3px solid #fa2828');
}
},
unhighlight: function (element) {
var elemId = $(element).get(0).id || '';
if(element.type == 'radio') {
$(element).parent().css('border', '0');
} else if ('comCertification' == elemId) {
// 사업자등록증: 같은 row 의 .file_text 만 복귀 (전역 .file_text 복원 시 다른 항목 강조를 덮어씀)
$(element).closest('.certification_box').find('.file_text').css('border', '1px solid #d0d0d0');
} else if (/^comAddiCert\d+$/.test(elemId)) {
$(element).closest('.certification_box').find('.file_text').css('border', '1px solid #d0d0d0');
} else {
$(element).css('border', '1px solid #d0d0d0');
}
}
if (item.require === 'y') {
settings.rules[idx].required = true;
var $markTarget;
// 추가 첨부 (comAddiCertN) 정책 키는 실제 input name 이 comAddiCert[N][file] 형태이므로 별도 매칭
var addiCertMatch = idx.match(/^comAddiCert(\d+)$/);
if (addiCertMatch) {
var addiCertRuleKey = 'comAddiCert[' + addiCertMatch[1] + '][file]';
$markTarget = $('input[name="' + addiCertRuleKey + '"]');
settings.rules[addiCertRuleKey] = {required: true};
} else {
$markTarget = $('input[name="' + idx + '"]');
if ($markTarget.length < 1) {
$markTarget = $('select[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('textarea[name="' + idx + '"]');
}
if ($markTarget.length < 1) {
$markTarget = $('input[name="' + idx + '[]"]');
settings.rules[idx + '[]'] = {required: true};
}
}
$markTarget.removeClass('ignore');
$markTarget.closest('div.input_content').prev('div').addClass('required');
if (isComCertificationRequired && hasDeleteSno && isFileEmpty && !isDeleteChecked) {
$comCertification.rules("remove");
}
// 추가 첨부 항목도 row 별로 동일 우회 적용
$('input.js_addi_cert_file').each(function () {
var $addiInput = $(this);
var matched = ($addiInput.attr('name') || '').match(/^comAddiCert\[(\d+)\]\[file\]$/);
if (!matched) return;
var $addiDelBox = $('input[name="comAddiCert[' + matched[1] + '][DeleteSno]"]');
var rules = $addiInput.rules();
var addiRequired = !!(rules && rules.required);
var addiFileEmpty = !$addiInput.val();
var addiDeleteChecked = $addiDelBox.is(':checked');
var addiHasDeleteSno = !!$addiDelBox.val();
if (addiRequired && addiHasDeleteSno && addiFileEmpty && !addiDeleteChecked) {
$addiInput.rules("remove");
}
});
$(form).find('select').prop('disabled',false);
validate.settings.submitHandler = func;
}
if (validate.form()) {
$(form).find('select').prop('disabled',false);
 
data/skin/mobile/mygreek/member/_join_view_business.html+160
변경 전_join_view_business.html
</div>
</div>
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</div>
<!--{/}-->
<script type="text/javascript">
}
}
});
 
 
 
$(document).on('change', '.upload_btn_box .file', function(){
var i = $(this).val();
$('label[for=' + $(this).attr('id') + ']').find('.file_text').val(i);
});
 
 
 
 
 
 
 
 
 
 
 
 
 
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</script>
</div>
</div>
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</div>
<!--{/}-->
<script type="text/javascript">
}
}
});
 
 
 
$(document).on('change', '.upload_btn_box .file', function(){
var i = $(this).val();
$('label[for=' + $(this).attr('id') + ']').find('.file_text').val(i);
});
 
 
 
 
 
 
 
 
 
 
 
 
 
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</script>
 
변경 후_join_view_business.html
</div>
</div>
<!--{/}-->
<!--{ @ comAddiCerts }-->
<!--{? .value_.use == 'y'}-->
<div class="input_wrap">
<div class="input_title"><label for="comAddiCert{=substr(.key_, 11)}">{=.value_.name}</label></div>
<div class="input_content">
<!--{? .value_.file.imageFileNm}-->
<div class="form_element">
<a href="../member/company_certification.php?mode=download&sno={.value_.file.sno}" class="link_file_down">{=.value_.file.imageFileNm}</a>
<input type="checkbox" id="comAddiCertDeleteSno{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][DeleteSno]" class="js_addi_cert_delete" value="{.value_.file.sno}" />
<label for="comAddiCertDeleteSno{=substr(.key_, 11)}" class="check_s">{=__('삭제')}</label>
</div>
<!--{/}-->
<div class="certification_box">
<label for="comAddiCert{=substr(.key_, 11)}">
<input type="text" class="file_text" title="{=__('파일 첨부하기')}" readonly="readonly"/>
</label>
<div class="upload_btn_box">
<button type="button" class="zipcode_btn" title="{=__('찾아보기')}">{=__('찾아보기')}</button>
<input type="file" id="comAddiCert{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][file]" class="file js_addi_cert_file" accept="image/*, application/pdf" data-max-size="{.value_.certificationFileSize}"/>
</div>
</div>
</div>
</div>
<!--{/}-->
<!--{ / }-->
</div>
<!--{/}-->
<script type="text/javascript">
}
}
});
<!--{/}-->
 
// 파일 선택시 파일명 표시 (사업자등록증/추가첨부 공용 — comCertification if 영향 받지 않도록 밖에 둠)
$(document).on('change', '.upload_btn_box .file', function(){
var i = $(this).val();
$('label[for=' + $(this).attr('id') + ']').find('.file_text').val(i);
});
 
<!--{? !isMyPage}-->
// 가입 시: 첨부된 파일의 텍스트박스 클릭 → 삭제 확인 후 첨부/텍스트박스 비움
$(document).on('click', '.file_text', function (e) {
if (!$(this).val()) { return; } // 미첨부: 기본 동작(찾아보기) 허용
e.preventDefault(); // 첨부됨: 재선택(파일창) 차단 후 삭제 확인
if (confirm('첨부 파일을 삭제하시겠습니까?')) {
var forId = $(this).closest('label').attr('for');
var fileInput = forId ? document.getElementById(forId) : null;
if (fileInput) { fileInput.value = ''; }
$(this).val('');
}
});
<!--{/}-->
 
 
$(document).on('change', '.js_addi_cert_file', function (e) {
const $input = $(this);
const file = this.files[0];
if (!file) return;
const maxSize = parseInt($input.data('max-size'), 10) || 2;
const allowedExt = ['pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
// 표시 핸들러가 먼저 채운 파일명을 검증 실패 시 함께 비우기 위해 textbox 참조
const $fileText = $('label[for="' + this.id + '"]').find('.file_text');
 
// 확장자 검사
const ext = file.name.split('.').pop().toLowerCase();
if (!allowedExt.includes(ext)) {
e.target.value = '';
$fileText.val('');
alert(__('등록이 불가한 파일 형식입니다.'));
return;
}
 
// 파일 크기 검사
const fileSizeMB = file.size / (1024 * 1024);
if (fileSizeMB > maxSize) {
e.target.value = '';
$fileText.val('');
alert(__('파일은 최대 %1$sMB 이하로만 등록 가능합니다.', maxSize.toString()));
}
});
 
$(document).on('change', '.js_addi_cert_delete', function (e) {
const $box = $(this);
const $label = $('label[for="' + $box.attr('id') + '"]');
if ($box.is(':checked')) {
const confirmDelete = confirm('등록된 첨부파일을 삭제하시겠습니까?\n회원정보 최종 저장 시 삭제되며, 복구가 불가합니다.');
if (!confirmDelete) {
$label.removeClass('on');
$box.prop('checked', false);
}
}
});
</script>
</div>
</div>
<!--{/}-->
<!--{ @ comAddiCerts }-->
<!--{? .value_.use == 'y'}-->
<div class="input_wrap">
<div class="input_title"><label for="comAddiCert{=substr(.key_, 11)}">{=.value_.name}</label></div>
<div class="input_content">
<!--{? .value_.file.imageFileNm}-->
<div class="form_element">
<a href="../member/company_certification.php?mode=download&sno={.value_.file.sno}" class="link_file_down">{=.value_.file.imageFileNm}</a>
<input type="checkbox" id="comAddiCertDeleteSno{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][DeleteSno]" class="js_addi_cert_delete" value="{.value_.file.sno}" />
<label for="comAddiCertDeleteSno{=substr(.key_, 11)}" class="check_s">{=__('삭제')}</label>
</div>
<!--{/}-->
<div class="certification_box">
<label for="comAddiCert{=substr(.key_, 11)}">
<input type="text" class="file_text" title="{=__('파일 첨부하기')}" readonly="readonly"/>
</label>
<div class="upload_btn_box">
<button type="button" class="zipcode_btn" title="{=__('찾아보기')}">{=__('찾아보기')}</button>
<input type="file" id="comAddiCert{=substr(.key_, 11)}" name="comAddiCert[{=substr(.key_, 11)}][file]" class="file js_addi_cert_file" accept="image/*, application/pdf" data-max-size="{.value_.certificationFileSize}"/>
</div>
</div>
</div>
</div>
<!--{/}-->
<!--{ / }-->
</div>
<!--{/}-->
<script type="text/javascript">
}
}
});
<!--{/}-->
 
// 파일 선택시 파일명 표시 (사업자등록증/추가첨부 공용 — comCertification if 영향 받지 않도록 밖에 둠)
$(document).on('change', '.upload_btn_box .file', function(){
var i = $(this).val();
$('label[for=' + $(this).attr('id') + ']').find('.file_text').val(i);
});
 
<!--{? !isMyPage}-->
// 가입 시: 첨부된 파일의 텍스트박스 클릭 → 삭제 확인 후 첨부/텍스트박스 비움
$(document).on('click', '.file_text', function (e) {
if (!$(this).val()) { return; } // 미첨부: 기본 동작(찾아보기) 허용
e.preventDefault(); // 첨부됨: 재선택(파일창) 차단 후 삭제 확인
if (confirm('첨부 파일을 삭제하시겠습니까?')) {
var forId = $(this).closest('label').attr('for');
var fileInput = forId ? document.getElementById(forId) : null;
if (fileInput) { fileInput.value = ''; }
$(this).val('');
}
});
<!--{/}-->
 
 
$(document).on('change', '.js_addi_cert_file', function (e) {
const $input = $(this);
const file = this.files[0];
if (!file) return;
const maxSize = parseInt($input.data('max-size'), 10) || 2;
const allowedExt = ['pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'];
// 표시 핸들러가 먼저 채운 파일명을 검증 실패 시 함께 비우기 위해 textbox 참조
const $fileText = $('label[for="' + this.id + '"]').find('.file_text');
 
// 확장자 검사
const ext = file.name.split('.').pop().toLowerCase();
if (!allowedExt.includes(ext)) {
e.target.value = '';
$fileText.val('');
alert(__('등록이 불가한 파일 형식입니다.'));
return;
}
 
// 파일 크기 검사
const fileSizeMB = file.size / (1024 * 1024);
if (fileSizeMB > maxSize) {
e.target.value = '';
$fileText.val('');
alert(__('파일은 최대 %1$sMB 이하로만 등록 가능합니다.', maxSize.toString()));
}
});
 
$(document).on('change', '.js_addi_cert_delete', function (e) {
const $box = $(this);
const $label = $('label[for="' + $box.attr('id') + '"]');
if ($box.is(':checked')) {
const confirmDelete = confirm('등록된 첨부파일을 삭제하시겠습니까?\n회원정보 최종 저장 시 삭제되며, 복구가 불가합니다.');
if (!confirmDelete) {
$label.removeClass('on');
$box.prop('checked', false);
}
}
});
</script>
 
data/skin/mobile/mygreek/mypage/my_page.html+2-2
변경 전my_page.html
{*** 회원정보 변경 | mypage/my_page.php ***}
{ # header }
<div class="my_page" id="memberjoin">
<form id="formJoin" name="formJoin" action="{mypageActionUrl}" method="post" enctype="multipart/form-data">
<input type="hidden" name="memNo" value="{data.memNo}"/>
<input type="hidden" name="memberFl" value="{data.memberFl}"/>
{*** 회원정보 변경 | mypage/my_page.php ***}
{ # header }
<div class="my_page" id="memberjoin">
<form id="formJoin" name="formJoin" action="{mypageActionUrl}" method="post" enctype="multipart/form-data">
<input type="hidden" name="memNo" value="{data.memNo}"/>
<input type="hidden" name="memberFl" value="{data.memberFl}"/>
 
변경 후my_page.html
{*** 회원정보 변경 | mypage/my_page.php ***}
{ # header }
<div class="my_page join" id="memberjoin">
<form id="formJoin" name="formJoin" action="{mypageActionUrl}" method="post" enctype="multipart/form-data">
<input type="hidden" name="memNo" value="{data.memNo}"/>
<input type="hidden" name="memberFl" value="{data.memberFl}"/>
{*** 회원정보 변경 | mypage/my_page.php ***}
{ # header }
<div class="my_page join" id="memberjoin">
<form id="formJoin" name="formJoin" action="{mypageActionUrl}" method="post" enctype="multipart/form-data">
<input type="hidden" name="memNo" value="{data.memNo}"/>
<input type="hidden" name="memberFl" value="{data.memberFl}"/>
 
관리자 내 마케팅 콘텐츠 노출 영역 신설
Admin/base/index.php+27-22
변경 전index.php
var main_setting = <?= json_encode($setting);?>;
</script>
<link type="text/css" href="<?= PATH_ADMIN_GD_SHARE ?>script/slider/slick/slick.css" rel="stylesheet"/>
 
<script type="text/javascript" src="<?= PATH_ADMIN_GD_SHARE ?>script/slider/slick/slick.js"></script>
<script type="text/javascript" src="<?= PATH_ADMIN_GD_SHARE ?>script/main.js" charset="utf-8"></script>
 
 
<div class="row">
<div class="col-xs-6">
<!-- 공지사항 / godo:플러스샵 -->
<div class="main-section">
<div class="table-title">
<span class="">공지사항</span>
<div class="pull-right">
<div id="panel_link_noticeLink" class="pull-right more-view"></div>
</div>
</div>
<div class="board-list-newest content list-unstyled reform" id="panel_board_noticeAPI">
 
 
 
 
 
 
 
 
 
 
</div>
 
 
</div>
</div>
<div class="col-xs-6">
<!-- 패치&업그레이드 -->
<div class="main-section">
<div class="table-title">
<span class="">업데이트</span>
<div class="pull-right">
<div id="panel_link_patchLink" class="pull-right more-view"></div>
</div>
</div>
<ol class="board-list-newest content list-unstyled reform" id="panel_board_patchAPI">
</ol>
</div>
</div>
</div>
 
<!-- 관리자 메인 게시판 시작 -->
 
<?php if (gd_is_provider() === false) { ?>
<!-- 관리자 메인 중간 배너 시작 -->
<div id="panel_banner_mainMiddle" class="main-section"></div>
<!-- 관리자 메인 중간 배너 끝 -->
<?php } ?>
 
<!-- 더 좋아지는 고도몰 -->
<ul class="nav nav-tabs mgt35 display-none">
<li role="presentation" class="active">
 
변경 후index.php
var main_setting = <?= json_encode($setting);?>;
</script>
<link type="text/css" href="<?= PATH_ADMIN_GD_SHARE ?>script/slider/slick/slick.css" rel="stylesheet"/>
<link type="text/css" href="<?= PATH_ADMIN_GD_SHARE ?>css/admin_main.css" rel="stylesheet"/>
<script type="text/javascript" src="<?= PATH_ADMIN_GD_SHARE ?>script/slider/slick/slick.js"></script>
<script type="text/javascript" src="<?= PATH_ADMIN_GD_SHARE ?>script/main.js" charset="utf-8"></script>
 
 
<div class="row">
<div class="col-xs-6">
<!-- 공지/업데이트 통합 -->
<div class="main-section">
<div class="table-title board-notice-header">
<ul class="board-notice-tab board-notice-tabs">
<li>
<button type="button" class="board-notice-tab__btn is-active" data-notice-tab="all">
전체
</button>
</li>
<li>
<button type="button" class="board-notice-tab__btn" data-notice-tab="notice">공지</button>
</li>
<li>
<button type="button" class="board-notice-tab__btn" data-notice-tab="update">업데이트</button>
</li>
</ul>
<div id="panel_link_noticeLink" class="more-view"></div>
<div id="panel_link_patchLink" class="more-view" style="display:none"></div>
<div id="panel_link_allLink" class="more-view" style="display:none"></div>
</div>
<ul class="board-list-newest content list-unstyled reform" id="panel_board_noticeUpdateAPI">
</ul>
</div>
</div>
<div class="col-xs-6">
<!-- 셀러팁 -->
<div class="main-section">
<div class="table-title board-notice-header">
<b class="board-notice-header__seller">셀러팁</b>
<div id="panel_link_sellerTipLink" class="more-view"></div>
 
 
</div>
<ul class="board-list-newest content list-unstyled reform" id="panel_board_sellerTipAPI">
</ul>
</div>
</div>
</div>
 
<!-- 관리자 메인 게시판 시작 -->
 
 
 
 
 
 
 
<!-- 더 좋아지는 고도몰 -->
<ul class="nav nav-tabs mgt35 display-none">
<li role="presentation" class="active">
 
Controller/Admin/Share/AdminPanelApiController.php+14-1
변경 전AdminPanelApiController.php
{
public const NOTICE_2DEPTH_CATEGORY_NO = ['36', '42']; // cos 게시판-게시판관리-소식-공지사항- 2차 카테고리 no 값(공통, 고도몰)
public const PATCH_2DEPTH_CATEGORY_NO = '39'; // cos 게시판-게시판관리-소식-업데이트- 2차 카테고리 no 값 (고도몰)
 
 
 
 
/**
* Cos Panel section Code
$indexBoardPanelKey = [
'noticeAPI',
'patchAPI',
 
'betterAPI',
];
 
$cosCategoryMap = [
'noticeAPI' => self::NOTICE_2DEPTH_CATEGORY_NO,
'patchAPI' => self::PATCH_2DEPTH_CATEGORY_NO,
 
 
 
 
 
 
];
 
foreach ($indexBoardPanelKey as $panelKey) {
if (array_key_exists($panelKey, $cosCategoryMap)) {
$setData = $cosApi->getBoardData($cosCategoryMap[$panelKey]);
 
} else {
$setData = $godoApi->getGodoServerData($panelKey);
}
private function addLinkPanels(GodoGongjiServerApi $godoApi)
{
$arrLink = [
 
'noticeLink',
'patchLink',
 
'betterLink',
'customerLink',
];
 
변경 후AdminPanelApiController.php
{
public const NOTICE_2DEPTH_CATEGORY_NO = ['36', '42']; // cos 게시판-게시판관리-소식-공지사항- 2차 카테고리 no 값(공통, 고도몰)
public const PATCH_2DEPTH_CATEGORY_NO = '39'; // cos 게시판-게시판관리-소식-업데이트- 2차 카테고리 no 값 (고도몰)
public const SELLERTIP_BOARD_CODE = 'COMMERCE_CLASS'; // cos 게시판-게시판관리-셀러팁 boardCode
public const SELLERTIP_CATEGORY_NO = '80'; // cos 게시판-게시판관리-셀러팁- 고도몰 카테고리 no 값
public const DEFAULT_BOARD_SIZE = 8; // cos 게시판 보드당 조회 개수
 
/**
* Cos Panel section Code
$indexBoardPanelKey = [
'noticeAPI',
'patchAPI',
'sellerTipAPI',
'betterAPI',
];
 
$cosCategoryMap = [
'noticeAPI' => self::NOTICE_2DEPTH_CATEGORY_NO,
'patchAPI' => self::PATCH_2DEPTH_CATEGORY_NO,
'sellerTipAPI' => self::SELLERTIP_CATEGORY_NO,
];
 
// cos boardCode override (default: COMMERCE_NEWS)
$cosBoardCodeMap = [
'sellerTipAPI' => self::SELLERTIP_BOARD_CODE,
];
 
foreach ($indexBoardPanelKey as $panelKey) {
if (array_key_exists($panelKey, $cosCategoryMap)) {
$boardCode = $cosBoardCodeMap[$panelKey] ?? 'COMMERCE_NEWS';
$setData = $cosApi->getBoardData($cosCategoryMap[$panelKey], self::DEFAULT_BOARD_SIZE, $boardCode);
} else {
$setData = $godoApi->getGodoServerData($panelKey);
}
private function addLinkPanels(GodoGongjiServerApi $godoApi)
{
$arrLink = [
'allLink',
'noticeLink',
'patchLink',
'sellerTipLink',
'betterLink',
'customerLink',
];
 
상품 리스트, 기획전, 플러스리뷰 페이지 보안 강화
Component/Goods/Goods.php+8-8
변경 전Goods.php
 
public function getDisplayEventThemeInfo($whereArray, $orderby='')
{
if(trim($orderby) !== ''){
 
 
$orderby = " ORDER BY " . $orderby;
 
 
}
$whereArray[] = "kind='event'";
$strWhere = gd_implode(" AND ", $whereArray);
 
if (isset($sortCode[$sort]) === true) {
return $sortCode[$sort];
} else {
// SQLi 취약점 개선사항 sort 파라미터 변조 방지
preg_match('/(if|ifnull|isnull|case when|nvl)|([=,]+)/', $sort, $matches);
if(gd_count($matches[0]) > 0) {
$sort = 'g.regDt asc';
}
return $sort;
}
 
 
 
}
 
/**
 
변경 후Goods.php
 
public function getDisplayEventThemeInfo($whereArray, $orderby='')
{
// 화이트리스트에 없는 값은 정렬 적용하지 않음 (SQL Injection 방지)
$allowedOrderBy = ['regDt desc', 'themeNm asc', 'displayEndDate asc'];
if (trim($orderby) !== '' && in_array($orderby, $allowedOrderBy, true)) {
$orderby = " ORDER BY " . $orderby;
} else {
$orderby = '';
}
$whereArray[] = "kind='event'";
$strWhere = gd_implode(" AND ", $whereArray);
 
if (isset($sortCode[$sort]) === true) {
return $sortCode[$sort];
 
 
 
 
 
 
 
}
 
// 화이트리스트에 없는 값은 기본 정렬로 강제 (SQL Injection 방지)
return 'g.regDt asc';
}
 
/**
 
Controller/Admin/Promotion/EventSaleConfigController.php+2-2
변경 전EventSaleConfigController.php
gd_isset($data['otherEventDisplayFl'], 'n');
gd_isset($data['otherEventBottomFirstFl'], 'n');
gd_isset($data['otherEventSortType'], 'auto');
gd_isset($data['otherEventSortTypeTa'], 'regdt desc');
gd_isset($data['otherEventSortTypeTb'], 'top');
$data['otherEventSortTypeTaList'] = [
'regdt desc' => '최근 등록순',
'themeNm asc' => '가나다순',
'displayEndDate asc' => '종료 임박순',
];
 
변경 후EventSaleConfigController.php
gd_isset($data['otherEventDisplayFl'], 'n');
gd_isset($data['otherEventBottomFirstFl'], 'n');
gd_isset($data['otherEventSortType'], 'auto');
gd_isset($data['otherEventSortTypeTa'], 'regDt desc');
gd_isset($data['otherEventSortTypeTb'], 'top');
$data['otherEventSortTypeTaList'] = [
'regDt desc' => '최근 등록순',
'themeNm asc' => '가나다순',
'displayEndDate asc' => '종료 임박순',
];
 
Payco ID 로그인 사용 시 회원가입 항목 설정의 부가정보가 정상적으로 표시되도록 개선되었어요.
Controller/Admin/Member/PaycoLoginConfigController.php+2-2
변경 전PaycoLoginConfigController.php
 
$policy['baseInfo_Y'] = ArrayUtils::renderAssocAndIndexImplode($policy['items']['baseInfo']['requireY']);
$policy['baseInfo_N'] = ArrayUtils::renderAssocAndIndexImplode($policy['items']['baseInfo']['requireN']);
$policy['supplementInfo_Y'] = ArrayUtils::renderAssocAndIndexImplode($policy['items']['supplementInfo_Y']['requireY']);
$policy['supplementInfo_N'] = ArrayUtils::renderAssocAndIndexImplode($policy['items']['supplementInfo_N']['requireN']);
$policy['additionInfo_Y'] = ArrayUtils::renderAssocAndIndexImplode($policy['items']['additionInfo']['requireY'], "name");
$policy['additionInfo_N'] = ArrayUtils::renderAssocAndIndexImplode($policy['items']['additionInfo']['requireN'], "name");
 
 
변경 후PaycoLoginConfigController.php
 
$policy['baseInfo_Y'] = ArrayUtils::renderAssocAndIndexImplode($policy['items']['baseInfo']['requireY']);
$policy['baseInfo_N'] = ArrayUtils::renderAssocAndIndexImplode($policy['items']['baseInfo']['requireN']);
$policy['supplementInfo_Y'] = ArrayUtils::renderAssocAndIndexImplode($policy['items']['supplementInfo']['requireY']);
$policy['supplementInfo_N'] = ArrayUtils::renderAssocAndIndexImplode($policy['items']['supplementInfo']['requireN']);
$policy['additionInfo_Y'] = ArrayUtils::renderAssocAndIndexImplode($policy['items']['additionInfo']['requireY'], "name");
$policy['additionInfo_N'] = ArrayUtils::renderAssocAndIndexImplode($policy['items']['additionInfo']['requireN'], "name");
 
 
상품 리스트 페이지 보안 강화
Controller/Front/Goods/GoodsListController.php+12-3
변경 전GoodsListController.php
use Framework\Debug\Exception\AlertBackException;
use Framework\Debug\Exception\AlertOnlyException;
use Framework\Debug\Exception\AlertRedirectException;
 
use Framework\Debug\Exception\Framework\Debug\Exception;
use Framework\Utility\ProducerUtils;
use Message;
* @version 1.0
* @since 1.0
* @copyright Copyright (c), Godosoft
* @throws Except
*/
public function index()
{
}
 
if (gd_isset($cateInfo['themeCd']) === null) {
throw new \Exception(__('상품의 테마 설정을 확인해주세요.'));
}
 
if ($cateInfo['recomDisplayFl'] == 'y' && $cateInfo['recomGoodsNo']) {
}
} catch (AlertRedirectException $e) {
throw $e;
 
 
 
 
 
} catch (\Exception $e) {
throw new AlertRedirectException($e->getMessage(),null,null,"/");
 
 
 
}
 
$this->setData('goodsCategoryList', gd_isset($goodsCategoryList));
 
변경 후GoodsListController.php
use Framework\Debug\Exception\AlertBackException;
use Framework\Debug\Exception\AlertOnlyException;
use Framework\Debug\Exception\AlertRedirectException;
use Framework\Debug\Exception\DatabaseException;
use Framework\Debug\Exception\Framework\Debug\Exception;
use Framework\Utility\ProducerUtils;
use Message;
* @version 1.0
* @since 1.0
* @copyright Copyright (c), Godosoft
* @throws AlertRedirectException
*/
public function index()
{
}
 
if (gd_isset($cateInfo['themeCd']) === null) {
throw new AlertRedirectException(__('상품의 테마 설정을 확인해주세요.'), null, null, "/");
}
 
if ($cateInfo['recomDisplayFl'] == 'y' && $cateInfo['recomGoodsNo']) {
}
} catch (AlertRedirectException $e) {
throw $e;
} catch (DatabaseException $e) {
\Logger::channel('goods')->warning(
sprintf('[%s:%d] %s', $e->getFile(), $e->getLine(), $e->getMessage())
);
throw new AlertRedirectException(__('잘못된 접근입니다.'), null, null, "/");
} catch (\Exception $e) {
\Logger::channel('goods')->warning(
sprintf('[%s:%d] %s', $e->getFile(), $e->getLine(), $e->getMessage())
);
throw new AlertRedirectException($e->getMessage(), null, null, "/");
}
 
$this->setData('goodsCategoryList', gd_isset($goodsCategoryList));
 
Controller/Mobile/Goods/GoodsListController.php+12-3
변경 전GoodsListController.php
 
use Framework\Debug\Exception\AlertBackException;
use Framework\Debug\Exception\AlertRedirectException;
 
use Framework\Debug\Exception\Framework\Debug\Exception;
use Message;
use Globals;
* @version 1.0
* @since 1.0
* @copyright Copyright (c), Godosoft
* @throws Except
*/
public function index()
{
}
 
if(gd_isset($cateInfo['themeCd']) ===null) {
throw new \Exception(__('상품의 테마 설정을 확인해주세요.'));
}
 
// 마일리지 정보
 
} catch (AlertRedirectException $e) {
throw $e;
 
 
 
 
 
} catch (\Exception $e) {
throw new AlertRedirectException($e->getMessage(),null,null,"/");
 
 
 
}
}
}
 
변경 후GoodsListController.php
 
use Framework\Debug\Exception\AlertBackException;
use Framework\Debug\Exception\AlertRedirectException;
use Framework\Debug\Exception\DatabaseException;
use Framework\Debug\Exception\Framework\Debug\Exception;
use Message;
use Globals;
* @version 1.0
* @since 1.0
* @copyright Copyright (c), Godosoft
* @throws AlertRedirectException
*/
public function index()
{
}
 
if(gd_isset($cateInfo['themeCd']) ===null) {
throw new AlertRedirectException(__('상품의 테마 설정을 확인해주세요.'), null, null, "/");
}
 
// 마일리지 정보
 
} catch (AlertRedirectException $e) {
throw $e;
} catch (DatabaseException $e) {
\Logger::channel('goods')->warning(
sprintf('[%s:%d] %s', $e->getFile(), $e->getLine(), $e->getMessage())
);
throw new AlertRedirectException(__('잘못된 접근입니다.'), null, null, "/");
} catch (\Exception $e) {
\Logger::channel('goods')->warning(
sprintf('[%s:%d] %s', $e->getFile(), $e->getLine(), $e->getMessage())
);
throw new AlertRedirectException($e->getMessage(), null, null, "/");
}
}
}
 
공통 헤더 스크롤 동작 안정화
Admin/scm/scm_regist.php+6-1
변경 전scm_regist.php
if (gd_isset($popupMode) == 'yes') {
?>
$(window).scroll(function () {
$('#content').css('padding-top','52px');
 
 
 
 
 
var height = $(document).scrollTop();
 
if (height >= 1) {
 
변경 후scm_regist.php
if (gd_isset($popupMode) == 'yes') {
?>
$(window).scroll(function () {
const isFixed = $('.scm-regist .page-header').hasClass('affix');
if (isFixed) {
$('#content').css('padding-top','52px');
} else {
$('#content').css('padding-top','');
}
var height = $(document).scrollTop();
 
if (height >= 1) {
 
CRM 반복그룹 이메일 발송이 개선되었어요.
Admin/member/mail_send.php+29-21
변경 전mail_send.php
window.open('../share/popup_add_member.php?sendMode=mail', 'member_search', 'width=1450, height=760, scrollbars=no');
});
 
// CRM 그룹 선택
$('#btnSearchCrm').click(function (e) {
// 팝업 창 열기
window.open("/member/crm_group_select.php", "popupWindow", "width=1150,height=745");
// 메시지 수신 이벤트 리스너 추가
window.addEventListener('message', function(event) {
let receivedData = event.data || {};
// crm_group_select(CRM aggregator)에서 전달받은 반복추출 그룹 여부를 발송 폼 전송용 y/n 으로 정규화
receivedData.isRepeat = receivedData.isRepeat ? 'y' : 'n';
let crmGroupCountTemplate = _.template($('#templateCrmGroupCount').html());
$('#crmGroupCount').html(crmGroupCountTemplate(receivedData));
 
let crmGroupItemTemplate = _.template($('#templateCrmGroupItem').html());
$('#crmGroupItem').html(crmGroupItemTemplate(receivedData));
 
// CRM 그룹 삭제 event 추가
$('.crm-group-delete').click(function (e) {
$("#member_groupLayer").remove();
let crmGroupCountTemplate = _.template($('#templateCrmGroupCount').html());
$('#crmGroupCount').html(crmGroupCountTemplate({memberCount: 0, optOutMemberCount: 0}));
});
});
 
 
 
 
 
 
 
});
 
//수신동의, 수신거절 에디터 생성
window.open("/member/crm_group_select.php", "popupWindow", "width=1150,height=745");
// 메시지 수신 이벤트 리스너 추가
window.addEventListener('message', function(event) {
let receivedData = event.data;
 
 
let crmGroupCountTemplate = _.template($('#templateCrmGroupCount').html());
$('#crmGroupCount').html(crmGroupCountTemplate(receivedData));
 
<div id="info_crm_group_<%= targetNo %>" class="btn-group btn-group-xs">
<input type="hidden" name="crmGroupNo" value="<%= targetNo %>">
<input type="hidden" name="crmGroupName" value="<%= name %>">
 
<span class="btn"><%= name %></span>
<button type="button" class="btn btn-icon-delete crm-group-delete" data-target="#info_crm_group_<%= targetNo %>">삭제</button>
</div>
 
변경 후mail_send.php
window.open('../share/popup_add_member.php?sendMode=mail', 'member_search', 'width=1450, height=760, scrollbars=no');
});
 
// CRM 그룹 선택 - 팝업으로부터 메시지 수신 (리스너는 한 번만 등록하여 중첩 방지)
window.addEventListener('message', function (event) {
let receivedData = event.data || {};
// CRM 그룹 선택 팝업(aggregator)이 보낸 메시지만 처리한다.
if (!receivedData.targetNo) {
return;
}
// crm_group_select(CRM aggregator)에서 전달받은 반복추출 그룹 여부를 발송 폼 전송용 y/n 으로 정규화
receivedData.isRepeat = receivedData.isRepeat ? 'y' : 'n';
 
 
 
let crmGroupCountTemplate = _.template($('#templateCrmGroupCount').html());
$('#crmGroupCount').html(crmGroupCountTemplate(receivedData));
 
let crmGroupItemTemplate = _.template($('#templateCrmGroupItem').html());
$('#crmGroupItem').html(crmGroupItemTemplate(receivedData));
});
 
// CRM 그룹 삭제 - 이벤트 위임으로 처리하여 중첩 바인딩 방지
$('#crmGroupItem').on('click', '.crm-group-delete', function (e) {
$("#member_groupLayer").remove();
let crmGroupCountTemplate = _.template($('#templateCrmGroupCount').html());
$('#crmGroupCount').html(crmGroupCountTemplate({memberCount: 0, optOutMemberCount: 0}));
});
 
// CRM 그룹 선택 - 팝업 열기만 담당
$('#btnSearchCrm').click(function (e) {
window.open("/member/crm_group_select.php", "popupWindow", "width=1150,height=745");
});
 
//수신동의, 수신거절 에디터 생성
window.open("/member/crm_group_select.php", "popupWindow", "width=1150,height=745");
// 메시지 수신 이벤트 리스너 추가
window.addEventListener('message', function(event) {
let receivedData = event.data || {};
// crm_group_select(CRM aggregator)에서 전달받은 반복추출 그룹 여부를 발송 폼 전송용 y/n 으로 정규화
receivedData.isRepeat = receivedData.isRepeat ? 'y' : 'n';
let crmGroupCountTemplate = _.template($('#templateCrmGroupCount').html());
$('#crmGroupCount').html(crmGroupCountTemplate(receivedData));
 
<div id="info_crm_group_<%= targetNo %>" class="btn-group btn-group-xs">
<input type="hidden" name="crmGroupNo" value="<%= targetNo %>">
<input type="hidden" name="crmGroupName" value="<%= name %>">
<input type="hidden" name="isRepeat" value="<%= isRepeat %>">
<span class="btn"><%= name %></span>
<button type="button" class="btn btn-icon-delete crm-group-delete" data-target="#info_crm_group_<%= targetNo %>">삭제</button>
</div>
 
Component/Mail/MailAdmin.php+3-1
변경 전MailAdmin.php
$sendType = $requestParams['sendType'];
$senderEmail = $requestParams['senderEmail'];
$selectTargetFl = $requestParams['selectTargetFl'];
 
 
 
$v = new Validator();
$v->init();
// CRM 그룹 멤버 조회
/** @var CrmGroupService $crmGroupService */
$crmGroupService = \App::getInstance(CrmGroupService::class);
$memberNos = $crmGroupService->getAllCrmGroupMemberNos($requestParams['crmGroupNo'], $menuCode, null, $emailAgreed);
 
// 수신거부 대상자 조회
/** @var MemberRepository $memberRepository */
 
변경 후MailAdmin.php
$sendType = $requestParams['sendType'];
$senderEmail = $requestParams['senderEmail'];
$selectTargetFl = $requestParams['selectTargetFl'];
// 반복추출 CRM 그룹 여부 (폼에서 y/n 으로 전달, 미존재 시 일반 그룹)
$isRepeat = ($requestParams['isRepeat'] ?? 'n') === 'y';
 
$v = new Validator();
$v->init();
// CRM 그룹 멤버 조회
/** @var CrmGroupService $crmGroupService */
$crmGroupService = \App::getInstance(CrmGroupService::class);
$memberNos = $crmGroupService->getAllCrmGroupMemberNos($requestParams['crmGroupNo'], $menuCode, null, $emailAgreed, $isRepeat);
 
// 수신거부 대상자 조회
/** @var MemberRepository $memberRepository */
 
사은품 지급 수량 최대값 확대 (127 → 10,000개)
Admin/goods/gift_present_register.php+7
변경 전gift_present_register.php
return false;
}
 
 
 
 
 
 
 
 
}
return true;
},'');
 
변경 후gift_present_register.php
return false;
}
 
// 사은품 지급 수량 검증
var giveCntVal = $.trim($('input[name="gift[giveCnt]['+i+']"]').val());
if (parseInt(giveCntVal) > 10000) {
$.validator.messages.optionCheck = '사은품 지급 수량은 최대 10,000개까지 입력하실 수 있습니다.';
return false;
}
 
}
return true;
},'');
 
주문 카운트 토픽 발행 안정성 강화
Component/Order/OrderNew.php+10-4
변경 전OrderNew.php
}
 
$kafka = new ProducerUtils();
$result = $kafka->send($kafka::TOPIC_PRODUCT_ORDER_COUNT, $kafka->makeData($arrOrderGoodsSno['mq'], 'p'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', $result);
 
 
 
 
unset($arrOrderGoodsSno['mq']);
 
}
 
$kafka = new ProducerUtils();
$result = $kafka->send($kafka::TOPIC_PRODUCT_ORDER_COUNT, $kafka->makeData($mqData, 'p'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', $result);
 
 
 
unset($mqData);
 
// 현재 상태 수정 처리
 
변경 후OrderNew.php
}
 
$kafka = new ProducerUtils();
// 주문카운트 대상이 있을 때만 발행 (없으면 null 메시지 방지)
if (!empty($arrOrderGoodsSno['mq'])) {
$result = $kafka->send($kafka::TOPIC_PRODUCT_ORDER_COUNT, $kafka->makeData($arrOrderGoodsSno['mq'], 'p'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', $result);
}
 
unset($arrOrderGoodsSno['mq']);
 
}
 
$kafka = new ProducerUtils();
// 주문카운트 대상이 있을 때만 발행 (없으면 null 메시지 방지)
if (!empty($mqData)) {
$result = $kafka->send($kafka::TOPIC_PRODUCT_ORDER_COUNT, $kafka->makeData($mqData, 'p'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', $result);
}
unset($mqData);
 
// 현재 상태 수정 처리
 
Component/Order/Order.php+10-4
변경 전Order.php
}
 
$kafka = new ProducerUtils();
$result = $kafka->send($kafka::TOPIC_PRODUCT_ORDER_COUNT, $kafka->makeData($arrOrderGoodsSno['mq'], 'p'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', $result);
 
 
 
unset($arrOrderGoodsSno['mq']);
 
$arrOrderGoodsSno['GoodsSno'] = $arrOrderGoodsSno['sno'];
}
 
$kafka = new ProducerUtils();
$result = $kafka->send($kafka::TOPIC_PRODUCT_ORDER_COUNT, $kafka->makeData($mqData, 'p'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', $result);
 
 
 
unset($mqData);
 
// 현재 상태 수정 처리
 
변경 후Order.php
}
 
$kafka = new ProducerUtils();
// 주문카운트 대상이 있을 때만 발행 (없으면 null 메시지 방지)
if (!empty($arrOrderGoodsSno['mq'])) {
$result = $kafka->send($kafka::TOPIC_PRODUCT_ORDER_COUNT, $kafka->makeData($arrOrderGoodsSno['mq'], 'p'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', $result);
}
unset($arrOrderGoodsSno['mq']);
 
$arrOrderGoodsSno['GoodsSno'] = $arrOrderGoodsSno['sno'];
}
 
$kafka = new ProducerUtils();
// 주문카운트 대상이 있을 때만 발행 (없으면 null 메시지 방지)
if (!empty($mqData)) {
$result = $kafka->send($kafka::TOPIC_PRODUCT_ORDER_COUNT, $kafka->makeData($mqData, 'p'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', $result);
}
unset($mqData);
 
// 현재 상태 수정 처리
 
SMS 발송 관련 로그 처리 최적화
Component/Sms/SmsAuto.php-2
변경 전SmsAuto.php
} catch (\Exception $e) {
$exceptionMessage = __METHOD__ . ', ' . $e->getFile() . '[' . $e->getLine() . '], ' . $e->getMessage();
$logger->warning($exceptionMessage);
\Logger::channel('exception')->info($exceptionMessage, $e->getTrace());
 
return false;
}
$logger->info(__METHOD__ . ' Send Sms Result', $result);
 
변경 후SmsAuto.php
} catch (\Exception $e) {
$exceptionMessage = __METHOD__ . ', ' . $e->getFile() . '[' . $e->getLine() . '], ' . $e->getMessage();
$logger->warning($exceptionMessage);
 
 
return false;
}
$logger->info(__METHOD__ . ' Send Sms Result', $result);
 
외부 저장소 게시판에서 파일 미첨부 시 글 등록 개선
Component/Board/BoardUtil.php+4-2
변경 전BoardUtil.php
static public function setFilename(&$uploadFileNm, &$saveFileNm)
{
$ext = '';
$maxStr = @floor((700 - gd_count(Request::files()->get('upfiles.tmp_name'))) / gd_count(Request::files()->get('upfiles.tmp_name')));
if (empty(Request::files()->get('upfiles.tmp_name')) === false) {
 
 
foreach ($uploadFileNm as $key=>$val) {
if (($val)) {
if (strlen($val) > $maxStr) {
 
변경 후BoardUtil.php
static public function setFilename(&$uploadFileNm, &$saveFileNm)
{
$ext = '';
$uploadTmpNames = Request::files()->get('upfiles.tmp_name');
if (!empty($uploadTmpNames)) {
$uploadCount = gd_count($uploadTmpNames);
$maxStr = floor((700 - $uploadCount) / $uploadCount);
foreach ($uploadFileNm as $key=>$val) {
if (($val)) {
if (strlen($val) > $maxStr) {
 
바로구매 후 로그인 과정의 구매 진행 안내 개선
Component/Member/PageAccess.php+7-3
변경 전PageAccess.php
$returnUrl = preg_match('~member/login.php~', $request->getReturnUrl()) == 1 ? '' : $request->getReturnUrl();
if ($request->getDirectoryUri() == 'order' && ($request->getFileUri() == 'order.php' || $request->getFileUri() == 'order_ps.php')) {
$moveUrl = $pathHome . 'member/login.php?guestOrder=1&returnUrl=' . urlencode($request->getReturnUrl($returnUrl));
if (stripos($request->getReferer(), 'goodsNo=') !== false) {
$orderReferer = explode('=', $request->getReferer());
$moveUrl .= '&goodsNo=' . $orderReferer[1];
 
 
 
 
}
} else {
$moveUrl = $pathHome . 'member/login.php?returnUrl=' . urlencode($request->getReturnUrl($returnUrl));
 
변경 후PageAccess.php
$returnUrl = preg_match('~member/login.php~', $request->getReturnUrl()) == 1 ? '' : $request->getReturnUrl();
if ($request->getDirectoryUri() == 'order' && ($request->getFileUri() == 'order.php' || $request->getFileUri() == 'order_ps.php')) {
$moveUrl = $pathHome . 'member/login.php?guestOrder=1&returnUrl=' . urlencode($request->getReturnUrl($returnUrl));
// Referer 의 goodsNo 안전 추출 - '=' 다중 포함 시 explode 인덱스 오파싱(goodsNo=1 손상) 방지
$refererQuery = parse_url($request->getReferer(), PHP_URL_QUERY);
if (!empty($refererQuery)) {
parse_str($refererQuery, $refererParams);
if (!empty($refererParams['goodsNo']) && is_string($refererParams['goodsNo'])) {
$moveUrl .= '&goodsNo=' . urlencode($refererParams['goodsNo']);
}
}
} else {
$moveUrl = $pathHome . 'member/login.php?returnUrl=' . urlencode($request->getReturnUrl($returnUrl));
 
처리 완료된 클레임의 상태값 보호 강화
Component/Order/OrderAdminNew.php+9
변경 전OrderAdminNew.php
return false;
}
 
 
 
 
 
 
 
 
 
 
$partCompleteData = [];
foreach ($arrData['statusCheck'] as $val) {
$bundleData = [];
 
변경 후OrderAdminNew.php
return false;
}
 
// [#6126] 관리자 수동 승인/거절 시, 이미 처리된 신청 건 재처리 차단 (stale 화면/동시성 대응)
// 자동 환불 등 자동 처리(autoProceess) 흐름은 자체 선행 조건을 따르므로 가드 대상에서 제외한다.
if ($autoProceess !== true) {
$processGuard = \App::getInstance(\Component\Order\UserHandleProcessGuard::class);
if ($processGuard->hasAlreadyProcessed($arrData['statusCheck'] ?? [])) {
throw new AlertBackException(__('이미 승인 또는 거절 처리가 된 신청 건입니다. 페이지 새로고침 후 확인해 주세요.'));
}
}
 
$partCompleteData = [];
foreach ($arrData['statusCheck'] as $val) {
$bundleData = [];
 
Component/Order/OrderAdmin.php+9
변경 전OrderAdmin.php
return false;
}
 
 
 
 
 
 
 
 
 
 
$partCompleteData = [];
foreach ($arrData['statusCheck'] as $val) {
$bundleData = [];
 
변경 후OrderAdmin.php
return false;
}
 
// [#6126] 관리자 수동 승인/거절 시, 이미 처리된 신청 건 재처리 차단 (stale 화면/동시성 대응)
// 자동 환불 등 자동 처리(autoProceess) 흐름은 자체 선행 조건을 따르므로 가드 대상에서 제외한다.
if ($autoProceess !== true) {
$processGuard = \App::getInstance(\Component\Order\UserHandleProcessGuard::class);
if ($processGuard->hasAlreadyProcessed($arrData['statusCheck'] ?? [])) {
throw new AlertBackException(__('이미 승인 또는 거절 처리가 된 신청 건입니다. 페이지 새로고침 후 확인해 주세요.'));
}
}
 
$partCompleteData = [];
foreach ($arrData['statusCheck'] as $val) {
$bundleData = [];
 
Component/Order/ReOrderCalculation.php+8
변경 전ReOrderCalculation.php
use Component\Cart\CartAdmin;
use Component\Delivery\OverseasDelivery;
use Exception;
 
use Framework\Utility\ArrayUtils;
use Framework\Utility\NumberUtils;
use Framework\Utility\StringUtils;
public function setUserSameExchangeOrderGoods($postData)
{
$claimStatus = 'e';
 
 
 
 
 
 
 
$order = App::load(\Component\Order\Order::class);
$returnOrderGoodsSno = $addOrderGoodsSnoArr = [];
$changeStatus = $this->setAddExchangeOrderGoodsStatus(0);
 
변경 후ReOrderCalculation.php
use Component\Cart\CartAdmin;
use Component\Delivery\OverseasDelivery;
use Exception;
use Framework\Debug\Exception\AlertBackException;
use Framework\Utility\ArrayUtils;
use Framework\Utility\NumberUtils;
use Framework\Utility\StringUtils;
public function setUserSameExchangeOrderGoods($postData)
{
$claimStatus = 'e';
 
// [#6126] 이미 승인/거절 처리된 신청 건 재처리 차단 (stale 화면/동시성 대응)
$processGuard = App::getInstance(\Component\Order\UserHandleProcessGuard::class);
if ($processGuard->hasAlreadyProcessed($postData['statusCheck'] ?? [])) {
throw new AlertBackException(__('이미 승인 또는 거절 처리가 된 신청 건입니다. 페이지 새로고침 후 확인해 주세요.'));
}
 
$order = App::load(\Component\Order\Order::class);
$returnOrderGoodsSno = $addOrderGoodsSnoArr = [];
$changeStatus = $this->setAddExchangeOrderGoodsStatus(0);
 
Component/Order/UserHandleProcessGuard.php+71
변경 전UserHandleProcessGuard.php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
변경 후UserHandleProcessGuard.php
<?php
/*
* Copyright (C) 2026 NHN COMMERCE. - All Rights Reserved
*
* Unauthorized copying or redistribution of this file in source and binary forms via any medium
* is strictly prohibited.
*/
 
namespace Bundle\Component\Order;
 
use Repository\Order\OrderUserHandleRepository;
 
/**
* 고객 클레임(교환/반품/환불) 신청 건의 승인/거절 처리 전 상태 검증 가드
*
* 이미 승인(userHandleFl='y') 또는 거절(userHandleFl='n') 처리된 신청 건에 대해
* 중복 승인/거절이 발생하지 않도록, 처리 직전 현재 상태를 재확인한다.
*
* 목록 화면 로드 이후 다른 관리자/자동환불 등으로 상태가 바뀐 stale 상황에서
* 승인/거절을 시도하면, 환불 완료 등 이미 종결된 건이 다시 신청 상태로 되돌아가
* 환불 재시도가 불가해지는 문제(고객센터 문의 인입)를 방지한다.
*
* @package Bundle\Component\Order
*/
class UserHandleProcessGuard
{
public function __construct(
private readonly OrderUserHandleRepository $orderUserHandleRepository
) {}
 
/**
* statusCheck 항목들 중 이미 승인/거절 처리된(userHandleFl != 'r') 클레임이 있는지 여부
*
* @param array $statusCheckList 체크박스 value 목록
* (orderNo||orderGoodsSno||userHandleSno||cnt||originCnt)
* @return bool 하나라도 이미 처리된 건이 있으면 true
*/
public function hasAlreadyProcessed(array $statusCheckList): bool
{
$userHandleSnoList = $this->extractUserHandleSnoList($statusCheckList);
if (empty($userHandleSnoList)) {
return false;
}
 
return $this->orderUserHandleRepository->existsAlreadyProcessed($userHandleSnoList);
}
 
/**
* statusCheck value 목록에서 클레임 신청 sno(es_orderUserHandle.sno) 목록을 추출한다.
*
* statusCheck value 포맷: orderNo || orderGoodsSno || userHandleSno || cnt || originCnt
* (INT_DIVISION 구분, layout_order_goods_list.php 의 checkBoxCd 생성 규칙과 동일)
*
* @param array $statusCheckList
* @return int[]
*/
public function extractUserHandleSnoList(array $statusCheckList): array
{
$snoList = [];
foreach ($statusCheckList as $statusCheckValue) {
// 포맷: orderNo || orderGoodsSno || userHandleSno || cnt || originCnt (index 2 = userHandleSno)
$columns = explode(INT_DIVISION, (string) $statusCheckValue);
if (empty($columns[2])) {
continue;
}
$snoList[] = (int) $columns[2];
}
 
return array_values(array_unique(array_filter($snoList)));
}
}
 
Controller/Admin/Order/LayerUserAcceptController.php+11
변경 전LayerUserAcceptController.php
*/
namespace Bundle\Controller\Admin\Order;
 
 
use Exception;
use Request;
 
try {
// POST 리퀘스트
$postValue = Request::post()->toArray();
 
 
 
 
 
 
 
 
 
 
$this->setData('data', $postValue);
 
// 타이틀 설정
 
변경 후LayerUserAcceptController.php
*/
namespace Bundle\Controller\Admin\Order;
 
use App;
use Exception;
use Request;
 
try {
// POST 리퀘스트
$postValue = Request::post()->toArray();
 
// [#6126] 이미 승인/거절 처리된 신청 건이 포함된 경우 모달을 띄우지 않고 알럿 처리
$processGuard = App::getInstance(\Component\Order\UserHandleProcessGuard::class);
if ($processGuard->hasAlreadyProcessed($postValue['statusCheck'] ?? [])) {
$this->json([
'code' => 0,
'message' => __('이미 승인 또는 거절 처리가 된 신청 건입니다.') . "\n" . __('페이지 새로고침 후 확인해 주세요.'),
]);
}
 
$this->setData('data', $postValue);
 
// 타이틀 설정
 
Controller/Admin/Order/LayerUserRejectController.php+11
변경 전LayerUserRejectController.php
*/
namespace Bundle\Controller\Admin\Order;
 
 
use Request;
use Exception;
 
try {
// POST 리퀘스트
$postValue = Request::post()->toArray();
 
 
 
 
 
 
 
 
 
 
$this->setData('data', $postValue);
 
// 타이틀 설정
 
변경 후LayerUserRejectController.php
*/
namespace Bundle\Controller\Admin\Order;
 
use App;
use Request;
use Exception;
 
try {
// POST 리퀘스트
$postValue = Request::post()->toArray();
 
// [#6126] 이미 승인/거절 처리된 신청 건이 포함된 경우 모달을 띄우지 않고 알럿 처리
$processGuard = App::getInstance(\Component\Order\UserHandleProcessGuard::class);
if ($processGuard->hasAlreadyProcessed($postValue['statusCheck'] ?? [])) {
$this->json([
'code' => 0,
'message' => __('이미 승인 또는 거절 처리가 된 신청 건입니다.') . "\n" . __('페이지 새로고침 후 확인해 주세요.'),
]);
}
 
$this->setData('data', $postValue);
 
// 타이틀 설정
 
Repository/Order/OrderUserHandleRepository.php+17
변경 전OrderUserHandleRepository.php
->get()
->toArray();
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
변경 후OrderUserHandleRepository.php
->get()
->toArray();
}
 
/**
* 주어진 클레임 신청 sno 목록 중 이미 승인/거절 처리된(userHandleFl != 'r') 건이 존재하는지 확인
*
* 승인/거절 처리 직전 현재 상태를 재확인하여, stale 화면(목록 로드 이후 다른 관리자/
* 자동환불 등으로 상태가 변경된 경우)에서의 중복 처리를 차단하기 위해 사용한다.
*
* @param int[] $userHandleSnoList es_orderUserHandle.sno 목록
* @return bool 하나라도 신청(미처리, 'r') 이 아닌 건이 있으면 true
*/
public function existsAlreadyProcessed(array $userHandleSnoList): bool
{
return OrderUserHandle::query()
->whereIn('sno', array_map('intval', $userHandleSnoList))
->where('userHandleFl', '!=', UserHandleFl::REQUEST->value)
->exists();
}
}
 
결제 취소 시 결제 진행 상태 안정적으로 정리
Component/Order/OrderAdminNew.php+16
변경 전OrderAdminNew.php
{
// 상품 데이타 존재여부 체크
if (empty($goodsData) === true) {
 
 
 
 
 
return;
}
 
*/
return true;
} else {
 
 
 
 
 
 
 
 
 
 
 
return false;
}
}
 
변경 후OrderAdminNew.php
{
// 상품 데이타 존재여부 체크
if (empty($goodsData) === true) {
// 주문상품 조회 실패로 상태변경이 누락되는 경우 추적을 위한 로그 (복제 지연된 secondary 조회 등)
\Logger::channel('order')->warning(
__METHOD__ . '[' . __LINE__ . '], goodsData EMPTY - status change skipped',
['orderNo' => $orderNo, 'statusMode' => $statusMode, 'changeStatus' => $changeStatus, 'isFront' => $isFront]
);
return;
}
 
*/
return true;
} else {
// 변경 가능한 주문상품이 없어 상태변경이 수행되지 않은 경우 추적을 위한 로그 (당시 상품 상태 스냅샷 포함)
\Logger::channel('order')->warning(
__METHOD__ . '[' . __LINE__ . '], changeCheck FALSE - status change skipped',
[
'orderNo' => $orderNo,
'statusMode' => $statusMode,
'changeStatus' => $changeStatus,
'isFront' => $isFront,
'goodsStatus' => array_column($goodsData, 'orderStatus', 'sno'),
]
);
return false;
}
}
 
Component/Order/OrderNew.php+6
변경 전OrderNew.php
unset($arrBind);
 
if (empty($getData) === true) {
 
 
 
 
 
 
return false;
}
 
 
변경 후OrderNew.php
unset($arrBind);
 
if (empty($getData) === true) {
// 차감 대상 주문상품이 조회되지 않아 재고차감이 수행되지 않은 경우 추적을 위한 로그
// (이미 차감된 경우 minusStockFl='y' 정상 케이스, 그 외 주문상품 조회 실패 케이스 구분용)
\Logger::channel('order')->warning(
__METHOD__ . '[' . __LINE__ . '], no order goods rows for stock cutback - skipped',
['orderNo' => $orderNo, 'arrGoodsSno' => $arrGoodsSno]
);
return false;
}
 
 
취소복원 시 재고 부족으로 복원이 보류되면 마일리지도 함께 보류되도록 개선
Component/Order/ReOrderCalculation.php+82
변경 전ReOrderCalculation.php
public function setOrderRestore($orderNo, $claimStatus)
{
$exceptMsg = [];
 
 
 
 
// Original 존재 확인
$count = $this->getOrderOriginalCount($orderNo, $claimStatus);
if ($count < 1) {
$exceptMsg[] = $stockResult['desc'][$getKey];
}
 
 
 
 
 
 
 
 
 
$giftFl = false; // 사은품
$cashFl = false; // 현금영수증
if ($claimStatus == 'c') {
return true;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* getSelectOrderGoodsAddData
* 상품 추가 데이터
 
변경 후ReOrderCalculation.php
public function setOrderRestore($orderNo, $claimStatus)
{
$exceptMsg = [];
 
// 실제 차감 전 복원 가능 여부 사전검증
$this->assertOrderRestoreAvailable($orderNo, $claimStatus);
 
// Original 존재 확인
$count = $this->getOrderOriginalCount($orderNo, $claimStatus);
if ($count < 1) {
$exceptMsg[] = $stockResult['desc'][$getKey];
}
 
// 재고 차감 실패(재고 부족 등) 시 마일리지/예치금 차감 이전에 중단한다.
// setMemberMileage 는 별도 커밋되어 이후 throw 로 롤백되지 않으므로, 반드시 차감 전에 throw 해야 한다.
if (!empty($exceptMsg)) {
$message = '<b>' . __('취소복원이 불가합니다. 복원 불가 사유를 확인해주세요.') . '</b><br /><br />'
. implode('<br />', $exceptMsg);
throw new Exception($message);
}
 
$giftFl = false; // 사은품
$cashFl = false; // 현금영수증
if ($claimStatus == 'c') {
return true;
}
 
/**
* 주문 취소 복원 사전검증 (READ-ONLY)
*
* setOrderRestore 는 예치금/마일리지 차감 시 Mileage::setMemberMileage 내부 트랜잭션이
* 외부 DB::transaction 과 중첩 커밋되어 롤백이 불가능하다. 그 결과 회원 보유분이 부족한 경우
* 일부만 반영된 상태 불일치가 발생할 수 있으므로, 실제 차감 전에 회원의 예치금/마일리지로
* 복원이 가능한지 먼저 확인하고 불가 시 throw
*
* @throws Exception 복원 불가 사유가 있을 경우
*/
private function assertOrderRestoreAvailable(string $orderNo, string $claimStatus): void
{
try {
$exceptMsg = $this->precheckRestoreAddPayment($orderNo, $claimStatus);
} catch (\Throwable $e) {
\Logger::channel('order')->warning('Order restore precheck failed', [
'orderNo' => $orderNo,
'claimStatus' => $claimStatus,
'error' => $e->getMessage()
]);
return;
}
 
if (empty($exceptMsg)) {
return;
}
 
$message = '<b>' . __('취소복원이 불가합니다. 복원 불가 사유를 확인해주세요.') . '</b><br /><br />'
. implode('<br />', $exceptMsg);
throw new Exception($message);
}
 
/**
* 예치금/마일리지 복원 가능 여부 사전검증. 원본과 현재 주문의 사용 차액을 회원 보유분으로 차감 가능한지 확인
*
* @return array 복원 불가 사유 메시지 배열 (정상 시 빈 배열)
*/
private function precheckRestoreAddPayment(string $orderNo, string $claimStatus): array
{
$original = $this->getOrderOriginalDepositMileageData($orderNo, $claimStatus);
$current = $this->getOrderDepositMileageData($orderNo);
 
// precheck 는 setOrderRestore 진입 직후(member 초기화 이전)에 호출되므로 직접 로드한다.
if (!is_object($this->member)) {
$this->member = \App::load('\\Component\\Member\\Member');
}
 
$memInfo = [];
if (is_array($original) && !empty($original['memNo'])) {
$memInfo = $this->member->getMemberInfo($original['memNo']);
}
 
$exceptMsg = [];
$checks = [
['field' => 'useDeposit', 'hold' => 'deposit', 'msg' => '고객이 보유한 예치금 부족'],
['field' => 'useMileage', 'hold' => 'mileage', 'msg' => '고객이 보유한 마일리지 부족'],
];
foreach ($checks as $check) {
$diff = gd_isset($current[$check['field']], 0) - gd_isset($original[$check['field']], 0);
if ($diff === 0) {
continue;
}
if (empty($memInfo) || (gd_isset($memInfo[$check['hold']], 0) - abs($diff) < 0)) {
$exceptMsg[] = $check['msg'];
}
}
 
return $exceptMsg;
}
 
/**
* getSelectOrderGoodsAddData
* 상품 추가 데이터
 
주문 다운로드 엑셀에 '배송번호' 항목 추가 및 '배송비코드' 명칭 변경
Component/Excel/ExcelForm.php+2
변경 전ExcelForm.php
'receiverAddressTotal' =>['name'=>__('수취인 전체주소'),'orderFl'=>'y'],
'orderMemo' =>['name'=>__('주문시 남기는 글'),'orderFl'=>'y'],
'orderDeliverySno' =>['name'=>__('배송번호'),'scmDisplayFl'=>'n'],
 
'goodsDeliveryCollectFl' =>['name'=>__('배송비 구분'),'scmDisplayFl'=>'n'],
'scmNo' =>['name'=>__('공급사코드'),'scmDisplayFl'=>'n'],
'scmNm' =>['name'=>__('공급사명'),'scmDisplayFl'=>'n'],
'orderMemo' =>['name'=>__('주문시 남기는 글'),'orderFl'=>'y'],
 
'orderDeliverySno' =>['name'=>__('배송번호'),'scmDisplayFl'=>'n'],
 
'goodsDeliveryCollectFl' =>['name'=>__('배송비 구분'),'scmDisplayFl'=>'n'],
'scmNo' =>['name'=>__('공급사코드'),'scmDisplayFl'=>'n'],
'scmNm' =>['name'=>__('공급사명'),'scmDisplayFl'=>'n'],
 
변경 후ExcelForm.php
'receiverAddressTotal' =>['name'=>__('수취인 전체주소'),'orderFl'=>'y'],
'orderMemo' =>['name'=>__('주문시 남기는 글'),'orderFl'=>'y'],
'orderDeliverySno' =>['name'=>__('배송번호'),'scmDisplayFl'=>'n'],
'deliverySno' =>['name'=>__('배송비코드'),'scmDisplayFl'=>'n'],
'goodsDeliveryCollectFl' =>['name'=>__('배송비 구분'),'scmDisplayFl'=>'n'],
'scmNo' =>['name'=>__('공급사코드'),'scmDisplayFl'=>'n'],
'scmNm' =>['name'=>__('공급사명'),'scmDisplayFl'=>'n'],
'orderMemo' =>['name'=>__('주문시 남기는 글'),'orderFl'=>'y'],
 
'orderDeliverySno' =>['name'=>__('배송번호'),'scmDisplayFl'=>'n'],
'deliverySno' =>['name'=>__('배송비코드'),'scmDisplayFl'=>'n'],
'goodsDeliveryCollectFl' =>['name'=>__('배송비 구분'),'scmDisplayFl'=>'n'],
'scmNo' =>['name'=>__('공급사코드'),'scmDisplayFl'=>'n'],
'scmNm' =>['name'=>__('공급사명'),'scmDisplayFl'=>'n'],
 
Component/Excel/ExcelRequest.php+6
변경 전ExcelRequest.php
$tmpData[] = gd_implode('', $excelAddField);
break;
case 'orderDeliverySno':
 
 
 
$tmpData[] = "<td>" . $val['deliverySno'] . "</td>";
break;
case 'goodsType':
$tmpData[] = gd_implode('', $excelAddField);
break;
case 'orderDeliverySno':
 
 
 
$tmpData[] = "<td>" . $val['deliverySno'] . "</td>";
break;
case 'goodsType':
 
변경 후ExcelRequest.php
$tmpData[] = gd_implode('', $excelAddField);
break;
case 'orderDeliverySno':
$tmpData[] = "<td>" . $val['orderDeliverySno'] . "</td>";
break;
case 'deliverySno':
$tmpData[] = "<td>" . $val['deliverySno'] . "</td>";
break;
case 'goodsType':
$tmpData[] = gd_implode('', $excelAddField);
break;
case 'orderDeliverySno':
$tmpData[] = "<td>" . $val['orderDeliverySno'] . "</td>";
break;
case 'deliverySno':
$tmpData[] = "<td>" . $val['deliverySno'] . "</td>";
break;
case 'goodsType':
 
Component/Order/OrderAdminGrid.php+1-1
변경 전OrderAdminGrid.php
'brandNm' => '브랜드',
'goodsModelNo' => '모델명',
'makerNm' => '제조사',
'deliverySno' => '배송번호',
'scmNm' => '공급사',
'commission' => '수수료율',
'costPrice' => '매입가',
 
변경 후OrderAdminGrid.php
'brandNm' => '브랜드',
'goodsModelNo' => '모델명',
'makerNm' => '제조사',
'deliverySno' => '배송비코드',
'scmNm' => '공급사',
'commission' => '수수료율',
'costPrice' => '매입가',