본문으로 건너뛰기

소스 변경 전체 보기

PHP 8 · GODO25
변경 파일 수: 129개
변경 파일 목록
총 129개
주문 적용 쿠폰 회원 다운로드 발급 방식 추가
coupon_list.phpAdmin/promotion/coupon_manage.phpAdmin/promotion/coupon_regist.phpAdmin/promotion/CouponAdmin.phpComponent/Coupon/CouponDAO.phpComponent/Coupon/Coupon.phpComponent/Coupon/Goods.phpComponent/Goods/NaverDbUrl3.phpComponent/Worker/CouponListController.phpController/Admin/Promotion/CouponManageController.phpController/Admin/Promotion/CouponPsController.phpController/Admin/Promotion/CouponRegistController.phpController/Admin/Promotion/CouponzoneController.phpController/Front/Event/LayerCouponDownController.phpController/Front/Goods/LayerCouponPsController.phpController/Front/Goods/CouponPsController.phpController/Front/Mypage/LayerCouponApplyOrderController.phpController/Front/Order/LayerCouponDownController.phpController/Mobile/Goods/LayerCouponPsController.phpController/Mobile/Goods/CouponPsController.phpController/Mobile/Mypage/LayerCouponApplyOrderController.phpController/Mobile/Order/coupon.cssdata/skin/front/moment/css/event/couponzone.htmldata/skin/front/moment/event/layer_coupon_down.htmldata/skin/front/moment/goods/coupon.cssdata/skin/front/mygreek/css/event/couponzone.htmldata/skin/front/mygreek/event/layer_coupon_down.htmldata/skin/front/mygreek/goods/gd_contents.cssdata/skin/front/story_g/css/couponzone.htmldata/skin/front/story_g/event/layer_coupon_down.htmldata/skin/front/story_g/goods/coupon.cssdata/skin/mobile/moment/css/event/event.cssdata/skin/mobile/moment/css/event/couponzone.htmldata/skin/mobile/moment/event/layer_coupon_down.htmldata/skin/mobile/moment/goods/coupon.cssdata/skin/mobile/mygreek/css/event/couponzone.htmldata/skin/mobile/mygreek/event/layer_coupon_down.htmldata/skin/mobile/mygreek/goods/gd_contents.cssdata/skin/mobile/story_g/css/couponzone.htmldata/skin/mobile/story_g/event/layer_coupon_down.htmldata/skin/mobile/story_g/goods/icon-check-black.pngdata/skin/mobile/story_g/img/icon/
카카오 회원 가입 팝업 처리 개선
PageAccess.phpComponent/Member/
최신 iOS Safari 환경 네이버페이(주문형) 이동 안정성 개선
NaverPayController.phpController/Front/Goods/
예치금·마일리지 포함 주문 환불 처리 안정성 개선
refund_do_new.phpAdmin/order/ReOrderCalculation.phpComponent/Order/
배송지 수정 기능 보안 강화
inc_order_view.phpAdmin/order/layout_order_goods_list.phpAdmin/order/layout_order_goods_simple_list.phpAdmin/order/layout_order_list.phpAdmin/order/logistics_layout_order_goods_list.phpAdmin/order/popup_order_packet.phpAdmin/order/ReplaceCode.phpComponent/Design/OrderNew.phpComponent/Order/Order.phpComponent/Order/LayerReceiverInfoController.phpController/Admin/Order/OrderViewController.phpController/Admin/Order/LayerShippingAddressController.phpController/Admin/Share/OrderViewController.phpController/Front/Mypage/ShippingController.phpController/Front/Mypage/LayerShippingAddressController.phpController/Front/Order/LayerShippingAddressRegistController.phpController/Front/Order/OrderEndController.phpController/Front/Order/LayerShippingAddressRegistController.phpController/Mobile/Mypage/OrderViewController.phpController/Mobile/Mypage/ShippingController.phpController/Mobile/Mypage/OrderController.phpController/Mobile/Order/OrderEndController.phpController/Mobile/Order/OrderPsController.phpController/Mobile/Order/order.htmldata/skin/mobile/moment/order/order.htmldata/skin/mobile/mygreek/order/order.htmldata/skin/mobile/story_g/order/
네이버 판매지수 집계 정확도 개선
NaverDbUrl.phpComponent/Worker/
상품 수정시 정가/매입가/판매가 입력 안정성 개선
GoodsAdmin.phpComponent/Goods/GoodsBenefit.phpComponent/Goods/
상품 엑셀 업로드 시 단위가격 반영 개선
ExcelGoodsConvert.phpComponent/Excel/
엑셀 다운로드 시 자체상품코드 텍스트 서식 적용
ExcelDataConvert.phpComponent/Excel/ExcelRequest.phpComponent/Excel/ExcelSample.phpComponent/Excel/
보안서버 HTTPS 리다이렉트 처리 개선
SiteLink.phpComponent/SiteLink/
변경 파일 코드
추가삭제
주문 적용 쿠폰 회원 다운로드 발급 방식 추가
Admin/promotion/coupon_list.php+2-1
변경 전coupon_list.php
 
<form id="frmCouponList" action="../promotion/coupon_ps.php" method="post">
<input type="hidden" name="mode" value="deleteCouponList"/>
 
<table class="table table-rows promotion-coupon-list">
<thead>
<tr>
method: "POST",
cache: false,
url: "../promotion/coupon_ps.php",
data: "mode=modifyCouponList&couponNo=" + couponNo + "&couponType=" + couponType,
dataType: 'json'
}).success(function (data) {
BootstrapDialog.alert({
 
변경 후coupon_list.php
 
<form id="frmCouponList" action="../promotion/coupon_ps.php" method="post">
<input type="hidden" name="mode" value="deleteCouponList"/>
<input type="hidden" name="couponListToken" value="<?= $couponListToken ?>"/>
<table class="table table-rows promotion-coupon-list">
<thead>
<tr>
method: "POST",
cache: false,
url: "../promotion/coupon_ps.php",
data: "mode=modifyCouponList&couponNo=" + couponNo + "&couponType=" + couponType + "&couponListToken=" + $('input[name=couponListToken]').val(),
dataType: 'json'
}).success(function (data) {
BootstrapDialog.alert({
 
Admin/promotion/coupon_manage.php+3-2
변경 전coupon_manage.php
<tbody>
<tr>
<th>쿠폰명</th>
<td><?= $getData['couponNm']; ?></td>
</tr>
<tr>
<th>쿠폰설명</th>
<td><?= $getData['couponDescribed']; ?></td>
</tr>
<tr>
<th>사용기간</th>
 
<form id="frmMemberCouponList" action="../promotion/coupon_ps.php" method="post">
<input type="hidden" name="mode" value="deleteCouponManage" />
 
<input type="hidden" name="couponNo" value="<?= $getData['couponNo']; ?>" />
<table class="table table-rows">
<colgroup>
 
변경 후coupon_manage.php
<tbody>
<tr>
<th>쿠폰명</th>
<td><?= gd_htmlspecialchars($getData['couponNm']); ?></td>
</tr>
<tr>
<th>쿠폰설명</th>
<td><?= gd_htmlspecialchars($getData['couponDescribed']); ?></td>
</tr>
<tr>
<th>사용기간</th>
 
<form id="frmMemberCouponList" action="../promotion/coupon_ps.php" method="post">
<input type="hidden" name="mode" value="deleteCouponManage" />
<input type="hidden" name="couponManageToken" value="<?= $couponManageToken ?>" />
<input type="hidden" name="couponNo" value="<?= $getData['couponNo']; ?>" />
<table class="table table-rows">
<colgroup>
 
Admin/promotion/coupon_regist.php+5-8
변경 전coupon_regist.php
<input type="hidden" name="ypage" value="<?= $ypage; ?>"/>
<input type="hidden" name="couponNo" value="<?= $couponData['couponNo']; ?>"/>
<input type="hidden" name="couponKind" value="<?= $couponData['couponKind']; ?>"/>
 
<input type="hidden" name="couponType" value="<?= $couponData['couponType']; ?>"/>
 
<div class="page-header js-affix">
쿠폰명
</th>
<td colspan="3">
<input type="text" name="couponNm" value="<?= $couponData['couponNm'] ?>" class="form-control width-xl" maxlength="30"/>
</td>
</tr>
<tr>
쿠폰설명
</th>
<td colspan="3">
<input type="text" name="couponDescribed" value="<?= $couponData['couponDescribed'] ?>" class="form-control width100p" maxlength="50"/>
</td>
</tr>
<tr class="tr_auto">
// 발급방식
$('input:radio[name="couponSaveType"]:eq(0)').prop("disabled", false);
$('input:radio[name="couponSaveType"]:eq(1)').prop("disabled", false);
$('input:radio[name="couponSaveType"]:eq(2)').prop("disabled", true);
if ($('input:radio[name="couponSaveType"]:checked').val() == 'down') {
$('input:radio[name="couponSaveType"]:eq(2)').prop("checked", false);
$('input:radio[name="couponSaveType"]:eq(0)').prop("checked", true);
}
$('#labelCouponSaveTypeManual').show();
$('#labelCouponSaveTypeAuto').show();
$('#labelCouponSaveTypeDown').hide();
// 혜택구분
$('input:radio[name="couponKindType"]:eq(0)').prop("disabled", false);
if ($('input:radio[name="couponKindType"]:checked').val() == 'delivery') {
 
변경 후coupon_regist.php
<input type="hidden" name="ypage" value="<?= $ypage; ?>"/>
<input type="hidden" name="couponNo" value="<?= $couponData['couponNo']; ?>"/>
<input type="hidden" name="couponKind" value="<?= $couponData['couponKind']; ?>"/>
<input type="hidden" name="couponRegistToken" value="<?= $couponRegistToken ?>"/>
<input type="hidden" name="couponType" value="<?= $couponData['couponType']; ?>"/>
 
<div class="page-header js-affix">
쿠폰명
</th>
<td colspan="3">
<input type="text" name="couponNm" value="<?= gd_htmlspecialchars($couponData['couponNm']) ?>" class="form-control width-xl" maxlength="30"/>
</td>
</tr>
<tr>
쿠폰설명
</th>
<td colspan="3">
<input type="text" name="couponDescribed" value="<?= gd_htmlspecialchars($couponData['couponDescribed']) ?>" class="form-control width100p" maxlength="50"/>
</td>
</tr>
<tr class="tr_auto">
// 발급방식
$('input:radio[name="couponSaveType"]:eq(0)').prop("disabled", false);
$('input:radio[name="couponSaveType"]:eq(1)').prop("disabled", false);
$('input:radio[name="couponSaveType"]:eq(2)').prop("disabled", false);
 
 
 
 
$('#labelCouponSaveTypeManual').show();
$('#labelCouponSaveTypeAuto').show();
$('#labelCouponSaveTypeDown').show();
// 혜택구분
$('input:radio[name="couponKindType"]:eq(0)').prop("disabled", false);
if ($('input:radio[name="couponKindType"]:checked').val() == 'delivery') {
 
Component/Coupon/CouponAdmin.php+154-121
변경 전CouponAdmin.php
use Component\Sms\SmsAdmin;
use Component\Sms\SmsAutoCode;
use Component\Validator\Validator;
 
use Framework\File\FileHandler;
use Framework\ObjectStorage\Service\ImageUploadService;
use Framework\Utility\ArrayUtils;
use Framework\Utility\ProducerUtils;
 
use Globals;
use Origin\Enum\ApiClient\Notification\SmsPersonalInfoAccessLogEventType;
use Origin\Service\WebHook\PromotionWebHookService;
*/
public function getCouponAdminList($mode = null, $addSaveTypeWhere = '')
{
$getValue = Request::get()->toArray();
$this->setCouponAdminSearch($getValue);
 
$sort['fieldName'] = gd_isset($getValue['sort']['name']);
$sort['sortMode'] = gd_isset($getValue['sort']['mode']);
if (empty($sort['fieldName']) || empty($sort['sortMode'])) {
$sort['fieldName'] = 'c.regDt';
$sort['sortMode'] = 'desc';
} else {
$sort['fieldName'] = 'c' . $sort['fieldName'];
}
// 화이트리스트 검증 — SQL Injection 방지
if (!in_array($sort['fieldName'], self::ALLOWED_SORT_FIELDS_COUPON, true)) {
$sort['fieldName'] = 'c.regDt';
}
if (!in_array($sort['sortMode'], self::ALLOWED_SORT_MODES, true)) {
$sort['sortMode'] = 'desc';
}
 
 
// 레이어에서 자바스크립트 페이징 처리시 사용되는 구문
if (gd_isset($getValue['pagelink'])) {
$getValue['page'] = (int) str_replace('page=', '', preg_replace('/^{page=[0-9]+}/', '', gd_isset($getValue['pagelink'])));
}
gd_isset($getValue['page'], 1);
gd_isset($getValue['pageNum'], 10);
 
$page = \App::load('\\Component\\Page\\Page', $getValue['page']);
$page->page['list'] = $getValue['pageNum'];
 
if (!$mode) {
$mode = 'online';
}
 
if ($addSaveTypeWhere != '') {
$this->arrWhere[] = 'c.couponSaveType = ?';
$this->db->bind_param_push($this->arrBind, $this->fieldTypes['coupon']['couponSaveType'], $addSaveTypeWhere);
$addSaveTypeWhere = " AND couponSaveType = '".$addSaveTypeWhere."'";
}
 
if ($mode == 'all') {
$this->arrWhere[] = '1';
$amountSql = 'SELECT count(couponNo) FROM ' . DB_COUPON . ' WHERE 1' . $addSaveTypeWhere;
} else {
$this->arrWhere[] = 'c.couponKind = ?';
$this->db->bind_param_push($this->arrBind, $this->fieldTypes['coupon']['couponKind'], $mode);
$amountSql = 'SELECT count(couponNo) FROM ' . DB_COUPON . ' WHERE couponKind = "' . $mode . '"' . $addSaveTypeWhere;
}
list($page->recode['amount']) = $this->db->fetch($amountSql, 'row');
$page->setPage();
$page->setUrl(\Request::getQueryString());
 
 
 
 
 
 
 
 
 
 
$this->db->strField = "c.*";
$this->db->strWhere = gd_implode(' AND ', gd_isset($this->arrWhere));
$this->db->strOrder = $sort['fieldName'] . ' ' . $sort['sortMode'];
if($getValue['couponUseLayer'] != 'attendance_detail') { // 출석체크 쿠폰 혜택지급 레이어에서는 전체 쿠폰리스트 필요하여 limit 삭제
$this->db->strLimit = $page->recode['start'] . ',' . $getValue['pageNum'];
}
// 검색 카운트
$strSQL = ' SELECT COUNT(c.couponNo) AS cnt FROM ' . DB_COUPON .' as c ' . ' WHERE ' . $this->db->strWhere;
$res = $this->db->query_fetch($strSQL, $this->arrBind, false);
$page->recode['total'] = $res['cnt']; // 검색 레코드 수
$page->setPage();
$page->setUrl(\Request::getQueryString());
 
$query = $this->db->query_complete();
$strSQL = 'SELECT ' . array_shift($query) . ',m.isDelete FROM ' . DB_COUPON . ' as c LEFT OUTER JOIN ' . DB_MANAGER . " as m ON c.managerNo = m.sno" . gd_implode(' ', $query);
// \Logger::debug($strSQL, $this->arrBind);
$data = $this->db->query_fetch($strSQL, $this->arrBind);
Manager::displayListData($data);
 
$getData['data'] = gd_htmlspecialchars_stripslashes(gd_isset($data));
 
 
$getData['sort'] = $sort;
$getData['search'] = gd_htmlspecialchars($this->search);
$getData['checked'] = $this->checked;
 
return $getData;
 
 
 
 
}
 
/**
*/
public function getMemberCouponAdminList()
{
$getValue = Request::get()->toArray();
$this->setMemberCouponAdminSearch($getValue);
 
$sort['fieldName'] = gd_isset($getValue['sort']['name']);
$sort['sortMode'] = gd_isset($getValue['sort']['mode']);
if (empty($sort['fieldName']) || empty($sort['sortMode'])) {
$sort['fieldName'] = 'mc.regDt';
$sort['sortMode'] = 'desc';
} else {
$sort['fieldName'] = 'mc.' . $sort['fieldName'];
}
// 화이트리스트 검증 — SQL Injection 방지
if (!in_array($sort['fieldName'], self::ALLOWED_SORT_FIELDS_MEMBER_COUPON, true)) {
$sort['fieldName'] = 'mc.regDt';
}
if (!in_array($sort['sortMode'], self::ALLOWED_SORT_MODES, true)) {
$sort['sortMode'] = 'desc';
}
 
 
gd_isset($getValue['page'], 1);
gd_isset($getValue['pageNum'], 10);
 
$page = \App::load('\\Component\\Page\\Page', $getValue['page']);
$page->page['list'] = $getValue['pageNum'];
$arrBindTotal = [];
$this->db->bind_param_push($arrBindTotal, 'i', $getValue['couponNo']);
$total = $this->db->query_fetch('SELECT count(mc.memNo) as total FROM ' . DB_MEMBER_COUPON . ' as mc WHERE mc.couponNo = ?', $arrBindTotal, false);
$page->recode['amount'] = $total['total'];
$page->setPage();
$page->setUrl(\Request::getQueryString());
 
$this->db->strField = "mc.*, c.couponNm, c.couponDescribed, c.couponSaveType, ";
$this->db->strField .= " m.memId, m.memNm, m.groupSno, IF(ms.connectFl='y', ms.snsTypeFl, '') AS snsTypeFl";
$this->db->strWhere = gd_implode(' AND ', gd_isset($this->arrWhere));
$this->db->strJoin = 'LEFT JOIN ' . DB_MEMBER . ' as m ON m.memNo = mc.memNo ';
$this->db->strJoin .= 'LEFT JOIN ' . DB_MEMBER_SNS . ' as ms ON mc.memNo = ms.memNo ';
$this->db->strJoin .= ' LEFT JOIN ' . DB_COUPON . ' as c ON c.couponNo = mc.couponNo';
$this->db->strOrder = $sort['fieldName'] . ' ' . $sort['sortMode'];
$this->db->strLimit = $page->recode['start'] . ',' . $getValue['pageNum'];
 
// 검색 카운트
$strSQL = ' SELECT COUNT(mc.memNo) AS cnt FROM ' . DB_MEMBER_COUPON .' as mc ' . $this->db->strJoin . ' WHERE ' . $this->db->strWhere;
$res = $this->db->query_fetch($strSQL, $this->arrBind, false);
$page->recode['total'] = $res['cnt']; // 검색 레코드 수
$page->setPage();
$page->setUrl(\Request::getQueryString());
 
$query = $this->db->query_complete();
$strSQL = 'SELECT ' . array_shift($query) . ' FROM ' . DB_MEMBER_COUPON . ' as mc ' . gd_implode(' ', $query);
$data = $this->db->query_fetch($strSQL, $this->arrBind);
 
$getData['data'] = gd_htmlspecialchars_stripslashes(gd_isset($data));
$getData['sort'] = $sort;
$getData['search'] = gd_htmlspecialchars($this->search);
$getData['checked'] = $this->checked;
return $getData;
 
 
 
 
}
 
/**
// 발급방식에 따른 체크
// 회원다운로드 일 경우
if ($arrData['couponSaveType'] == 'down') {
if ($arrData['couponUseType'] == 'order' || $arrData['couponUseType'] == 'delivery') { // 쿠폰유형–상품쿠폰(‘product’),주문쿠폰(‘order’),배송비쿠폰('delivery')
throw new \Exception(__('회원다운로드 발급은 상품 쿠폰만 생성할 수 있습니다.'));
}
$validator->add('couponDisplayType', 'yn', true); // 상세노출기간종류–즉시(‘n’),예약(‘y’)
if ($arrData['couponDisplayType'] == 'y') {
}
}
 
 
$validator->add('couponNm', null, true); // 쿠폰명
// $validator->add('couponNm', 'maxlen', true, null, 30); // 쿠폰명 최대 30자
$validator->add('couponDescribed', '', null); // 쿠폰설명
}
 
// 발급 가능 회원등급 선택
$arrData['couponApplyMemberGroupDisplayType'] = 'n';
$validator->add('couponApplyMemberGroupDisplayType', null, null); // 발급/사용 가능한 회원등급에게만 쿠폰노출
 
 
 
if ($arrData['couponSaveType'] == 'manual') { // 발급방식이 '수동발급' 경우
$arrData['couponApplyMemberGroup'] = '';
$validator->add('couponApplyMemberGroup', null, null); // 선택된 회원등급
// 키워드 검색
if ($this->search['key'] && $this->search['keyword']) {
if(empty($getValue['couponUseType']) === true) { // 출석체크 상세보기 레이어에서는 쿠폰검색이 아닌 회원검색이므로 해당 where절 포함안함
 
 
 
 
if ($this->search['key'] == 'all') {
$tmpWhere = ['couponNm', 'couponDescribed', 'couponInsertAdminId'];
$arrWhereAll = [];
}
// 키워드 검색
if ($this->search['key'] && $this->search['keyword']) {
 
 
 
 
if ($this->search['key'] == 'all') {
$tmpWhere = ['memId', 'memNm'];
$arrWhereAll = [];
 
변경 후CouponAdmin.php
use Component\Sms\SmsAdmin;
use Component\Sms\SmsAutoCode;
use Component\Validator\Validator;
use Framework\Debug\Exception\DatabaseException;
use Framework\File\FileHandler;
use Framework\ObjectStorage\Service\ImageUploadService;
use Framework\Utility\ArrayUtils;
use Framework\Utility\ProducerUtils;
use Framework\Utility\StringUtils;
use Globals;
use Origin\Enum\ApiClient\Notification\SmsPersonalInfoAccessLogEventType;
use Origin\Service\WebHook\PromotionWebHookService;
*/
public function getCouponAdminList($mode = null, $addSaveTypeWhere = '')
{
try {
$getValue = Request::get()->toArray();
$this->setCouponAdminSearch($getValue);
 
$sort['fieldName'] = gd_isset($getValue['sort']['name']);
$sort['sortMode'] = gd_isset($getValue['sort']['mode']);
if (empty($sort['fieldName']) || empty($sort['sortMode'])) {
$sort['fieldName'] = 'c.regDt';
$sort['sortMode'] = 'desc';
} else {
$sort['fieldName'] = 'c' . $sort['fieldName'];
}
// 화이트리스트 검증 — SQL Injection 방지
if (!in_array($sort['fieldName'], self::ALLOWED_SORT_FIELDS_COUPON, true)) {
$sort['fieldName'] = 'c.regDt';
}
if (!in_array($sort['sortMode'], self::ALLOWED_SORT_MODES, true)) {
$sort['sortMode'] = 'desc';
}
 
// 레이어에서 자바스크립트 페이징 처리시 사용되는 구문
if (gd_isset($getValue['pagelink'])) {
$getValue['page'] = (int) str_replace('page=', '', preg_replace('/^{page=[0-9]+}/', '', gd_isset($getValue['pagelink'])));
}
gd_isset($getValue['page'], 1);
gd_isset($getValue['pageNum'], 10);
 
$page = \App::load('\\Component\\Page\\Page', $getValue['page']);
$page->page['list'] = $getValue['pageNum'];
 
if (!$mode) {
$mode = 'online';
}
 
$hasSaveTypeWhere = ($addSaveTypeWhere != '');
if ($hasSaveTypeWhere) {
$this->arrWhere[] = 'c.couponSaveType = ?';
$this->db->bind_param_push($this->arrBind, $this->fieldTypes['coupon']['couponSaveType'], $addSaveTypeWhere);
}
 
// 페이징 총계 쿼리 — SQL Injection 방지: 문자열 보간 대신 바인딩 재사용(SEC-POL-001, Dooray 1308)
$amountBind = [];
if ($mode == 'all') {
$this->arrWhere[] = '1';
$amountWhereParts = ['1'];
} else {
$this->arrWhere[] = 'c.couponKind = ?';
$this->db->bind_param_push($this->arrBind, $this->fieldTypes['coupon']['couponKind'], $mode);
$amountWhereParts = ['couponKind = ?'];
$this->db->bind_param_push($amountBind, $this->fieldTypes['coupon']['couponKind'], $mode);
}
if ($hasSaveTypeWhere) {
$amountWhereParts[] = 'couponSaveType = ?';
$this->db->bind_param_push($amountBind, $this->fieldTypes['coupon']['couponSaveType'], $addSaveTypeWhere);
}
$amountSql = 'SELECT count(couponNo) as cnt FROM ' . DB_COUPON . ' WHERE ' . implode(' AND ', $amountWhereParts);
$amountRow = $this->db->query_fetch($amountSql, $amountBind, false);
$page->recode['amount'] = $amountRow['cnt'];
$page->setPage();
$page->setUrl(\Request::getQueryString());
 
$this->db->strField = "c.*";
$this->db->strWhere = gd_implode(' AND ', gd_isset($this->arrWhere));
$this->db->strOrder = $sort['fieldName'] . ' ' . $sort['sortMode'];
if($getValue['couponUseLayer'] != 'attendance_detail') { // 출석체크 쿠폰 혜택지급 레이어에서는 전체 쿠폰리스트 필요하여 limit 삭제
$this->db->strLimit = $page->recode['start'] . ',' . $getValue['pageNum'];
}
// 검색 카운트
$strSQL = ' SELECT COUNT(c.couponNo) AS cnt FROM ' . DB_COUPON .' as c ' . ' WHERE ' . $this->db->strWhere;
$res = $this->db->query_fetch($strSQL, $this->arrBind, false);
$page->recode['total'] = $res['cnt']; // 검색 레코드 수
$page->setPage();
$page->setUrl(\Request::getQueryString());
 
$query = $this->db->query_complete();
$strSQL = 'SELECT ' . array_shift($query) . ',m.isDelete FROM ' . DB_COUPON . ' as c LEFT OUTER JOIN ' . DB_MANAGER . " as m ON c.managerNo = m.sno" . gd_implode(' ', $query);
// \Logger::debug($strSQL, $this->arrBind);
$data = $this->db->query_fetch($strSQL, $this->arrBind);
Manager::displayListData($data);
 
$getData['data'] = gd_htmlspecialchars(gd_isset($data));
 
 
$getData['sort'] = $sort;
$getData['search'] = gd_htmlspecialchars($this->search);
$getData['checked'] = $this->checked;
 
return $getData;
} catch (DatabaseException $e) {
\App::getInstance('logger')->channel('coupon')->error('쿠폰 목록 조회 실패', ['exception' => $e]);
throw new \Exception(__('쿠폰 목록 조회에 실패하였습니다.'));
}
}
 
/**
*/
public function getMemberCouponAdminList()
{
try {
$getValue = Request::get()->toArray();
$this->setMemberCouponAdminSearch($getValue);
 
$sort['fieldName'] = gd_isset($getValue['sort']['name']);
$sort['sortMode'] = gd_isset($getValue['sort']['mode']);
if (empty($sort['fieldName']) || empty($sort['sortMode'])) {
$sort['fieldName'] = 'mc.regDt';
$sort['sortMode'] = 'desc';
} else {
$sort['fieldName'] = 'mc.' . $sort['fieldName'];
}
// 화이트리스트 검증 — SQL Injection 방지
if (!in_array($sort['fieldName'], self::ALLOWED_SORT_FIELDS_MEMBER_COUPON, true)) {
$sort['fieldName'] = 'mc.regDt';
}
if (!in_array($sort['sortMode'], self::ALLOWED_SORT_MODES, true)) {
$sort['sortMode'] = 'desc';
}
 
gd_isset($getValue['page'], 1);
gd_isset($getValue['pageNum'], 10);
 
$page = \App::load('\\Component\\Page\\Page', $getValue['page']);
$page->page['list'] = $getValue['pageNum'];
$arrBindTotal = [];
$this->db->bind_param_push($arrBindTotal, 'i', $getValue['couponNo']);
$total = $this->db->query_fetch('SELECT count(mc.memNo) as total FROM ' . DB_MEMBER_COUPON . ' as mc WHERE mc.couponNo = ?', $arrBindTotal, false);
$page->recode['amount'] = $total['total'];
$page->setPage();
$page->setUrl(\Request::getQueryString());
 
$this->db->strField = "mc.*, c.couponNm, c.couponDescribed, c.couponSaveType, ";
$this->db->strField .= " m.memId, m.memNm, m.groupSno, IF(ms.connectFl='y', ms.snsTypeFl, '') AS snsTypeFl";
$this->db->strWhere = gd_implode(' AND ', gd_isset($this->arrWhere));
$this->db->strJoin = 'LEFT JOIN ' . DB_MEMBER . ' as m ON m.memNo = mc.memNo ';
$this->db->strJoin .= 'LEFT JOIN ' . DB_MEMBER_SNS . ' as ms ON mc.memNo = ms.memNo ';
$this->db->strJoin .= ' LEFT JOIN ' . DB_COUPON . ' as c ON c.couponNo = mc.couponNo';
$this->db->strOrder = $sort['fieldName'] . ' ' . $sort['sortMode'];
$this->db->strLimit = $page->recode['start'] . ',' . $getValue['pageNum'];
 
// 검색 카운트
$strSQL = ' SELECT COUNT(mc.memNo) AS cnt FROM ' . DB_MEMBER_COUPON .' as mc ' . $this->db->strJoin . ' WHERE ' . $this->db->strWhere;
$res = $this->db->query_fetch($strSQL, $this->arrBind, false);
$page->recode['total'] = $res['cnt']; // 검색 레코드 수
$page->setPage();
$page->setUrl(\Request::getQueryString());
 
$query = $this->db->query_complete();
$strSQL = 'SELECT ' . array_shift($query) . ' FROM ' . DB_MEMBER_COUPON . ' as mc ' . gd_implode(' ', $query);
$data = $this->db->query_fetch($strSQL, $this->arrBind);
 
$getData['data'] = gd_htmlspecialchars(gd_isset($data));
$getData['sort'] = $sort;
$getData['search'] = gd_htmlspecialchars($this->search);
$getData['checked'] = $this->checked;
return $getData;
} catch (DatabaseException $e) {
\App::getInstance('logger')->channel('coupon')->error('쿠폰별 회원 목록 조회 실패', ['exception' => $e]);
throw new \Exception(__('쿠폰별 회원 목록 조회에 실패하였습니다.'));
}
}
 
/**
// 발급방식에 따른 체크
// 회원다운로드 일 경우
if ($arrData['couponSaveType'] == 'down') {
if ($arrData['couponUseType'] === 'delivery' || $arrData['couponUseType'] === 'gift') { // 쿠폰유형–상품쿠폰('product'),주문쿠폰('order'),배송비쿠폰('delivery'),기프트쿠폰('gift') → delivery·gift는 회원다운로드 불가
throw new \Exception(__('회원다운로드 발급은 상품·주문 쿠폰만 생성할 수 있습니다.'));
}
$validator->add('couponDisplayType', 'yn', true); // 상세노출기간종류–즉시(‘n’),예약(‘y’)
if ($arrData['couponDisplayType'] == 'y') {
}
}
 
$arrData['couponNm'] = StringUtils::xssClean($arrData['couponNm']);
$validator->add('couponNm', null, true); // 쿠폰명
// $validator->add('couponNm', 'maxlen', true, null, 30); // 쿠폰명 최대 30자
$validator->add('couponDescribed', '', null); // 쿠폰설명
}
 
// 발급 가능 회원등급 선택
// 회원다운로드는 다운로드 목록 노출에 사용하므로 전송값 유지함
if ($arrData['couponSaveType'] !== 'down') {
$arrData['couponApplyMemberGroupDisplayType'] = 'n';
$validator->add('couponApplyMemberGroupDisplayType', null, null); // 발급/사용 가능한 회원등급에게만 쿠폰노출
}
if ($arrData['couponSaveType'] == 'manual') { // 발급방식이 '수동발급' 경우
$arrData['couponApplyMemberGroup'] = '';
$validator->add('couponApplyMemberGroup', null, null); // 선택된 회원등급
// 키워드 검색
if ($this->search['key'] && $this->search['keyword']) {
if(empty($getValue['couponUseType']) === true) { // 출석체크 상세보기 레이어에서는 쿠폰검색이 아닌 회원검색이므로 해당 where절 포함안함
// 화이트리스트 검증 — SQL Injection 방지
if (!in_array($this->search['key'], array_keys($this->search['combineSearch']), true)) {
throw new \Exception(__('올바르지 않은 검색 조건입니다.'));
}
if ($this->search['key'] == 'all') {
$tmpWhere = ['couponNm', 'couponDescribed', 'couponInsertAdminId'];
$arrWhereAll = [];
}
// 키워드 검색
if ($this->search['key'] && $this->search['keyword']) {
// 화이트리스트 검증 — SQL Injection 방지
if (!in_array($this->search['key'], array_keys($this->search['combineSearch']), true)) {
throw new \Exception(__('올바르지 않은 검색 조건입니다.'));
}
if ($this->search['key'] == 'all') {
$tmpWhere = ['memId', 'memNm'];
$arrWhereAll = [];
 
Component/Coupon/CouponDAO.php+80
변경 전CouponDAO.php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
변경 후CouponDAO.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\Coupon;
 
use App;
use Component\Database\DBTableField;
use Framework\Database\DBTool;
use Exception;
 
class CouponDAO
{
/** @var DBTool $db */
protected $db;
protected $fieldTypes;
protected $logger;
 
public function __construct()
{
$this->db = App::load('DB');
$this->fieldTypes['coupon'] = DBTableField::getFieldTypes('tableCoupon');
$this->logger = App::getInstance('logger');
}
 
/**
* 설정수량 검증과 회원쿠폰 등록을 하나의 트랜잭션으로 처리
*
* @param array $arrData 회원쿠폰 등록 데이터
*
* @throws Exception
*/
public function insertMemberCoupon(array $arrData): void
{
$arrBind = [];
try {
$this->db->begin_tran();
if (!$this->updateCouponSaveCount($arrData['couponNo'])) {
throw new Exception();
}
$arrBind = $this->db->get_binding(DBTableField::tableMemberCoupon(), $arrData, 'insert', array_keys($arrData), ['memberCouponNo']);
$this->db->set_insert_db(DB_MEMBER_COUPON, $arrBind['param'], $arrBind['bind'], 'y');
$this->db->commit();
} catch (\Throwable $e) {
$this->db->rollback();
$this->logger->channel('coupon')->warning('회원쿠폰 발급 실패', ['couponNo' => $arrData['couponNo'], 'exception' => $e]);
throw new Exception('발급 조건이 맞지 않습니다.');
} finally {
unset($arrBind);
}
}
 
/**
* 조건부 UPDATE로 설정수량 초과 여부를 원자적으로 검증
*
* @param int $couponNo 쿠폰 고유 번호
*
* @return bool 설정수량 이내에서 발급 수 증가 성공 여부
*/
protected function updateCouponSaveCount($couponNo): bool
{
$arrBind = [];
$this->db->bind_param_push($arrBind, $this->fieldTypes['coupon']['couponNo'], $couponNo);
$affectedRows = $this->db->set_update_db(
DB_COUPON,
'couponSaveCount = couponSaveCount+1',
"couponNo = ? AND (couponAmountType != 'y' OR couponSaveCount < couponAmount)",
$arrBind,
false,
false
);
unset($arrBind);
 
return $affectedRows >= 1;
}
}
 
Component/Coupon/Coupon.php+371-179
변경 전Coupon.php
use Component\Storage\Storage;
use Component\Cart\CartAdmin;
use Framework\Object\SimpleStorage;
 
use Framework\Utility\ArrayUtils;
use Globals;
use Request;
{
const ERROR_VIEW = 'ERROR_VIEW';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
const ECT_ALREADY_GIVE = 'Coupon.ECT_ALREADY_GIVE';
const ECT_NOTMATCH_SERIAL = 'Coupon.ECT_NOTMATCH_SERIAL';
const ECT_WRONG_EXPIREDATE = 'Coupon.ECT_WRONG_EXPIREDATE';
protected $goodsCouponDownList;
protected $changeStatusAuto;
 
 
 
/**
* 생성자
*/
// 발급여부 쿠폰(발급중)
$arrWhere[] = 'c.couponType=?';
$this->db->bind_param_push($arrBind, $this->fieldTypes['coupon']['couponType'], 'y');
// 상품 쿠폰
$arrWhere[] = 'c.couponUseType=?';
$this->db->bind_param_push($arrBind, $this->fieldTypes['coupon']['couponUseType'], 'product');
 
 
// 회원다운로드 쿠폰
$arrWhere[] = 'c.couponSaveType=?';
$this->db->bind_param_push($arrBind, $this->fieldTypes['coupon']['couponSaveType'], 'down');
$couponListData[$key]['chkMemberCoupon'] = 'YES';
}
}
// 발급 제외 공급사
if ($val['couponExceptProviderType'] == 'y') {
$exceptProviderGroupArr = explode(INT_DIVISION, $val['couponExceptProvider']);
if (gd_array_search($goodsData['scmNo'], $exceptProviderGroupArr) !== false) {//공급사 존재
$removeKey[] = $key;
continue;
} else {//공급사 존재안함
$couponListData[$key]['chkMemberCoupon'] = 'YES';
}
}
// 발급 제외 카테고리
if ($val['couponExceptCategoryType'] == 'y') {
$exceptCategoryGroupArr = explode(INT_DIVISION, $val['couponExceptCategory']);
$matchCateData = 0;
foreach ($cateCdArr as $cateKey => $cateVal) {
if (gd_array_search($cateVal, $exceptCategoryGroupArr) !== false) {//카테고리 존재
$matchCateData++;
} else {//카테고리 존재안함
$couponListData[$key]['chkMemberCoupon'] = 'YES';
}
}
if ($matchCateData > 0) {// 상품의 적용된 카테고리와 쿠폰 허용 카테고리 존재
$removeKey[] = $key;
continue;
} else {// 상품의 적용된 카테고리와 쿠폰 허용 카테고리 존재안함
$couponListData[$key]['chkMemberCoupon'] = 'YES';
 
 
 
 
 
 
 
 
 
 
 
 
}
}
// 발급 제외 브랜드
if ($val['couponExceptBrandType'] == 'y') {
$exceptBrandGroupArr = explode(INT_DIVISION, $val['couponExceptBrand']);
if (gd_array_search($goodsData['brandCd'], $exceptBrandGroupArr) !== false) {//브랜드 존재
$removeKey[] = $key;
continue;
} else {//브랜드 존재안함
$couponListData[$key]['chkMemberCoupon'] = 'YES';
}
}
// 발급 제외 상품
if ($val['couponExceptGoodsType'] == 'y') {
$exceptGoodsGroupArr = explode(INT_DIVISION, $val['couponExceptGoods']);
if (gd_array_search($goodsNo, $exceptGoodsGroupArr) !== false) {//상품 존재
$removeKey[] = $key;
continue;
} else {//상품 존재안함
$couponListData[$key]['chkMemberCoupon'] = 'YES';
}
}
// 발급 허용 체크
if ($val['couponApplyProductType'] == 'all') {//전체 발급
 
} else if ($val['couponApplyProductType'] == 'provider') {//공급사 발급
$applyProviderGroupArr = explode(INT_DIVISION, $val['couponApplyProvider']);
if (gd_array_search($goodsData['scmNo'], $applyProviderGroupArr) !== false) {//공급사 존재
$couponListData[$key]['chkMemberCoupon'] = 'YES';
} else {//공급사 존재안함
$removeKey[] = $key;
continue;
}
} else if ($val['couponApplyProductType'] == 'category') {//카테고리 발급
$applyCategoryGroupArr = explode(INT_DIVISION, $val['couponApplyCategory']);
$matchCateData = 0;
foreach ($cateCdArr as $cateKey => $cateVal) {
if (gd_array_search($cateVal, $applyCategoryGroupArr) !== false) {//카테고리 존재
$matchCateData++;
} else {//카테고리 존재안함
$couponListData[$key]['chkMemberCoupon'] = 'YES';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
}
if ($matchCateData > 0) {// 상품의 적용된 카테고리와 쿠폰 허용 카테고리 존재
$couponListData[$key]['chkMemberCoupon'] = 'YES';
} else {// 상품의 적용된 카테고리와 쿠폰 허용 카테고리 존재안함
$removeKey[] = $key;
continue;
}
} else if ($val['couponApplyProductType'] == 'brand') {//브랜드 발급
$applyBrandGroupArr = explode(INT_DIVISION, $val['couponApplyBrand']);
if (gd_array_search($goodsData['brandCd'], $applyBrandGroupArr) !== false) {//브랜드 존재
$couponListData[$key]['chkMemberCoupon'] = 'YES';
} else {//브랜드 존재안함
$removeKey[] = $key;
continue;
}
} else if ($val['couponApplyProductType'] == 'goods') {//상품 발급
$applyGoodsGroupArr = explode(INT_DIVISION, $val['couponApplyGoods']);
if (gd_array_search($goodsNo, $applyGoodsGroupArr) !== false) {//상품 존재
$couponListData[$key]['chkMemberCoupon'] = 'YES';
} else {//상품 존재안함
$removeKey[] = $key;
continue;
}
}
if ($memNo) {
}
unset($removeKey);
 
 
 
 
 
 
 
return $couponListData;
}
 
}
}
// 쿠폰 사용 회원등급
$data = $this->db->query_fetch("SELECT couponUseMemberGroup FROM " . DB_COUPON_USE_MEMBER_GROUP . " WHERE couponNo = " . $couponData['couponNo'] . " ORDER BY couponUseMemberGroup");
 
 
if ($data) {
foreach ($data as $key => $val) {
$groupNm = GroupUtil::getGroupName('sno=' . $val['couponUseMemberGroup']);
}
} else {
// 쿠폰 사용 회원등급
$data = $this->db->query_fetch("SELECT couponUseMemberGroup FROM " . DB_COUPON_USE_MEMBER_GROUP . " WHERE couponNo = " . $couponVal['couponNo'] . " ORDER BY couponUseMemberGroup");
 
 
if ($data) {
unset($couponArrData[$couponKey]['couponApplyMemberGroup']);
foreach ($data as $key => $val) {
unset($this->arrBind);
unset($this->arrWhere);
 
$memberCouponData['data'] = gd_htmlspecialchars_stripslashes(gd_isset($data));
$memberCouponData['sort'] = $sort;
$memberCouponData['search'] = gd_htmlspecialchars($this->search);
$memberCouponData['selected'] = $this->selected;
unset($this->arrBind);
unset($this->arrWhere);
 
$memberCouponData['data'] = gd_htmlspecialchars_stripslashes(gd_isset($data));
 
return $memberCouponData;
}
} else if ($val['couponSaveType'] == 'manual') {
$convertCouponArrData[$key]['couponSaveType'] = '수동발급';
}
 
 
if ($val['couponUseType'] == 'product') {
$convertCouponArrData[$key]['couponUseType'] = '상품적용쿠폰';
} else if ($val['couponUseType'] == 'order') {
unset($arrBind);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 상품에 적용된 회원다운로드 쿠폰을 발급 받기
*
public function setGoodsCouponMemberSave($couponNo, $goodsNo, $memNo, $memGroupNo, $scmNo = null, $brandCd = null)
{
$checkCoupon = false;
 
$goodsMemberCouponArrData = $this->getGoodsCouponDownList($goodsNo, $memNo, $memGroupNo, null, null, $scmNo, $brandCd);
 
 
foreach ($goodsMemberCouponArrData as $val) {
 
if ($val['chkMemberCoupon'] == 'YES') {
$couponNoData[] = $val['couponNo'];
}
}
 
if (is_array($couponNo)) {
 
 
 
 
 
 
foreach ($couponNo as $val) {
$checkCoupon = gd_in_array($val, $couponNoData);
 
if ($checkCoupon == true) {
$arrData = [];
$arrData['couponNo'] = $val;
$arrData['couponSaveAdminId'] = $goodsNo . '의 상품쿠폰';
$arrData['memberCouponStartDate'] = $this->getMemberCouponStartDate($val);
$arrData['memberCouponEndDate'] = $this->getMemberCouponEndDate($val);
$arrData['memberCouponState'] = 'y';
$arrData['memNo'] = $memNo;
$arrBind = $this->db->get_binding(DBTableField::tableMemberCoupon(), $arrData, 'insert', gd_array_keys($arrData), ['memberCouponNo']);
$this->db->set_insert_db(DB_MEMBER_COUPON, $arrBind['param'], $arrBind['bind'], 'y');
$this->setCouponMemberSaveCount($val);
 
 
 
 
 
 
 
 
 
 
 
 
 
} else {
 
throw new \Exception('발급 조건이 맞지 않는 쿠폰이있습니다. 쿠폰다운창을 다시 열고 받아주세요.');
}
}
$checkCoupon = gd_in_array($couponNo, $couponNoData);
 
if ($checkCoupon == true) {
$arrData = [];
$arrData['couponNo'] = $couponNo;
$arrData['couponSaveAdminId'] = $goodsNo . '의 상품쿠폰';
$arrData['memberCouponStartDate'] = $this->getMemberCouponStartDate($couponNo);
$arrData['memberCouponEndDate'] = $this->getMemberCouponEndDate($couponNo);
$arrData['memberCouponState'] = 'y';
$arrData['memNo'] = Session::get('member.memNo');
$arrBind = $this->db->get_binding(DBTableField::tableMemberCoupon(), $arrData, 'insert', gd_array_keys($arrData), ['memberCouponNo']);
$this->db->set_insert_db(DB_MEMBER_COUPON, $arrBind['param'], $arrBind['bind'], 'y');
$this->setCouponMemberSaveCount($couponNo);
 
 
 
 
 
 
 
 
 
 
 
 
 
} else {
 
throw new \Exception('발급 조건이 맞지 않습니다.');
}
}
}
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 회원다운로드 쿠폰의 링크클릭으로 쿠폰 발급
*
*/
public function setCouponLinkDown($couponNo, $memNo, $memGroupNo)
{
$couponLinkDownData = $this->getCouponLinkDownUsable($couponNo, $memNo, $memGroupNo);
if ($couponLinkDownData) {
$arrData = [];
$arrData['couponNo'] = $couponNo;
$arrData['couponSaveAdminId'] = '회원다운로드쿠폰 링크 다운';
$arrData['memberCouponStartDate'] = $this->getMemberCouponStartDate($couponNo);
$arrData['memberCouponEndDate'] = $this->getMemberCouponEndDate($couponNo);
$arrData['memberCouponState'] = 'y';
$arrData['memNo'] = $memNo;
$arrBind = $this->db->get_binding(DBTableField::tableMemberCoupon(), $arrData, 'insert', gd_array_keys($arrData), ['memberCouponNo']);
$this->db->set_insert_db(DB_MEMBER_COUPON, $arrBind['param'], $arrBind['bind'], 'y');
 
unset($arrData);
unset($arrBind);
// 쿠폰 발급 카운트 증가
$this->setCouponMemberSaveCount($couponNo);
} else {
throw new \Exception($couponLinkDownData);
 
 
 
 
 
 
 
}
}
 
return gd_htmlspecialchars_stripslashes($getData);
}
 
 
 
 
 
 
 
 
 
 
 
/**
* 상품의 해당 쿠폰 리스트용 전체 쿠폰 리스트 추출
*
// 발급여부 쿠폰(발급중)
$arrWhere[] = 'c.couponType=?';
$this->db->bind_param_push($arrBind, $this->fieldTypes['coupon']['couponType'], 'y');
// 상품 쿠폰
$arrWhere[] = 'c.couponUseType=?';
$this->db->bind_param_push($arrBind, $this->fieldTypes['coupon']['couponUseType'], 'product');
 
 
 
// 회원다운로드 쿠폰
$arrWhere[] = 'c.couponSaveType=?';
$this->db->bind_param_push($arrBind, $this->fieldTypes['coupon']['couponSaveType'], 'down');
// 쿠폰 노출 기간
$arrWhere[] = ' ( couponDisplayType = \'n\' OR ( couponDisplayType = \'y\' AND couponDisplayStartDate < now() AND couponDisplayEndDate > now()) )';
// 쿠폰 사용 기간 만료 체크
$arrWhere[] = ' ((couponUsePeriodType = \'period\' and couponUsePeriodEndDate <> \'0000-00-00 00:00:00\' and couponUsePeriodEndDate > now()) OR (couponUsePeriodType = \'day\' and (couponUseDateLimit is not null or couponUseDateLimit = \'0000-00-00 00:00:00\' or couponUseDateLimit > now())))';
 
$this->db->strLimit = 20;
if($couponConfig['couponzoneSort'] != 'custom') $this->db->strOrder = $couponConfig['couponzoneSort'];
}
}
 
 
 
 
 
 
 
 
 
return $list;
}
/**
}
 
if (is_array($couponNo)) {
 
 
 
 
 
 
$success = 0;
foreach ($couponNo as $val) {
$couponLinkDownData = $this->getCouponLinkDownUsable($val, $memNo, $memGroupNo, true);
if ($couponLinkDownData) {
$arrData = [];
$arrData['couponNo'] = $val;
$arrData['couponSaveAdminId'] = '쿠폰존';
$arrData['memberCouponStartDate'] = $this->getMemberCouponStartDate($val);
$arrData['memberCouponEndDate'] = $this->getMemberCouponEndDate($val);
$arrData['memberCouponState'] = 'y';
$arrData['memNo'] = $memNo;
$arrBind = $this->db->get_binding(DBTableField::tableMemberCoupon(), $arrData, 'insert', gd_array_keys($arrData), ['memberCouponNo']);
$this->db->set_insert_db(DB_MEMBER_COUPON, $arrBind['param'], $arrBind['bind'], 'y');
 
if ($barcodeDisplayFl === 'y') {
//바코드 발급. - 2018.11.07 parkjs
$memCouponNo = $this->db->insert_id();
$barcodeResult = $barcodeCoupon->setCouponNo([$arrData['couponNo']])->setMemberCouponNo($memCouponNo)->couponBarcodeGenarator('give');
}
 
 
 
 
 
 
 
unset($arrData);
unset($arrBind);
// 쿠폰 발급 카운트 증가
$this->setCouponMemberSaveCount($val);
$success++;
 
 
 
}
}
$return['return'] = true;
$return['success'] = $success;
return $return;
} else {
$couponLinkDownData = $this->getCouponLinkDownUsable($couponNo, $memNo, $memGroupNo);
if ($couponLinkDownData) {
$arrData = [];
$arrData['couponNo'] = $couponNo;
$arrData['couponSaveAdminId'] = '쿠폰존';
$arrData['memberCouponStartDate'] = $this->getMemberCouponStartDate($couponNo);
$arrData['memberCouponEndDate'] = $this->getMemberCouponEndDate($couponNo);
$arrData['memberCouponState'] = 'y';
$arrData['memNo'] = $memNo;
$arrBind = $this->db->get_binding(DBTableField::tableMemberCoupon(), $arrData, 'insert', gd_array_keys($arrData), ['memberCouponNo']);
$this->db->set_insert_db(DB_MEMBER_COUPON, $arrBind['param'], $arrBind['bind'], 'y');
 
if ($barcodeDisplayFl === 'y') {
//바코드 발급. - 2018.11.07 parkjs
$memCouponNo = $this->db->insert_id();
$barcodeResult = $barcodeCoupon->setCouponNo([$arrData['couponNo']])->setMemberCouponNo($memCouponNo)->couponBarcodeGenarator('give');
}
 
 
 
 
 
 
unset($arrData);
unset($arrBind);
// 쿠폰 발급 카운트 증가
$this->setCouponMemberSaveCount($couponNo);
$return['return'] = true;
$return['success'] = 1;
return $return;
} else {
throw new \Exception($couponLinkDownData);
 
 
 
}
}
}
public function getCouponUseMemberGroup($couponNo)
{
if ($couponNo) {
$memberGroup = $this->db->query_fetch("SELECT couponUseMemberGroup FROM " . DB_COUPON_USE_MEMBER_GROUP . " WHERE couponNo = " . $couponNo);
 
 
if ($memberGroup) {
$resultMemberGroup = array();
foreach ($memberGroup as $val) {
 
변경 후Coupon.php
use Component\Storage\Storage;
use Component\Cart\CartAdmin;
use Framework\Object\SimpleStorage;
use Framework\SimpleCache\SimpleCache;
use Framework\Utility\ArrayUtils;
use Globals;
use Request;
{
const ERROR_VIEW = 'ERROR_VIEW';
 
/** 발급 잠금 키 접두사 */
const MEMBER_SAVE_LOCK_KEY_PREFIX = 'coupon_member_save_';
 
/** 반복 발급 카운트 키 접두사 */
const ISSUE_COUNT_CACHE_KEY_PREFIX = 'coupon_issue_count_';
 
/** 반복 발급 요청 수를 세는 기준 시간(초) */
const ISSUE_RATE_LIMIT_WINDOW_SECONDS = 60;
 
/** 기준 시간 안에 같은 회원·쿠폰으로 허용하는 최대 발급 요청 횟수 (초과 시 거부) */
const ISSUE_RATE_LIMIT_MAX_COUNT = 30;
 
/** [전체 다운받기]로 한 번에 요청할 수 있는 쿠폰 개수의 상한 */
const COUPON_DOWN_ALL_MAX = 300;
 
/** 한 번에 요청한 쿠폰 수가 상한을 넘었을 때의 안내 문구 */
const COUPON_DOWN_ALL_EXCEED_MESSAGE = '쿠폰 발급 개수가 초과되어 발급할 수 없습니다.';
 
const ECT_ALREADY_GIVE = 'Coupon.ECT_ALREADY_GIVE';
const ECT_NOTMATCH_SERIAL = 'Coupon.ECT_NOTMATCH_SERIAL';
const ECT_WRONG_EXPIREDATE = 'Coupon.ECT_WRONG_EXPIREDATE';
protected $goodsCouponDownList;
protected $changeStatusAuto;
 
protected array $couponUseTypes = ['product'];
 
/**
* 생성자
*/
// 발급여부 쿠폰(발급중)
$arrWhere[] = 'c.couponType=?';
$this->db->bind_param_push($arrBind, $this->fieldTypes['coupon']['couponType'], 'y');
$arrPlaceHolder = implode(',', array_fill(0, count($this->couponUseTypes), '?'));
$arrWhere[] = 'c.couponUseType IN (' . $arrPlaceHolder . ')';
foreach ($this->couponUseTypes as $couponUseType) {
$this->db->bind_param_push($arrBind, $this->fieldTypes['coupon']['couponUseType'], $couponUseType);
}
// 회원다운로드 쿠폰
$arrWhere[] = 'c.couponSaveType=?';
$this->db->bind_param_push($arrBind, $this->fieldTypes['coupon']['couponSaveType'], 'down');
$couponListData[$key]['chkMemberCoupon'] = 'YES';
}
}
if ($val['couponUseType'] !== 'order') { // 주문쿠폰은 상품 무관 — 상품범위 제외·허용 판정 비적용
// 발급 제외 공급사
if ($val['couponExceptProviderType'] == 'y') {
$exceptProviderGroupArr = explode(INT_DIVISION, $val['couponExceptProvider']);
if (gd_array_search($goodsData['scmNo'], $exceptProviderGroupArr) !== false) {//공급사 존재
$removeKey[] = $key;
continue;
} else {//공급사 존재안함
 
 
 
 
 
 
 
 
 
 
$couponListData[$key]['chkMemberCoupon'] = 'YES';
}
}
// 발급 제외 카테고리
if ($val['couponExceptCategoryType'] == 'y') {
$exceptCategoryGroupArr = explode(INT_DIVISION, $val['couponExceptCategory']);
$matchCateData = 0;
foreach ($cateCdArr as $cateKey => $cateVal) {
if (gd_array_search($cateVal, $exceptCategoryGroupArr) !== false) {//카테고리 존재
$matchCateData++;
} else {//카테고리 존재안함
$couponListData[$key]['chkMemberCoupon'] = 'YES';
}
}
if ($matchCateData > 0) {// 상품의 적용된 카테고리와 쿠폰 허용 카테고리 존재
$removeKey[] = $key;
continue;
} else {// 상품의 적용된 카테고리와 쿠폰 허용 카테고리 존재안함
$couponListData[$key]['chkMemberCoupon'] = 'YES';
}
}
// 발급 제외 브랜드
if ($val['couponExceptBrandType'] == 'y') {
$exceptBrandGroupArr = explode(INT_DIVISION, $val['couponExceptBrand']);
if (gd_array_search($goodsData['brandCd'], $exceptBrandGroupArr) !== false) {//브랜드 존재
$removeKey[] = $key;
continue;
} else {//브랜드 존재안함
$couponListData[$key]['chkMemberCoupon'] = 'YES';
}
}
// 발급 제외 상품
if ($val['couponExceptGoodsType'] == 'y') {
$exceptGoodsGroupArr = explode(INT_DIVISION, $val['couponExceptGoods']);
if (gd_array_search($goodsNo, $exceptGoodsGroupArr) !== false) {//상품 존재
$removeKey[] = $key;
continue;
} else {//상품 존재안함
$couponListData[$key]['chkMemberCoupon'] = 'YES';
}
}
// 발급 허용 체크
if ($val['couponApplyProductType'] == 'all') {//전체 발급
 
 
} else if ($val['couponApplyProductType'] == 'provider') {//공급사 발급
$applyProviderGroupArr = explode(INT_DIVISION, $val['couponApplyProvider']);
if (gd_array_search($goodsData['scmNo'], $applyProviderGroupArr) !== false) {//공급사 존재
 
 
 
 
 
 
 
 
 
 
 
 
$couponListData[$key]['chkMemberCoupon'] = 'YES';
} else {//공급사 존재안함
$removeKey[] = $key;
continue;
}
} else if ($val['couponApplyProductType'] == 'category') {//카테고리 발급
$applyCategoryGroupArr = explode(INT_DIVISION, $val['couponApplyCategory']);
$matchCateData = 0;
foreach ($cateCdArr as $cateKey => $cateVal) {
if (gd_array_search($cateVal, $applyCategoryGroupArr) !== false) {//카테고리 존재
$matchCateData++;
} else {//카테고리 존재안함
$couponListData[$key]['chkMemberCoupon'] = 'YES';
}
}
if ($matchCateData > 0) {// 상품의 적용된 카테고리와 쿠폰 허용 카테고리 존재
$couponListData[$key]['chkMemberCoupon'] = 'YES';
} else {// 상품의 적용된 카테고리와 쿠폰 허용 카테고리 존재안함
$removeKey[] = $key;
continue;
}
} else if ($val['couponApplyProductType'] == 'brand') {//브랜드 발급
$applyBrandGroupArr = explode(INT_DIVISION, $val['couponApplyBrand']);
if (gd_array_search($goodsData['brandCd'], $applyBrandGroupArr) !== false) {//브랜드 존재
$couponListData[$key]['chkMemberCoupon'] = 'YES';
} else {//브랜드 존재안함
$removeKey[] = $key;
continue;
}
} else if ($val['couponApplyProductType'] == 'goods') {//상품 발급
$applyGoodsGroupArr = explode(INT_DIVISION, $val['couponApplyGoods']);
if (gd_array_search($goodsNo, $applyGoodsGroupArr) !== false) {//상품 존재
$couponListData[$key]['chkMemberCoupon'] = 'YES';
} else {//상품 존재안함
$removeKey[] = $key;
continue;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
}
if ($memNo) {
}
unset($removeKey);
 
foreach ($couponListData as $key => $couponRow) {
if (isset($couponRow['couponNm'])) {
$couponListData[$key]['couponNm'] = gd_htmlspecialchars($couponRow['couponNm']);
}
}
 
return $couponListData;
}
 
}
}
// 쿠폰 사용 회원등급
$useMemberGroupBind = [];
$this->db->bind_param_push($useMemberGroupBind, 'i', $couponData['couponNo']);
$data = $this->db->query_fetch("SELECT couponUseMemberGroup FROM " . DB_COUPON_USE_MEMBER_GROUP . " WHERE couponNo = ? ORDER BY couponUseMemberGroup", $useMemberGroupBind);
if ($data) {
foreach ($data as $key => $val) {
$groupNm = GroupUtil::getGroupName('sno=' . $val['couponUseMemberGroup']);
}
} else {
// 쿠폰 사용 회원등급
$useMemberGroupBind = [];
$this->db->bind_param_push($useMemberGroupBind, 'i', $couponVal['couponNo']);
$data = $this->db->query_fetch("SELECT couponUseMemberGroup FROM " . DB_COUPON_USE_MEMBER_GROUP . " WHERE couponNo = ? ORDER BY couponUseMemberGroup", $useMemberGroupBind);
if ($data) {
unset($couponArrData[$couponKey]['couponApplyMemberGroup']);
foreach ($data as $key => $val) {
unset($this->arrBind);
unset($this->arrWhere);
 
$memberCouponData['data'] = gd_htmlspecialchars(gd_isset($data));
$memberCouponData['sort'] = $sort;
$memberCouponData['search'] = gd_htmlspecialchars($this->search);
$memberCouponData['selected'] = $this->selected;
unset($this->arrBind);
unset($this->arrWhere);
 
$memberCouponData['data'] = gd_htmlspecialchars(gd_isset($data));
 
return $memberCouponData;
}
} else if ($val['couponSaveType'] == 'manual') {
$convertCouponArrData[$key]['couponSaveType'] = '수동발급';
}
// 배지 유형 판별용 원값 보존(아래 한글 라벨 변환 전)
$convertCouponArrData[$key]['couponUseTypeCode'] = $val['couponUseType'];
if ($val['couponUseType'] == 'product') {
$convertCouponArrData[$key]['couponUseType'] = '상품적용쿠폰';
} else if ($val['couponUseType'] == 'order') {
unset($arrBind);
}
 
/**
* 회원 다운로드 발급 거부 감사로그 (실패 시도만 기록 / 성공 발급은 es_memberCoupon 적재)
*
* @param mixed $couponNo 쿠폰고유번호(단건 또는 배열)
* @param int $memNo 회원고유번호
* @param string $reason 거부 사유
*/
protected function logCouponDownFail($couponNo, $memNo, $reason)
{
\App::getInstance('logger')->channel('coupon')->warning('쿠폰 발급 실패', array_merge(
$this->couponDownLogContext($couponNo, $memNo),
['reason' => $reason]
));
}
 
/**
* 회원 다운로드 발급 성공 감사로그
*
* @param mixed $couponNo 쿠폰고유번호(단건 또는 배열)
* @param integer $memNo 회원고유번호
*/
protected function logCouponDownSuccess($couponNo, $memNo)
{
\App::getInstance('logger')->channel('coupon')->info('쿠폰 발급 성공', $this->couponDownLogContext($couponNo, $memNo));
}
 
/**
* 발급 감사로그 공통 컨텍스트(행위자·쿠폰번호·접속지 정보)
*
* @param mixed $couponNo
* @param integer $memNo
* @return array
*/
protected function couponDownLogContext($couponNo, $memNo)
{
$request = \App::getInstance('request');
return [
'couponNo' => $couponNo,
'memNo' => $memNo,
'ip' => $request->getRemoteAddress(),
'userAgent' => $request->getUserAgent(),
'uri' => $request->getRequestUri(),
];
}
 
/**
* 상품에 적용된 회원다운로드 쿠폰을 발급 받기
*
public function setGoodsCouponMemberSave($couponNo, $goodsNo, $memNo, $memGroupNo, $scmNo = null, $brandCd = null)
{
$checkCoupon = false;
$this->setCouponUseTypes(['product', 'order']);
$goodsMemberCouponArrData = $this->getGoodsCouponDownList($goodsNo, $memNo, $memGroupNo, null, null, $scmNo, $brandCd);
$this->setCouponUseTypes(['product']);
$couponUseTypeMap = [];
foreach ($goodsMemberCouponArrData as $val) {
$couponUseTypeMap[$val['couponNo']] = $val['couponUseType'];
if ($val['chkMemberCoupon'] == 'YES') {
$couponNoData[] = $val['couponNo'];
}
}
 
if (is_array($couponNo)) {
// 동일 쿠폰번호 중복 삽입을 1건으로 축약
$couponNo = array_values(array_unique($couponNo));
if (count($couponNo) > self::COUPON_DOWN_ALL_MAX) {
$this->logCouponDownFail($couponNo, $memNo, self::COUPON_DOWN_ALL_EXCEED_MESSAGE);
throw new \Exception(self::COUPON_DOWN_ALL_EXCEED_MESSAGE);
}
foreach ($couponNo as $val) {
$checkCoupon = gd_in_array($val, $couponNoData);
 
if ($checkCoupon == true) {
$redisKey = sprintf(self::MEMBER_SAVE_LOCK_KEY_PREFIX . '%s_%s', $val, $memNo);
try {
SimpleCache::init(SimpleCache::REDIS)->executeWithLock($redisKey, 'coupon', function () use ($val, $memNo, $memGroupNo, $goodsNo, $couponUseTypeMap) {
$this->checkRapidReissueRequest($val, $memNo);
// 중복 발급 방지 재확인
$this->getCouponLinkDownUsable($val, $memNo, $memGroupNo);
$arrData = [];
$arrData['couponNo'] = $val;
$couponUseType = $couponUseTypeMap[$val] ?? 'product';
$arrData['couponSaveAdminId'] = $goodsNo . ($couponUseType === 'order' ? '의 주문쿠폰' : '의 상품쿠폰');
$arrData['memberCouponStartDate'] = $this->getMemberCouponStartDate($val);
$arrData['memberCouponEndDate'] = $this->getMemberCouponEndDate($val);
$arrData['memberCouponState'] = 'y';
$arrData['memNo'] = $memNo;
$couponDao = \App::load('\\Component\\Coupon\\CouponDAO');
$couponDao->insertMemberCoupon($arrData);
$this->checkCouponType($arrData['couponNo']); // 발급 수 증가로 발급종료 상태로 변경 될 수 있어 실행
});
$this->logCouponDownSuccess($val, $memNo);
} catch (\Exception $e) {
$this->logCouponDownFail($val, $memNo, $e->getMessage());
throw $e;
}
} else {
$this->logCouponDownFail($val, $memNo, '발급 조건이 맞지 않는 쿠폰이있습니다. 쿠폰다운창을 다시 열고 받아주세요.');
throw new \Exception('발급 조건이 맞지 않는 쿠폰이있습니다. 쿠폰다운창을 다시 열고 받아주세요.');
}
}
$checkCoupon = gd_in_array($couponNo, $couponNoData);
 
if ($checkCoupon == true) {
$couponUseType = $couponUseTypeMap[$couponNo] ?? 'product';
$saveMemNo = Session::get('member.memNo');
$redisKey = sprintf(self::MEMBER_SAVE_LOCK_KEY_PREFIX . '%s_%s', $couponNo, $saveMemNo);
try {
SimpleCache::init(SimpleCache::REDIS)->executeWithLock($redisKey, 'coupon', function () use ($couponNo, $saveMemNo, $memGroupNo, $goodsNo, $couponUseType) {
$this->checkRapidReissueRequest($couponNo, $saveMemNo);
$this->getCouponLinkDownUsable($couponNo, $saveMemNo, $memGroupNo);
$arrData = [];
$arrData['couponNo'] = $couponNo;
$arrData['couponSaveAdminId'] = $goodsNo . ($couponUseType === 'order' ? '의 주문쿠폰' : '의 상품쿠폰');
$arrData['memberCouponStartDate'] = $this->getMemberCouponStartDate($couponNo);
$arrData['memberCouponEndDate'] = $this->getMemberCouponEndDate($couponNo);
$arrData['memberCouponState'] = 'y';
$arrData['memNo'] = $saveMemNo;
$couponDao = \App::load('\\Component\\Coupon\\CouponDAO');
$couponDao->insertMemberCoupon($arrData);
$this->checkCouponType($arrData['couponNo']); // 발급 수 증가로 발급종료 상태로 변경 될 수 있어 실행
});
$this->logCouponDownSuccess($couponNo, $saveMemNo);
} catch (\Exception $e) {
$this->logCouponDownFail($couponNo, $saveMemNo, $e->getMessage());
throw $e;
}
} else {
$this->logCouponDownFail($couponNo, $saveMemNo, '발급 조건이 맞지 않습니다.');
throw new \Exception('발급 조건이 맞지 않습니다.');
}
}
}
}
 
/**
* 같은 회원·쿠폰의 짧은 시간 내 반복 발급 요청 차단
*
* @param int $couponNo 쿠폰고유번호
* @param int $memNo 회원고유번호
*
* @throws \Exception 기준 시간 안에 허용 횟수를 초과한 반복 요청일 때
*/
protected function checkRapidReissueRequest($couponNo, $memNo)
{
$cache = SimpleCache::init(SimpleCache::REDIS);
$countKey = self::ISSUE_COUNT_CACHE_KEY_PREFIX . $couponNo . '_' . $memNo;
$count = (int) $cache->get($countKey, fn() => 0);
if ($count >= self::ISSUE_RATE_LIMIT_MAX_COUNT) {
throw new \Exception('잠시 후 다시 시도해주십시오.');
}
$cache->set($countKey, $count + 1, self::ISSUE_RATE_LIMIT_WINDOW_SECONDS);
}
 
/**
* 회원다운로드 쿠폰의 링크클릭으로 쿠폰 발급
*
*/
public function setCouponLinkDown($couponNo, $memNo, $memGroupNo)
{
$redisKey = sprintf(self::MEMBER_SAVE_LOCK_KEY_PREFIX . '%s_%s', $couponNo, $memNo);
try {
SimpleCache::init(SimpleCache::REDIS)->executeWithLock($redisKey, 'coupon', function () use ($couponNo, $memNo, $memGroupNo) {
$this->checkRapidReissueRequest($couponNo, $memNo);
$couponLinkDownData = $this->getCouponLinkDownUsable($couponNo, $memNo, $memGroupNo);
if ($couponLinkDownData) {
$arrData = [];
$arrData['couponNo'] = $couponNo;
$arrData['couponSaveAdminId'] = '회원다운로드쿠폰 링크 다운';
$arrData['memberCouponStartDate'] = $this->getMemberCouponStartDate($couponNo);
$arrData['memberCouponEndDate'] = $this->getMemberCouponEndDate($couponNo);
$arrData['memberCouponState'] = 'y';
$arrData['memNo'] = $memNo;
$couponDao = \App::load('\\Component\\Coupon\\CouponDAO');
$couponDao->insertMemberCoupon($arrData);
$this->checkCouponType($arrData['couponNo']); // 발급 수 증가로 발급종료 상태로 변경 될 수 있어 실행
unset($arrData);
} else {
throw new \Exception($couponLinkDownData ?: '발급 조건이 맞지 않습니다.');
}
});
$this->logCouponDownSuccess($couponNo, $memNo);
} catch (\Exception $e) {
$this->logCouponDownFail($couponNo, $memNo, $e->getMessage());
throw $e;
}
}
 
return gd_htmlspecialchars_stripslashes($getData);
}
 
/**
* 쿠폰 사용 유형 설정
*
* @param array $types 쿠폰 사용 유형 배열 (ex: ['product'], ['product', 'order'])
*/
public function setCouponUseTypes(array $types)
{
$this->couponUseTypes = $types;
}
 
/**
* 상품의 해당 쿠폰 리스트용 전체 쿠폰 리스트 추출
*
// 발급여부 쿠폰(발급중)
$arrWhere[] = 'c.couponType=?';
$this->db->bind_param_push($arrBind, $this->fieldTypes['coupon']['couponType'], 'y');
// 쿠폰 적용 대상 유형(product=상품, order=주문 등)
$arrPlaceHolder = implode(',', array_fill(0, count($this->couponUseTypes), '?'));
$arrWhere[] = 'c.couponUseType IN (' . $arrPlaceHolder . ')';
foreach ($this->couponUseTypes as $couponUseType) {
$this->db->bind_param_push($arrBind, $this->fieldTypes['coupon']['couponUseType'], $couponUseType);
}
// 회원다운로드 쿠폰
$arrWhere[] = 'c.couponSaveType=?';
$this->db->bind_param_push($arrBind, $this->fieldTypes['coupon']['couponSaveType'], 'down');
// 쿠폰 노출 기간
$arrWhere[] = ' ( couponDisplayType = \'n\' OR ( couponDisplayType = \'y\' AND couponDisplayStartDate < now() AND couponDisplayEndDate > now()) )';
// 쿠폰 사용 기간 만료 체크
$arrWhere[] = ' ((couponUsePeriodType = \'period\' and couponUsePeriodEndDate <> \'0000-00-00 00:00:00\' and couponUsePeriodEndDate > now()) OR (couponUsePeriodType = \'day\' and (couponUseDateLimit is null or couponUseDateLimit = \'0000-00-00 00:00:00\' or couponUseDateLimit > now())))';
 
$this->db->strLimit = 20;
if($couponConfig['couponzoneSort'] != 'custom') $this->db->strOrder = $couponConfig['couponzoneSort'];
}
}
 
foreach ($list as $key => $zoneData) {
foreach ($zoneData['list'] as $cKey => $couponRow) {
if (isset($couponRow['couponNm'])) {
$list[$key]['list'][$cKey]['couponNm'] = gd_htmlspecialchars($couponRow['couponNm']);
}
}
}
 
return $list;
}
/**
}
 
if (is_array($couponNo)) {
// 동일 쿠폰번호 중복 삽입을 1건으로 축약
$couponNo = array_values(array_unique($couponNo));
if (count($couponNo) > self::COUPON_DOWN_ALL_MAX) {
$this->logCouponDownFail($couponNo, $memNo, self::COUPON_DOWN_ALL_EXCEED_MESSAGE);
throw new \Exception(self::COUPON_DOWN_ALL_EXCEED_MESSAGE);
}
$success = 0;
foreach ($couponNo as $val) {
$redisKey = sprintf(self::MEMBER_SAVE_LOCK_KEY_PREFIX . '%s_%s', $val, $memNo);
// 실패 항목은 건너뜀
try {
SimpleCache::init(SimpleCache::REDIS)->executeWithLock($redisKey, 'coupon', function () use ($val, $memNo, $memGroupNo, $barcodeDisplayFl, &$barcodeCoupon, &$success) {
$this->checkRapidReissueRequest($val, $memNo);
$couponLinkDownData = $this->getCouponLinkDownUsable($val, $memNo, $memGroupNo, true);
if ($couponLinkDownData) {
$arrData = [];
$arrData['couponNo'] = $val;
$arrData['couponSaveAdminId'] = '쿠폰존';
$arrData['memberCouponStartDate'] = $this->getMemberCouponStartDate($val);
$arrData['memberCouponEndDate'] = $this->getMemberCouponEndDate($val);
$arrData['memberCouponState'] = 'y';
$arrData['memNo'] = $memNo;
$couponDao = \App::load('\\Component\\Coupon\\CouponDAO');
$couponDao->insertMemberCoupon($arrData);
$this->checkCouponType($arrData['couponNo']); // 발급 수 증가로 발급종료 상태로 변경 될 수 있어 실행
 
if ($barcodeDisplayFl === 'y') {
//바코드 발급
$memCouponNo = $this->db->insert_id();
$barcodeResult = $barcodeCoupon->setCouponNo([$arrData['couponNo']])->setMemberCouponNo($memCouponNo)->couponBarcodeGenarator('give');
}
 
unset($arrData);
$success++;
$this->logCouponDownSuccess($val, $memNo);
}
});
} catch (\Exception $e) {
$this->logCouponDownFail($val, $memNo, $e->getMessage());
continue;
}
}
$return['return'] = true;
$return['success'] = $success;
return $return;
} else {
$redisKey = sprintf(self::MEMBER_SAVE_LOCK_KEY_PREFIX . '%s_%s', $couponNo, $memNo);
try {
return SimpleCache::init(SimpleCache::REDIS)->executeWithLock($redisKey, 'coupon', function () use ($couponNo, $memNo, $memGroupNo, $barcodeDisplayFl, &$barcodeCoupon) {
$this->checkRapidReissueRequest($couponNo, $memNo);
$couponLinkDownData = $this->getCouponLinkDownUsable($couponNo, $memNo, $memGroupNo);
if ($couponLinkDownData) {
$arrData = [];
$arrData['couponNo'] = $couponNo;
$arrData['couponSaveAdminId'] = '쿠폰존';
$arrData['memberCouponStartDate'] = $this->getMemberCouponStartDate($couponNo);
$arrData['memberCouponEndDate'] = $this->getMemberCouponEndDate($couponNo);
$arrData['memberCouponState'] = 'y';
$arrData['memNo'] = $memNo;
$couponDao = \App::load('\\Component\\Coupon\\CouponDAO');
$couponDao->insertMemberCoupon($arrData);
$this->checkCouponType($arrData['couponNo']); // 발급 수 증가로 발급종료 상태로 변경 될 수 있어 실행
 
if ($barcodeDisplayFl === 'y') {
//바코드 발급
$memCouponNo = $this->db->insert_id();
$barcodeResult = $barcodeCoupon->setCouponNo([$arrData['couponNo']])->setMemberCouponNo($memCouponNo)->couponBarcodeGenarator('give');
}
 
unset($arrData);
$return['return'] = true;
$return['success'] = 1;
$this->logCouponDownSuccess($couponNo, $memNo);
return $return;
} else {
throw new \Exception($couponLinkDownData ?: '발급 조건이 맞지 않습니다.');
}
});
} catch (\Exception $e) {
$this->logCouponDownFail($couponNo, $memNo, $e->getMessage());
throw $e;
}
}
}
public function getCouponUseMemberGroup($couponNo)
{
if ($couponNo) {
$useMemberGroupBind = [];
$this->db->bind_param_push($useMemberGroupBind, 'i', $couponNo);
$memberGroup = $this->db->query_fetch("SELECT couponUseMemberGroup FROM " . DB_COUPON_USE_MEMBER_GROUP . " WHERE couponNo = ?", $useMemberGroupBind);
if ($memberGroup) {
$resultMemberGroup = array();
foreach ($memberGroup as $val) {
 
Component/Goods/Goods.php+12-1
변경 전Goods.php
// 쿠폰 할인 금액
if ($couponConfig['couponUseType'] == 'y' && $couponPriceYN && $getData['goodsPrice'] > 0 && empty($getData['goodsPriceString']) === true) {
// 해당 상품의 모든 쿠폰
 
 
 
 
$couponArrData = $this->coupon->getGoodsCouponDownList($getData['goodsNo'], Session::get('member.memNo'), Session::get('member.groupSno'), null, null, $getData['scmNo'], $getData['brandCd']);
 
 
 
 
// 상품의 해당 쿠폰 리스트 저장 (2022.06 상품리스트 및 상세 성능개선)
if (gd_count($couponArrData) > 0) {
$this->coupon->setGoodsCouponDownInfo($couponArrData);
}
 
 
 
 
 
// 해당 상품의 쿠폰가
$getData['couponDcPrice'] = $couponSalePrice = $this->coupon->getGoodsCouponDisplaySalePrice($couponArrData, $getData['goodsPrice']);
if ($couponSalePrice) {
$getData['couponPrice'] = $getData['goodsPrice'] - $couponSalePrice;
$getData['couponSalePrice'] = $couponSalePrice;
 
변경 후Goods.php
// 쿠폰 할인 금액
if ($couponConfig['couponUseType'] == 'y' && $couponPriceYN && $getData['goodsPrice'] > 0 && empty($getData['goodsPriceString']) === true) {
// 해당 상품의 모든 쿠폰
$supportsCouponUseTypeFilter = method_exists($this->coupon, 'setCouponUseTypes');
if ($supportsCouponUseTypeFilter) {
$this->coupon->setCouponUseTypes(['product', 'order']);
}
$couponArrData = $this->coupon->getGoodsCouponDownList($getData['goodsNo'], Session::get('member.memNo'), Session::get('member.groupSno'), null, null, $getData['scmNo'], $getData['brandCd']);
if ($supportsCouponUseTypeFilter) {
$this->coupon->setCouponUseTypes(['product']);
}
 
// 상품의 해당 쿠폰 리스트 저장 (2022.06 상품리스트 및 상세 성능개선)
if (gd_count($couponArrData) > 0) {
$this->coupon->setGoodsCouponDownInfo($couponArrData);
}
 
$goodsCouponArrData = array_filter($couponArrData ?: [], function ($downCoupon) {
return ($downCoupon['couponUseType'] ?? 'product') !== 'order';
});
 
// 해당 상품의 쿠폰가
$getData['couponDcPrice'] = $couponSalePrice = $this->coupon->getGoodsCouponDisplaySalePrice($goodsCouponArrData, $getData['goodsPrice']);
if ($couponSalePrice) {
$getData['couponPrice'] = $getData['goodsPrice'] - $couponSalePrice;
$getData['couponSalePrice'] = $couponSalePrice;
 
Component/Worker/NaverDbUrl3.php+28
변경 전NaverDbUrl3.php
/** @var null|\Bundle\Component\Goods\DefineGoods */
private $_defineGoods = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* init
*
 
변경 후NaverDbUrl3.php
/** @var null|\Bundle\Component\Goods\DefineGoods */
private $_defineGoods = null;
 
/**
* 사용가능한 네이버 EP 쿠폰 목록 조회
*
* 네이버 EP에서 사용 가능한 상품·주문 다운로드 쿠폰을 조회
* PC·모바일 각각의 쿠폰 목록을 별도 조회하여 저장
*
* @override
*/
protected function loadCoupon()
{
$where[] = "couponMinOrderPrice = 0 ";
$where[] = "couponAmountType = 'n' ";
$where[] = "(couponApplyMemberGroup = '' or couponApplyMemberGroup is null) ";
 
$canSetCouponUseTypes = method_exists($this->componentCoupon, 'setCouponUseTypes');
// 네이버 EP는 상품·주문 다운로드 쿠폰을 조회 대상에 포함
if ($canSetCouponUseTypes) {
$this->componentCoupon->setCouponUseTypes(['product', 'order']);
}
$this->couponForEpPcList = $this->componentCoupon->getGoodsCouponDownListAll($where, "pc");
$this->couponForEpMobileList = $this->componentCoupon->getGoodsCouponDownListAll($where, "mobile");
 
if ($canSetCouponUseTypes) {
$this->componentCoupon->setCouponUseTypes(['product']);
}
unset($where);
}
 
/**
* init
*
 
Controller/Admin/Promotion/CouponListController.php+2
변경 전CouponListController.php
 
use Exception;
use Framework\Debug\Exception\LayerException;
 
use Request;
 
class CouponListController extends \Controller\Admin\Controller
$this->setData('searchKindASelectBox', \Component\Member\Member::getSearchKindASelectBox());
$this->setData('checked', $getData['checked']);
$this->setData('page', $page);
 
}
}
 
변경 후CouponListController.php
 
use Exception;
use Framework\Debug\Exception\LayerException;
use Framework\Security\Token;
use Request;
 
class CouponListController extends \Controller\Admin\Controller
$this->setData('searchKindASelectBox', \Component\Member\Member::getSearchKindASelectBox());
$this->setData('checked', $getData['checked']);
$this->setData('page', $page);
$this->setData('couponListToken', Token::generate('couponListToken'));
}
}
 
Controller/Admin/Promotion/CouponManageController.php+2
변경 전CouponManageController.php
use Component\Database\DBTableField;
use Exception;
use Framework\Debug\Exception\LayerException;
 
use Request;
 
class CouponManageController extends \Controller\Admin\Controller
$this->setData('search', gd_isset($getMemberData['search']));
$this->setData('searchKindASelectBox', \Component\Member\Member::getSearchKindASelectBox());
$this->setData('page', $page);
 
}
}
 
변경 후CouponManageController.php
use Component\Database\DBTableField;
use Exception;
use Framework\Debug\Exception\LayerException;
use Framework\Security\Token;
use Request;
 
class CouponManageController extends \Controller\Admin\Controller
$this->setData('search', gd_isset($getMemberData['search']));
$this->setData('searchKindASelectBox', \Component\Member\Member::getSearchKindASelectBox());
$this->setData('page', $page);
$this->setData('couponManageToken', Token::generate('couponManageToken'));
}
}
 
Controller/Admin/Promotion/CouponPsController.php+45-5
변경 전CouponPsController.php
use Component\Coupon\CouponAdmin;
use Component\Sms\SmsSender;
use Framework\Debug\Exception\LayerNotReloadException;
 
use Message;
use Origin\Service\Sms\OccupancyAuth\SendGateService;
use Request;
$postValue = Request::post()->toArray();
$filesValue = Request::files()->toArray();
if (Request::post()->get('couponKind') == 'online') {
 
 
 
 
$couponAdmin->saveCoupon($postValue, $filesValue);
$this->layer(__('저장이 완료되었습니다.'), 'parent.unload_callback("' . $postValue['couponEventType'] . '");top.location.href="coupon_list.php?page=' . $ypage . '";');
} else if (Request::post()->get('couponKind') == 'offline') {
}
break;
case 'modifyCouponList':
 
 
 
 
 
 
case 'modifyCouponOfflineList':
$couponAdmin->changeCouponType();
break;
case 'deleteCouponList':
 
 
 
 
 
 
 
case 'deleteCouponOfflineList':
$couponAdmin->deleteCoupon();
if (Request::post()->get('mode') == 'deleteCouponList') {
$this->layer(__('삭제 되었습니다.'), 'top.location.reload()');
} else if (Request::post()->get('mode') == 'deleteCouponOfflineList') {
$this->layer(__('삭제 되었습니다.'), 'top.location.href="coupon_offline_list.php";');
}
break;
case 'deleteCouponManage':
 
 
 
 
 
 
 
case 'deleteCouponOfflineManage':
$couponAdmin->deleteMemberCoupon();
$this->layer(__('삭제 되었습니다.'), 'top.location.reload()');
throw new LayerNotReloadException($e->getMessage()); //새로고침안됨
}
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
변경 후CouponPsController.php
use Component\Coupon\CouponAdmin;
use Component\Sms\SmsSender;
use Framework\Debug\Exception\LayerNotReloadException;
use Framework\Security\Token;
use Message;
use Origin\Service\Sms\OccupancyAuth\SendGateService;
use Request;
$postValue = Request::post()->toArray();
$filesValue = Request::files()->toArray();
if (Request::post()->get('couponKind') == 'online') {
// CSRF 토큰 판별 - 미전송·위조 시 로그 수집
$couponRegistToken = Request::post()->get('couponRegistToken');
Token::check('couponRegistToken', ['couponRegistToken' => $couponRegistToken], false, null, true);
$this->validateRequestOrigin();
$couponAdmin->saveCoupon($postValue, $filesValue);
$this->layer(__('저장이 완료되었습니다.'), 'parent.unload_callback("' . $postValue['couponEventType'] . '");top.location.href="coupon_list.php?page=' . $ypage . '";');
} else if (Request::post()->get('couponKind') == 'offline') {
}
break;
case 'modifyCouponList':
// CSRF 토큰 판별 - 미전송·위조 시 로그 수집
$couponListToken = Request::post()->get('couponListToken');
Token::check('couponListToken', ['couponListToken' => $couponListToken], false, null, true);
$this->validateRequestOrigin();
$couponAdmin->changeCouponType();
break;
case 'modifyCouponOfflineList':
$couponAdmin->changeCouponType();
break;
case 'deleteCouponList':
// CSRF 토큰 판별 - 미전송·위조 시 로그 수집
$couponListToken = Request::post()->get('couponListToken');
Token::check('couponListToken', ['couponListToken' => $couponListToken], false, null, true);
$this->validateRequestOrigin();
$couponAdmin->deleteCoupon();
$this->layer(__('삭제 되었습니다.'), 'top.location.reload()');
break;
case 'deleteCouponOfflineList':
$couponAdmin->deleteCoupon();
$this->layer(__('삭제 되었습니다.'), 'top.location.href="coupon_offline_list.php";');
 
 
 
 
break;
case 'deleteCouponManage':
// CSRF 토큰 판별 - 미전송·위조 시 로그 수집
$couponManageToken = Request::post()->get('couponManageToken');
Token::check('couponManageToken', ['couponManageToken' => $couponManageToken], false, null, true);
$this->validateRequestOrigin();
$couponAdmin->deleteMemberCoupon();
$this->layer(__('삭제 되었습니다.'), 'top.location.reload()');
break;
case 'deleteCouponOfflineManage':
$couponAdmin->deleteMemberCoupon();
$this->layer(__('삭제 되었습니다.'), 'top.location.reload()');
throw new LayerNotReloadException($e->getMessage()); //새로고침안됨
}
}
 
/**
* @return void
* @throws LayerNotReloadException
*/
protected function validateRequestOrigin()
{
$httpOrigin = Request::server()->get('HTTP_ORIGIN');
if (empty($httpOrigin)) {
return;
}
 
$originHost = strtolower((string) parse_url($httpOrigin, PHP_URL_HOST));
$allowedHosts = [strtolower((string) Request::getHostNoPort()), strtolower((string) Request::getServerName())];
if (empty($originHost) || !in_array($originHost, $allowedHosts, true)) {
\App::getInstance('logger')->channel('coupon')->warning('허용되지 않은 요청 도메인', ['origin' => $httpOrigin, 'host' => $allowedHosts[0]]);
throw new LayerNotReloadException(__('허용되지 않은 도메인에서의 접근입니다.'));
}
}
}
 
Controller/Admin/Promotion/CouponRegistController.php+4
변경 전CouponRegistController.php
use Component\Database\DBTableField;
use Exception;
use Framework\Debug\Exception\LayerException;
 
use Request;
 
class CouponRegistController extends \Controller\Admin\Controller
'promotion/gd_promotion_common.js',
]);
$this->setData('couponData', gd_isset($couponData));
 
 
 
$this->setData('checked', gd_isset($checked));
$this->setData('selected', gd_isset($selected));
$this->setData('ypage', gd_isset($ypage,1));
 
변경 후CouponRegistController.php
use Component\Database\DBTableField;
use Exception;
use Framework\Debug\Exception\LayerException;
use Framework\Security\Token;
use Request;
 
class CouponRegistController extends \Controller\Admin\Controller
'promotion/gd_promotion_common.js',
]);
$this->setData('couponData', gd_isset($couponData));
if (isset($couponData['couponKind']) && $couponData['couponKind'] == 'online') {
$this->setData('couponRegistToken', Token::generate('couponRegistToken'));
}
$this->setData('checked', gd_isset($checked));
$this->setData('selected', gd_isset($selected));
$this->setData('ypage', gd_isset($ypage,1));
 
Controller/Front/Event/CouponzoneController.php+12
변경 전CouponzoneController.php
use Framework\Debug\Exception\AlertRedirectException;
use Component\Coupon\Coupon;
use Framework\ObjectStorage\Service\ImageUploadService;
 
 
/**
* Class AttendStampController
*/
class CouponzoneController extends \Controller\Front\Controller
{
 
 
 
/**
* @inheritdoc
*/
$couponList = $coupon->getCouponzoneList();
 
$this->setData('couponList', $couponList);
 
 
 
if($couponConfig['couponImageType'] == 'basic') {
$couponConfig['pcCouponImagePath'] = PATH_ADMIN_GD_SHARE . 'img/defaultCouponzonePc.png';
}
$couponConfig['pcContents'] = gd_htmlspecialchars_decode($couponConfig['pcContents']);
$couponConfig['pcContents'] = str_replace('<p>&nbsp;</p>', '', $couponConfig['pcContents']);
 
 
 
 
// 웹취약점 개선사항 상단영역 에디터 업로드 이미지 alt 추가
if ($couponConfig['pcContents']) {
} else {
$couponConfig['mobileContents'] = gd_htmlspecialchars_decode($couponConfig['mobileContents']);
$couponConfig['mobileContents'] = str_replace('<p>&nbsp;</p>', '', $couponConfig['mobileContents']);
 
 
 
}
 
$this->setData('couponConfig', $couponConfig);
 
변경 후CouponzoneController.php
use Framework\Debug\Exception\AlertRedirectException;
use Component\Coupon\Coupon;
use Framework\ObjectStorage\Service\ImageUploadService;
use Framework\Security\Token;
 
/**
* Class AttendStampController
*/
class CouponzoneController extends \Controller\Front\Controller
{
// 에디터를 비워 저장하면 남는 값
protected const EMPTY_EDITOR_CONTENTS = '<p><br></p>';
 
/**
* @inheritdoc
*/
$couponList = $coupon->getCouponzoneList();
 
$this->setData('couponList', $couponList);
// 발급 검증용 쿠폰 전용 토큰
$this->setData('couponToken', Token::generate('couponToken'));
 
if($couponConfig['couponImageType'] == 'basic') {
$couponConfig['pcCouponImagePath'] = PATH_ADMIN_GD_SHARE . 'img/defaultCouponzonePc.png';
}
$couponConfig['pcContents'] = gd_htmlspecialchars_decode($couponConfig['pcContents']);
$couponConfig['pcContents'] = str_replace('<p>&nbsp;</p>', '', $couponConfig['pcContents']);
$couponConfig['pcContents'] = trim(str_replace(self::EMPTY_EDITOR_CONTENTS, '', $couponConfig['pcContents'])) === ''
? ''
: $couponConfig['pcContents'];
 
// 웹취약점 개선사항 상단영역 에디터 업로드 이미지 alt 추가
if ($couponConfig['pcContents']) {
} else {
$couponConfig['mobileContents'] = gd_htmlspecialchars_decode($couponConfig['mobileContents']);
$couponConfig['mobileContents'] = str_replace('<p>&nbsp;</p>', '', $couponConfig['mobileContents']);
$couponConfig['mobileContents'] = trim(str_replace(self::EMPTY_EDITOR_CONTENTS, '', $couponConfig['mobileContents'])) === ''
? ''
: $couponConfig['mobileContents'];
}
 
$this->setData('couponConfig', $couponConfig);
 
Controller/Front/Goods/LayerCouponDownController.php+21-6
변경 전LayerCouponDownController.php
use App;
use Framework\Debug\Exception\WarningException;
 
use Session;
use Request;
use Exception;
$coupon = App::load(\Component\Coupon\Coupon::class);
$post = Request::post()->toArray();
// 상품의 쿠폰리스트
$goodsCouponArrData = $coupon->getGoodsCouponDownList($post['goodsNo'],Session::get('member.memNo'),Session::get('member.groupSno'), null, null, $post['scmNo'], $post['brandCd']);
// 해당 상품의 모든 쿠폰을 보기용으로 변환
$convertCouponArrData = $coupon->convertCouponArrData($goodsCouponArrData);
// 상품의 다운받을 수 있는 쿠폰의 개수
$goodsCouponCnt = $coupon->getGoodsCouponDownListCount($goodsCouponArrData);
 
 
 
 
 
 
 
 
 
 
$this->setData('goodsCouponArrData', $goodsCouponArrData);
 
$this->setData('convertCouponArrData', $convertCouponArrData);
$this->setData('goodsNo', $post['goodsNo']);
$this->setData('scmNo', $post['scmNo']);
$this->setData('brandCd', $post['brandCd']);
 
$this->setData('goodsCouponCnt', $goodsCouponCnt);
 
 
} else {
$this->json([
'error' => 10,
 
변경 후LayerCouponDownController.php
use App;
use Framework\Debug\Exception\WarningException;
use Framework\Security\Token;
use Session;
use Request;
use Exception;
$coupon = App::load(\Component\Coupon\Coupon::class);
$post = Request::post()->toArray();
$supportsCouponUseTypeFilter = method_exists($coupon, 'setCouponUseTypes');
if ($supportsCouponUseTypeFilter) {
$coupon->setCouponUseTypes(['product', 'order']);
}
$downCouponArrData = $coupon->getGoodsCouponDownList($post['goodsNo'],Session::get('member.memNo'),Session::get('member.groupSno'), null, null, $post['scmNo'], $post['brandCd']);
if ($supportsCouponUseTypeFilter) {
$coupon->setCouponUseTypes(['product']);
}
$convertCouponArrData = $coupon->convertCouponArrData($downCouponArrData);
$orderCouponArrData = array_filter($downCouponArrData, function ($downCoupon) {
return ($downCoupon['couponUseType'] ?? '') === 'order';
});
$goodsCouponArrData = array_filter($downCouponArrData, function ($downCoupon) {
return ($downCoupon['couponUseType'] ?? '') === 'product';
});
$this->setData('goodsCouponArrData', $goodsCouponArrData);
$this->setData('orderCouponArrData', $orderCouponArrData);
$this->setData('convertCouponArrData', $convertCouponArrData);
$this->setData('goodsNo', $post['goodsNo']);
$this->setData('scmNo', $post['scmNo']);
$this->setData('brandCd', $post['brandCd']);
$goodsCouponCnt = empty($downCouponArrData) ? 0 : $coupon->getGoodsCouponDownListCount($downCouponArrData);
$this->setData('goodsCouponCnt', $goodsCouponCnt);
// 발급 검증용 쿠폰 전용 토큰
$this->setData('couponToken', Token::generate('couponToken'));
} else {
$this->json([
'error' => 10,
 
Controller/Front/Goods/LayerCouponPsController.php+16-1
변경 전LayerCouponPsController.php
use App;
use Framework\Debug\Exception\WarningException;
 
use Session;
use Request;
use Exception;
// 쿠폰 다운
case 'coupon_down':
case 'coupon_down_all':
 
 
 
 
 
 
// --- 쿠폰 class
$coupon = \App::load('\\Component\\Coupon\\Coupon');
$coupon->setGoodsCouponMemberSave(Request::post()->get('couponNo'), Request::post()->get('goodsNo'),Session::get('member.memNo'),Session::get('member.groupSno'), $post['scmNo'], $post['brandCd']);
// 상품의 다운받을 수 있는 쿠폰의 개수
$goodsCouponCnt = $coupon->getGoodsCouponDownListCount(null, $post['goodsNo'], Session::get('member.memNo'), Session::get('member.groupSno'));
 
 
 
 
 
 
 
 
$this->json([
'code' => 200,
 
변경 후LayerCouponPsController.php
use App;
use Framework\Debug\Exception\WarningException;
use Framework\Security\Token;
use Session;
use Request;
use Exception;
// 쿠폰 다운
case 'coupon_down':
case 'coupon_down_all':
if (Request::getMethod() !== 'POST') {
throw new Exception(__('잘못된 요청입니다.'));
}
// 쿠폰 전용 토큰 판별 - 미전송·위조 시 로그 수집
$couponToken = Request::post()->get('couponToken');
Token::check('couponToken', ['couponToken' => $couponToken], false, null, true);
// --- 쿠폰 class
$coupon = \App::load('\\Component\\Coupon\\Coupon');
$coupon->setGoodsCouponMemberSave(Request::post()->get('couponNo'), Request::post()->get('goodsNo'),Session::get('member.memNo'),Session::get('member.groupSno'), $post['scmNo'], $post['brandCd']);
// 상품의 다운받을 수 있는 쿠폰의 개수
$supportsCouponUseTypeFilter = method_exists($coupon, 'setCouponUseTypes');
if ($supportsCouponUseTypeFilter) {
$coupon->setCouponUseTypes(['product', 'order']);
}
$downCouponArrData = $coupon->getGoodsCouponDownList($post['goodsNo'], Session::get('member.memNo'), Session::get('member.groupSno'), null, null, $post['scmNo'], $post['brandCd']);
if ($supportsCouponUseTypeFilter) {
$coupon->setCouponUseTypes(['product']);
}
$goodsCouponCnt = empty($downCouponArrData) ? 0 : $coupon->getGoodsCouponDownListCount($downCouponArrData);
$this->json([
'code' => 200,
 
Controller/Front/Mypage/CouponPsController.php+7
변경 전CouponPsController.php
use Exception;
use Framework\Debug\Exception\AlertOnlyException;
use Framework\Debug\Exception\AlertReloadException;
 
use App;
use Session;
use Request;
case 'couponDown' :
case 'couponDownAll' :
try {
 
 
 
 
 
 
$result = $coupon->setCouponzoneDown(Request::post()->get('couponNo'), Session::get('member.memNo'), Session::get('member.groupSno'));
 
if ($result['success'] == 0) {
 
변경 후CouponPsController.php
use Exception;
use Framework\Debug\Exception\AlertOnlyException;
use Framework\Debug\Exception\AlertReloadException;
use Framework\Security\Token;
use App;
use Session;
use Request;
case 'couponDown' :
case 'couponDownAll' :
try {
if (Request::getMethod() !== 'POST' || !Request::isAjax()) {
throw new Exception(__('잘못된 요청입니다.'));
}
// 쿠폰 전용 토큰 판별 - 미전송·위조 시 로그 수집
$couponToken = Request::post()->get('couponToken');
Token::check('couponToken', ['couponToken' => $couponToken], false, null, true);
$result = $coupon->setCouponzoneDown(Request::post()->get('couponNo'), Session::get('member.memNo'), Session::get('member.groupSno'));
 
if ($result['success'] == 0) {
 
Controller/Front/Order/LayerCouponApplyOrderController.php+18
변경 전LayerCouponApplyOrderController.php
}
}
 
 
 
 
 
 
 
 
 
$this->setData('memberCouponArrData', $memberCouponArrData);
$this->setData('convertMemberCouponArrData', $convertMemberCouponArrData);
$this->setData('convertMemberCouponPriceArrData', $convertMemberCouponPriceArrData);
}
}
}
 
 
 
 
 
 
 
 
 
$this->setData('goodsCouponArrData', $goodsCouponData['goodsCouponArrData']); // 쿠폰 DB 데이터
$this->setData('convertGoodsCouponArrData', $goodsCouponData['convertGoodsCouponArrData']); // 변환 쿠폰 데이터
$this->setData('convertGoodsCouponPriceArrData', $goodsCouponData['convertGoodsCouponPriceArrData']); // 쿠폰 가격 데이터
 
변경 후LayerCouponApplyOrderController.php
}
}
// 쿠폰명은 원문 저장되어 화면 출력 전 인코딩함
foreach (['order', 'delivery'] as $couponUseType) {
if (is_array($memberCouponArrData[$couponUseType])) {
foreach ($memberCouponArrData[$couponUseType] as &$memberCoupon) {
$memberCoupon['couponNm'] = gd_htmlspecialchars($memberCoupon['couponNm']);
}
unset($memberCoupon);
}
}
$this->setData('memberCouponArrData', $memberCouponArrData);
$this->setData('convertMemberCouponArrData', $convertMemberCouponArrData);
$this->setData('convertMemberCouponPriceArrData', $convertMemberCouponPriceArrData);
}
}
}
if (is_array($goodsCouponData['goodsCouponArrData'])) {
foreach ($goodsCouponData['goodsCouponArrData'] as &$goodsCouponList) {
foreach ($goodsCouponList as &$goodsCoupon) {
$goodsCoupon['couponNm'] = gd_htmlspecialchars($goodsCoupon['couponNm']);
}
unset($goodsCoupon);
}
unset($goodsCouponList);
}
$this->setData('goodsCouponArrData', $goodsCouponData['goodsCouponArrData']); // 쿠폰 DB 데이터
$this->setData('convertGoodsCouponArrData', $goodsCouponData['convertGoodsCouponArrData']); // 변환 쿠폰 데이터
$this->setData('convertGoodsCouponPriceArrData', $goodsCouponData['convertGoodsCouponPriceArrData']); // 쿠폰 가격 데이터
 
Controller/Mobile/Goods/LayerCouponDownController.php+21-6
변경 전LayerCouponDownController.php
use App;
use Framework\Debug\Exception\WarningException;
 
use Session;
use Request;
use Exception;
$coupon = App::load(\Component\Coupon\Coupon::class);
$post = Request::request()->toArray();
// 상품의 쿠폰리스트
$goodsCouponArrData = $coupon->getGoodsCouponDownList($post['goodsNo'],Session::get('member.memNo'),Session::get('member.groupSno'), null, null, $post['scmNo'], $post['brandCd']);
// 해당 상품의 모든 쿠폰을 보기용으로 변환
$convertCouponArrData = $coupon->convertCouponArrData($goodsCouponArrData);
// 상품의 다운받을 수 있는 쿠폰의 개수
$goodsCouponCnt = $coupon->getGoodsCouponDownListCount($goodsCouponArrData);
 
 
 
 
 
 
 
 
 
 
$this->setData('goodsCouponArrData', $goodsCouponArrData);
 
$this->setData('convertCouponArrData', $convertCouponArrData);
$this->setData('goodsNo', $post['goodsNo']);
$this->setData('scmNo', $post['scmNo']);
$this->setData('brandCd', $post['brandCd']);
 
$this->setData('goodsCouponCnt', $goodsCouponCnt);
 
 
} else {
$this->json([
'error' => 10,
 
변경 후LayerCouponDownController.php
use App;
use Framework\Debug\Exception\WarningException;
use Framework\Security\Token;
use Session;
use Request;
use Exception;
$coupon = App::load(\Component\Coupon\Coupon::class);
$post = Request::request()->toArray();
$supportsCouponUseTypeFilter = method_exists($coupon, 'setCouponUseTypes');
if ($supportsCouponUseTypeFilter) {
$coupon->setCouponUseTypes(['product', 'order']);
}
$downCouponArrData = $coupon->getGoodsCouponDownList($post['goodsNo'],Session::get('member.memNo'),Session::get('member.groupSno'), null, null, $post['scmNo'], $post['brandCd']);
if ($supportsCouponUseTypeFilter) {
$coupon->setCouponUseTypes(['product']);
}
$convertCouponArrData = $coupon->convertCouponArrData($downCouponArrData);
$orderCouponArrData = array_filter($downCouponArrData, function ($downCoupon) {
return ($downCoupon['couponUseType'] ?? '') === 'order';
});
$goodsCouponArrData = array_filter($downCouponArrData, function ($downCoupon) {
return ($downCoupon['couponUseType'] ?? '') === 'product';
});
$this->setData('goodsCouponArrData', $goodsCouponArrData);
$this->setData('orderCouponArrData', $orderCouponArrData);
$this->setData('convertCouponArrData', $convertCouponArrData);
$this->setData('goodsNo', $post['goodsNo']);
$this->setData('scmNo', $post['scmNo']);
$this->setData('brandCd', $post['brandCd']);
$goodsCouponCnt = empty($downCouponArrData) ? 0 : $coupon->getGoodsCouponDownListCount($downCouponArrData);
$this->setData('goodsCouponCnt', $goodsCouponCnt);
// 발급 검증용 쿠폰 전용 토큰
$this->setData('couponToken', Token::generate('couponToken'));
} else {
$this->json([
'error' => 10,
 
Controller/Mobile/Goods/LayerCouponPsController.php+16-1
변경 전LayerCouponPsController.php
namespace Bundle\Controller\Mobile\Goods;
use App;
 
use Session;
use Request;
use Exception;
// 쿠폰 다운
case 'coupon_down':
case 'coupon_down_all':
 
 
 
 
 
 
// --- 쿠폰 class
$coupon = \App::load('\\Component\\Coupon\\Coupon');
$coupon->setGoodsCouponMemberSave(Request::post()->get('couponNo'), Request::post()->get('goodsNo'),Session::get('member.memNo'),Session::get('member.groupSno'), $post['scmNo'], $post['brandCd']);
// 상품의 다운받을 수 있는 쿠폰의 개수
$goodsCouponCnt = $coupon->getGoodsCouponDownListCount(null, $post['goodsNo'], Session::get('member.memNo'), Session::get('member.groupSno'));
 
 
 
 
 
 
 
 
$this->json([
'code' => 200,
 
변경 후LayerCouponPsController.php
namespace Bundle\Controller\Mobile\Goods;
use App;
use Framework\Security\Token;
use Session;
use Request;
use Exception;
// 쿠폰 다운
case 'coupon_down':
case 'coupon_down_all':
if (Request::getMethod() !== 'POST') {
throw new Exception(__('잘못된 요청입니다.'));
}
// 쿠폰 전용 토큰 판별 - 미전송·위조 시 로그 수집
$couponToken = Request::post()->get('couponToken');
Token::check('couponToken', ['couponToken' => $couponToken], false, null, true);
// --- 쿠폰 class
$coupon = \App::load('\\Component\\Coupon\\Coupon');
$coupon->setGoodsCouponMemberSave(Request::post()->get('couponNo'), Request::post()->get('goodsNo'),Session::get('member.memNo'),Session::get('member.groupSno'), $post['scmNo'], $post['brandCd']);
// 상품의 다운받을 수 있는 쿠폰의 개수
$supportsCouponUseTypeFilter = method_exists($coupon, 'setCouponUseTypes');
if ($supportsCouponUseTypeFilter) {
$coupon->setCouponUseTypes(['product', 'order']);
}
$downCouponArrData = $coupon->getGoodsCouponDownList($post['goodsNo'], Session::get('member.memNo'), Session::get('member.groupSno'), null, null, $post['scmNo'], $post['brandCd']);
if ($supportsCouponUseTypeFilter) {
$coupon->setCouponUseTypes(['product']);
}
$goodsCouponCnt = empty($downCouponArrData) ? 0 : $coupon->getGoodsCouponDownListCount($downCouponArrData);
$this->json([
'code' => 200,
 
Controller/Mobile/Mypage/CouponPsController.php+7
변경 전CouponPsController.php
use Exception;
use Framework\Debug\Exception\AlertOnlyException;
use Framework\Debug\Exception\AlertReloadException;
 
use Request;
use Session;
 
case 'couponDown' :
case 'couponDownAll' :
try {
 
 
 
 
 
 
$result = $coupon->setCouponzoneDown(Request::post()->get('couponNo'), Session::get('member.memNo'), Session::get('member.groupSno'));
 
if ($result['success'] == 0) {
 
변경 후CouponPsController.php
use Exception;
use Framework\Debug\Exception\AlertOnlyException;
use Framework\Debug\Exception\AlertReloadException;
use Framework\Security\Token;
use Request;
use Session;
 
case 'couponDown' :
case 'couponDownAll' :
try {
if (Request::getMethod() !== 'POST' || !Request::isAjax()) {
throw new Exception(__('잘못된 요청입니다.'));
}
// 쿠폰 전용 토큰 판별 - 미전송·위조 시 로그 수집
$couponToken = Request::post()->get('couponToken');
Token::check('couponToken', ['couponToken' => $couponToken], false, null, true);
$result = $coupon->setCouponzoneDown(Request::post()->get('couponNo'), Session::get('member.memNo'), Session::get('member.groupSno'));
 
if ($result['success'] == 0) {
 
Controller/Mobile/Order/LayerCouponApplyOrderController.php+18
변경 전LayerCouponApplyOrderController.php
}
}
 
 
 
 
 
 
 
 
 
$this->setData('memberCouponArrData', $memberCouponArrData);
$this->setData('convertMemberCouponArrData', $convertMemberCouponArrData);
$this->setData('convertMemberCouponPriceArrData', $convertMemberCouponPriceArrData);
}
}
}
 
 
 
 
 
 
 
 
 
$this->setData('goodsCouponArrData', $goodsCouponData['goodsCouponArrData']); // 쿠폰 DB 데이터
$this->setData('convertGoodsCouponArrData', $goodsCouponData['convertGoodsCouponArrData']); // 변환 쿠폰 데이터
$this->setData('convertGoodsCouponPriceArrData', $goodsCouponData['convertGoodsCouponPriceArrData']); // 쿠폰 가격 데이터
 
변경 후LayerCouponApplyOrderController.php
}
}
// 쿠폰명은 원문 저장되어 화면 출력 전 인코딩함
foreach (['order', 'delivery'] as $couponUseType) {
if (is_array($memberCouponArrData[$couponUseType])) {
foreach ($memberCouponArrData[$couponUseType] as &$memberCoupon) {
$memberCoupon['couponNm'] = gd_htmlspecialchars($memberCoupon['couponNm']);
}
unset($memberCoupon);
}
}
$this->setData('memberCouponArrData', $memberCouponArrData);
$this->setData('convertMemberCouponArrData', $convertMemberCouponArrData);
$this->setData('convertMemberCouponPriceArrData', $convertMemberCouponPriceArrData);
}
}
}
if (is_array($goodsCouponData['goodsCouponArrData'])) {
foreach ($goodsCouponData['goodsCouponArrData'] as &$goodsCouponList) {
foreach ($goodsCouponList as &$goodsCoupon) {
$goodsCoupon['couponNm'] = gd_htmlspecialchars($goodsCoupon['couponNm']);
}
unset($goodsCoupon);
}
unset($goodsCouponList);
}
$this->setData('goodsCouponArrData', $goodsCouponData['goodsCouponArrData']); // 쿠폰 DB 데이터
$this->setData('convertGoodsCouponArrData', $goodsCouponData['convertGoodsCouponArrData']); // 변환 쿠폰 데이터
$this->setData('convertGoodsCouponPriceArrData', $goodsCouponData['convertGoodsCouponPriceArrData']); // 쿠폰 가격 데이터
 
data/skin/front/moment/css/event/coupon.css+15
변경 전coupon.css
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
변경 후coupon.css
@charset "utf-8";
 
/* 쿠폰존 — 사용처 배지 */
.coupon_content .cp_list_wrap .cp_list li .box_coupon .text_wrap .text_info .cp_use_badge{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;height:22px;padding:0 5px;border-radius:2px;margin-bottom:6px;font-size:12px;font-weight:700;line-height:1;letter-spacing:-0.02em;}
.coupon_content .cp_list_wrap .cp_list li .box_coupon .text_wrap .text_info .cp_use_badge.order{background:#555d87;color:#fff;}
.coupon_content .cp_list_wrap .cp_list li .box_coupon .text_wrap .text_info .cp_use_badge.prod{background:#eef2f6;color:#555;border:1px solid #d4dce4;}
.coupon_content .cp_list_wrap .cp_list li .box_coupon .text_wrap .text_info .date{margin-top:14px;vertical-align:top;}
 
/* 쿠폰 다운받기 레이어 — 「상품쿠폰」/「주문쿠폰」 섹션 제목 */
.coupon_down_layer .coupon_section_tit{margin:18px 0 0; padding-bottom:6px; color:#222; font-size:15px; font-weight:700; border-bottom:1px solid #333;}
 
/* 쿠폰 다운받기 레이어 */
.coupon_down_layer .coupon_completed.coupon-grade-limit{padding:0; color:#838383; background:none;}
.coupon_down_layer .top_table_type table{table-layout:fixed;}
.coupon_down_layer .top_table_type td:first-child{word-break:keep-all; word-wrap:break-word;}
 
data/skin/front/moment/event/couponzone.html+9-2
변경 전couponzone.html
{*** 쿠폰존 | event/couponzone.php ***}
{ # header }
<div class="content">
 
<div class="mypage_cont">
<div class="coupon_content">
<h2>쿠폰존</h2>
<div class="img_cp"><img src="{=couponConfig.pcCouponImagePath}" alt="{=__('쿠폰이미지')}" /></div>
<div class="text_wrap">
<div class="text_info">
 
 
 
 
 
<span class="tit">{..couponNm}</span>
<span class="dis">{..couponBenefit}</span>
<span class="txt">{..couponKindType}</span>
method: "POST",
cache: false,
url: "../mypage/coupon_ps.php",
data: "mode=couponDown&couponNo=" + couponNo,
dataType: 'json',
async: false,
success: function (data) {
var params = {
total: total,
couponNo: couponArrData,
mode: 'couponDownAll'
 
};
$.ajax({
method: "POST",
 
변경 후couponzone.html
{*** 쿠폰존 | event/couponzone.php ***}
{ # header }
<div class="content">
<link type="text/css" rel="stylesheet" href="{=setBrowserCache('../css/event/coupon.css')}" />
<div class="mypage_cont">
<div class="coupon_content">
<h2>쿠폰존</h2>
<div class="img_cp"><img src="{=couponConfig.pcCouponImagePath}" alt="{=__('쿠폰이미지')}" /></div>
<div class="text_wrap">
<div class="text_info">
<!--{ ? ..couponUseTypeCode == 'order' }-->
<span class="cp_use_badge order">{=__('주문 적용')}</span>
<!--{ : ..couponUseTypeCode == 'product' }-->
<span class="cp_use_badge prod">{=__('상품 적용')}</span>
<!--{ / }-->
<span class="tit">{..couponNm}</span>
<span class="dis">{..couponBenefit}</span>
<span class="txt">{..couponKindType}</span>
method: "POST",
cache: false,
url: "../mypage/coupon_ps.php",
data: "mode=couponDown&couponNo=" + couponNo + "&couponToken=" + encodeURIComponent('{=couponToken}'),
dataType: 'json',
async: false,
success: function (data) {
var params = {
total: total,
couponNo: couponArrData,
mode: 'couponDownAll',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
 
data/skin/front/moment/goods/layer_coupon_down.html+62-4
변경 전layer_coupon_down.html
{*** 쿠폰 다운받기 레이어 | goods/layer_coupon_down.php ***}
 
<div class="layer_wrap_cont">
<div class="ly_tit">
<h4>
<div class="ly_cont">
<div class="scroll_box">
<!--{ ? gd_is_login() }-->
 
 
<div class="top_table_type">
<table>
<colgroup>
</td>
<td>
<!--{ ? .chkMemberCoupon == 'NO_MEMBER_GROUP' }-->
<strong class="coupon_completed">{=__('해당 회원등급이 아닙니다.')}</strong>
<!--{ : .chkMemberCoupon == 'DUPLICATE_COUPON' }-->
<strong class="coupon_completed">{=__('발급완료')}</strong>
<!--{ : .chkMemberCoupon == 'YES' }-->
</tbody>
</table>
</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<!--{ : }-->
<div class="coupon_down_txt"><p>{=__('로그인하셔야 본 서비스를 이용하실 수 있습니다.')}</p></div>
<!--{ / }-->
mode: 'coupon_down',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}'
 
};
$.ajax({
method: "POST",
mode: 'coupon_down_all',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}'
 
};
$.ajax({
method: "POST",
});
//-->
</script>
<!--{ / }-->
 
변경 후layer_coupon_down.html
{*** 쿠폰 다운받기 레이어 | goods/layer_coupon_down.php ***}
<link type="text/css" rel="stylesheet" href="{=setBrowserCache('../css/event/coupon.css')}" />
<div class="layer_wrap_cont">
<div class="ly_tit">
<h4>
<div class="ly_cont">
<div class="scroll_box">
<!--{ ? gd_is_login() }-->
<!--{ ? goodsCouponArrData }-->
<p class="coupon_section_tit">{=__('상품쿠폰')}</p>
<div class="top_table_type">
<table>
<colgroup>
</td>
<td>
<!--{ ? .chkMemberCoupon == 'NO_MEMBER_GROUP' }-->
<strong class="coupon_completed coupon-grade-limit">{=__('해당 회원등급이 아닙니다.')}</strong>
<!--{ : .chkMemberCoupon == 'DUPLICATE_COUPON' }-->
<strong class="coupon_completed">{=__('발급완료')}</strong>
<!--{ : .chkMemberCoupon == 'YES' }-->
</tbody>
</table>
</div>
<!--{ / }-->
<!--{ ? orderCouponArrData }-->
<p class="coupon_section_tit">{=__('주문쿠폰')}</p>
<div class="top_table_type">
<table>
<colgroup>
<col style="width:150px" />
<col style="width:300px" />
<col>
</colgroup>
<thead>
<tr>
<th>{=__('쿠폰')}</th>
<th>{=__('혜택')}</th>
<th>{=__('다운받기')}</th>
</tr>
</thead>
<tbody>
<!--{ @ orderCouponArrData }-->
<tr>
<td>
<strong>{.couponNm}</strong>
</td>
<td class="td_left">
<strong class="coupon_price"><b>{convertCouponArrData[.key_].couponBenefit}</b> { convertCouponArrData[.key_].couponKindType }</strong>
<span class="text_info">
<!--{ ? convertCouponArrData[.key_].couponMaxBenefit }-->
- {convertCouponArrData[.key_].couponMaxBenefit}<br />
<!--{ / }-->
<!--{ ? convertCouponArrData[.key_].couponMinOrderPrice }-->
- {convertCouponArrData[.key_].couponMinOrderPrice}<br />
<!--{ / }-->
- {convertCouponArrData[.key_].couponApplyDuplicateType}
</span>
</td>
<td>
<!--{ ? .chkMemberCoupon == 'NO_MEMBER_GROUP' }-->
<strong class="coupon_completed coupon-grade-limit">{=__('해당 회원등급이 아닙니다.')}</strong>
<!--{ : .chkMemberCoupon == 'DUPLICATE_COUPON' }-->
<strong class="coupon_completed">{=__('발급완료')}</strong>
<!--{ : .chkMemberCoupon == 'YES' }-->
<div class="btn_down_box">
<span class="btn_gray_list btn_coupon_down" data-coupon-no="{.couponNo}"><a href="#" class="btn_gray_small"><em class="icon_download">{=__('쿠폰 다운받기')}</em></a></span>
<em class="text_info">({convertCouponArrData[.key_].useEndDate})</em>
</div>
<!--{ / }-->
</td>
</tr>
<!--{ / }-->
</tbody>
</table>
</div>
<!--{ / }-->
<!--{ : }-->
<div class="coupon_down_txt"><p>{=__('로그인하셔야 본 서비스를 이용하실 수 있습니다.')}</p></div>
<!--{ / }-->
mode: 'coupon_down',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
mode: 'coupon_down_all',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
});
//-->
</script>
<!--{ / }-->
 
data/skin/front/mygreek/css/event/coupon.css+19
변경 전coupon.css
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
변경 후coupon.css
@charset "utf-8";
 
/* 쿠폰존 — 사용처 배지 */
.coupon_content .cp_list_wrap .cp_list li .box_coupon .text_wrap .text_info .cp_use_badge{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;height:22px;padding:0 5px;border-radius:2px;margin-bottom:6px;font-size:12px;font-weight:700;line-height:1;letter-spacing:-0.02em;}
.coupon_content .cp_list_wrap .cp_list li .box_coupon .text_wrap .text_info .cp_use_badge.order{background:#555d87;color:#fff;}
.coupon_content .cp_list_wrap .cp_list li .box_coupon .text_wrap .text_info .cp_use_badge.prod{background:#eef2f6;color:#555;border:1px solid #d4dce4;}
.coupon_content .cp_list_wrap .cp_list li .box_coupon .text_wrap .text_info .date{margin-top:14px;vertical-align:top;}
 
/* 쿠폰 다운받기 레이어 — 「상품쿠폰」/「주문쿠폰」 섹션 제목 */
.coupon_down_layer .coupon_section_tit{margin:18px 0 0; padding-bottom:6px; color:#222; font-size:15px; font-weight:700; border-bottom:1px solid #333;}
 
/* 쿠폰 다운받기 레이어 */
.coupon_down_layer .coupon_completed:not(.coupon-grade-limit){display:inline-block; min-height:17px; padding-left:23px; line-height:17px; background:url('../../img/common/layer/icon_completed.png') no-repeat left center;}
.coupon_down_layer .coupon_completed.coupon-grade-limit{color:#838383;}
.coupon_down_layer .top_table_type table{table-layout:fixed;}
.coupon_down_layer .top_table_type td:first-child{word-break:keep-all; word-wrap:break-word;}
/* 쿠폰존 */
.coupon_content .cp_list_wrap .cp_list{width:920px;}
.coupon_content .cp_list_wrap .cp_list li{margin-right:10px;}
 
data/skin/front/mygreek/event/couponzone.html+9-2
변경 전couponzone.html
{*** 쿠폰존 | event/couponzone.php ***}
{ # header }
<div class="content">
 
<div class="mypage_cont">
<div class="coupon_content">
<h2>쿠폰존</h2>
<div class="img_cp"><img src="{=couponConfig.pcCouponImagePath}" alt="{=__('쿠폰이미지')}" /></div>
<div class="text_wrap">
<div class="text_info">
 
 
 
 
 
<span class="tit">{..couponNm}</span>
<span class="dis">{..couponBenefit}</span>
<span class="txt">{..couponKindType}</span>
method: "POST",
cache: false,
url: "../mypage/coupon_ps.php",
data: "mode=couponDown&couponNo=" + couponNo,
dataType: 'json',
async: false,
success: function (data) {
var params = {
total: total,
couponNo: couponArrData,
mode: 'couponDownAll'
 
};
$.ajax({
method: "POST",
 
변경 후couponzone.html
{*** 쿠폰존 | event/couponzone.php ***}
{ # header }
<div class="content">
<link type="text/css" rel="stylesheet" href="{=setBrowserCache('../css/event/coupon.css')}" />
<div class="mypage_cont">
<div class="coupon_content">
<h2>쿠폰존</h2>
<div class="img_cp"><img src="{=couponConfig.pcCouponImagePath}" alt="{=__('쿠폰이미지')}" /></div>
<div class="text_wrap">
<div class="text_info">
<!--{ ? ..couponUseTypeCode == 'order' }-->
<span class="cp_use_badge order">{=__('주문 적용')}</span>
<!--{ : ..couponUseTypeCode == 'product' }-->
<span class="cp_use_badge prod">{=__('상품 적용')}</span>
<!--{ / }-->
<span class="tit">{..couponNm}</span>
<span class="dis">{..couponBenefit}</span>
<span class="txt">{..couponKindType}</span>
method: "POST",
cache: false,
url: "../mypage/coupon_ps.php",
data: "mode=couponDown&couponNo=" + couponNo + "&couponToken=" + encodeURIComponent('{=couponToken}'),
dataType: 'json',
async: false,
success: function (data) {
var params = {
total: total,
couponNo: couponArrData,
mode: 'couponDownAll',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
 
data/skin/front/mygreek/goods/layer_coupon_down.html+61-3
변경 전layer_coupon_down.html
{*** 쿠폰 다운받기 레이어 | goods/layer_coupon_down.php ***}
 
<div class="layer_wrap_cont">
<div class="ly_tit">
<h4>
<div class="ly_cont">
<div class="scroll_box">
<!--{ ? gd_is_login() }-->
 
 
<div class="top_table_type">
<table>
<colgroup>
</td>
<td>
<!--{ ? .chkMemberCoupon == 'NO_MEMBER_GROUP' }-->
<strong class="coupon_completed">{=__('해당 회원등급이 아닙니다.')}</strong>
<!--{ : .chkMemberCoupon == 'DUPLICATE_COUPON' }-->
<strong class="coupon_completed">{=__('발급완료')}</strong>
<!--{ : .chkMemberCoupon == 'YES' }-->
</tbody>
</table>
</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<!--{ : }-->
<div class="coupon_down_txt"><p>{=__('로그인하셔야 본 서비스를 이용하실 수 있습니다.')}</p></div>
<!--{ / }-->
mode: 'coupon_down',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}'
 
};
$.ajax({
method: "POST",
mode: 'coupon_down_all',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}'
 
};
$.ajax({
method: "POST",
 
변경 후layer_coupon_down.html
{*** 쿠폰 다운받기 레이어 | goods/layer_coupon_down.php ***}
<link type="text/css" rel="stylesheet" href="{=setBrowserCache('../css/event/coupon.css')}" />
<div class="layer_wrap_cont">
<div class="ly_tit">
<h4>
<div class="ly_cont">
<div class="scroll_box">
<!--{ ? gd_is_login() }-->
<!--{ ? goodsCouponArrData }-->
<p class="coupon_section_tit">{=__('상품쿠폰')}</p>
<div class="top_table_type">
<table>
<colgroup>
</td>
<td>
<!--{ ? .chkMemberCoupon == 'NO_MEMBER_GROUP' }-->
<strong class="coupon_completed coupon-grade-limit">{=__('해당 회원등급이 아닙니다.')}</strong>
<!--{ : .chkMemberCoupon == 'DUPLICATE_COUPON' }-->
<strong class="coupon_completed">{=__('발급완료')}</strong>
<!--{ : .chkMemberCoupon == 'YES' }-->
</tbody>
</table>
</div>
<!--{ / }-->
<!--{ ? orderCouponArrData }-->
<p class="coupon_section_tit">{=__('주문쿠폰')}</p>
<div class="top_table_type">
<table>
<colgroup>
<col style="width:150px" />
<col style="width:300px" />
<col>
</colgroup>
<thead>
<tr>
<th>{=__('쿠폰')}</th>
<th>{=__('혜택')}</th>
<th>{=__('다운받기')}</th>
</tr>
</thead>
<tbody>
<!--{ @ orderCouponArrData }-->
<tr>
<td>
<strong>{.couponNm}</strong>
</td>
<td class="td_left">
<strong class="coupon_price"><b>{convertCouponArrData[.key_].couponBenefit}</b> { convertCouponArrData[.key_].couponKindType }</strong>
<span class="text_info">
<!--{ ? convertCouponArrData[.key_].couponMaxBenefit }-->
- {convertCouponArrData[.key_].couponMaxBenefit}<br />
<!--{ / }-->
<!--{ ? convertCouponArrData[.key_].couponMinOrderPrice }-->
- {convertCouponArrData[.key_].couponMinOrderPrice}<br />
<!--{ / }-->
- {convertCouponArrData[.key_].couponApplyDuplicateType}
</span>
</td>
<td>
<!--{ ? .chkMemberCoupon == 'NO_MEMBER_GROUP' }-->
<strong class="coupon_completed coupon-grade-limit">{=__('해당 회원등급이 아닙니다.')}</strong>
<!--{ : .chkMemberCoupon == 'DUPLICATE_COUPON' }-->
<strong class="coupon_completed">{=__('발급완료')}</strong>
<!--{ : .chkMemberCoupon == 'YES' }-->
<div class="btn_down_box">
<span class="btn_gray_list btn_coupon_down" data-coupon-no="{.couponNo}"><a href="#" class="btn_gray_small"><em class="icon_download">{=__('쿠폰 다운받기')}</em></a></span>
<em class="text_info">({convertCouponArrData[.key_].useEndDate})</em>
</div>
<!--{ / }-->
</td>
</tr>
<!--{ / }-->
</tbody>
</table>
</div>
<!--{ / }-->
<!--{ : }-->
<div class="coupon_down_txt"><p>{=__('로그인하셔야 본 서비스를 이용하실 수 있습니다.')}</p></div>
<!--{ / }-->
mode: 'coupon_down',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
mode: 'coupon_down_all',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
 
data/skin/front/story_g/css/gd_contents.css+12
변경 전gd_contents.css
/*** 회원가입 사업자 정보 | member/_join_view_business.html ***/
.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;}
 
 
 
 
 
 
 
 
 
 
 
 
 
변경 후gd_contents.css
/*** 회원가입 사업자 정보 | member/_join_view_business.html ***/
.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;}
 
/* 쿠폰 다운받기 레이어 — 「상품쿠폰」/「주문쿠폰」 섹션 제목 */
.coupon-down-layer .coupon_section_tit{margin:16px 0 0;padding-bottom:6px;color:#222;font-size:15px;font-weight:700;border-bottom:1px solid #333;text-align:left;}
/* 쿠폰존 — 사용처 배지 */
.coupon_content .cp_list_wrap .cp_list li .box_coupon .text_wrap .text_info .cp_use_badge{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;height:22px;padding:0 5px;border-radius:2px;margin-bottom:8px;font-size:12px;font-weight:700;line-height:1;letter-spacing:-0.02em;}
.coupon_content .cp_list_wrap .cp_list li .text_info .cp_use_badge.order{background:#555d87;color:#fff;}
.coupon_content .cp_list_wrap .cp_list li .text_info .cp_use_badge.prod{background:#eef2f6;color:#555;border:1px solid #d4dce4;}
.coupon_content .cp_list_wrap .cp_list li .box_coupon .text_wrap .text_info .date{margin-top:14px;vertical-align:top;}
/* 쿠폰 다운받기 레이어 */
.coupon-down-layer .view > p .goods-coupon-cnt{color:#fa2828;}
.coupon-down-layer .view .table1 .guide .coupon-benefit{color:#fa2828;}
.coupon-down-layer .table1 > table tbody td .completed.coupon-grade-limit{padding:0; background:none; color:#838383;}
 
data/skin/front/story_g/event/couponzone.html+8-2
변경 전couponzone.html
<div class="img_cp"><img src="{=couponConfig.pcCouponImagePath}" alt="쿠폰이미지" /></div>
<div class="text_wrap">
<div class="text_info">
 
 
 
 
 
<span class="tit">{..couponNm}</span>
<span class="dis">{..couponBenefit}</span>
<span class="txt">{..couponKindType}</span>
method: "POST",
cache: false,
url: "../mypage/coupon_ps.php",
data: "mode=couponDown&couponNo=" + couponNo,
dataType: 'json',
async: false,
success: function (data) {
var params = {
total: total,
couponNo: couponArrData,
mode: 'couponDownAll'
 
};
$.ajax({
method: "POST",
 
변경 후couponzone.html
<div class="img_cp"><img src="{=couponConfig.pcCouponImagePath}" alt="쿠폰이미지" /></div>
<div class="text_wrap">
<div class="text_info">
<!--{ ? ..couponUseTypeCode == 'order' }-->
<span class="cp_use_badge order">{=__('주문 적용')}</span>
<!--{ : ..couponUseTypeCode == 'product' }-->
<span class="cp_use_badge prod">{=__('상품 적용')}</span>
<!--{ / }-->
<span class="tit">{..couponNm}</span>
<span class="dis">{..couponBenefit}</span>
<span class="txt">{..couponKindType}</span>
method: "POST",
cache: false,
url: "../mypage/coupon_ps.php",
data: "mode=couponDown&couponNo=" + couponNo + "&couponToken=" + encodeURIComponent('{=couponToken}'),
dataType: 'json',
async: false,
success: function (data) {
var params = {
total: total,
couponNo: couponArrData,
mode: 'couponDownAll',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
 
data/skin/front/story_g/goods/layer_coupon_down.html+63-4
변경 전layer_coupon_down.html
<p>{=__('다운로드 가능한 총')} <strong class="goods-coupon-cnt"><!--{ goodsCouponCnt }-->{=__('개%s의 쿠폰이 있습니다.', '</strong>')}</p>
 
<div class="scroll-box">
 
 
<div class="table1">
<table>
<colgroup>
<!--<span class="coupon-icon">55,000<b>원</b></span>-->
</td>
<td class="guide">
<strong>{ convertCouponArrData[.key_].couponBenefit } { convertCouponArrData[.key_].couponKindType }</strong>
<div class="msg">
<!--{ ? convertCouponArrData[.key_].couponMaxBenefit }-->
<span>- { convertCouponArrData[.key_].couponMaxBenefit }</span>
</td>
<td class="ta-c">
<!--{ ? .chkMemberCoupon == 'NO_MEMBER_GROUP' }-->
<strong class="completed">{=__('해당 회원등급이 아닙니다.')}</strong>
<!--{ : .chkMemberCoupon == 'DUPLICATE_COUPON' }-->
<strong class="completed">{=__('발급완료')}</strong>
<!--{ : .chkMemberCoupon == 'YES' }-->
</tbody>
</table>
</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</div>
<div class="btn">
<button class="skinbtn point1 layer-close btn-close"><em>{=__('취소')}</em></button>
mode: 'coupon_down',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}'
 
};
$.ajax({
method: "POST",
mode: 'coupon_down_all',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}'
 
};
$.ajax({
method: "POST",
 
변경 후layer_coupon_down.html
<p>{=__('다운로드 가능한 총')} <strong class="goods-coupon-cnt"><!--{ goodsCouponCnt }-->{=__('개%s의 쿠폰이 있습니다.', '</strong>')}</p>
 
<div class="scroll-box">
<!--{ ? goodsCouponArrData }-->
<p class="coupon_section_tit">{=__('상품쿠폰')}</p>
<div class="table1">
<table>
<colgroup>
<!--<span class="coupon-icon">55,000<b>원</b></span>-->
</td>
<td class="guide">
<strong><span class="coupon-benefit">{ convertCouponArrData[.key_].couponBenefit }</span> { convertCouponArrData[.key_].couponKindType }</strong>
<div class="msg">
<!--{ ? convertCouponArrData[.key_].couponMaxBenefit }-->
<span>- { convertCouponArrData[.key_].couponMaxBenefit }</span>
</td>
<td class="ta-c">
<!--{ ? .chkMemberCoupon == 'NO_MEMBER_GROUP' }-->
<strong class="completed coupon-grade-limit">{=__('해당 회원등급이 아닙니다.')}</strong>
<!--{ : .chkMemberCoupon == 'DUPLICATE_COUPON' }-->
<strong class="completed">{=__('발급완료')}</strong>
<!--{ : .chkMemberCoupon == 'YES' }-->
</tbody>
</table>
</div>
<!--{ / }-->
<!--{ ? orderCouponArrData }-->
<p class="coupon_section_tit">{=__('주문쿠폰')}</p>
<div class="table1">
<table>
<colgroup>
<col style="width:151px"/>
<col/>
<col/>
</colgroup>
<thead>
<tr>
<th>{=__('쿠폰')}</th>
<th>{=__('혜택')}</th>
<th>{=__('다운받기')}</th>
</tr>
</thead>
<tbody>
<!--{ @ orderCouponArrData }-->
<tr>
<td class="ta-c">
<strong>{ .couponNm }</strong>
<!--<span class="coupon-icon">55,000<b>원</b></span>-->
</td>
<td class="guide">
<strong><span class="coupon-benefit">{ convertCouponArrData[.key_].couponBenefit }</span> { convertCouponArrData[.key_].couponKindType }</strong>
<div class="msg">
<!--{ ? convertCouponArrData[.key_].couponMaxBenefit }-->
<span>- { convertCouponArrData[.key_].couponMaxBenefit }</span>
<!--{ / }-->
<!--{ ? convertCouponArrData[.key_].couponMinOrderPrice }-->
<span>- { convertCouponArrData[.key_].couponMinOrderPrice }</span>
<!--{ / }-->
<span>- <!--{ convertCouponArrData[.key_].couponApplyDuplicateType }--></span>
</div>
</td>
<td class="ta-c">
<!--{ ? .chkMemberCoupon == 'NO_MEMBER_GROUP' }-->
<strong class="completed coupon-grade-limit">{=__('해당 회원등급이 아닙니다.')}</strong>
<!--{ : .chkMemberCoupon == 'DUPLICATE_COUPON' }-->
<strong class="completed">{=__('발급완료')}</strong>
<!--{ : .chkMemberCoupon == 'YES' }-->
<button class="normal-btn small1 btn-coupon-down" data-coupon-no="{ .couponNo }">
<em>{=__('쿠폰 다운받기')}<img class="down" src="../img/etc/down.png" alt="{=__('쿠폰 다운받기')}"/></em></button>
<div class="msg">
<span>(<!--{ convertCouponArrData[.key_].useEndDate }-->)</span>
</div>
<!--{ / }-->
</td>
</tr>
<!--{ / }-->
</tbody>
</table>
</div>
<!--{ / }-->
</div>
<div class="btn">
<button class="skinbtn point1 layer-close btn-close"><em>{=__('취소')}</em></button>
mode: 'coupon_down',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
mode: 'coupon_down_all',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
 
data/skin/mobile/moment/css/event/coupon.css+16
변경 전coupon.css
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
변경 후coupon.css
@charset "utf-8";
 
/* 쿠폰존 — 사용처 배지 */
.coupon_content .cp_list_wrap .cp_list li .text_wrap .text_info .cp_use_badge{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;height:20px;padding:0 4px;border-radius:2px;margin-bottom:3px;font-size:11px;font-weight:700;line-height:1;letter-spacing:-0.02em;}
.coupon_content .cp_list_wrap .cp_list li .text_wrap .text_info .cp_use_badge.order{background:#555d87;color:#fff;}
.coupon_content .cp_list_wrap .cp_list li .text_wrap .text_info .cp_use_badge.prod{background:#eef2f6;color:#555;border:1px solid #d4dce4;}
 
/* 쿠폰 다운받기 레이어 — 「상품쿠폰」/「주문쿠폰」 섹션 제목 */
.layer_coupon_down .coupon_down_list .coupon_section_tit {margin:14px 0 0; padding-bottom:5px; color:#222; font-size:14px; font-weight:700; border-bottom:1px solid #333;}
 
/* 쿠폰 다운받기 레이어 */
.layer_coupon_down .ly_content .coupondown .my_info ul li:nth-child(1) strong span{color:var(--primary-default);}
.layer_coupon_down .ly_content .coupon_down_list ul li .coupon_left dl dt strong{color:var(--primary-default);}
.layer_coupon_down .coupon_down_list .coupon_left dd .c_red{color:inherit;}
/* 쿠폰존 */
.coupon_content .cp_list_wrap .cp_list li .text_wrap .text_info .tit{height:auto; max-height:38px;}
 
data/skin/mobile/moment/css/event/event.css+1-1
변경 전event.css
.coupon_content .cp_list_wrap .btn_all{padding:0 15px;margin-top:7px;}
.coupon_content .cp_list_none{display:none; text-align:center;padding:65px 0 100px;}
.coupon_content .cp_list_none p{padding-top:102px;font-weight:700;font-size:15px;letter-spacing:-0.05em;color:#222;background:url('../../img/icon/bg_notice.png') no-repeat 50% 0;background-size:80px 80px;}
/* //쿠폰존 페이지 */
 
변경 후event.css
.coupon_content .cp_list_wrap .btn_all{padding:0 15px;margin-top:7px;}
.coupon_content .cp_list_none{display:none; text-align:center;padding:65px 0 100px;}
.coupon_content .cp_list_none p{padding-top:102px;font-weight:700;font-size:15px;letter-spacing:-0.05em;color:#222;background:url('../../img/icon/bg_notice.png') no-repeat 50% 0;background-size:80px 80px;}
/* //쿠폰존 페이지 */
 
data/skin/mobile/moment/event/couponzone.html+9-2
변경 전couponzone.html
{*** 쿠폰존 | event/couponzone.php ***}
{ # header }
 
<div class="coupon">
<!-- 20190522 추가 -->
<!-- 쿠폰존 -->
</div>
<div class="text_wrap">
<div class="text_info">
 
 
 
 
 
<span class="tit">{..couponNm}</span>
<span class="date">{..useEndDate}</span>
</div>
method: "POST",
cache: false,
url: "../mypage/coupon_ps.php",
data: "mode=couponDown&couponNo=" + couponNo,
dataType: 'json',
async: false,
success: function (data) {
var params = {
total: total,
couponNo: couponArrData,
mode: 'couponDownAll'
 
};
$.ajax({
method: "POST",
 
변경 후couponzone.html
{*** 쿠폰존 | event/couponzone.php ***}
{ # header }
<link type="text/css" rel="stylesheet" href="{=setBrowserCache('../css/event/coupon.css')}" />
<div class="coupon">
<!-- 20190522 추가 -->
<!-- 쿠폰존 -->
</div>
<div class="text_wrap">
<div class="text_info">
<!--{ ? ..couponUseTypeCode == 'order' }-->
<span class="cp_use_badge order">{=__('주문 적용')}</span>
<!--{ : ..couponUseTypeCode == 'product' }-->
<span class="cp_use_badge prod">{=__('상품 적용')}</span>
<!--{ / }-->
<span class="tit">{..couponNm}</span>
<span class="date">{..useEndDate}</span>
</div>
method: "POST",
cache: false,
url: "../mypage/coupon_ps.php",
data: "mode=couponDown&couponNo=" + couponNo + "&couponToken=" + encodeURIComponent('{=couponToken}'),
dataType: 'json',
async: false,
success: function (data) {
var params = {
total: total,
couponNo: couponArrData,
mode: 'couponDownAll',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
 
data/skin/mobile/moment/goods/layer_coupon_down.html+45-3
변경 전layer_coupon_down.html
{*** 쿠폰 다운받기 레이어 | goods/layer_coupon_down.php ***}
 
<div class="layer_coupon_down">
<div class="ly_head">
<h2 class="h_tit">{=__('쿠폰 다운받기')}</h2>
</ul>
</div>
<div class="coupon_down_list">
 
 
<ul>
<!--{ @ goodsCouponArrData }-->
<li>
<!--{ ? convertCouponArrData[.key_].couponMinOrderPrice }-->
<dd>{ convertCouponArrData[.key_].couponMinOrderPrice }</dd>
<!--{ / }-->
<!--{ convertCouponArrData[.key_].couponApplyDuplicateType }-->
<!--{ ? .chkMemberCoupon == 'YES' }-->
<dd><img src="../img/icon/icon_chk_red.png" alt="{=__('체크')}" class="chk_img"><span class="c_red"><!--{ convertCouponArrData[.key_].useEndDate }--></span></dd>
<!--{ / }-->
</li>
<!--{ / }-->
</ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</div>
</div>
</div>
mode: 'coupon_down',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}'
 
};
$.ajax({
method: "POST",
mode: 'coupon_down_all',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}'
 
};
$.ajax({
method: "POST",
 
변경 후layer_coupon_down.html
{*** 쿠폰 다운받기 레이어 | goods/layer_coupon_down.php ***}
<link type="text/css" rel="stylesheet" href="{=setBrowserCache('../css/event/coupon.css')}" />
<div class="layer_coupon_down">
<div class="ly_head">
<h2 class="h_tit">{=__('쿠폰 다운받기')}</h2>
</ul>
</div>
<div class="coupon_down_list">
<!--{ ? goodsCouponArrData }-->
<p class="coupon_section_tit">{=__('상품쿠폰')}</p>
<ul>
<!--{ @ goodsCouponArrData }-->
<li>
<!--{ ? convertCouponArrData[.key_].couponMinOrderPrice }-->
<dd>{ convertCouponArrData[.key_].couponMinOrderPrice }</dd>
<!--{ / }-->
<dd><!--{ convertCouponArrData[.key_].couponApplyDuplicateType }--></dd>
<!--{ ? .chkMemberCoupon == 'YES' }-->
<dd><img src="../img/icon/icon_chk_red.png" alt="{=__('체크')}" class="chk_img"><span class="c_red"><!--{ convertCouponArrData[.key_].useEndDate }--></span></dd>
<!--{ / }-->
</li>
<!--{ / }-->
</ul>
<!--{ / }-->
<!--{ ? orderCouponArrData }-->
<p class="coupon_section_tit">{=__('주문쿠폰')}</p>
<ul>
<!--{ @ orderCouponArrData }-->
<li>
<div class="coupon_left">
<dl>
<dt>{ .couponNm } <strong>{ convertCouponArrData[.key_].couponBenefit }</strong> { convertCouponArrData[.key_].couponKindType }</dt>
<!--{ ? convertCouponArrData[.key_].couponMaxBenefit }-->
<dd>{ convertCouponArrData[.key_].couponMaxBenefit }</dd>
<!--{ / }-->
<!--{ ? convertCouponArrData[.key_].couponMinOrderPrice }-->
<dd>{ convertCouponArrData[.key_].couponMinOrderPrice }</dd>
<!--{ / }-->
<dd><!--{ convertCouponArrData[.key_].couponApplyDuplicateType }--></dd>
<!--{ ? .chkMemberCoupon == 'YES' }-->
<dd><img src="../img/icon/icon_chk_red.png" alt="{=__('체크')}" class="chk_img"><span class="c_red"><!--{ convertCouponArrData[.key_].useEndDate }--></span></dd>
<!--{ / }-->
<!--{ ? .chkMemberCoupon == 'NO_MEMBER_GROUP' }-->
<dd>{=__('해당 회원등급이 아닙니다.')}</dd>
<!--{ / }-->
</dl>
</div>
<div class="coupon_right">
<!--{ ? .chkMemberCoupon == 'NO_MEMBER_GROUP' }-->
<span class="coupon_download_no_btn">{=__('발급불가')}</span>
<!--{ : .chkMemberCoupon == 'DUPLICATE_COUPON' }-->
<span class="coupon_download_ok_btn">{=__('발급완료')}</span>
<!--{ : .chkMemberCoupon == 'YES' }-->
<span><a class="coupon_download_btn btn_coupon_down" data-coupon-no="{ .couponNo }">{=__('다운로드')}</a></span>
<!--{ / }-->
</div>
</li>
<!--{ / }-->
</ul>
<!--{ / }-->
</div>
</div>
</div>
mode: 'coupon_down',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
mode: 'coupon_down_all',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
 
data/skin/mobile/mygreek/css/event/coupon.css+18
변경 전coupon.css
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
변경 후coupon.css
@charset "utf-8";
 
/* 쿠폰존 — 사용처 배지 */
.coupon_content .cp_list_wrap .cp_list li .text_wrap .text_info .cp_use_badge{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;height:20px;padding:0 4px;border-radius:2px;margin-bottom:3px;font-size:11px;font-weight:700;line-height:1;letter-spacing:-0.02em;}
.coupon_content .cp_list_wrap .cp_list li .text_wrap .text_info .cp_use_badge.order{background:#555d87;color:#fff;}
.coupon_content .cp_list_wrap .cp_list li .text_wrap .text_info .cp_use_badge.prod{background:#eef2f6;color:#555;border:1px solid #d4dce4;}
 
/* 쿠폰 다운받기 레이어 — 「상품쿠폰」/「주문쿠폰」 섹션 제목 */
.layer_coupon_down .coupon_down_list .coupon_section_tit {margin:14px 0 0; padding-bottom:5px; color:#222; font-size:14px; font-weight:700; border-bottom:1px solid #333;}
 
/* 쿠폰 다운받기 레이어 */
.layer_coupon_down .ly_content .coupondown .my_info ul li{vertical-align:middle;}
.layer_coupon_down .ly_content .coupondown .my_info ul li:nth-child(2){padding-bottom:0;}
.layer_coupon_down .ly_content .coupondown .my_info ul li:nth-child(1) strong span{color:var(--primary-default);}
.layer_coupon_down .ly_content .coupon_down_list ul li .coupon_left dl dt strong{color:var(--primary-default);}
.layer_coupon_down .ly_content .coupon_down_list ul li .coupon_left dl dd .chk_img{vertical-align:middle;}
/* 쿠폰존 */
.coupon_content .cp_list_wrap .cp_list li .text_wrap .text_info .tit{height:auto; max-height:38px;}
 
data/skin/mobile/mygreek/event/couponzone.html+9-2
변경 전couponzone.html
{*** 쿠폰존 | event/couponzone.php ***}
{ # header }
 
<div class="coupon">
<!-- 20190522 추가 -->
<!-- 쿠폰존 -->
</div>
<div class="text_wrap">
<div class="text_info">
 
 
 
 
 
<span class="tit">{..couponNm}</span>
<span class="date">{..useEndDate}</span>
</div>
method: "POST",
cache: false,
url: "../mypage/coupon_ps.php",
data: "mode=couponDown&couponNo=" + couponNo,
dataType: 'json',
async: false,
success: function (data) {
var params = {
total: total,
couponNo: couponArrData,
mode: 'couponDownAll'
 
};
$.ajax({
method: "POST",
 
변경 후couponzone.html
{*** 쿠폰존 | event/couponzone.php ***}
{ # header }
<link type="text/css" rel="stylesheet" href="{=setBrowserCache('../css/event/coupon.css')}" />
<div class="coupon">
<!-- 20190522 추가 -->
<!-- 쿠폰존 -->
</div>
<div class="text_wrap">
<div class="text_info">
<!--{ ? ..couponUseTypeCode == 'order' }-->
<span class="cp_use_badge order">{=__('주문 적용')}</span>
<!--{ : ..couponUseTypeCode == 'product' }-->
<span class="cp_use_badge prod">{=__('상품 적용')}</span>
<!--{ / }-->
<span class="tit">{..couponNm}</span>
<span class="date">{..useEndDate}</span>
</div>
method: "POST",
cache: false,
url: "../mypage/coupon_ps.php",
data: "mode=couponDown&couponNo=" + couponNo + "&couponToken=" + encodeURIComponent('{=couponToken}'),
dataType: 'json',
async: false,
success: function (data) {
var params = {
total: total,
couponNo: couponArrData,
mode: 'couponDownAll',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
 
data/skin/mobile/mygreek/goods/layer_coupon_down.html+45-3
변경 전layer_coupon_down.html
{*** 쿠폰 다운받기 레이어 | goods/layer_coupon_down.php ***}
 
<div class="layer_coupon_down">
<div class="ly_head">
<h2 class="h_tit">{=__('쿠폰 다운받기')}</h2>
</ul>
</div>
<div class="coupon_down_list">
 
 
<ul>
<!--{ @ goodsCouponArrData }-->
<li>
<!--{ ? convertCouponArrData[.key_].couponMinOrderPrice }-->
<dd>{ convertCouponArrData[.key_].couponMinOrderPrice }</dd>
<!--{ / }-->
<!--{ convertCouponArrData[.key_].couponApplyDuplicateType }-->
<!--{ ? .chkMemberCoupon == 'YES' }-->
<dd><img src="../img/icon/icon_chk_red.png" alt="{=__('체크')}" class="chk_img"><span class="c_red"><!--{ convertCouponArrData[.key_].useEndDate }--></span></dd>
<!--{ / }-->
</li>
<!--{ / }-->
</ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</div>
</div>
</div>
mode: 'coupon_down',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}'
 
};
$.ajax({
method: "POST",
mode: 'coupon_down_all',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}'
 
};
$.ajax({
method: "POST",
 
변경 후layer_coupon_down.html
{*** 쿠폰 다운받기 레이어 | goods/layer_coupon_down.php ***}
<link type="text/css" rel="stylesheet" href="{=setBrowserCache('../css/event/coupon.css')}" />
<div class="layer_coupon_down">
<div class="ly_head">
<h2 class="h_tit">{=__('쿠폰 다운받기')}</h2>
</ul>
</div>
<div class="coupon_down_list">
<!--{ ? goodsCouponArrData }-->
<p class="coupon_section_tit">{=__('상품쿠폰')}</p>
<ul>
<!--{ @ goodsCouponArrData }-->
<li>
<!--{ ? convertCouponArrData[.key_].couponMinOrderPrice }-->
<dd>{ convertCouponArrData[.key_].couponMinOrderPrice }</dd>
<!--{ / }-->
<dd><!--{ convertCouponArrData[.key_].couponApplyDuplicateType }--></dd>
<!--{ ? .chkMemberCoupon == 'YES' }-->
<dd><img src="../img/icon/icon_chk_red.png" alt="{=__('체크')}" class="chk_img"><span class="c_red"><!--{ convertCouponArrData[.key_].useEndDate }--></span></dd>
<!--{ / }-->
</li>
<!--{ / }-->
</ul>
<!--{ / }-->
<!--{ ? orderCouponArrData }-->
<p class="coupon_section_tit">{=__('주문쿠폰')}</p>
<ul>
<!--{ @ orderCouponArrData }-->
<li>
<div class="coupon_left">
<dl>
<dt>{ .couponNm } <strong>{ convertCouponArrData[.key_].couponBenefit }</strong> { convertCouponArrData[.key_].couponKindType }</dt>
<!--{ ? convertCouponArrData[.key_].couponMaxBenefit }-->
<dd>{ convertCouponArrData[.key_].couponMaxBenefit }</dd>
<!--{ / }-->
<!--{ ? convertCouponArrData[.key_].couponMinOrderPrice }-->
<dd>{ convertCouponArrData[.key_].couponMinOrderPrice }</dd>
<!--{ / }-->
<dd><!--{ convertCouponArrData[.key_].couponApplyDuplicateType }--></dd>
<!--{ ? .chkMemberCoupon == 'YES' }-->
<dd><img src="../img/icon/icon_chk_red.png" alt="{=__('체크')}" class="chk_img"><span class="c_red"><!--{ convertCouponArrData[.key_].useEndDate }--></span></dd>
<!--{ / }-->
<!--{ ? .chkMemberCoupon == 'NO_MEMBER_GROUP' }-->
<dd>{=__('해당 회원등급이 아닙니다.')}</dd>
<!--{ / }-->
</dl>
</div>
<div class="coupon_right">
<!--{ ? .chkMemberCoupon == 'NO_MEMBER_GROUP' }-->
<span class="coupon_download_no_btn">{=__('발급불가')}</span>
<!--{ : .chkMemberCoupon == 'DUPLICATE_COUPON' }-->
<span class="coupon_download_ok_btn">{=__('발급완료')}</span>
<!--{ : .chkMemberCoupon == 'YES' }-->
<span><a class="coupon_download_btn btn_coupon_down" data-coupon-no="{ .couponNo }">{=__('다운로드')}</a></span>
<!--{ / }-->
</div>
</li>
<!--{ / }-->
</ul>
<!--{ / }-->
</div>
</div>
</div>
mode: 'coupon_down',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
mode: 'coupon_down_all',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
 
data/skin/mobile/story_g/css/gd_contents.css+14
변경 전gd_contents.css
label.check_s[for="certificationDeleteSno"],
label.check_s[for^="comAddiCertDeleteSno"] { min-height: 23px; line-height: 23px;}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
변경 후gd_contents.css
label.check_s[for="certificationDeleteSno"],
label.check_s[for^="comAddiCertDeleteSno"] { min-height: 23px; line-height: 23px;}
 
 
/* 쿠폰 다운받기 레이어 — 「상품쿠폰」/「주문쿠폰」 섹션 제목 */
.coupondown .cp_bx .coupon_section_tit{margin:0 12px;padding:14px 0 7px;color:#222;font-size:14px;font-weight:700;background:#fff;border-bottom:1px solid #333;}
/* 쿠폰존 — 사용처 배지 */
.cp_list_wrap .cp_list li .text_info .cp_use_badge{display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;height:20px;padding:0 4px;border-radius:2px;margin-bottom:3px;font-size:11px;font-weight:700;line-height:1;letter-spacing:-0.02em;}
.cp_list_wrap .cp_list li .text_info .cp_use_badge.order{background:#555d87;color:#fff;}
.cp_list_wrap .cp_list li .text_info .cp_use_badge.prod{background:#eef2f6;color:#555;border:1px solid #d4dce4;}
/* 쿠폰 다운받기 레이어 */
.coupondown .cp_bx label .tit .c-red{color:#999999 !important;}
.coupondown .cp_bx label .sale:not(.disabled):not(.complete){background:var(--primary-default);}
.coupondown .cp_bx label .sale.complete{border-color:var(--primary-default); color:var(--primary-default);}
.coupondown .cp_bx li{margin:0 12px;}
/* 쿠폰존 */
.coupon_content .cp_list_wrap .cp_list li .text_wrap .text_info .tit{height:auto; max-height:38px;}
 
data/skin/mobile/story_g/event/couponzone.html+8-2
변경 전couponzone.html
</div>
<div class="text_wrap">
<div class="text_info">
 
 
 
 
 
<span class="tit">{..couponNm}</span>
<span class="date">{..useEndDate}</span>
</div>
method: "POST",
cache: false,
url: "../mypage/coupon_ps.php",
data: "mode=couponDown&couponNo=" + couponNo,
dataType: 'json',
async: false,
success: function (data) {
var params = {
total: total,
couponNo: couponArrData,
mode: 'couponDownAll'
 
};
$.ajax({
method: "POST",
 
변경 후couponzone.html
</div>
<div class="text_wrap">
<div class="text_info">
<!--{ ? ..couponUseTypeCode == 'order' }-->
<span class="cp_use_badge order">{=__('주문 적용')}</span>
<!--{ : ..couponUseTypeCode == 'product' }-->
<span class="cp_use_badge prod">{=__('상품 적용')}</span>
<!--{ / }-->
<span class="tit">{..couponNm}</span>
<span class="date">{..useEndDate}</span>
</div>
method: "POST",
cache: false,
url: "../mypage/coupon_ps.php",
data: "mode=couponDown&couponNo=" + couponNo + "&couponToken=" + encodeURIComponent('{=couponToken}'),
dataType: 'json',
async: false,
success: function (data) {
var params = {
total: total,
couponNo: couponArrData,
mode: 'couponDownAll',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
 
data/skin/mobile/story_g/goods/layer_coupon_down.html+55-3
변경 전layer_coupon_down.html
<a href="#" class="bn_logout" id="btnAllCouponDown">{=__('전체다운로드')}</a>
</div>
<div class="cp_bx">
 
 
<ul>
<!--{ @ goodsCouponArrData }-->
<li>
<!--{ convertCouponArrData[.key_].couponApplyDuplicateType }-->
 
<!--{ ? .chkMemberCoupon == 'YES' }-->
<br/> <img src="../img/icon/icon-check-red.png" alt="" class="icon-check-red"><span class="c-red"> <!--{ convertCouponArrData[.key_].useEndDate }--></span>
<!--{ / }-->
 
 
</li>
<!--{ / }-->
</ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</div>
</div>
<button type="button" class="bn_cls v2 ly_btn_close" ><span class="sp">{=__('닫기')}</span></button>
mode: 'coupon_down',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}'
 
};
$.ajax({
method: "POST",
mode: 'coupon_down_all',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}'
 
};
$.ajax({
method: "POST",
 
변경 후layer_coupon_down.html
<a href="#" class="bn_logout" id="btnAllCouponDown">{=__('전체다운로드')}</a>
</div>
<div class="cp_bx">
<!--{ ? goodsCouponArrData }-->
<p class="coupon_section_tit">{=__('상품쿠폰')}</p>
<ul>
<!--{ @ goodsCouponArrData }-->
<li>
<!--{ convertCouponArrData[.key_].couponApplyDuplicateType }-->
 
<!--{ ? .chkMemberCoupon == 'YES' }-->
<br/> <img src="../img/icon/icon-check-black.png" alt="" class="icon-check-red"><span class="c-red"> <!--{ convertCouponArrData[.key_].useEndDate }--></span>
<!--{ / }-->
 
 
</li>
<!--{ / }-->
</ul>
<!--{ / }-->
<!--{ ? orderCouponArrData }-->
<p class="coupon_section_tit">{=__('주문쿠폰')}</p>
<ul>
<!--{ @ orderCouponArrData }-->
<li>
<label for="cp1">
<span class="tit">
 
{ .couponNm }
<strong>{ convertCouponArrData[.key_].couponBenefit }</strong> { convertCouponArrData[.key_].couponKindType }<br/>
<span>
<!--{ ? convertCouponArrData[.key_].couponMaxBenefit }-->
{ convertCouponArrData[.key_].couponMaxBenefit }<br/>
<!--{ / }-->
<!--{ ? convertCouponArrData[.key_].couponMinOrderPrice }-->
{ convertCouponArrData[.key_].couponMinOrderPrice }<br/>
<!--{ / }-->
<!--{ convertCouponArrData[.key_].couponApplyDuplicateType }-->
 
<!--{ ? .chkMemberCoupon == 'YES' }-->
<br/> <img src="../img/icon/icon-check-black.png" alt="" class="icon-check-red"><span class="c-red"> <!--{ convertCouponArrData[.key_].useEndDate }--></span>
<!--{ / }-->
 
 
<!--{ ? .chkMemberCoupon == 'NO_MEMBER_GROUP' }-->
<br/> {=__('해당 회원등급이 아닙니다.')}
<!--{ / }-->
 
</span>
</span>
<!--{ ? .chkMemberCoupon == 'NO_MEMBER_GROUP' }-->
<span class="sale disabled">
{=__('발급불가')}
<!--{ : .chkMemberCoupon == 'DUPLICATE_COUPON' }-->
<span class="sale complete">
{=__('발급완료')}
<!--{ : .chkMemberCoupon == 'YES' }-->
<span class="sale ">
<a class="btn-coupon-down" data-coupon-no="{ .couponNo }"><em>{=__('다운로드')}</em></a>
<!--{ / }-->
 
</span>
</label>
</li>
<!--{ / }-->
</ul>
<!--{ / }-->
</div>
</div>
<button type="button" class="bn_cls v2 ly_btn_close" ><span class="sp">{=__('닫기')}</span></button>
mode: 'coupon_down',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
mode: 'coupon_down_all',
goodsNo: '{goodsNo}',
scmNo: '{scmNo}',
brandCd: '{brandCd}',
couponToken: '{=couponToken}'
};
$.ajax({
method: "POST",
 
data/skin/mobile/story_g/img/icon/icon-check-black.png
변경 전icon-check-black.png
Binary files /dev/null and b/user/data/skin/mobile/story_g/img/icon/icon-check-black.png differ
 
변경 후icon-check-black.png
Binary files /dev/null and b/user/data/skin/mobile/story_g/img/icon/icon-check-black.png differ
 
14세 이상 연령 동의 항목 추가
Admin/member/_member_view.php+4
변경 전_member_view.php
</td>
</tr>
<?php endif; ?>
 
 
 
 
<tr>
<th>이메일</th>
<td>
 
변경 후_member_view.php
</td>
</tr>
<?php endif; ?>
<tr>
<th>만 14세 이상 가입동의</th>
<td colspan="3"><?= $data['under14ConsentText'] ?? '-' ?></td>
</tr>
<tr>
<th>이메일</th>
<td>
 
Component/Member/Util/MemberUtil.php+21
변경 전MemberUtil.php
return $items;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 회원 약관 동의 표시용 행 데이터 생성. 약관 행 설정 배열을 받아 뷰에서 그대로 출력할 표시용 배열을 반환한다 (HTML 미생성 — 마크업은 뷰가 담당).
* 약관이 늘어도 호출부에서 배열 항목만 추가하면 되고 메서드 시그니처는 불변.
 
변경 후MemberUtil.php
return $items;
}
 
/**
* 회원정보 '만 14세 이상 가입동의' 표시값. 현재 가입연령제한·동의항목 사용 설정과 무관하게 회원 동의값으로 노출하고, 승인제 상점은 승인일·비승인제는 가입일을 동의일로 본다.
*
* @param array $memberData 회원 데이터 (under14ConsentFl 'y'/'n', approvalDt 가입승인일, entryDt 가입일)
* @param array $joinPolicy 회원가입 정책 (appUseFl 가입승인 'y'/'n'/'company')
* @return string '동의 {일시}' / '동의'(일시 없음) / '-'(미노출)
*/
public static function buildUnder14ConsentText(array $memberData, array $joinPolicy): string
{
if (($memberData['under14ConsentFl'] ?? 'n') !== 'y') {
return '-';
}
$useApprovalDt = in_array($joinPolicy['appUseFl'] ?? 'n', ['y', 'company'], true);
$consentDt = $useApprovalDt ? ($memberData['approvalDt'] ?? '') : ($memberData['entryDt'] ?? '');
if (empty($consentDt) || $consentDt === '0000-00-00 00:00:00') {
return '동의';
}
 
return '동의 ' . $consentDt;
}
 
/**
* 회원 약관 동의 표시용 행 데이터 생성. 약관 행 설정 배열을 받아 뷰에서 그대로 출력할 표시용 배열을 반환한다 (HTML 미생성 — 마크업은 뷰가 담당).
* 약관이 늘어도 호출부에서 배열 항목만 추가하면 되고 메서드 시그니처는 불변.
 
Controller/Admin/Member/MemberModifyController.php+1
변경 전MemberModifyController.php
$memberData = gd_array_merge($memberData, $historyService->getLastReceiveAgreementByMember($memNo));
// 마케팅 목적 개인정보 수집 및 이용 동의/거부일 (없으면 '-')
$memberData['privateMktAgreementDt'] = $memberData['lastReceiveAgreementDt']['privateMkt'] ?? '-';
 
$memberHistory = $historyService->getMemberHistory($memNo, $request->get()->get('page', 1), $request->get()->get('pageNum', 10));
$memberData['recommendCnt'] = $memberService->getRecommendCount($memberData['memId']);
if ($memberData['rncheck'] == 'realname') {
 
변경 후MemberModifyController.php
$memberData = gd_array_merge($memberData, $historyService->getLastReceiveAgreementByMember($memNo));
// 마케팅 목적 개인정보 수집 및 이용 동의/거부일 (없으면 '-')
$memberData['privateMktAgreementDt'] = $memberData['lastReceiveAgreementDt']['privateMkt'] ?? '-';
$memberData['under14ConsentText'] = \Component\Member\Util\MemberUtil::buildUnder14ConsentText($memberData, gd_policy('member.join'));
$memberHistory = $historyService->getMemberHistory($memNo, $request->get()->get('page', 1), $request->get()->get('pageNum', 10));
$memberData['recommendCnt'] = $memberService->getRecommendCount($memberData['memId']);
if ($memberData['rncheck'] == 'realname') {
 
Controller/Admin/Member/MemberPsController.php+13-12
변경 전MemberPsController.php
throw new LayerException(__('재가입 불가 기간은 1~365일 사이에서 설정해야 합니다.'));
}
 
if ($policy->saveMemberJoin($request->post()->all())) {
if ($joinPolicyService->isRejoinEnabled($requestAllParams['rejoinFl']) === false) {
$this->json([
'messages' => [
__('탈퇴/재가입 설정 사용안함 시 탈퇴회원의 재가입이 허용됩니다.'),
__('저장이 완료되었습니다.')
]
]);
} else {
$this->json(__('저장이 완료되었습니다.'));
}
} else {
throw new Exception(__('처리중에 오류가 발생하여 실패되었습니다.'));
}
 
 
 
 
 
 
 
 
 
 
 
 
} catch (Exception $e) {
if ($request->isAjax()) {
throw $e;
 
변경 후MemberPsController.php
throw new LayerException(__('재가입 불가 기간은 1~365일 사이에서 설정해야 합니다.'));
}
 
if (!$policy->saveMemberJoin($request->post()->all())) {
 
 
 
 
 
 
 
 
 
 
 
throw new Exception(__('처리중에 오류가 발생하여 실패되었습니다.'));
}
$kakaoSyncSettingService = \App::getInstance(KakaoSyncSettingService::class);
$kakaoSyncSettingService->syncSettingWhenSaveMemberJoinPolicy();
if (!$joinPolicyService->isRejoinEnabled($requestAllParams['rejoinFl'])) {
$this->json([
'messages' => [
__('탈퇴/재가입 설정 사용안함 시 탈퇴회원의 재가입이 허용됩니다.'),
__('저장이 완료되었습니다.')
]
]);
} else {
$this->json(__('저장이 완료되었습니다.'));
}
} catch (Exception $e) {
if ($request->isAjax()) {
throw $e;
 
Controller/Admin/Member/MemberRegisterController.php+1
변경 전MemberRegisterController.php
$member = $vo->toArray();
$member['cellPhoneCountryCode'] = 'kr';
$member['phoneCountryCode'] = 'kr';
 
 
// 사업자 등록증 조회
$companyCertification = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
 
변경 후MemberRegisterController.php
$member = $vo->toArray();
$member['cellPhoneCountryCode'] = 'kr';
$member['phoneCountryCode'] = 'kr';
$member['under14ConsentText'] = MemberUtil::buildUnder14ConsentText($member, gd_policy('member.join'));
 
// 사업자 등록증 조회
$companyCertification = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
 
Controller/Admin/Share/MemberCrmDetailController.php+1
변경 전MemberCrmDetailController.php
];
// 마케팅 목적 개인정보 수집 및 이용 동의/거부일 (없으면 '-')
$memberData['privateMktAgreementDt'] = $memberData['lastReceiveAgreementDt']['privateMkt'] ?? '-';
 
 
// 하이픈 제거
$memberData['fax'] = str_replace("-", "", $memberData['fax']);
 
변경 후MemberCrmDetailController.php
];
// 마케팅 목적 개인정보 수집 및 이용 동의/거부일 (없으면 '-')
$memberData['privateMktAgreementDt'] = $memberData['lastReceiveAgreementDt']['privateMkt'] ?? '-';
$memberData['under14ConsentText'] = MemberUtil::buildUnder14ConsentText($memberData, gd_policy('member.join'));
 
// 하이픈 제거
$memberData['fax'] = str_replace("-", "", $memberData['fax']);
 
쿠폰 웹훅 기능 추가
Component/Coupon/CouponAdmin.php+61-1
변경 전CouponAdmin.php
use Framework\Utility\ProducerUtils;
use Globals;
use Origin\Enum\ApiClient\Notification\SmsPersonalInfoAccessLogEventType;
 
use Request;
use Session;
use UserFilePath;
$result = $this->db->set_update_db(DB_COUPON, $arrBind['param'], 'couponNo = ?', $arrBind['bind'], false);
if ($result > 0) {
echo json_encode(['result' => 'ok', 'msg' => __('쿠폰 발급상태가 변경되었습니다.')]);
 
} else {
echo json_encode(['result' => 'fail', 'msg' => __('다시 시도해 주세요.')]);
}
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 쿠폰 삭제하기
*
$couponField = ['imageStorage', 'couponImage'];
$deletedCouponData = $this->getCouponInfo($couponNo, gd_implode(',', $couponField));
 
 
 
 
$arrBind = [
'i',
$couponNo,
];
// --- 삭제
$this->db->set_delete_db(DB_COUPON, 'couponNo = ?', $arrBind);
 
 
 
 
// 이미지 삭제
if (gd_isset($deletedCouponData['imageStorage']) && $deletedCouponData['imageStorage'] == 'obs') {
 
throw new \Exception(__('쿠폰 등록에 실패하였습니다. 고객센터에 문의해주세요.'));
}
 
 
break;
}
case 'modify' : {
throw new \Exception(__('쿠폰 수정에 실패하였습니다. 고객센터에 문의해주세요.'));
}
 
 
 
// 이미지를 새롭게 등록하는 경우, 기존 OBS 이미지 삭제
if ($isImageUploaded && gd_isset($couponDataBeforeUpdate['imageStorage']) && gd_isset($couponDataBeforeUpdate['couponImage'])) {
$this->deleteCouponImage($couponDataBeforeUpdate['imageStorage'], $couponDataBeforeUpdate['couponImage']);
 
throw new \Exception(__('오프라인 쿠폰 등록에 실패하였습니다. 고객센터에 문의해주세요.'));
}
 
 
break;
}
case 'modify' : {
throw new \Exception(__('오프라인 쿠폰 수정에 실패하였습니다. 고객센터에 문의해주세요.'));
}
 
 
 
// 이미지를 새롭게 등록하는 경우, 기존 OBS 이미지 삭제
if ($isImageUploaded && gd_isset($couponDataBeforeUpdate['imageStorage']) && gd_isset($couponDataBeforeUpdate['couponImage'])) {
$this->deleteCouponImage($couponDataBeforeUpdate['imageStorage'], $couponDataBeforeUpdate['couponImage']);
 
변경 후CouponAdmin.php
use Framework\Utility\ProducerUtils;
use Globals;
use Origin\Enum\ApiClient\Notification\SmsPersonalInfoAccessLogEventType;
use Origin\Service\WebHook\PromotionWebHookService;
use Request;
use Session;
use UserFilePath;
$result = $this->db->set_update_db(DB_COUPON, $arrBind['param'], 'couponNo = ?', $arrBind['bind'], false);
if ($result > 0) {
echo json_encode(['result' => 'ok', 'msg' => __('쿠폰 발급상태가 변경되었습니다.')]);
$this->sendCouponSavedWebHook($arrData['couponNo'], 'UPDATED');
} else {
echo json_encode(['result' => 'fail', 'msg' => __('다시 시도해 주세요.')]);
}
}
 
/**
* 쿠폰 등록/수정 웹훅 발송
*
* @param int|string $couponNo 쿠폰번호
* @param string $actionType 'CREATED' | 'UPDATED'
*
* @return void
*/
protected function sendCouponSavedWebHook($couponNo, string $actionType)
{
try {
$couponData = $this->getCouponInfo($couponNo, 'couponNm, couponKind, couponSaveType, couponType, couponUseType');
$promotionWebHookService = \App::getInstance(PromotionWebHookService::class);
$promotionWebHookService->sendCouponUpdatedWebHook((int)$couponNo, $actionType, $couponData);
} catch (\Throwable $e) {
\App::getInstance('logger')->channel('coupon')->warning(__METHOD__ . ' 쿠폰 등록/수정 웹훅 발송 실패', [
'couponNo' => $couponNo,
'actionType' => $actionType,
'exception' => $e,
]);
}
}
 
/**
* 쿠폰 삭제 웹훅 발송
*
* @param int|string $couponNo 쿠폰번호
* @param array $deletedCouponData 삭제 전 조회한 쿠폰 정보
*
* @return void
*/
protected function sendCouponDeletedWebHook($couponNo, $deletedCouponData)
{
try {
$promotionWebHookService = \App::getInstance(PromotionWebHookService::class);
$promotionWebHookService->sendCouponUpdatedWebHook((int)$couponNo, 'DELETED', $deletedCouponData);
} catch (\Throwable $e) {
\App::getInstance('logger')->channel('coupon')->warning(__METHOD__ . ' 쿠폰 삭제 웹훅 발송 실패', [
'couponNo' => $couponNo,
'exception' => $e,
]);
}
}
 
/**
* 쿠폰 삭제하기
*
$couponField = ['imageStorage', 'couponImage'];
$deletedCouponData = $this->getCouponInfo($couponNo, gd_implode(',', $couponField));
 
// 삭제 후에는 행이 없어 웹훅 발송용 정보를 삭제 전에 조회
$couponWebHookData = $this->getCouponInfo($couponNo, 'couponNm, couponKind, couponSaveType, couponType, couponUseType');
 
$arrBind = [
'i',
$couponNo,
];
// --- 삭제
$deletedCount = $this->db->set_delete_db(DB_COUPON, 'couponNo = ?', $arrBind);
if ($deletedCount > 0) {
$this->sendCouponDeletedWebHook($couponNo, $couponWebHookData);
}
 
// 이미지 삭제
if (gd_isset($deletedCouponData['imageStorage']) && $deletedCouponData['imageStorage'] == 'obs') {
 
throw new \Exception(__('쿠폰 등록에 실패하였습니다. 고객센터에 문의해주세요.'));
}
 
$this->sendCouponSavedWebHook($couponNo, 'CREATED');
break;
}
case 'modify' : {
throw new \Exception(__('쿠폰 수정에 실패하였습니다. 고객센터에 문의해주세요.'));
}
 
$this->sendCouponSavedWebHook($couponNo, 'UPDATED');
 
// 이미지를 새롭게 등록하는 경우, 기존 OBS 이미지 삭제
if ($isImageUploaded && gd_isset($couponDataBeforeUpdate['imageStorage']) && gd_isset($couponDataBeforeUpdate['couponImage'])) {
$this->deleteCouponImage($couponDataBeforeUpdate['imageStorage'], $couponDataBeforeUpdate['couponImage']);
 
throw new \Exception(__('오프라인 쿠폰 등록에 실패하였습니다. 고객센터에 문의해주세요.'));
}
 
$this->sendCouponSavedWebHook($couponNo, 'CREATED');
break;
}
case 'modify' : {
throw new \Exception(__('오프라인 쿠폰 수정에 실패하였습니다. 고객센터에 문의해주세요.'));
}
 
$this->sendCouponSavedWebHook($couponNo, 'UPDATED');
 
// 이미지를 새롭게 등록하는 경우, 기존 OBS 이미지 삭제
if ($isImageUploaded && gd_isset($couponDataBeforeUpdate['imageStorage']) && gd_isset($couponDataBeforeUpdate['couponImage'])) {
$this->deleteCouponImage($couponDataBeforeUpdate['imageStorage'], $couponDataBeforeUpdate['couponImage']);
 
Component/Coupon/Coupon.php+36
변경 전Coupon.php
use Globals;
use Request;
use Session;
 
 
/**
* Coupon Class
$this->db->bind_param_push($arrBind['bind'], 'i', $arrData['couponNo']);
$this->db->set_update_db(DB_COUPON, $arrBind['param'], 'couponNo = ?', $arrBind['bind'], false);
$logger->info(sprintf(__('쿠폰 사용가능 상태 변경 couponNo [%1$s] date [%2$s] '), $arrData['couponNo'], $now) . Request::getReferer());
 
}
if(!$return && $couponType != 'f') {
$arrData['couponType'] = 'f';
$this->db->bind_param_push($arrBind['bind'], 'i', $arrData['couponNo']);
$this->db->set_update_db(DB_COUPON, $arrBind['param'], 'couponNo = ?', $arrBind['bind'], false);
$logger->info(sprintf(__('쿠폰 발급종료 상태 변경 [%1$s] couponNo [%2$s] date [%3$s] '), $msg, $arrData['couponNo'], $now) . Request::getReferer());
 
if ($couponIssuedQuantityCheck) {
$return = true;
}
return $return;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public function checkCouponTypeArr($couponNoArr)
{
if(!is_array($couponNoArr)) $couponNoArr = explode(INT_DIVISION, $couponNoArr);
 
변경 후Coupon.php
use Globals;
use Request;
use Session;
use Origin\Service\WebHook\PromotionWebHookService;
 
/**
* Coupon Class
$this->db->bind_param_push($arrBind['bind'], 'i', $arrData['couponNo']);
$this->db->set_update_db(DB_COUPON, $arrBind['param'], 'couponNo = ?', $arrBind['bind'], false);
$logger->info(sprintf(__('쿠폰 사용가능 상태 변경 couponNo [%1$s] date [%2$s] '), $arrData['couponNo'], $now) . Request::getReferer());
$this->sendCouponStatusChangedWebHook($couponNo, $coupon, $arrData['couponType']);
}
if(!$return && $couponType != 'f') {
$arrData['couponType'] = 'f';
$this->db->bind_param_push($arrBind['bind'], 'i', $arrData['couponNo']);
$this->db->set_update_db(DB_COUPON, $arrBind['param'], 'couponNo = ?', $arrBind['bind'], false);
$logger->info(sprintf(__('쿠폰 발급종료 상태 변경 [%1$s] couponNo [%2$s] date [%3$s] '), $msg, $arrData['couponNo'], $now) . Request::getReferer());
$this->sendCouponStatusChangedWebHook($couponNo, $coupon, $arrData['couponType']);
if ($couponIssuedQuantityCheck) {
$return = true;
}
return $return;
}
 
/**
* 발급상태 자동 전환 웹훅 발송
*
* checkCouponType() 은 현재 상태와 무관하게 UPDATE 를 재실행하므로
* 실제로 값이 바뀌는 경우에만 발송해 프론트 요청마다 중복 발행되는 것을 막는다.
* 웹훅 필드는 checkCouponType() 의 공용 조회에 섞지 않고 상태가 바뀐 때만 따로 조회하며,
* 웹훅 실패가 발급 가능 여부 판정을 막지 않도록 예외는 로그만 남긴다.
*
* @param int|string $couponNo 쿠폰번호
* @param array|mixed $coupon 변경 전 쿠폰 정보 (발급상태 비교용)
* @param string|mixed $changedCouponType 변경된 발급상태
*
* @return void
*/
protected function sendCouponStatusChangedWebHook($couponNo, $coupon, $changedCouponType)
{
try {
$beforeCouponType = is_array($coupon) ? ($coupon['couponType'] ?? '') : '';
if ($beforeCouponType === (string)$changedCouponType) {
return;
}
 
$couponData = $this->getCouponInfo($couponNo, 'couponNm, couponKind, couponSaveType, couponType, couponUseType');
$promotionWebHookService = \App::getInstance(PromotionWebHookService::class);
$promotionWebHookService->sendCouponUpdatedWebHook((int)$couponNo, 'UPDATED', $couponData);
} catch (\Throwable $e) {
\App::getInstance('logger')->channel('coupon')->warning(__METHOD__ . ' 쿠폰 발급상태 변경 웹훅 발송 실패', [
'couponNo' => $couponNo,
'exception' => $e,
]);
}
}
 
public function checkCouponTypeArr($couponNoArr)
{
if(!is_array($couponNoArr)) $couponNoArr = explode(INT_DIVISION, $couponNoArr);
 
SMS 발송 세팅 현황 안내 추가
Admin/member/sms_auto.php+17
변경 전sms_auto.php
</div>
</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<div class="table-title gd-help-manual">
SMS 발송 정보 설정
</div>
 
변경 후sms_auto.php
</div>
</div>
 
<?php if (isset($smsSendSettingItems)): ?>
<div class="design-notice-box mgb20 sms-send-setting-status">
<strong>원활한 SMS 발송을 위해서는 아래 항목이 모두 <span class="sms-send-setting-completed">완료</span>로 표기되어야 합니다.</strong>
<ul class="sms-send-setting-list">
<?php foreach ($smsSendSettingItems as $smsSendSettingItem): ?>
<li>
<?= gd_htmlspecialchars($smsSendSettingItem['name']) ?> :
<span class="<?= gd_htmlspecialchars($smsSendSettingItem['statusClass'] ?? '') ?>"><?= gd_htmlspecialchars($smsSendSettingItem['statusText']) ?></span>
</li>
<?php endforeach; ?>
<?php if (!empty($smsSendSettingGuideUrl)): ?>
<li>상세 항목별 설정 방법은 <a href="<?= gd_htmlspecialchars($smsSendSettingGuideUrl) ?>" target="_blank" rel="noopener noreferrer" class="sms-send-setting-guide-link">SMS 발송 설정 가이드</a> 를 확인해주세요.</li>
<?php endif; ?>
</ul>
</div>
<?php endif; ?>
 
<div class="table-title gd-help-manual">
SMS 발송 정보 설정
</div>
 
Controller/Admin/Member/SmsAutoController.php+3
변경 전SmsAutoController.php
/** @var SmsManageCallNumberService $smsManageCallNumberService */
$smsManageCallNumberService = \App::getInstance(SmsManageCallNumberService::class);
$hasRegisteredCallNumber = $smsManageCallNumberService->hasRegisteredCallNumber();
 
 
$checked = $smsAutoData['checked'];
 
$this->setData('smsAutoData', gd_htmlspecialchars($smsAutoData));
$this->setData('checked', gd_isset($checked));
$this->setData('hasRegisteredCallNumber', $hasRegisteredCallNumber);
 
$this->setData('policy', ComponentUtils::getPolicy('sms.sms080'));
$this->setData('memberJoin', ComponentUtils::getPolicy('member.join'));
$this->setData('useApprovalFlag', ($memberJoin['appUseFl'] != 'n' || $memberJoin['under14Fl'] == 'y'));
$this->setData('commerceSmsIntroUrl', ConfigUrlUtils::getNhnCommerceMyGodoUrl('sms-intro'));
$this->setData('commerceShopMainUrl', ConfigUrlUtils::getNhnCommerceMyGodoUrl('shop-main'));
$this->setData('commerceSmsRefusalIntroUrl', ConfigUrlUtils::getNhnCommerceEchostUrl('sms-refusal-intro'));
 
}
}
 
변경 후SmsAutoController.php
/** @var SmsManageCallNumberService $smsManageCallNumberService */
$smsManageCallNumberService = \App::getInstance(SmsManageCallNumberService::class);
$hasRegisteredCallNumber = $smsManageCallNumberService->hasRegisteredCallNumber();
$smsSendSettingItems = $smsManageCallNumberService->getSendSettingStatusItems();
 
$checked = $smsAutoData['checked'];
 
$this->setData('smsAutoData', gd_htmlspecialchars($smsAutoData));
$this->setData('checked', gd_isset($checked));
$this->setData('hasRegisteredCallNumber', $hasRegisteredCallNumber);
$this->setData('smsSendSettingItems', $smsSendSettingItems);
$this->setData('policy', ComponentUtils::getPolicy('sms.sms080'));
$this->setData('memberJoin', ComponentUtils::getPolicy('member.join'));
$this->setData('useApprovalFlag', ($memberJoin['appUseFl'] != 'n' || $memberJoin['under14Fl'] == 'y'));
$this->setData('commerceSmsIntroUrl', ConfigUrlUtils::getNhnCommerceMyGodoUrl('sms-intro'));
$this->setData('commerceShopMainUrl', ConfigUrlUtils::getNhnCommerceMyGodoUrl('shop-main'));
$this->setData('commerceSmsRefusalIntroUrl', ConfigUrlUtils::getNhnCommerceEchostUrl('sms-refusal-intro'));
$this->setData('smsSendSettingGuideUrl', $smsManageCallNumberService->getSendSettingGuideUrl());
}
}
 
카카오 회원 가입 팝업 처리 개선
Component/Member/PageAccess.php+15
변경 전PageAccess.php
'guest' => '0',
'intro' => 'x',
],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
'kakao/kakaoo_login.php' => [
'member' => '0',
'guest' => '0',
 
변경 후PageAccess.php
'guest' => '0',
'intro' => 'x',
],
'member/kakao_sync.php' => [
'member' => 'x',
'guest' => '0',
'intro' => 'x',
],
'member/kakao_connect.php' => [
'member' => 'x',
'guest' => '0',
'intro' => 'x',
],
'member/kakao_connect_ps.php' => [
'member' => 'x',
'guest' => '0',
'intro' => 'x',
],
'kakao/kakaoo_login.php' => [
'member' => '0',
'guest' => '0',
 
최신 iOS Safari 환경 네이버페이(주문형) 이동 안정성 개선
Controller/Front/Goods/NaverPayController.php+11-12
변경 전NaverPayController.php
?>
<html>
<body>
<form name="frm" method="get" action="<?= $redirectUrl ?>">
</form>
</body>
<?php echo $fbScript; ?>
<script>
<?php if(\Request::isMobileDevice()){ ?>
<?php if($naverPayConfig['mobileButtonTarget'] == 'new') {?>
document.frm.target = "_blank";
<?php }
else {?>
document.frm.target = "_top";
<?php }?>
document.frm.submit();
<?php }else{ ?>
document.frm.submit();
 
<?php } ?>
window.onpageshow = function(event) {
/**
 
변경 후NaverPayController.php
?>
<html>
<body>
 
 
</body>
<?php echo $fbScript; ?>
<script>
/**
* iOS Safari ITP 대응: 폼 자동 submit 대신 location.replace로 최상위 이동
* (최상위 내비게이션은 ITP 차단 대상이 아니라 이동 끊김이 줄어듬)
* 페이스북 픽셀($fbScript)은 측정 유지를 위해 이동 직전에 먼저 출력
*/
<?php if (\Request::isMobileDevice() && $naverPayConfig['mobileButtonTarget'] === 'new') { ?>
window.open("<?= $redirectUrl ?>"); // 모바일 '새 창' 설정
<?php } elseif (\Request::isMobileDevice()) { ?>
window.top.location.replace("<?= $redirectUrl ?>"); // 모바일 _top 이동
<?php } else { ?>
location.replace("<?= $redirectUrl ?>"); // PC 현재 창 이동
<?php } ?>
window.onpageshow = function(event) {
/**
 
예치금·마일리지 포함 주문 환불 처리 안정성 개선
Admin/order/refund_do_new.php+6-3
변경 전refund_do_new.php
if ($(this).val() == '') {
$(this).val(0);
}
if ($.isNumeric($(this).val())) {
refundPriceSum += parseInt($(this).val());
lessEachRefund = lessRefundPrice + parseInt($(this).val());
 
 
 
} else {
$(this).focus();
}
 
변경 후refund_do_new.php
if ($(this).val() == '') {
$(this).val(0);
}
// 콤마만 제거한 값으로 합계 검증 - 콤마 포함 값은 $.isNumeric 을 우회해 그대로 전송된다.
// (소수점은 제거하지 않는다 - decimal "75900.00" 의 소수점을 지우면 ×100)
var refundPriceVal = String($(this).val()).replace(/,/g, '');
if ($.isNumeric(refundPriceVal)) {
refundPriceSum += parseInt(refundPriceVal);
lessEachRefund = lessRefundPrice + parseInt(refundPriceVal);
} else {
$(this).focus();
}
 
Component/Order/ReOrderCalculation.php+68
변경 전ReOrderCalculation.php
{
use CommonLogStorageTrait; // 공용 로그 저장
 
 
 
 
/**
* @var null|object 디비 접속
*/
}
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public function setRefundCompleteOrderGoodsNew($getData, $autoProcess = false, $userHandleFl = false)
{
$goods = \App::load(\Component\Goods\Goods::class);
$orderAdmin = App::load(\Component\Order\OrderAdmin::class);
 
 
 
 
 
 
 
 
 
// 환불수단에 맞지않는 금액값이 넘어오면 리턴처리
if ($getData['info']['refundMethod'] == '현금환불') {
if ($getData['info']['completePgPrice'] > 0 || $getData['info']['completeDepositPrice'] > 0 || $getData['info']['completeMileagePrice'] > 0) {
}
$checkDivisionVal = 0;
do {
 
foreach ($arrayData as $k => $v) {
if ($checkKey != '') {
if (isset($v['orderDeliverySno']) && $checkKey != '' && $checkKey != $v['orderDeliverySno']) {
}
}
}
 
 
 
 
 
 
 
 
 
 
 
 
} while ($checkDivisionVal == 0);
}
 
$checkDivisionVal = 1;
 
do {
 
 
 
// free supply vat 순으로 체크하면서 오버되면 재분배
if ($orgTotalData['realTaxFreePrice'] < $tempTaxFreeSum) { // 환불 업데이트 free 합계값이 오버인경우
// 오버값
$checkDivisionVal = 0;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
} while ($checkDivisionVal == 1);
 
return [$updateDeliveryData, $refundDeliveryData];
 
변경 후ReOrderCalculation.php
{
use CommonLogStorageTrait; // 공용 로그 저장
 
// 환불 방법 설정의 결제수단별 완료 환불 금액 입력 키 (산술 처리 전 정규화 대상)
const REFUND_COMPLETE_PRICE_KEYS = ['completeCashPrice', 'completePgPrice', 'completeDepositPrice', 'completeMileagePrice'];
 
/**
* @var null|object 디비 접속
*/
}
}
 
/**
* 환불 금액을 산술 처리 가능한 정수로 정규화한다.
*
* 콤마만 제거하고 소수점은 보존한다. 비숫자를 일괄 제거하면 decimal(12,2) 값
* "75900.00" 의 소수점까지 지워져 ×100 이 된다.
*
* @param string|int|float $completePrice 환불 금액 입력값
* @return int
* @throws Exception 숫자가 아니거나 음수인 경우
*/
protected function normalizeRefundCompletePrice(string|int|float $completePrice): int
{
$normalizedPrice = trim(str_replace(',', '', (string)$completePrice));
 
if ($normalizedPrice === '') {
return 0;
}
if (!is_numeric($normalizedPrice)) {
throw new Exception(__('환불 금액을 숫자로 확인할 수 없습니다. 다시 확인해주세요.'));
}
if ((float)$normalizedPrice < 0) {
throw new Exception(__('환불 금액은 0 보다 작을 수 없습니다. 다시 확인해주세요.'));
}
 
// 소수부 절사 ("75900.00" → 75900)
return (int)(float)$normalizedPrice;
}
 
public function setRefundCompleteOrderGoodsNew($getData, $autoProcess = false, $userHandleFl = false)
{
$goods = \App::load(\Component\Goods\Goods::class);
$orderAdmin = App::load(\Component\Order\OrderAdmin::class);
 
// 콤마가 섞인 값("347,180")은 형변환 시 347 로 잘려 안분 합계가 어긋나 무한루프를 유발한다.
foreach (self::REFUND_COMPLETE_PRICE_KEYS as $completePriceKey) {
if (!isset($getData['info'][$completePriceKey])) {
continue;
}
$getData['info'][$completePriceKey] = $this->normalizeRefundCompletePrice($getData['info'][$completePriceKey]);
}
 
// 환불수단에 맞지않는 금액값이 넘어오면 리턴처리
if ($getData['info']['refundMethod'] == '현금환불') {
if ($getData['info']['completePgPrice'] > 0 || $getData['info']['completeDepositPrice'] > 0 || $getData['info']['completeMileagePrice'] > 0) {
}
$checkDivisionVal = 0;
do {
$beforeDivisionVal = $tempDivisionVal;
foreach ($arrayData as $k => $v) {
if ($checkKey != '') {
if (isset($v['orderDeliverySno']) && $checkKey != '' && $checkKey != $v['orderDeliverySno']) {
}
}
}
// 무한루프 방지: 1회 순회 동안 차액이 줄지 않으면 더 안분할 항목이 없으므로 종료한다.
if ($checkDivisionVal === 0 && $tempDivisionVal === $beforeDivisionVal) {
// 안분이 덜 된 상태로 환불이 진행되므로 error 로 남긴다. (추적용으로 대상 키를 함께 기록)
\Logger::channel('order')->error(__METHOD__ . '[' . __LINE__ . '], 안분 차액을 맞출 수 없어 루프 종료(무한루프 방지): ', [
'strText' => $strText,
'remainDivisionVal' => $tempDivisionVal,
'divisionSum' => $divisionSum,
'orgPrice' => $orgPrice,
'divisionKeys' => array_keys($arrayData),
]);
break;
}
} while ($checkDivisionVal == 0);
}
 
$checkDivisionVal = 1;
 
do {
// 무한루프 방지용 직전 순회 tax 합계 (변화가 없으면 재분배 불가로 보고 종료)
$beforeDivisionSignature = $tempTaxSupplySum . STR_DIVISION . $tempTaxVatSum . STR_DIVISION . $tempTaxFreeSum;
 
// free supply vat 순으로 체크하면서 오버되면 재분배
if ($orgTotalData['realTaxFreePrice'] < $tempTaxFreeSum) { // 환불 업데이트 free 합계값이 오버인경우
// 오버값
$checkDivisionVal = 0;
}
 
// 재분배 후에도 tax 합계가 동일하면 진행이 없는 상태이므로 종료
if ($checkDivisionVal === 1 && $beforeDivisionSignature === ($tempTaxSupplySum . STR_DIVISION . $tempTaxVatSum . STR_DIVISION . $tempTaxFreeSum)) {
// 배송비 tax 안분이 덜 된 상태로 환불이 진행되므로 error 로 남긴다. (추적용으로 대상 키를 함께 기록)
\Logger::channel('order')->error(__METHOD__ . '[' . __LINE__ . '], 배송비 tax 안분이 수렴하지 않아 루프 종료(무한루프 방지): ', [
'orgTotalData' => $orgTotalData,
'tempTaxSupplySum' => $tempTaxSupplySum,
'tempTaxVatSum' => $tempTaxVatSum,
'tempTaxFreeSum' => $tempTaxFreeSum,
'deliveryKeys' => array_keys($refundDeliveryData),
]);
break;
}
 
} while ($checkDivisionVal == 1);
 
return [$updateDeliveryData, $refundDeliveryData];
 
배송지 수정 기능 보안 강화
Admin/order/inc_order_view.php+8-8
변경 전inc_order_view.php
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>>
<?php if($val['receiverZonecode']){ echo "[".$val['receiverZonecode']."]"; } ?>
<?php if($val['receiverZipcode']){ echo "(".$val['receiverZipcode'].")"; } ?>
<br />
<?php if($val['receiverAddress']){ echo $val['receiverAddress']; } ?>
<?php if($val['receiverAddressSub']){ echo " ".$val['receiverAddressSub']; } ?>
</td>
<?php } ?>
<?php } else {?>
<?php if($rowAll === 0){ ?>
<td <?= $orderGoodsRowSpan ?>>
<?php if($data['receiverZonecode']){ echo "[".$data['receiverZonecode']."]"; } ?>
<?php if($data['receiverZipcode']){ echo "(".$data['receiverZipcode'].")"; } ?>
<br />
<?php if($data['receiverAddress']){ echo $data['receiverAddress']; } ?>
<?php if($data['receiverAddressSub']){ echo " ".$data['receiverAddressSub']; } ?>
</td>
<?php } ?>
<?php } ?>
 
변경 후inc_order_view.php
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>>
<?php if($val['receiverZonecode']){ echo "[".gd_htmlspecialchars($val['receiverZonecode'])."]"; } ?>
<?php if($val['receiverZipcode']){ echo "(".gd_htmlspecialchars($val['receiverZipcode']).")"; } ?>
<br />
<?php if($val['receiverAddress']){ echo gd_htmlspecialchars($val['receiverAddress']); } ?>
<?php if($val['receiverAddressSub']){ echo " ".gd_htmlspecialchars($val['receiverAddressSub']); } ?>
</td>
<?php } ?>
<?php } else {?>
<?php if($rowAll === 0){ ?>
<td <?= $orderGoodsRowSpan ?>>
<?php if($data['receiverZonecode']){ echo "[".gd_htmlspecialchars($data['receiverZonecode'])."]"; } ?>
<?php if($data['receiverZipcode']){ echo "(".gd_htmlspecialchars($data['receiverZipcode']).")"; } ?>
<br />
<?php if($data['receiverAddress']){ echo gd_htmlspecialchars($data['receiverAddress']); } ?>
<?php if($data['receiverAddressSub']){ echo " ".gd_htmlspecialchars($data['receiverAddressSub']); } ?>
</td>
<?php } ?>
<?php } ?>
 
Admin/order/layout_order_goods_list.php+16-16
변경 전layout_order_goods_list.php
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>>
<?=($val['orderMemo']) ? gd_html_cut($val['orderMemo'], 30, '..') : '-'?>
</td>
<?php } ?>
<?php } else {?>
<?php
if($val['multiShippingFl'] === 'y'){
if($val['multiShippingOrderMemo']){
echo gd_html_cut($val['multiShippingOrderMemo'], 30, '..');
if(((int)$val['multiShippingOrderMemoCount']-1) > 0){
echo ' 외 ' . ((int)$val['multiShippingOrderMemoCount']-1) . '건';
}
}
else {
if($val['orderMemo']){
echo gd_html_cut($val['orderMemo'], 30, '..');
}
else {
echo '-';
<?php } // 주문번호 ?>
 
<?php if($gridKey === 'orderName' && $rowChk === 0){ // 주문자 ?>
<td <?= $orderGoodsRowSpan; ?> class="js-member-info" data-member-no="<?= $val['memNo'] ?>" data-member-name="<?= $memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName']); ?>" data-cell-phone="<?= $memberMasking->masking('order','tel',$val['smsCellPhone']); ?>">
<?= $memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName']); ?>
<p class="mgb0">
<?php if (!$val['memNo']) { ?>
<?php if (!$val['memNoCheck']) { ?>
<?php if($gridKey === 'receiverName'){ // 수령자 ?>
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>><?= $memberMasking->masking('order', 'name', $data[$orderNo]['withdrawnMembersPersonalData']['receiverName'] ?: $val['receiverName']) ?></td>
<?php } ?>
<?php } else {?>
<?php if($rowChk === 0){ ?>
<?php
if($val['multiShippingFl'] === 'y'){
if($val['multiShippingReceiverName']){
echo $memberMasking->masking('order', 'name', $val['multiShippingReceiverName']);
if(((int)$val['multiShippingReceiverNameCount']-1) > 0){
echo ' 외 ' . ((int)$val['multiShippingReceiverNameCount']-1) . '명';
}
}
}
else {
echo $memberMasking->masking('order', 'name', $data[$orderNo]['withdrawnMembersPersonalData']['receiverName'] ?: $val['receiverName']);
}
?>
</td>
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>>
<?php if($val['receiverZonecode']){ echo "[".$val['receiverZonecode']."]"; } ?>
<?php if($val['receiverZipcode']){ echo "(".$val['receiverZipcode'].")"; } ?>
<br />
<?php if($val['receiverAddress']){ echo $val['receiverAddress']; } ?>
<?php if($val['receiverAddressSub']){ echo " ".$val['receiverAddressSub']; } ?>
</td>
<?php } ?>
<?php } else {?>
<?php if($rowChk === 0){ ?>
<td <?= $orderGoodsRowSpan ?>>
<?php if($val['receiverZonecode']){ echo "[".$val['receiverZonecode']."]"; } ?>
<?php if($val['receiverZipcode']){ echo "(".$val['receiverZipcode'].")"; } ?>
<br />
<?php if($val['receiverAddress']){ echo $val['receiverAddress']; } ?>
<?php if($val['receiverAddressSub']){ echo " ".$val['receiverAddressSub']; } ?>
</td>
<?php } ?>
<?php } ?>
 
변경 후layout_order_goods_list.php
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>>
<?=($val['orderMemo']) ? gd_htmlspecialchars(gd_html_cut($val['orderMemo'], 30, '..')) : '-'?>
</td>
<?php } ?>
<?php } else {?>
<?php
if($val['multiShippingFl'] === 'y'){
if($val['multiShippingOrderMemo']){
echo gd_htmlspecialchars(gd_html_cut($val['multiShippingOrderMemo'], 30, '..'));
if(((int)$val['multiShippingOrderMemoCount']-1) > 0){
echo ' 외 ' . ((int)$val['multiShippingOrderMemoCount']-1) . '건';
}
}
else {
if($val['orderMemo']){
echo gd_htmlspecialchars(gd_html_cut($val['orderMemo'], 30, '..'));
}
else {
echo '-';
<?php } // 주문번호 ?>
 
<?php if($gridKey === 'orderName' && $rowChk === 0){ // 주문자 ?>
<td <?= $orderGoodsRowSpan; ?> class="js-member-info" data-member-no="<?= $val['memNo'] ?>" data-member-name="<?= gd_htmlspecialchars($memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName'])); ?>" data-cell-phone="<?= gd_htmlspecialchars($memberMasking->masking('order','tel',$val['smsCellPhone'])); ?>">
<?= gd_htmlspecialchars($memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName'])); ?>
<p class="mgb0">
<?php if (!$val['memNo']) { ?>
<?php if (!$val['memNoCheck']) { ?>
<?php if($gridKey === 'receiverName'){ // 수령자 ?>
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>><?= gd_htmlspecialchars($memberMasking->masking('order', 'name', $data[$orderNo]['withdrawnMembersPersonalData']['receiverName'] ?: $val['receiverName'])) ?></td>
<?php } ?>
<?php } else {?>
<?php if($rowChk === 0){ ?>
<?php
if($val['multiShippingFl'] === 'y'){
if($val['multiShippingReceiverName']){
echo gd_htmlspecialchars($memberMasking->masking('order', 'name', $val['multiShippingReceiverName']));
if(((int)$val['multiShippingReceiverNameCount']-1) > 0){
echo ' 외 ' . ((int)$val['multiShippingReceiverNameCount']-1) . '명';
}
}
}
else {
echo gd_htmlspecialchars($memberMasking->masking('order', 'name', $data[$orderNo]['withdrawnMembersPersonalData']['receiverName'] ?: $val['receiverName']));
}
?>
</td>
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>>
<?php if($val['receiverZonecode']){ echo "[".gd_htmlspecialchars($val['receiverZonecode'])."]"; } ?>
<?php if($val['receiverZipcode']){ echo "(".gd_htmlspecialchars($val['receiverZipcode']).")"; } ?>
<br />
<?php if($val['receiverAddress']){ echo gd_htmlspecialchars($val['receiverAddress']); } ?>
<?php if($val['receiverAddressSub']){ echo " ".gd_htmlspecialchars($val['receiverAddressSub']); } ?>
</td>
<?php } ?>
<?php } else {?>
<?php if($rowChk === 0){ ?>
<td <?= $orderGoodsRowSpan ?>>
<?php if($val['receiverZonecode']){ echo "[".gd_htmlspecialchars($val['receiverZonecode'])."]"; } ?>
<?php if($val['receiverZipcode']){ echo "(".gd_htmlspecialchars($val['receiverZipcode']).")"; } ?>
<br />
<?php if($val['receiverAddress']){ echo gd_htmlspecialchars($val['receiverAddress']); } ?>
<?php if($val['receiverAddressSub']){ echo " ".gd_htmlspecialchars($val['receiverAddressSub']); } ?>
</td>
<?php } ?>
<?php } ?>
 
Admin/order/layout_order_goods_simple_list.php+10-10
변경 전layout_order_goods_simple_list.php
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>>
<?=($val['orderMemo']) ? gd_html_cut($val['orderMemo'], 30, '..') : '-'?>
</td>
<?php } ?>
<?php } else {?>
<td <?= $orderGoodsRowSpan ?>>
<?php
if($val['orderMemo']){
echo gd_html_cut($val['orderMemo'], 30, '..');
if($val['multiShippingFl'] === 'y'){
echo ' 외' . ((int)$val['totalOrderInfoCount']-1) . '건';
}
<?php } // 주문번호 ?>
 
<?php if($gridKey === 'orderName' && $rowChk === 0){ // 주문자 ?>
<td <?= $orderGoodsRowSpan; ?> class="js-member-info" data-member-no="<?= $val['memNo'] ?>" data-member-name="<?= $memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName']); ?>" data-cell-phone="<?= $memberMasking->masking('order','tel',$val['smsCellPhone']); ?>">
<?= $memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName']); ?>
<p class="mgb0">
<?php if (!$val['memNo']) { ?>
<?php if (!$val['memNoCheck']) { ?>
<?php if($gridKey === 'receiverName'){ // 수령자 ?>
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>><?= $memberMasking->masking('order', 'name', $data[$orderNo]['withdrawnMembersPersonalData']['receiverName'] ?: $val['receiverName']) ?></td>
<?php } ?>
<?php } else {?>
<?php if($rowChk === 0){ ?>
<td <?= $orderGoodsRowSpan ?>>
<?php
echo $memberMasking->masking('order', 'name', $data[$orderNo]['withdrawnMembersPersonalData']['receiverName'] ?: $val['receiverName']);
if($val['totalOrderInfoCount'] > 1){
echo ' 외 ' . ((int)$val['totalOrderInfoCount']-1) . '명';
}
 
<?php if($gridKey === 'receiverAddress' && $rowChk === 0){ //수령자 주소?>
<td <?= $orderGoodsRowSpan ?>>
<?php if($val['receiverZonecode']){ echo "[".$val['receiverZonecode']."]"; } ?>
<?php if($val['receiverZipcode']){ echo "(".$val['receiverZipcode'].")"; } ?>
<br />
<?php if($val['receiverAddress']){ echo $val['receiverAddress']; } ?>
<?php if($val['receiverAddressSub']){ echo " ".$val['receiverAddressSub']; } ?>
</td>
<?php } //수령자 주소?>
 
 
변경 후layout_order_goods_simple_list.php
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>>
<?=($val['orderMemo']) ? gd_htmlspecialchars(gd_html_cut($val['orderMemo'], 30, '..')) : '-'?>
</td>
<?php } ?>
<?php } else {?>
<td <?= $orderGoodsRowSpan ?>>
<?php
if($val['orderMemo']){
echo gd_htmlspecialchars(gd_html_cut($val['orderMemo'], 30, '..'));
if($val['multiShippingFl'] === 'y'){
echo ' 외' . ((int)$val['totalOrderInfoCount']-1) . '건';
}
<?php } // 주문번호 ?>
 
<?php if($gridKey === 'orderName' && $rowChk === 0){ // 주문자 ?>
<td <?= $orderGoodsRowSpan; ?> class="js-member-info" data-member-no="<?= $val['memNo'] ?>" data-member-name="<?= gd_htmlspecialchars($memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName'])); ?>" data-cell-phone="<?= gd_htmlspecialchars($memberMasking->masking('order','tel',$val['smsCellPhone'])); ?>">
<?= gd_htmlspecialchars($memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName'])); ?>
<p class="mgb0">
<?php if (!$val['memNo']) { ?>
<?php if (!$val['memNoCheck']) { ?>
<?php if($gridKey === 'receiverName'){ // 수령자 ?>
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>><?= gd_htmlspecialchars($memberMasking->masking('order', 'name', $data[$orderNo]['withdrawnMembersPersonalData']['receiverName'] ?: $val['receiverName'])) ?></td>
<?php } ?>
<?php } else {?>
<?php if($rowChk === 0){ ?>
<td <?= $orderGoodsRowSpan ?>>
<?php
echo gd_htmlspecialchars($memberMasking->masking('order', 'name', $data[$orderNo]['withdrawnMembersPersonalData']['receiverName'] ?: $val['receiverName']));
if($val['totalOrderInfoCount'] > 1){
echo ' 외 ' . ((int)$val['totalOrderInfoCount']-1) . '명';
}
 
<?php if($gridKey === 'receiverAddress' && $rowChk === 0){ //수령자 주소?>
<td <?= $orderGoodsRowSpan ?>>
<?php if($val['receiverZonecode']){ echo "[".gd_htmlspecialchars($val['receiverZonecode'])."]"; } ?>
<?php if($val['receiverZipcode']){ echo "(".gd_htmlspecialchars($val['receiverZipcode']).")"; } ?>
<br />
<?php if($val['receiverAddress']){ echo gd_htmlspecialchars($val['receiverAddress']); } ?>
<?php if($val['receiverAddressSub']){ echo " ".gd_htmlspecialchars($val['receiverAddressSub']); } ?>
</td>
<?php } //수령자 주소?>
 
 
Admin/order/layout_order_list.php+10-10
변경 전layout_order_list.php
<?php
if($val['multiShippingFl'] === 'y'){
if($val['multiShippingOrderMemo']){
echo gd_html_cut($val['multiShippingOrderMemo'], 30, '..');
if(((int)$val['multiShippingOrderMemoCount']-1) > 0){
echo ' 외 ' . ((int)$val['multiShippingOrderMemoCount']-1) . '건';
}
}
else {
if($val['orderMemo']){
echo gd_html_cut($val['orderMemo'], 30, '..');
}
else {
echo '-';
<?php } //주문번호 ?>
 
<?php if($gridKey === 'orderName'){ //주문자 ?>
<td class="js-member-info" data-member-no="<?= $val['memNo'] ?>" data-member-name="<?= $memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName']); ?>" data-cell-phone="<?= $memberMasking->masking('order','tel',$val['smsCellPhone']); ?>">
<?= $memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName']); ?>
<p class="mgb0">
<?php if (!$val['memNo']) { ?>
<?php if (!$val['memNoCheck']) { ?>
<?php
if($val['multiShippingFl'] === 'y'){
if($val['multiShippingReceiverName']){
echo $memberMasking->masking('order', 'name', $val['multiShippingReceiverName']);
if(((int)$val['multiShippingReceiverNameCount']-1) > 0){
echo ' 외 ' . ((int)$val['multiShippingReceiverNameCount']-1) . '명';
}
}
}
else {
echo $memberMasking->masking('order', 'name', $data[$orderNo]['withdrawnMembersPersonalData']['receiverName'] ?: $val['receiverName']);
}
?>
</td>
 
<?php if($gridKey === 'receiverAddress'){ //수령자 주소 ?>
<td>
<?php if($val['receiverZonecode']){ echo "[".$val['receiverZonecode']."]"; } ?>
<?php if($val['receiverZipcode']){ echo "(".$val['receiverZipcode'].")"; } ?>
<br />
<?php if($val['receiverAddress']){ echo $val['receiverAddress']; } ?>
<?php if($val['receiverAddressSub']){ echo " ".$val['receiverAddressSub']; } ?>
</td>
<?php } //수령자 주소 ?>
 
 
변경 후layout_order_list.php
<?php
if($val['multiShippingFl'] === 'y'){
if($val['multiShippingOrderMemo']){
echo gd_htmlspecialchars(gd_html_cut($val['multiShippingOrderMemo'], 30, '..'));
if(((int)$val['multiShippingOrderMemoCount']-1) > 0){
echo ' 외 ' . ((int)$val['multiShippingOrderMemoCount']-1) . '건';
}
}
else {
if($val['orderMemo']){
echo gd_htmlspecialchars(gd_html_cut($val['orderMemo'], 30, '..'));
}
else {
echo '-';
<?php } //주문번호 ?>
 
<?php if($gridKey === 'orderName'){ //주문자 ?>
<td class="js-member-info" data-member-no="<?= $val['memNo'] ?>" data-member-name="<?= gd_htmlspecialchars($memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName'])); ?>" data-cell-phone="<?= gd_htmlspecialchars($memberMasking->masking('order','tel',$val['smsCellPhone'])); ?>">
<?= gd_htmlspecialchars($memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName'])); ?>
<p class="mgb0">
<?php if (!$val['memNo']) { ?>
<?php if (!$val['memNoCheck']) { ?>
<?php
if($val['multiShippingFl'] === 'y'){
if($val['multiShippingReceiverName']){
echo gd_htmlspecialchars($memberMasking->masking('order', 'name', $val['multiShippingReceiverName']));
if(((int)$val['multiShippingReceiverNameCount']-1) > 0){
echo ' 외 ' . ((int)$val['multiShippingReceiverNameCount']-1) . '명';
}
}
}
else {
echo gd_htmlspecialchars($memberMasking->masking('order', 'name', $data[$orderNo]['withdrawnMembersPersonalData']['receiverName'] ?: $val['receiverName']));
}
?>
</td>
 
<?php if($gridKey === 'receiverAddress'){ //수령자 주소 ?>
<td>
<?php if($val['receiverZonecode']){ echo "[".gd_htmlspecialchars($val['receiverZonecode'])."]"; } ?>
<?php if($val['receiverZipcode']){ echo "(".gd_htmlspecialchars($val['receiverZipcode']).")"; } ?>
<br />
<?php if($val['receiverAddress']){ echo gd_htmlspecialchars($val['receiverAddress']); } ?>
<?php if($val['receiverAddressSub']){ echo " ".gd_htmlspecialchars($val['receiverAddressSub']); } ?>
</td>
<?php } //수령자 주소 ?>
 
 
Admin/order/logistics_layout_order_goods_list.php+16-16
변경 전logistics_layout_order_goods_list.php
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>>
<?=($val['orderMemo']) ? gd_html_cut($val['orderMemo'], 30, '..') : '-'?>
</td>
<?php } ?>
<?php } else {?>
<?php
if($val['multiShippingFl'] === 'y'){
if($val['multiShippingOrderMemo']){
echo gd_html_cut($val['multiShippingOrderMemo'], 30, '..');
if(((int)$val['multiShippingOrderMemoCount']-1) > 0){
echo ' 외 ' . ((int)$val['multiShippingOrderMemoCount']-1) . '건';
}
}
else {
if($val['orderMemo']){
echo gd_html_cut($val['orderMemo'], 30, '..');
}
else {
echo '-';
</td>
<?php } ?>
<?php if($gridKey === 'orderName' && $rowChk === 0){ ?>
<td <?= $orderGoodsRowSpan; ?> class="js-member-info" data-member-no="<?= $val['memNo'] ?>" data-member-name="<?= $memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName']) ?>" data-cell-phone="<?= $memberMasking->masking('order','tel',$val['smsCellPhone']); ?>">
<?= $memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName']) ?>
<p class="mgb0">
<?php if (!$val['memNo']) { ?>
<?php if (!$val['memNoCheck']) { ?>
<?php if($gridKey === 'receiverName'){ ?>
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>><?= $data[$orderNo]['withdrawnMembersPersonalData']['receiverName'] ?: $val['receiverName'] ?></td>
<?php } ?>
<?php } else {?>
<?php if($rowChk === 0){ ?>
<?php
if($val['multiShippingFl'] === 'y'){
if($val['multiShippingReceiverName']){
echo $val['multiShippingReceiverName'];
if(((int)$val['multiShippingReceiverNameCount']-1) > 0){
echo ' 외 ' . ((int)$val['multiShippingReceiverNameCount']-1) . '명';
}
}
}
else {
echo $data[$orderNo]['withdrawnMembersPersonalData']['receiverName'] ?: $val['receiverName'];
}
?>
</td>
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>>
<?php if($val['receiverZonecode']){ echo "[".$val['receiverZonecode']."]"; } ?>
<?php if($val['receiverZipcode']){ echo "(".$val['receiverZipcode'].")"; } ?>
<br />
<?php if($val['receiverAddress']){ echo $val['receiverAddress']; } ?>
<?php if($val['receiverAddressSub']){ echo " ".$val['receiverAddressSub']; } ?>
</td>
<?php } ?>
<?php } else {?>
<?php if($rowChk === 0){ ?>
<td <?= $orderGoodsRowSpan ?>>
<?php if($val['receiverZonecode']){ echo "[".$val['receiverZonecode']."]"; } ?>
<?php if($val['receiverZipcode']){ echo "(".$val['receiverZipcode'].")"; } ?>
<br />
<?php if($val['receiverAddress']){ echo $val['receiverAddress']; } ?>
<?php if($val['receiverAddressSub']){ echo " ".$val['receiverAddressSub']; } ?>
</td>
<?php } ?>
<?php } ?>
 
변경 후logistics_layout_order_goods_list.php
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>>
<?=($val['orderMemo']) ? gd_htmlspecialchars(gd_html_cut($val['orderMemo'], 30, '..')) : '-'?>
</td>
<?php } ?>
<?php } else {?>
<?php
if($val['multiShippingFl'] === 'y'){
if($val['multiShippingOrderMemo']){
echo gd_htmlspecialchars(gd_html_cut($val['multiShippingOrderMemo'], 30, '..'));
if(((int)$val['multiShippingOrderMemoCount']-1) > 0){
echo ' 외 ' . ((int)$val['multiShippingOrderMemoCount']-1) . '건';
}
}
else {
if($val['orderMemo']){
echo gd_htmlspecialchars(gd_html_cut($val['orderMemo'], 30, '..'));
}
else {
echo '-';
</td>
<?php } ?>
<?php if($gridKey === 'orderName' && $rowChk === 0){ ?>
<td <?= $orderGoodsRowSpan; ?> class="js-member-info" data-member-no="<?= $val['memNo'] ?>" data-member-name="<?= gd_htmlspecialchars($memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName'])) ?>" data-cell-phone="<?= gd_htmlspecialchars($memberMasking->masking('order','tel',$val['smsCellPhone'])); ?>">
<?= gd_htmlspecialchars($memberMasking->masking('order','name',$data[$orderNo]['withdrawnMembersPersonalData']['orderName'] ?: $val['orderName'])) ?>
<p class="mgb0">
<?php if (!$val['memNo']) { ?>
<?php if (!$val['memNoCheck']) { ?>
<?php if($gridKey === 'receiverName'){ ?>
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>><?= gd_htmlspecialchars($data[$orderNo]['withdrawnMembersPersonalData']['receiverName'] ?: $val['receiverName']) ?></td>
<?php } ?>
<?php } else {?>
<?php if($rowChk === 0){ ?>
<?php
if($val['multiShippingFl'] === 'y'){
if($val['multiShippingReceiverName']){
echo gd_htmlspecialchars($val['multiShippingReceiverName']);
if(((int)$val['multiShippingReceiverNameCount']-1) > 0){
echo ' 외 ' . ((int)$val['multiShippingReceiverNameCount']-1) . '명';
}
}
}
else {
echo gd_htmlspecialchars($data[$orderNo]['withdrawnMembersPersonalData']['receiverName'] ?: $val['receiverName']);
}
?>
</td>
<?php if($useMultiShippingKey === true){ ?>
<?php if($rowMultiShipping === 0){ ?>
<td <?= $orderMultiShippingRowSpan ?>>
<?php if($val['receiverZonecode']){ echo "[".gd_htmlspecialchars($val['receiverZonecode'])."]"; } ?>
<?php if($val['receiverZipcode']){ echo "(".gd_htmlspecialchars($val['receiverZipcode']).")"; } ?>
<br />
<?php if($val['receiverAddress']){ echo gd_htmlspecialchars($val['receiverAddress']); } ?>
<?php if($val['receiverAddressSub']){ echo " ".gd_htmlspecialchars($val['receiverAddressSub']); } ?>
</td>
<?php } ?>
<?php } else {?>
<?php if($rowChk === 0){ ?>
<td <?= $orderGoodsRowSpan ?>>
<?php if($val['receiverZonecode']){ echo "[".gd_htmlspecialchars($val['receiverZonecode'])."]"; } ?>
<?php if($val['receiverZipcode']){ echo "(".gd_htmlspecialchars($val['receiverZipcode']).")"; } ?>
<br />
<?php if($val['receiverAddress']){ echo gd_htmlspecialchars($val['receiverAddress']); } ?>
<?php if($val['receiverAddressSub']){ echo " ".gd_htmlspecialchars($val['receiverAddressSub']); } ?>
</td>
<?php } ?>
<?php } ?>
 
Admin/order/popup_order_packet.php+3-3
변경 전popup_order_packet.php
}
?>
</td>
<td class="center"><?=$data['receiverName']?></td>
<td class="center">
<div><?php echo (gd_count($data['receiverPhone']) > 0) ? gd_implode("-", $data['receiverPhone']) : '-'; ?></div>
<div><?php echo (gd_count($data['receiverCellPhone']) > 0) ? gd_implode("-", $data['receiverCellPhone']) : '-'; ?></div>
</td>
<td class="center">
<?php if (empty($data['isDefaultMall']) === true) { ?>
(<?=$data['receiverZonecode']?>) <?=$data['receiverAddressSub']?> <?=$data['receiverState']?> <?=$data['receiverCity']?> <?=$data['receiverAddress']?> <?=$data['receiverCountry']?>
<?php } else { ?>
(<?=$data['receiverZonecode']?>) <?=$data['receiverAddress']?> <?=$data['receiverAddressSub']?>
<?php } ?>
</td>
<td class="center">
 
변경 후popup_order_packet.php
}
?>
</td>
<td class="center"><?=gd_htmlspecialchars($data['receiverName'])?></td>
<td class="center">
<div><?php echo (gd_count($data['receiverPhone']) > 0) ? gd_implode("-", $data['receiverPhone']) : '-'; ?></div>
<div><?php echo (gd_count($data['receiverCellPhone']) > 0) ? gd_implode("-", $data['receiverCellPhone']) : '-'; ?></div>
</td>
<td class="center">
<?php if (empty($data['isDefaultMall']) === true) { ?>
(<?=gd_htmlspecialchars($data['receiverZonecode'])?>) <?=gd_htmlspecialchars($data['receiverAddressSub'])?> <?=gd_htmlspecialchars($data['receiverState'])?> <?=gd_htmlspecialchars($data['receiverCity'])?> <?=gd_htmlspecialchars($data['receiverAddress'])?> <?=gd_htmlspecialchars($data['receiverCountry'])?>
<?php } else { ?>
(<?=gd_htmlspecialchars($data['receiverZonecode'])?>) <?=gd_htmlspecialchars($data['receiverAddress'])?> <?=gd_htmlspecialchars($data['receiverAddressSub'])?>
<?php } ?>
</td>
<td class="center">
 
Component/Design/ReplaceCode.php+53-52
변경 전ReplaceCode.php
use Framework\Utility\ComponentUtils;
use Framework\Utility\DateTimeUtils;
use Framework\Utility\SkinUtils;
 
use Globals;
use Logger;
 
Logger::info(__METHOD__);
$this->replaceSrc['{rc_memNm}'] = [
'desc' => __('회원명'),
'val' => $replaceData['memNm'],
];
$this->replaceSrc['{rc_orderDt}'] = [
'desc' => __('주문일시'),
];
$this->replaceSrc['{rc_orderNm}'] = [
'desc' => __('주문자명'),
'val' => $replaceData['orderNm'],
];
$this->replaceSrc['{rc_orderNo}'] = [
'desc' => __('주문번호'),
];
$this->replaceSrc['{rc_receiverNm}'] = [
'desc' => __('받는 사람'),
'val' => $replaceData['receiverNm'],
];
$this->replaceSrc['{rc_receiverZipcode}'] = [
'desc' => __('구 우편번호 (6자리)'),
'val' => $replaceData['receiverZipcode'],
];
$this->replaceSrc['{rc_receiverZonecode}'] = [
'desc' => __('우편번호'),
'val' => $replaceData['receiverZonecode'],
];
$this->replaceSrc['{rc_receiverAddress}'] = [
'desc' => __('주소'),
'val' => $replaceData['receiverAddress'],
];
$this->replaceSrc['{rc_receiverAddressSub}'] = [
'desc' => __('상세주소'),
'val' => $replaceData['receiverAddressSub'],
];
$this->replaceSrc['{rc_receiverPhone}'] = [
'desc' => __('전화번호'),
'val' => $replaceData['receiverPhone'],
];
$this->replaceSrc['{rc_receiverCellPhone}'] = [
'desc' => __('휴대폰번호'),
'val' => $replaceData['receiverCellPhone'],
];
$this->replaceSrc['{rc_receiverMemo}'] = [
'desc' => __('배송메시지'),
'val' => $replaceData['receiverMemo'],
];
$this->replaceSrc['{rc_receiverPhonePrefix}'] = [
'desc' => __('전화번호 국가번호'),
'val' => $replaceData['receiverPhonePrefix'],
];
$this->replaceSrc['{rc_receiverCellPhonePrefix}'] = [
'desc' => __('휴대폰번호 국가번호'),
'val' => $replaceData['receiverCellPhonePrefix'],
];
$this->replaceSrc['{rc_receiverPhonePrefixCode}'] = [
'desc' => __('전화번호 국가코드'),
'val' => $replaceData['receiverPhonePrefixCode'],
];
$this->replaceSrc['{rc_receiverCellPhonePrefixCode}'] = [
'desc' => __('휴대폰번호 국가코드'),
'val' => $replaceData['receiverCellPhonePrefixCode'],
];
$this->replaceSrc['{rc_receiverCountry}'] = [
'desc' => __('수취인 국가'),
'val' => $replaceData['receiverCountry'],
];
$this->replaceSrc['{rc_receiverCity}'] = [
'desc' => __('수취인 도시'),
'val' => $replaceData['receiverCity'],
];
$this->replaceSrc['{rc_receiverState}'] = [
'desc' => __('수취인 주소'),
'val' => $replaceData['receiverState'],
];
$this->replaceSrc['{rc_totalDeliveryInsuranceFee}'] = [
'desc' => __('EMS 해외 총 보험료'),
];
$this->replaceSrc['{rc_receiverNmAdd}'] = [
'desc' => __('받는 사람'),
'val' => $replaceData['receiverNmAdd'],
];
$this->replaceSrc['{rc_receiverZipcodeAdd}'] = [
'desc' => __('구 우편번호 (6자리)'),
'val' => $replaceData['receiverZipcodeAdd'],
];
$this->replaceSrc['{rc_receiverZonecodeAdd}'] = [
'desc' => __('우편번호'),
'val' => $replaceData['receiverZonecodeAdd'],
];
$this->replaceSrc['{rc_receiverAddressAdd}'] = [
'desc' => __('주소'),
'val' => $replaceData['receiverAddressAdd'],
];
$this->replaceSrc['{rc_receiverAddressSubAdd}'] = [
'desc' => __('상세주소'),
'val' => $replaceData['receiverAddressSubAdd'],
];
$this->replaceSrc['{rc_receiverPhoneAdd}'] = [
'desc' => __('전화번호'),
'val' => $replaceData['receiverPhoneAdd'],
];
$this->replaceSrc['{rc_receiverCellPhoneAdd}'] = [
'desc' => __('휴대폰번호'),
'val' => $replaceData['receiverCellPhoneAdd'],
];
$this->replaceSrc['{rc_orderMemoAdd}'] = [
'desc' => __('배송메시지'),
'val' => $replaceData['orderMemoAdd'],
];
$this->replaceSrc['{rc_expirationDate}'] = [
'desc' => __('입금만료일(yyyy-mm-dd hh:mm)'),
];
$this->replaceSrc['{rc_orderNm}'] = [
'desc' => __('주문자명'),
'val' => $replaceData['orderNm'],
];
$this->replaceSrc['{rc_bankSender}'] = [
'desc' => __('입금자명'),
'val' => $replaceData['bankSender'],
];
$this->replaceSrc['{rc_orderNo}'] = [
'desc' => __('주문번호'),
Logger::info(__METHOD__);
$this->replaceSrc['{rc_orderNm}'] = [
'desc' => __('주문자명'),
'val' => $replaceData['orderNm'],
];
$this->replaceSrc['{rc_bankSender}'] = [
'desc' => __('입금자명'),
'val' => $replaceData['bankSender'],
];
$this->replaceSrc['{rc_orderNo}'] = [
'desc' => __('주문번호'),
];
$this->replaceSrc['{rc_receiverNm}'] = [
'desc' => __('받는 사람'),
'val' => $replaceData['receiverNm'],
];
$this->replaceSrc['{rc_receiverZipcode}'] = [
'desc' => __('구 우편번호 (6자리)'),
'val' => $replaceData['receiverZipcode'],
];
$this->replaceSrc['{rc_receiverZonecode}'] = [
'desc' => __('우편번호'),
'val' => $replaceData['receiverZonecode'],
];
$this->replaceSrc['{rc_receiverAddress}'] = [
'desc' => __('주소'),
'val' => $replaceData['receiverAddress'],
];
$this->replaceSrc['{rc_receiverAddressSub}'] = [
'desc' => __('상세주소'),
'val' => $replaceData['receiverAddressSub'],
];
$this->replaceSrc['{rc_receiverPhone}'] = [
'desc' => __('전화번호'),
'val' => $replaceData['receiverPhone'],
];
$this->replaceSrc['{rc_receiverCellPhone}'] = [
'desc' => __('휴대폰번호'),
'val' => $replaceData['receiverCellPhone'],
];
$this->replaceSrc['{rc_receiverMemo}'] = [
'desc' => __('배송메시지'),
'val' => $replaceData['receiverMemo'],
];
$this->replaceSrc['{rc_receiverPhonePrefix}'] = [
'desc' => __('전화번호 국가번호'),
'val' => $replaceData['receiverPhonePrefix'],
];
$this->replaceSrc['{rc_receiverCellPhonePrefix}'] = [
'desc' => __('휴대폰번호 국가번호'),
'val' => $replaceData['receiverCellPhonePrefix'],
];
$this->replaceSrc['{rc_receiverPhonePrefixCode}'] = [
'desc' => __('전화번호 국가코드'),
'val' => $replaceData['receiverPhonePrefixCode'],
];
$this->replaceSrc['{rc_receiverCellPhonePrefixCode}'] = [
'desc' => __('휴대폰번호 국가코드'),
'val' => $replaceData['receiverCellPhonePrefixCode'],
];
$this->replaceSrc['{rc_receiverCountry}'] = [
'desc' => __('수취인 국가'),
'val' => $replaceData['receiverCountry'],
];
$this->replaceSrc['{rc_receiverCity}'] = [
'desc' => __('수취인 도시'),
'val' => $replaceData['receiverCity'],
];
$this->replaceSrc['{rc_receiverState}'] = [
'desc' => __('수취인 주소'),
'val' => $replaceData['receiverState'],
];
$this->replaceSrc['{rc_receiverNmAdd}'] = [
'desc' => __('받는 사람'),
'val' => $replaceData['receiverNmAdd'],
];
$this->replaceSrc['{rc_receiverZipcodeAdd}'] = [
'desc' => __('구 우편번호 (6자리)'),
'val' => $replaceData['receiverZipcodeAdd'],
];
$this->replaceSrc['{rc_receiverZonecodeAdd}'] = [
'desc' => __('우편번호'),
'val' => $replaceData['receiverZonecodeAdd'],
];
$this->replaceSrc['{rc_receiverAddressAdd}'] = [
'desc' => __('주소'),
'val' => $replaceData['receiverAddressAdd'],
];
$this->replaceSrc['{rc_receiverAddressSubAdd}'] = [
'desc' => __('상세주소'),
'val' => $replaceData['receiverAddressSubAdd'],
];
$this->replaceSrc['{rc_receiverPhoneAdd}'] = [
'desc' => __('전화번호'),
'val' => $replaceData['receiverPhoneAdd'],
];
$this->replaceSrc['{rc_receiverCellPhoneAdd}'] = [
'desc' => __('휴대폰번호'),
'val' => $replaceData['receiverCellPhoneAdd'],
];
$this->replaceSrc['{rc_orderMemoAdd}'] = [
'desc' => __('배송메시지'),
'val' => $replaceData['orderMemoAdd'],
];
}
 
 
변경 후ReplaceCode.php
use Framework\Utility\ComponentUtils;
use Framework\Utility\DateTimeUtils;
use Framework\Utility\SkinUtils;
use Framework\Utility\StringUtils;
use Globals;
use Logger;
 
Logger::info(__METHOD__);
$this->replaceSrc['{rc_memNm}'] = [
'desc' => __('회원명'),
'val' => StringUtils::htmlSpecialChars($replaceData['memNm'] ?? ''),
];
$this->replaceSrc['{rc_orderDt}'] = [
'desc' => __('주문일시'),
];
$this->replaceSrc['{rc_orderNm}'] = [
'desc' => __('주문자명'),
'val' => StringUtils::htmlSpecialChars($replaceData['orderNm'] ?? ''),
];
$this->replaceSrc['{rc_orderNo}'] = [
'desc' => __('주문번호'),
];
$this->replaceSrc['{rc_receiverNm}'] = [
'desc' => __('받는 사람'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverNm'] ?? ''),
];
$this->replaceSrc['{rc_receiverZipcode}'] = [
'desc' => __('구 우편번호 (6자리)'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverZipcode'] ?? ''),
];
$this->replaceSrc['{rc_receiverZonecode}'] = [
'desc' => __('우편번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverZonecode'] ?? ''),
];
$this->replaceSrc['{rc_receiverAddress}'] = [
'desc' => __('주소'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverAddress'] ?? ''),
];
$this->replaceSrc['{rc_receiverAddressSub}'] = [
'desc' => __('상세주소'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverAddressSub'] ?? ''),
];
$this->replaceSrc['{rc_receiverPhone}'] = [
'desc' => __('전화번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverPhone'] ?? ''),
];
$this->replaceSrc['{rc_receiverCellPhone}'] = [
'desc' => __('휴대폰번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverCellPhone'] ?? ''),
];
$this->replaceSrc['{rc_receiverMemo}'] = [
'desc' => __('배송메시지'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverMemo'] ?? ''),
];
$this->replaceSrc['{rc_receiverPhonePrefix}'] = [
'desc' => __('전화번호 국가번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverPhonePrefix'] ?? ''),
];
$this->replaceSrc['{rc_receiverCellPhonePrefix}'] = [
'desc' => __('휴대폰번호 국가번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverCellPhonePrefix'] ?? ''),
];
$this->replaceSrc['{rc_receiverPhonePrefixCode}'] = [
'desc' => __('전화번호 국가코드'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverPhonePrefixCode'] ?? ''),
];
$this->replaceSrc['{rc_receiverCellPhonePrefixCode}'] = [
'desc' => __('휴대폰번호 국가코드'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverCellPhonePrefixCode'] ?? ''),
];
$this->replaceSrc['{rc_receiverCountry}'] = [
'desc' => __('수취인 국가'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverCountry'] ?? ''),
];
$this->replaceSrc['{rc_receiverCity}'] = [
'desc' => __('수취인 도시'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverCity'] ?? ''),
];
$this->replaceSrc['{rc_receiverState}'] = [
'desc' => __('수취인 주소'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverState'] ?? ''),
];
$this->replaceSrc['{rc_totalDeliveryInsuranceFee}'] = [
'desc' => __('EMS 해외 총 보험료'),
];
$this->replaceSrc['{rc_receiverNmAdd}'] = [
'desc' => __('받는 사람'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverNmAdd'] ?? ''),
];
$this->replaceSrc['{rc_receiverZipcodeAdd}'] = [
'desc' => __('구 우편번호 (6자리)'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverZipcodeAdd'] ?? ''),
];
$this->replaceSrc['{rc_receiverZonecodeAdd}'] = [
'desc' => __('우편번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverZonecodeAdd'] ?? ''),
];
$this->replaceSrc['{rc_receiverAddressAdd}'] = [
'desc' => __('주소'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverAddressAdd'] ?? ''),
];
$this->replaceSrc['{rc_receiverAddressSubAdd}'] = [
'desc' => __('상세주소'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverAddressSubAdd'] ?? ''),
];
$this->replaceSrc['{rc_receiverPhoneAdd}'] = [
'desc' => __('전화번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverPhoneAdd'] ?? ''),
];
$this->replaceSrc['{rc_receiverCellPhoneAdd}'] = [
'desc' => __('휴대폰번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverCellPhoneAdd'] ?? ''),
];
$this->replaceSrc['{rc_orderMemoAdd}'] = [
'desc' => __('배송메시지'),
'val' => StringUtils::htmlSpecialChars($replaceData['orderMemoAdd'] ?? ''),
];
$this->replaceSrc['{rc_expirationDate}'] = [
'desc' => __('입금만료일(yyyy-mm-dd hh:mm)'),
];
$this->replaceSrc['{rc_orderNm}'] = [
'desc' => __('주문자명'),
'val' => StringUtils::htmlSpecialChars($replaceData['orderNm'] ?? ''),
];
$this->replaceSrc['{rc_bankSender}'] = [
'desc' => __('입금자명'),
'val' => StringUtils::htmlSpecialChars($replaceData['bankSender'] ?? ''),
];
$this->replaceSrc['{rc_orderNo}'] = [
'desc' => __('주문번호'),
Logger::info(__METHOD__);
$this->replaceSrc['{rc_orderNm}'] = [
'desc' => __('주문자명'),
'val' => StringUtils::htmlSpecialChars($replaceData['orderNm'] ?? ''),
];
$this->replaceSrc['{rc_bankSender}'] = [
'desc' => __('입금자명'),
'val' => StringUtils::htmlSpecialChars($replaceData['bankSender'] ?? ''),
];
$this->replaceSrc['{rc_orderNo}'] = [
'desc' => __('주문번호'),
];
$this->replaceSrc['{rc_receiverNm}'] = [
'desc' => __('받는 사람'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverNm'] ?? ''),
];
$this->replaceSrc['{rc_receiverZipcode}'] = [
'desc' => __('구 우편번호 (6자리)'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverZipcode'] ?? ''),
];
$this->replaceSrc['{rc_receiverZonecode}'] = [
'desc' => __('우편번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverZonecode'] ?? ''),
];
$this->replaceSrc['{rc_receiverAddress}'] = [
'desc' => __('주소'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverAddress'] ?? ''),
];
$this->replaceSrc['{rc_receiverAddressSub}'] = [
'desc' => __('상세주소'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverAddressSub'] ?? ''),
];
$this->replaceSrc['{rc_receiverPhone}'] = [
'desc' => __('전화번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverPhone'] ?? ''),
];
$this->replaceSrc['{rc_receiverCellPhone}'] = [
'desc' => __('휴대폰번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverCellPhone'] ?? ''),
];
$this->replaceSrc['{rc_receiverMemo}'] = [
'desc' => __('배송메시지'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverMemo'] ?? ''),
];
$this->replaceSrc['{rc_receiverPhonePrefix}'] = [
'desc' => __('전화번호 국가번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverPhonePrefix'] ?? ''),
];
$this->replaceSrc['{rc_receiverCellPhonePrefix}'] = [
'desc' => __('휴대폰번호 국가번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverCellPhonePrefix'] ?? ''),
];
$this->replaceSrc['{rc_receiverPhonePrefixCode}'] = [
'desc' => __('전화번호 국가코드'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverPhonePrefixCode'] ?? ''),
];
$this->replaceSrc['{rc_receiverCellPhonePrefixCode}'] = [
'desc' => __('휴대폰번호 국가코드'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverCellPhonePrefixCode'] ?? ''),
];
$this->replaceSrc['{rc_receiverCountry}'] = [
'desc' => __('수취인 국가'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverCountry'] ?? ''),
];
$this->replaceSrc['{rc_receiverCity}'] = [
'desc' => __('수취인 도시'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverCity'] ?? ''),
];
$this->replaceSrc['{rc_receiverState}'] = [
'desc' => __('수취인 주소'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverState'] ?? ''),
];
$this->replaceSrc['{rc_receiverNmAdd}'] = [
'desc' => __('받는 사람'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverNmAdd'] ?? ''),
];
$this->replaceSrc['{rc_receiverZipcodeAdd}'] = [
'desc' => __('구 우편번호 (6자리)'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverZipcodeAdd'] ?? ''),
];
$this->replaceSrc['{rc_receiverZonecodeAdd}'] = [
'desc' => __('우편번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverZonecodeAdd'] ?? ''),
];
$this->replaceSrc['{rc_receiverAddressAdd}'] = [
'desc' => __('주소'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverAddressAdd'] ?? ''),
];
$this->replaceSrc['{rc_receiverAddressSubAdd}'] = [
'desc' => __('상세주소'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverAddressSubAdd'] ?? ''),
];
$this->replaceSrc['{rc_receiverPhoneAdd}'] = [
'desc' => __('전화번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverPhoneAdd'] ?? ''),
];
$this->replaceSrc['{rc_receiverCellPhoneAdd}'] = [
'desc' => __('휴대폰번호'),
'val' => StringUtils::htmlSpecialChars($replaceData['receiverCellPhoneAdd'] ?? ''),
];
$this->replaceSrc['{rc_orderMemoAdd}'] = [
'desc' => __('배송메시지'),
'val' => StringUtils::htmlSpecialChars($replaceData['orderMemoAdd'] ?? ''),
];
}
 
 
Component/Order/OrderNew.php+88-3
변경 전OrderNew.php
const SETTLE_KIND_LATER = 'pl'; // 기타. 네이버페이에서 "후불결제"로 결제된 경우
const SETTLE_KIND_FINTECH_UNKNOWN = 'fu'; // 페이코/네이버페이에서 상품상세에서 주문시 결제수단을 알수 없는 경우
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* @var array 영수증 신청 상태 (n : 신청 안함, r : 현금 영수증, t : 세금 계산서)
*/
// 주문 추가 필드 정보
$getData['addField'] = $this->getOrderAddFieldView($getData['addField']);
 
// 남기실 내용
$getData['orderMemo'] = nl2br($getData['orderMemo']);
 
// 무통장 입금 은행 정보
$getData['bankAccount'] = explode(STR_DIVISION, $getData['bankAccount']);
 
return $getData;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 배송지 정보 수정
*/
 
변경 후OrderNew.php
const SETTLE_KIND_LATER = 'pl'; // 기타. 네이버페이에서 "후불결제"로 결제된 경우
const SETTLE_KIND_FINTECH_UNKNOWN = 'fu'; // 페이코/네이버페이에서 상품상세에서 주문시 결제수단을 알수 없는 경우
 
/**
* @var array 뷰 출력 전 이스케이프가 필요한 주문자·수령자 정보 필드
*/
const RECEIVER_ESCAPE_FIELDS = [
'orderName',
'orderPhone',
'orderPhonePrefix',
'orderCellPhone',
'orderCellPhonePrefix',
'orderEmail',
'orderZonecode',
'orderZipcode',
'orderAddress',
'orderAddressSub',
'orderCity',
'orderState',
'orderCountry',
'receiverName',
'receiverNm', // 멀티 배송지 정보의 수령자명 키
'receiverPhone',
'receiverPhonePrefix',
'receiverCellPhone',
'receiverCellPhonePrefix',
'receiverZonecode',
'receiverZipcode',
'receiverAddress',
'receiverAddressSub',
'receiverCity',
'receiverState',
'receiverCountry',
'visitName',
'visitPhone',
'visitAddress',
'visitMemo', // 방문수령 메모
];
 
/**
* @var array 영수증 신청 상태 (n : 신청 안함, r : 현금 영수증, t : 세금 계산서)
*/
// 주문 추가 필드 정보
$getData['addField'] = $this->getOrderAddFieldView($getData['addField']);
 
 
 
 
// 무통장 입금 은행 정보
$getData['bankAccount'] = explode(STR_DIVISION, $getData['bankAccount']);
 
return $getData;
}
 
/**
* 수령자 정보 필드를 뷰 출력용으로 이스케이프
*
* 주문 데이터 전체는 goodsImage·gift.imageUrl 처럼 서버에서 생성한 이미지 태그를
* 포함하므로 통째로 이스케이프할 수 없다.
* 남기실 내용은 이스케이프 뒤에 nl2br 을 거쳐야 줄바꿈이 글자로 보이지 않으므로
* 조회 메서드가 아니라 이 메서드가 줄바꿈 변환까지 담당한다.
* 수령자명·연락처를 가공하는 처리(선물하기 마스킹 등)가 있으면 그 뒤에 호출해야 한다.
*
* @param array $data 주문 정보 (필드별 배열인 멀티 배송지 정보도 그대로 사용 가능)
*
* @return array 수령자 정보가 이스케이프된 주문 정보
*/
public function escapeReceiverInfo(array $data): array
{
foreach (static::RECEIVER_ESCAPE_FIELDS as $receiverField) {
if (isset($data[$receiverField])) {
$data[$receiverField] = StringUtils::htmlSpecialChars($data[$receiverField]);
}
}
 
// 마이페이지 주문상세의 방문 수령지 주소는 배송지별 중첩 배열로 출력된다
if (isset($data['visitDeliveryInfo']['address'])) {
$data['visitDeliveryInfo']['address'] = StringUtils::htmlSpecialChars($data['visitDeliveryInfo']['address']);
}
 
// 남기실 내용은 이스케이프 뒤에 줄바꿈을 변환한다
if (isset($data['orderMemo'])) {
$data['orderMemo'] = $this->nl2brRecursive(
StringUtils::htmlSpecialChars($data['orderMemo'])
);
}
 
return $data;
}
 
/**
* 문자열 또는 배열에 nl2br 을 적용
*
* @param array|string|null $value 변환할 값 (멀티 배송지는 필드별 배열로 들어온다)
*
* @return array|string 줄바꿈이 <br /> 로 변환된 값
*/
protected function nl2brRecursive($value)
{
if (is_array($value)) {
return array_map([$this, 'nl2brRecursive'], $value);
}
 
return nl2br($value ?? '');
}
 
/**
* 배송지 정보 수정
*/
 
Component/Order/Order.php+88-3
변경 전Order.php
const SETTLE_KIND_LATER = 'pl'; // 기타. 네이버페이에서 "후불결제"로 결제된 경우
const SETTLE_KIND_FINTECH_UNKNOWN = 'fu'; // 페이코/네이버페이에서 상품상세에서 주문시 결제수단을 알수 없는 경우
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* @var array 영수증 신청 상태 (n : 신청 안함, r : 현금 영수증, t : 세금 계산서)
*/
// 주문 추가 필드 정보
$getData['addField'] = $this->getOrderAddFieldView($getData['addField']);
 
// 남기실 내용
$getData['orderMemo'] = nl2br($getData['orderMemo']);
 
// 무통장 입금 은행 정보
$getData['bankAccount'] = explode(STR_DIVISION, $getData['bankAccount']);
 
return $getData;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 배송지 정보 수정
*/
 
변경 후Order.php
const SETTLE_KIND_LATER = 'pl'; // 기타. 네이버페이에서 "후불결제"로 결제된 경우
const SETTLE_KIND_FINTECH_UNKNOWN = 'fu'; // 페이코/네이버페이에서 상품상세에서 주문시 결제수단을 알수 없는 경우
 
/**
* @var array 뷰 출력 전 이스케이프가 필요한 주문자·수령자 정보 필드
*/
const RECEIVER_ESCAPE_FIELDS = [
'orderName',
'orderPhone',
'orderPhonePrefix',
'orderCellPhone',
'orderCellPhonePrefix',
'orderEmail',
'orderZonecode',
'orderZipcode',
'orderAddress',
'orderAddressSub',
'orderCity',
'orderState',
'orderCountry',
'receiverName',
'receiverNm', // 멀티 배송지 정보의 수령자명 키
'receiverPhone',
'receiverPhonePrefix',
'receiverCellPhone',
'receiverCellPhonePrefix',
'receiverZonecode',
'receiverZipcode',
'receiverAddress',
'receiverAddressSub',
'receiverCity',
'receiverState',
'receiverCountry',
'visitName',
'visitPhone',
'visitAddress',
'visitMemo', // 방문수령 메모
];
 
/**
* @var array 영수증 신청 상태 (n : 신청 안함, r : 현금 영수증, t : 세금 계산서)
*/
// 주문 추가 필드 정보
$getData['addField'] = $this->getOrderAddFieldView($getData['addField']);
 
 
 
 
// 무통장 입금 은행 정보
$getData['bankAccount'] = explode(STR_DIVISION, $getData['bankAccount']);
 
return $getData;
}
 
/**
* 수령자 정보 필드를 뷰 출력용으로 이스케이프
*
* 주문 데이터 전체는 goodsImage·gift.imageUrl 처럼 서버에서 생성한 이미지 태그를
* 포함하므로 통째로 이스케이프할 수 없다.
* 남기실 내용은 이스케이프 뒤에 nl2br 을 거쳐야 줄바꿈이 글자로 보이지 않으므로
* 조회 메서드가 아니라 이 메서드가 줄바꿈 변환까지 담당한다.
* 수령자명·연락처를 가공하는 처리(선물하기 마스킹 등)가 있으면 그 뒤에 호출해야 한다.
*
* @param array $data 주문 정보 (필드별 배열인 멀티 배송지 정보도 그대로 사용 가능)
*
* @return array 수령자 정보가 이스케이프된 주문 정보
*/
public function escapeReceiverInfo(array $data): array
{
foreach (static::RECEIVER_ESCAPE_FIELDS as $receiverField) {
if (isset($data[$receiverField])) {
$data[$receiverField] = StringUtils::htmlSpecialChars($data[$receiverField]);
}
}
 
// 마이페이지 주문상세의 방문 수령지 주소는 배송지별 중첩 배열로 출력된다
if (isset($data['visitDeliveryInfo']['address'])) {
$data['visitDeliveryInfo']['address'] = StringUtils::htmlSpecialChars($data['visitDeliveryInfo']['address']);
}
 
// 남기실 내용은 이스케이프 뒤에 줄바꿈을 변환한다
if (isset($data['orderMemo'])) {
$data['orderMemo'] = $this->nl2brRecursive(
StringUtils::htmlSpecialChars($data['orderMemo'])
);
}
 
return $data;
}
 
/**
* 문자열 또는 배열에 nl2br 을 적용
*
* @param array|string|null $value 변환할 값 (멀티 배송지는 필드별 배열로 들어온다)
*
* @return array|string 줄바꿈이 <br /> 로 변환된 값
*/
protected function nl2brRecursive($value)
{
if (is_array($value)) {
return array_map([$this, 'nl2brRecursive'], $value);
}
 
return nl2br($value ?? '');
}
 
/**
* 배송지 정보 수정
*/
 
Controller/Admin/Order/LayerReceiverInfoController.php+4-1
변경 전LayerReceiverInfoController.php
use Exception;
use Request;
use App;
 
 
/**
* Class LayerReceiverInfoController
// 모듈 설정
$order = App::load(\Component\Order\OrderAdmin::class);
$getData = $order->getOrderView($postValue['orderNo']);
$this->setData('data', $getData);
 
 
// 국가데이터 가져오기
$countriesCode = $order->getUsableCountriesList($getData['mallSno']);
 
변경 후LayerReceiverInfoController.php
use Exception;
use Request;
use App;
use Framework\Utility\StringUtils;
 
/**
* Class LayerReceiverInfoController
// 모듈 설정
$order = App::load(\Component\Order\OrderAdmin::class);
$getData = $order->getOrderView($postValue['orderNo']);
 
// XSS 방지 - 뷰(스킨/Asset) 출력용 이스케이프
$this->setData('data', StringUtils::htmlSpecialChars($getData));
// 국가데이터 가져오기
$countriesCode = $order->getUsableCountriesList($getData['mallSno']);
 
Controller/Admin/Order/OrderViewController.php+26-2
변경 전OrderViewController.php
use Globals;
use Session;
use Request;
 
 
/**
* 주문 상세 페이지
}
}
 
// 네이버페이 메모
if ($naverPayMemo) {
$this->setData('naverPayMemo', $naverPayMemo);
}
 
if($naverpayIndividualCustomUniqueCode) {
// 템플릿 데이터 설정
$this->setData('order', $order);
if ($data['orderChannelFl'] == 'naverpay') {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$this->setData('data', gd_isset($data));
} else {
$this->setData('data', gd_htmlspecialchars(gd_isset($data)));
}
 
 
 
$this->setData('withdrawnMembersPersonalData', gd_isset($withdrawnMembersPersonalData));
$this->setData('addFieldData', gd_isset($addFieldData));
$this->setData('orderStatusCode', gd_isset($orderStatusCode));
 
변경 후OrderViewController.php
use Globals;
use Session;
use Request;
use Framework\Utility\StringUtils;
 
/**
* 주문 상세 페이지
}
}
 
// 네이버페이 메모 (네이버페이 주문은 남기실 내용 대신 이 값을 출력한다)
if ($naverPayMemo) {
$this->setData('naverPayMemo', StringUtils::htmlSpecialChars($naverPayMemo));
}
 
if($naverpayIndividualCustomUniqueCode) {
// 템플릿 데이터 설정
$this->setData('order', $order);
if ($data['orderChannelFl'] == 'naverpay') {
// 네이버페이는 goods 항목의 orderStatusStr 등에 서버가 생성한 HTML 이 포함되어 전체 이스케이프가 불가하다
$receiverEscapeFields = $order::RECEIVER_ESCAPE_FIELDS;
foreach ($receiverEscapeFields as $receiverEscapeField) {
if (isset($data[$receiverEscapeField])) {
$data[$receiverEscapeField] = StringUtils::htmlSpecialChars($data[$receiverEscapeField]);
}
}
// 방문 수령지 주소는 배송지별 중첩 배열이라 필드 목록 순회에 걸리지 않는다
if (isset($data['visitDeliveryInfo']['address'])) {
$data['visitDeliveryInfo']['address'] = StringUtils::htmlSpecialChars($data['visitDeliveryInfo']['address']);
}
if (!empty($data['multiShippingList'])) {
foreach ($data['multiShippingList'] as $multiShippingKey => $multiShippingData) {
foreach ($receiverEscapeFields as $receiverEscapeField) {
if (isset($multiShippingData[$receiverEscapeField])) {
$data['multiShippingList'][$multiShippingKey][$receiverEscapeField] = StringUtils::htmlSpecialChars($multiShippingData[$receiverEscapeField]);
}
}
}
}
$this->setData('data', gd_isset($data));
} else {
$this->setData('data', gd_htmlspecialchars(gd_isset($data)));
}
if (!empty($withdrawnMembersPersonalData)) {
$withdrawnMembersPersonalData = StringUtils::htmlSpecialChars($withdrawnMembersPersonalData);
}
$this->setData('withdrawnMembersPersonalData', gd_isset($withdrawnMembersPersonalData));
$this->setData('addFieldData', gd_isset($addFieldData));
$this->setData('orderStatusCode', gd_isset($orderStatusCode));
 
Controller/Admin/Share/LayerShippingAddressController.php+4-1
변경 전LayerShippingAddressController.php
use Exception;
use App;
use Framework\Debug\Exception\AlertCloseException;
 
 
/**
* Class LayerShippingAddress
 
$order = App::load('\\Component\\Order\\Order');
$deliveryAddress = $order->getShippingAddressList($getValue['page'], $getValue['pageNum'], $getValue['memNo']);
$this->setData('deliveryAddress', $deliveryAddress);
 
 
 
// 페이지
$pageObj = \App::load('\\Component\\Page\\Page');
 
변경 후LayerShippingAddressController.php
use Exception;
use App;
use Framework\Debug\Exception\AlertCloseException;
use Framework\Utility\StringUtils;
 
/**
* Class LayerShippingAddress
 
$order = App::load('\\Component\\Order\\Order');
$deliveryAddress = $order->getShippingAddressList($getValue['page'], $getValue['pageNum'], $getValue['memNo']);
 
// XSS 방지 - 뷰(스킨/Asset) 출력용 이스케이프
$this->setData('deliveryAddress', StringUtils::htmlSpecialChars($deliveryAddress));
 
// 페이지
$pageObj = \App::load('\\Component\\Page\\Page');
 
Controller/Front/Mypage/OrderViewController.php+14-2
변경 전OrderViewController.php
 
if ($orderData['multiShippingFl'] == 'y') {
$multiOrderInfo = $order->getMultiOrderInfo(Request::get()->get('orderNo'));
$this->setData('multiOrderInfo', $multiOrderInfo);
$this->setData('isUseMultiShipping', true);
}
 
// 배송 중, 배송 완료된 상품 카운트해서 버튼 생성 여부
$orderData = $order->getOrderSettleButton($orderData);
 
$this->setData('orderData', $orderData);
 
 
 
 
 
 
$orderData = $orderData[0];
// 회원할인에 회원 배송비 할인 추가
$orderData['totalMemberDcPrice'] += $orderData['totalMemberDeliveryDcPrice'];
 
 
 
 
 
 
 
$this->setData('orderInfo', $orderData);
$this->setData('guest', Request::get()->get('guest'));
 
 
변경 후OrderViewController.php
 
if ($orderData['multiShippingFl'] == 'y') {
$multiOrderInfo = $order->getMultiOrderInfo(Request::get()->get('orderNo'));
 
$this->setData('isUseMultiShipping', true);
}
 
// 배송 중, 배송 완료된 상품 카운트해서 버튼 생성 여부
$orderData = $order->getOrderSettleButton($orderData);
 
// XSS 방지 - 수령자 정보 뷰 출력용 이스케이프
$escapedOrderData = [];
foreach ($orderData as $orderKey => $orderRow) {
$escapedOrderData[$orderKey] = $order->escapeReceiverInfo($orderRow);
}
 
$this->setData('orderData', $escapedOrderData);
$orderData = $orderData[0];
// 회원할인에 회원 배송비 할인 추가
$orderData['totalMemberDcPrice'] += $orderData['totalMemberDeliveryDcPrice'];
 
// XSS 방지 - 수령자 정보 뷰 출력용 이스케이프
$orderData = $order->escapeReceiverInfo($orderData);
if (isset($multiOrderInfo)) {
$this->setData('multiOrderInfo', $order->escapeReceiverInfo($multiOrderInfo));
}
 
$this->setData('orderInfo', $orderData);
$this->setData('guest', Request::get()->get('guest'));
 
 
Controller/Front/Mypage/ShippingController.php+4-1
변경 전ShippingController.php
use Framework\Utility\DateTimeUtils;
use App;
use Request;
 
 
/**
* Class ShippingController
$pageNo = Request::get()->get('page', 1);
 
$shippingList = $order->getShippingAddressList($pageNo, 10);
$this->setData('shippingList', $shippingList);
 
 
 
// 페이징 처리
$page = App::load(\Component\Page\Page::class);
 
변경 후ShippingController.php
use Framework\Utility\DateTimeUtils;
use App;
use Request;
use Framework\Utility\StringUtils;
 
/**
* Class ShippingController
$pageNo = Request::get()->get('page', 1);
 
$shippingList = $order->getShippingAddressList($pageNo, 10);
 
// XSS 방지 - 뷰(스킨/Asset) 출력용 이스케이프
$this->setData('shippingList', StringUtils::htmlSpecialChars($shippingList));
 
// 페이징 처리
$page = App::load(\Component\Page\Page::class);
 
Controller/Front/Order/LayerShippingAddressController.php+4-1
변경 전LayerShippingAddressController.php
use Session;
use Request;
use Exception;
 
/**
* Class LayerDeliveryAddress
// 배송지 관리 리스트
$deliveryAddress = $order->getShippingAddressList($page);
$this->setData('deliveryAddress', $deliveryAddress);
 
 
$this->setData('shippingNo', \Request::get()->get('shippingNo'));
// 페이징 처리
 
변경 후LayerShippingAddressController.php
use Session;
use Request;
use Exception;
use Framework\Utility\StringUtils;
/**
* Class LayerDeliveryAddress
// 배송지 관리 리스트
$deliveryAddress = $order->getShippingAddressList($page);
// XSS 방지 - 뷰(스킨/Asset) 출력용 이스케이프
$this->setData('deliveryAddress', StringUtils::htmlSpecialChars($deliveryAddress));
$this->setData('shippingNo', \Request::get()->get('shippingNo'));
// 페이징 처리
 
Controller/Front/Order/LayerShippingAddressRegistController.php+4-1
변경 전LayerShippingAddressRegistController.php
use Exception;
use Framework\Debug\Exception\WarningException;
use Request;
 
/**
* Class LayerDeliveryAddress
if (Request::get()->has('sno') && is_numeric(Request::get()->get('sno'))) {
$data = $order->getShippingAddressData(Request::get()->get('sno'));
$this->setData('data', $data);
 
 
$this->setData('mode', 'shipping_modify');
} else {
if (empty($order->getShippingDefaultFlYn()) === true) {
 
변경 후LayerShippingAddressRegistController.php
use Exception;
use Framework\Debug\Exception\WarningException;
use Request;
use Framework\Utility\StringUtils;
/**
* Class LayerDeliveryAddress
if (Request::get()->has('sno') && is_numeric(Request::get()->get('sno'))) {
$data = $order->getShippingAddressData(Request::get()->get('sno'));
// XSS 방지 - 뷰(스킨/Asset) 출력용 이스케이프
$this->setData('data', StringUtils::htmlSpecialChars($data));
$this->setData('mode', 'shipping_modify');
} else {
if (empty($order->getShippingDefaultFlYn()) === true) {
 
Controller/Front/Order/OrderEndController.php+8-1
변경 전OrderEndController.php
 
if ($orderInfo['multiShippingFl'] == 'y') {
$multiOrderInfo = $order->getMultiOrderInfo($orderNo);
$this->setData('multiOrderInfo', $multiOrderInfo);
 
 
}
 
// 수취인 배송 국가명
}
 
$this->setData('naverCommonInflowScript', gd_isset($naverCommonInflowScript));
 
 
 
 
 
$this->setData('orderInfo', gd_isset($orderInfo));
 
} catch (\Exception $e) {
 
변경 후OrderEndController.php
 
if ($orderInfo['multiShippingFl'] == 'y') {
$multiOrderInfo = $order->getMultiOrderInfo($orderNo);
 
// XSS 방지 - 수령자 정보 뷰 출력용 이스케이프
$this->setData('multiOrderInfo', $order->escapeReceiverInfo($multiOrderInfo));
}
 
// 수취인 배송 국가명
}
 
$this->setData('naverCommonInflowScript', gd_isset($naverCommonInflowScript));
 
// XSS 방지 - 수령자 정보 뷰 출력용 이스케이프
if (!empty($orderInfo)) {
$orderInfo = $order->escapeReceiverInfo($orderInfo);
}
$this->setData('orderInfo', gd_isset($orderInfo));
 
} catch (\Exception $e) {
 
Controller/Mobile/Mypage/LayerShippingAddressRegistController.php+4-1
변경 전LayerShippingAddressRegistController.php
use Component\Member\Util\MemberUtil;
use Exception;
use Request;
 
/**
* 배송지 등록 레이어
if (Request::get()->has('sno') && is_numeric(Request::get()->get('sno'))) {
$data = $order->getShippingAddressData(Request::get()->get('sno'));
$this->setData('data', $data);
 
 
$this->setData('mode', 'shipping_modify');
} else {
if (empty($order->getShippingDefaultFlYn()) === true) {
 
변경 후LayerShippingAddressRegistController.php
use Component\Member\Util\MemberUtil;
use Exception;
use Request;
use Framework\Utility\StringUtils;
/**
* 배송지 등록 레이어
if (Request::get()->has('sno') && is_numeric(Request::get()->get('sno'))) {
$data = $order->getShippingAddressData(Request::get()->get('sno'));
// XSS 방지 - 뷰(스킨/Asset) 출력용 이스케이프
$this->setData('data', StringUtils::htmlSpecialChars($data));
$this->setData('mode', 'shipping_modify');
} else {
if (empty($order->getShippingDefaultFlYn()) === true) {
 
Controller/Mobile/Mypage/OrderViewController.php+15-3
변경 전OrderViewController.php
 
if ($orderData['multiShippingFl'] == 'y') {
$multiOrderInfo = $order->getMultiOrderInfo(Request::get()->get('orderNo'));
$this->setData('multiOrderInfo', $multiOrderInfo);
$this->setData('isUseMultiShipping', true);
}
 
// 배송 중, 배송 완료된 상품 카운트해서 버튼 생성 여부
$orderData = $order->getOrderSettleButton($orderData);
 
$this->setData('orderData', $orderData);
 
 
 
 
 
 
 
$ordersByRegisterDay = [];
foreach ($orderData as $index => $item) {
if (empty($item['regDt']) === false) {
$ordersByRegisterDay[DateTimeUtils::dateFormat('Y-m-d', $item['regDt'])][] = $item;
$ordersByRegisterDay[DateTimeUtils::dateFormat('Y-m-d', $item['regDt'])][$index]['orderGoodsCnt'] = gd_count($item['goods']);
$this->setData('ordersByRegisterDay', $ordersByRegisterDay);
 
$orderData = $orderData[0];
 
 
 
 
 
 
 
$this->setData('orderInfo', $orderData);
$this->setData('guest', Request::get()->get('guest'));
 
 
변경 후OrderViewController.php
 
if ($orderData['multiShippingFl'] == 'y') {
$multiOrderInfo = $order->getMultiOrderInfo(Request::get()->get('orderNo'));
 
$this->setData('isUseMultiShipping', true);
}
 
// 배송 중, 배송 완료된 상품 카운트해서 버튼 생성 여부
$orderData = $order->getOrderSettleButton($orderData);
 
// XSS 방지 - 수령자 정보 뷰 출력용 이스케이프
$escapedOrderData = [];
foreach ($orderData as $orderKey => $orderRow) {
$escapedOrderData[$orderKey] = $order->escapeReceiverInfo($orderRow);
}
 
$this->setData('orderData', $escapedOrderData);
 
$ordersByRegisterDay = [];
foreach ($escapedOrderData as $index => $item) {
if (empty($item['regDt']) === false) {
$ordersByRegisterDay[DateTimeUtils::dateFormat('Y-m-d', $item['regDt'])][] = $item;
$ordersByRegisterDay[DateTimeUtils::dateFormat('Y-m-d', $item['regDt'])][$index]['orderGoodsCnt'] = gd_count($item['goods']);
$this->setData('ordersByRegisterDay', $ordersByRegisterDay);
 
$orderData = $orderData[0];
 
// XSS 방지 - 수령자 정보 뷰 출력용 이스케이프
$orderData = $order->escapeReceiverInfo($orderData);
if (isset($multiOrderInfo)) {
$this->setData('multiOrderInfo', $order->escapeReceiverInfo($multiOrderInfo));
}
 
$this->setData('orderInfo', $orderData);
$this->setData('guest', Request::get()->get('guest'));
 
 
Controller/Mobile/Mypage/ShippingController.php+4-1
변경 전ShippingController.php
use Framework\Utility\DateTimeUtils;
use App;
use Request;
 
/**
* Class ShippingController
$pageNo = Request::get()->get('page', 1);
$shippingList = $order->getShippingAddressList($pageNo, 100);
$this->setData('shippingList', $shippingList);
 
 
// 페이징 처리
$page = App::load(\Component\Page\Page::class);
 
변경 후ShippingController.php
use Framework\Utility\DateTimeUtils;
use App;
use Request;
use Framework\Utility\StringUtils;
/**
* Class ShippingController
$pageNo = Request::get()->get('page', 1);
$shippingList = $order->getShippingAddressList($pageNo, 100);
// XSS 방지 - 뷰(스킨/Asset) 출력용 이스케이프
$this->setData('shippingList', StringUtils::htmlSpecialChars($shippingList));
// 페이징 처리
$page = App::load(\Component\Page\Page::class);
 
Controller/Mobile/Order/OrderController.php+3-1
변경 전OrderController.php
if((int)Session::get('member.memNo') > 0){
// 기본 배송지 정보 가져오기
$defaultShippingAddress = $order->getDefaultShippingAddress();
$this->setData('basiceShippingAddress', $defaultShippingAddress);
 
 
$this->setData('shippingDefaultFl', $order->getShippingDefaultFlYn());
}
 
 
변경 후OrderController.php
if((int)Session::get('member.memNo') > 0){
// 기본 배송지 정보 가져오기
$defaultShippingAddress = $order->getDefaultShippingAddress();
 
// XSS 방지 - 뷰 출력용 이스케이프 (원본은 아래 shippingCountryCode 판별에 재사용)
$this->setData('basiceShippingAddress', StringUtils::htmlSpecialChars($defaultShippingAddress));
$this->setData('shippingDefaultFl', $order->getShippingDefaultFlYn());
}
 
 
Controller/Mobile/Order/OrderEndController.php+8-1
변경 전OrderEndController.php
 
if ($orderInfo['multiShippingFl'] == 'y') {
$multiOrderInfo = $order->getMultiOrderInfo($orderNo);
$this->setData('multiOrderInfo', $multiOrderInfo);
 
 
}
 
$dbUrl = \App::load('\\Component\\Marketing\\DBUrl');
}
 
$this->setData('naverCommonInflowScript', gd_isset($naverCommonInflowScript));
 
 
 
 
 
$this->setData('orderInfo', gd_isset($orderInfo));
 
} catch (\Exception $e) {
 
변경 후OrderEndController.php
 
if ($orderInfo['multiShippingFl'] == 'y') {
$multiOrderInfo = $order->getMultiOrderInfo($orderNo);
 
// XSS 방지 - 수령자 정보 뷰 출력용 이스케이프
$this->setData('multiOrderInfo', $order->escapeReceiverInfo($multiOrderInfo));
}
 
$dbUrl = \App::load('\\Component\\Marketing\\DBUrl');
}
 
$this->setData('naverCommonInflowScript', gd_isset($naverCommonInflowScript));
 
// XSS 방지 - 수령자 정보 뷰 출력용 이스케이프
if (!empty($orderInfo)) {
$orderInfo = $order->escapeReceiverInfo($orderInfo);
}
$this->setData('orderInfo', gd_isset($orderInfo));
 
} catch (\Exception $e) {
 
Controller/Mobile/Order/OrderPsController.php+6
변경 전OrderPsController.php
use Framework\Debug\Exception\AlertBackException;
use Framework\Utility\NumberUtils;
use Framework\Utility\ProducerUtils;
 
use Globals;
use Origin\Service\Order\OrderInfoService;
use Request;
try {
$order = App::load(\Component\Order\Order::class);
$deliveryAddress = $order->getShippingAddressList(1, 999);
 
 
 
 
 
$this->json($deliveryAddress);
} catch (Exception $e) {
$this->json([
 
변경 후OrderPsController.php
use Framework\Debug\Exception\AlertBackException;
use Framework\Utility\NumberUtils;
use Framework\Utility\ProducerUtils;
use Framework\Utility\StringUtils;
use Globals;
use Origin\Service\Order\OrderInfoService;
use Request;
try {
$order = App::load(\Component\Order\Order::class);
$deliveryAddress = $order->getShippingAddressList(1, 999);
 
// XSS 방지 - 스킨이 innerHTML로 출력하는 shippingTitle만 이스케이프 (나머지 필드는 .val()로 input에 채워져 이스케이프하면 엔티티가 그대로 노출됨)
foreach ($deliveryAddress as $key => $shippingAddress) {
$deliveryAddress[$key]['shippingTitle'] = StringUtils::htmlSpecialChars($shippingAddress['shippingTitle']);
}
$this->json($deliveryAddress);
} catch (Exception $e) {
$this->json([
 
data/skin/mobile/moment/order/order.html-54
변경 전order.html
<div id="pgSettlementApplyLayer" data-key="pg-layer"></div>
<!--//PG 결제 적용하기 레이어 -->
<!-- 나의 배송지 관리 레이어 -->
<script id="myShippingList" type="text/html">
<li class="delivery_item">
<div class="inp_rdo">
 
<input type="radio" id="input<%=idx%>" name="shipping"/>
<label for="input<%=idx%>"></label>
 
</div>
<div class="del_body">
<label for="input1">
<div class="del-name">
<span class="shipping_name"><strong><%=shippingName%></strong></span>
<% if (defaultFl == 'y') { %>
<span>({=__('기본배송지')})</span>
<% } %>
</div>
<div class="del-address">
<span class="shipping_zonecode"><%=shippingZonecode%></span>
<% if (shippingZipcode != '') { %>
(
<span class="shipping_zipcode"><%=shippingZipcode%></span>
)
<% } %>
<!--{ ? gGlobal.isFront }-->
<span class="shipping_addresssub"><%=shippingAddressSub%></span>,
<span class="shipping_address"><%=shippingAddress%></span>,
<span class="shipping_state"><%=shippingState%></span>,
<span class="shipping_city"><%=shippingCity%></span>,
<span class="shipping_country"><%=shippingCountry%></span>
<span class="shipping_country_code dn"><%=shippingCountryCode%></span>
<!--{ : }-->
<span class="shipping_address"><%=shippingAddress%></span>
<span class="shipping_addresssub"><%=shippingAddressSub%></span>
<!--{ / }-->
</div>
<div class="del-callnum">
<!--{ ? gGlobal.isFront }-->
(+<span class="shipping_cellphone_prefix"><%=shippingCellPhonePrefix%></span>)
<span class="shipping_cellphone_prefixcode dn"><%=shippingCellPhonePrefixCode%></span>
<!--{ / }-->
<span class="shipping_cellphone"><%=shippingCellPhone%></span>
 
<span class="dn">
<!--{ ? gGlobal.isFront }-->
(+<span class="shipping_phone_prefix"><%=shippingPhonePrefix%></span>)
<span class="shipping_phone_prefixcode dn"><%=shippingPhonePrefixCode%></span>
<!--{ / }-->
<span class="shipping_phone"><%=shippingPhone%></span>
</span>
</div>
</label>
</div>
</li>
</script>
<!-- //나의 배송지 관리 레이어 -->
<!--{ ? isUseMultiShipping === true }-->
<script type="text/html" class="template" id="multiShippingRow">
 
변경 후order.html
<div id="pgSettlementApplyLayer" data-key="pg-layer"></div>
<!--//PG 결제 적용하기 레이어 -->
<!-- 나의 배송지 관리 레이어 -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<!-- //나의 배송지 관리 레이어 -->
<!--{ ? isUseMultiShipping === true }-->
<script type="text/html" class="template" id="multiShippingRow">
 
data/skin/mobile/mygreek/order/order.html-54
변경 전order.html
<div id="pgSettlementApplyLayer" data-key="pg-layer"></div>
<!--//PG 결제 적용하기 레이어 -->
<!-- 나의 배송지 관리 레이어 -->
<script id="myShippingList" type="text/html">
<li class="delivery_item">
<div class="inp_rdo">
 
<input type="radio" id="input<%=idx%>" name="shipping"/>
<label for="input<%=idx%>"></label>
 
</div>
<div class="del_body">
<label for="input1">
<div class="del-name">
<span class="shipping_name"><strong><%=shippingName%></strong></span>
<% if (defaultFl == 'y') { %>
<span>({=__('기본배송지')})</span>
<% } %>
</div>
<div class="del-address">
<span class="shipping_zonecode"><%=shippingZonecode%></span>
<% if (shippingZipcode != '') { %>
(
<span class="shipping_zipcode"><%=shippingZipcode%></span>
)
<% } %>
<!--{ ? gGlobal.isFront }-->
<span class="shipping_addresssub"><%=shippingAddressSub%></span>,
<span class="shipping_address"><%=shippingAddress%></span>,
<span class="shipping_state"><%=shippingState%></span>,
<span class="shipping_city"><%=shippingCity%></span>,
<span class="shipping_country"><%=shippingCountry%></span>
<span class="shipping_country_code dn"><%=shippingCountryCode%></span>
<!--{ : }-->
<span class="shipping_address"><%=shippingAddress%></span>
<span class="shipping_addresssub"><%=shippingAddressSub%></span>
<!--{ / }-->
</div>
<div class="del-callnum">
<!--{ ? gGlobal.isFront }-->
(+<span class="shipping_cellphone_prefix"><%=shippingCellPhonePrefix%></span>)
<span class="shipping_cellphone_prefixcode dn"><%=shippingCellPhonePrefixCode%></span>
<!--{ / }-->
<span class="shipping_cellphone"><%=shippingCellPhone%></span>
 
<span class="dn">
<!--{ ? gGlobal.isFront }-->
(+<span class="shipping_phone_prefix"><%=shippingPhonePrefix%></span>)
<span class="shipping_phone_prefixcode dn"><%=shippingPhonePrefixCode%></span>
<!--{ / }-->
<span class="shipping_phone"><%=shippingPhone%></span>
</span>
</div>
</label>
</div>
</li>
</script>
<!-- //나의 배송지 관리 레이어 -->
<!--{ ? isUseMultiShipping === true }-->
<script type="text/html" class="template" id="multiShippingRow">
 
변경 후order.html
<div id="pgSettlementApplyLayer" data-key="pg-layer"></div>
<!--//PG 결제 적용하기 레이어 -->
<!-- 나의 배송지 관리 레이어 -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<!-- //나의 배송지 관리 레이어 -->
<!--{ ? isUseMultiShipping === true }-->
<script type="text/html" class="template" id="multiShippingRow">
 
data/skin/mobile/story_g/order/order.html-54
변경 전order.html
<div id="pgSettlementApplyLayer" class="btm-fix-layer pg-layer" data-key="pg-layer"></div>
<!--//PG 결제 적용하기 레이어 -->
<!-- 나의 배송지 관리 레이어 -->
<script id="myShippingList" type="text/html">
<li class="delivery-item">
<div class="del-head inp_rdo">
 
<input type="radio" id="input<%=idx%>" name="shipping" class="sp">
<label for="input<%=idx%>"></label>
 
</div>
<div class="del-body">
<label for="input1">
<div class="del-name">
<span class="shipping-name"><strong><%=shippingName%></strong></span>
<% if (defaultFl == 'y') { %>
<span class="c-orange">({=__('기본배송지')})</span>
<% } %>
</div>
<div class="del-address">
<span class="shipping-zonecode"><%=shippingZonecode%></span>
<% if (shippingZipcode != '') { %>
(
<span class="shipping-zipcode"><%=shippingZipcode%></span>
)
<% } %>
<!--{ ? gGlobal.isFront }-->
<span class="shipping-addresssub"><%=shippingAddressSub%></span>,
<span class="shipping-address"><%=shippingAddress%></span>,
<span class="shipping-state"><%=shippingState%></span>,
<span class="shipping-city"><%=shippingCity%></span>,
<span class="shipping-country"><%=shippingCountry%></span>
<span class="shipping-country-code dn"><%=shippingCountryCode%></span>
<!--{ : }-->
<span class="shipping-address"><%=shippingAddress%></span>
<span class="shipping-addresssub"><%=shippingAddressSub%></span>
<!--{ / }-->
</div>
<div class="del-callnum">
<!--{ ? gGlobal.isFront }-->
(+<span class="shipping-cellphone-prefix"><%=shippingCellPhonePrefix%></span>)
<span class="shipping-cellphone-prefixcode dn"><%=shippingCellPhonePrefixCode%></span>
<!--{ / }-->
<span class="shipping-cellphone"><%=shippingCellPhone%></span>
 
<span class="dn">
<!--{ ? gGlobal.isFront }-->
(+<span class="shipping-phone-prefix"><%=shippingPhonePrefix%></span>)
<span class="shipping-phone-prefixcode dn"><%=shippingPhonePrefixCode%></span>
<!--{ / }-->
<span class="shipping-phone"><%=shippingPhone%></span>
</span>
</div>
</label>
</div>
</li>
</script>
 
<!--{ ? isUseMultiShipping === true }-->
<script type="text/html" class="template" id="multiShippingRow">
 
변경 후order.html
<div id="pgSettlementApplyLayer" class="btm-fix-layer pg-layer" data-key="pg-layer"></div>
<!--//PG 결제 적용하기 레이어 -->
<!-- 나의 배송지 관리 레이어 -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<!--{ ? isUseMultiShipping === true }-->
<script type="text/html" class="template" id="multiShippingRow">
 
주문 메뉴 개인정보 접속기록 미적재 및 엑셀 다운로드 처리건수 오류 수정
Component/Admin/AdminLogDAO.php+42-7
변경 전AdminLogDAO.php
use Framework\Utility\StringUtils;
use Origin\Service\Member\ManagerEditPolicy;
use Origin\Enum\Policy\AccessLogAction;
 
 
 
/**
* Class AdminLogDAO
* @return array
*/
public function setDisplayAdminLogList($data){
 
foreach ($data as $lKey => $lVal) {
$data[$lKey]['displayDetailLogFl'] = 'n';
$fileName = end(explode('/', $lVal['baseUri']));
 
 
 
 
 
 
 
 
// 회원정보 조회를 할 경우에만 상세로그 노출
switch ($fileName) {
*/
public function setDisplayAdminLogInfo($data)
{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$fileUri = explode('/', $data['baseUri']);
$fileName = end($fileUri);
$result['searchCnt'] = $data['data']['searchCnt'];
$result['searchData'] = $data['data']['searchData'];
$result['key'] = $data['data']['GET']['key'];
$result['keyword'] = $data['data']['GET']['keyword'];
$result['viewCnt'] = gd_count(explode(',', $data['data']['searchData']));
 
if ($data['data']['searchCnt'] > 1) {
 
 
if ($result['viewCnt'] > 1) {
$searchData = $data['data']['searchData'];
} else {
if (empty($data['data']['POST']['excelDownloadReason']) === false) {
$result['downloadReason'] = '사유 : ' . $data['data']['POST']['excelDownloadReason'];
}
if (empty($data['data']['POST']['totalCount']) === false) {
$result['searchTargetMsg'] .= '<br>처리건수 : ' . number_format($data['data']['POST']['totalCount']) . '건';
 
}
break;
case 'crema_ps.php':
if (empty($searchCondition) == false && $searchConditionMsgView === true) {
$result['searchConditionMsg'] = '처리조건 : ' . $searchCondition;
}
if (empty($searchViewCnt) == false && $searchViewCntView === true) {
$result['searchViewCnt'] = '처리건수 : ' . $searchViewCnt . '건';
}
if ($searchTarget != '') {
 
private function getActionName($pageData)
{
return $this->getValue('action', $pageData, '조회');
}
 
private function getMenuName($menu)
 
변경 후AdminLogDAO.php
use Framework\Utility\StringUtils;
use Origin\Service\Member\ManagerEditPolicy;
use Origin\Enum\Policy\AccessLogAction;
use Origin\Enum\Admin\AdminLogAction;
use Framework\Log\PrivacyLog\PrivacyLogResolverRegistry;
 
/**
* Class AdminLogDAO
* @return array
*/
public function setDisplayAdminLogList($data){
$registry = App::getInstance(PrivacyLogResolverRegistry::class);
foreach ($data as $lKey => $lVal) {
$data[$lKey]['displayDetailLogFl'] = 'n';
// 개인정보접속기록 엑셀 다운로드 내역처럼 baseUri 없이 조회한 목록도 있다
$baseUri = (string) ($lVal['baseUri'] ?? '');
$logData = is_string($lVal['data'] ?? null) ? (json_decode($lVal['data'], true) ?: []) : [];
if ($registry->findDisplayResolver($baseUri, $logData) !== null) {
$data[$lKey]['displayDetailLogFl'] = 'y';
continue;
}
$fileName = basename($baseUri);
 
// 회원정보 조회를 할 경우에만 상세로그 노출
switch ($fileName) {
*/
public function setDisplayAdminLogInfo($data)
{
$registry = App::getInstance(PrivacyLogResolverRegistry::class);
$resolver = $registry->findDisplayResolver($data['baseUri']);
if ($resolver !== null) {
$result = $resolver->getDisplayData($data['baseUri'], $data['data']);
$result['searchCnt'] = $data['data']['searchCnt'] ?? null;
$result['searchData'] = htmlspecialchars($result['searchData'], ENT_QUOTES, 'UTF-8');
$result['searchConditionMsg'] = '처리조건 : ' . htmlspecialchars($result['keyValue'], ENT_QUOTES, 'UTF-8');
if ($result['keyword'] !== '') {
$result['searchConditionMsg'] .= ' (' . htmlspecialchars($result['keyword'], ENT_QUOTES, 'UTF-8') . ')';
}
$result['searchViewCnt'] = '처리건수 : ' . $result['viewCnt'] . '건';
$contents = [$result['searchConditionMsg'], $result['searchViewCnt']];
if ($result['searchData'] !== '') {
$result['searchTargetMsg'] = '처리대상 : ' . $result['searchData'];
$contents[] = $result['searchTargetMsg'];
}
$result['logContents'] = implode('<br />', $contents);
 
return $result;
}
 
$data['data']['searchData'] = $data['data']['searchData'] ?? '';
$fileUri = explode('/', $data['baseUri']);
$fileName = end($fileUri);
$result['searchCnt'] = $data['data']['searchCnt'];
$result['searchData'] = $data['data']['searchData'];
$result['key'] = $data['data']['GET']['key'];
$result['keyword'] = $data['data']['GET']['keyword'];
$result['viewCnt'] = empty($data['data']['searchData']) ? 0 : count(explode(',', $data['data']['searchData']));
 
if ($result['viewCnt'] === 0) {
$searchData = '';
} elseif ($data['data']['searchCnt'] > 1) {
if ($result['viewCnt'] > 1) {
$searchData = $data['data']['searchData'];
} else {
if (empty($data['data']['POST']['excelDownloadReason']) === false) {
$result['downloadReason'] = '사유 : ' . $data['data']['POST']['excelDownloadReason'];
}
$totalCount = $data['data']['POST']['totalCount'] ?? null;
if ($totalCount !== null && $totalCount !== '') {
$result['searchTargetMsg'] .= '<br>처리건수 : ' . number_format($totalCount) . '건';
}
break;
case 'crema_ps.php':
if (empty($searchCondition) == false && $searchConditionMsgView === true) {
$result['searchConditionMsg'] = '처리조건 : ' . $searchCondition;
}
if ($searchViewCntView) {
$result['searchViewCnt'] = '처리건수 : ' . $searchViewCnt . '건';
}
if ($searchTarget != '') {
 
private function getActionName($pageData)
{
return $this->getValue('action', $pageData, AdminLogAction::VIEW);
}
 
private function getMenuName($menu)
 
Component/Bankda/BankdaGhostDepositor.php+3
변경 전BankdaGhostDepositor.php
/**
* 미확인 입금자 디비 저장
* @param array $arrData 미확인 입금자 배열
 
*/
public function registerGhostDepositor($arrData) {
$insertData['depositPrice'] = isset($arrData['depositPrice']) ? $arrData['depositPrice'] : '';
$arrBind = $this->db->get_binding(DBTableField::tableGhostDepositor(), $insertData, 'insert');
$this->db->set_insert_db(DB_GHOST_DEPOSITOR, $arrBind['param'], $arrBind['bind'], 'y');
 
 
}
/**
 
변경 후BankdaGhostDepositor.php
/**
* 미확인 입금자 디비 저장
* @param array $arrData 미확인 입금자 배열
* @return int|string 등록된 미확인 입금자 번호
*/
public function registerGhostDepositor($arrData) {
$insertData['depositPrice'] = isset($arrData['depositPrice']) ? $arrData['depositPrice'] : '';
$arrBind = $this->db->get_binding(DBTableField::tableGhostDepositor(), $insertData, 'insert');
$this->db->set_insert_db(DB_GHOST_DEPOSITOR, $arrBind['param'], $arrBind['bind'], 'y');
return $this->db->insert_id();
}
/**
 
Component/Excel/ExcelOrderConvert.php+1
변경 전ExcelOrderConvert.php
'fail' => $failCnt,
'functionAuth' => $functionAuthCnt,
'message' => $failMessage,
 
];
}
 
 
변경 후ExcelOrderConvert.php
'fail' => $failCnt,
'functionAuth' => $functionAuthCnt,
'message' => $failMessage,
'groupCd' => $groupCd,
];
}
 
 
Component/Excel/ExcelRequest.php+123-5
변경 전ExcelRequest.php
*/
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
public function makeExcelFile(&$arrData)
{
$excleForm = \App::load('\\Component\\Excel\\ExcelForm');
$this->fileConfig['menu'] = $formData['menu'];
$this->fileConfig['location'] = $formData['location'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
if (!is_dir(UserFilePath::data('excel', $formData['menu'])->getPathName())) {
mkdir(UserFilePath::data('excel', $formData['menu'])->getPathName(), 0707);
}
$tmpGetData = $this->getMemberMemberList(unserialize($arrData['whereCondition']), $formData['excelField'], $excelFieldName);
}
$getData = $tmpGetData['getData'];
$arrData['totalCount'] = $tmpGetData['totalCount'];
} else if ($formData['menu'] == 'promotion' && $formData['location'] == 'coupon_manage') {
$getData = $this->getPromotionCouponManage($arrData, $formData['excelField'], $excelFieldName);
} else if ($formData['menu'] == 'promotion' && $formData['location'] == 'coupon_offline_manage') {
}
 
if ($getData) {
 
if (\is_array($getData)) {
foreach ($getData as $k => $v) {
$this->genarateFile($v);
 
 
}
} else {
if (gd_isset($this->fileConfig['password'])) {
$arrData['filePath'] = "excel" . DS . $formData['menu'];
$arrData['fileName'] = gd_implode(STR_DIVISION, $this->fileConfig['fileName']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$arrData['state'] = "y";
$arrData['expiryDate'] = date("Y-m-d", strtotime("+7 day"));
 
$setData = $setHedData = [];
$setHedData[] = '<tr>';
foreach ($data as $k => $v) {
 
$tmpData = [];
foreach ($v as $key => $val) {
if (($key % 20 == 0 && $key != '0') || $totalNum - 1 == $key) {
$orderData = $orderAdmin->getOrderListForAdminExcel($whereCondition, $whereCondition['periodFl'], $isUserHandle, $orderType, $excelField, 0, $this->excelPageNum);
 
//튜닝한 업체를 위해 데이터 맞춤
if (empty($orderData['totalCount']) === true && empty($orderData['orderList']) === true) {
$isGenerator = false;
$totalNum = gd_count($orderData);
if ($this->excelPageNum) $orderList = array_chunk($orderData, $this->excelPageNum, true);
$totalNum = gd_count($orderData['totalCount']);
$orderList = $orderData['orderList'];
if (gd_is_provider() && $orderType == 'goods') {
$totalScmInfo = $orderData['totalScmInfo'];
}
}
 
 
 
 
//값이 입력되지 않은 것으로 간주하고 전체 다운로드.
if ($this->excelPageNum == 0) {
$pageNum = 0;
$data = $orderList[$i];
}
 
 
foreach ($data as $key => $val) {
$progress = ($totalNum == 1) ? 100 : round((100 / ($totalNum - 1)) * ($key + ($i * $this->excelPageNum)));
if ($progress % 20 == 0 || $progress == '100') {
} else {
fwrite($fh, gd_implode(chr(10), $tmpData));
}
 
unset($tmpData);
}
//exit;
fclose($fh);
 
$this->fileConfig['fileName'][] = $fileName . ".xls";
 
}
 
 
 
$totalNum = gd_count($data);
 
 
 
 
if ($this->excelPageNum) $data = array_chunk($data, $this->excelPageNum, true);
else $data = array_chunk($data, $totalNum, true);
 
$setHedData[] = "<tr>";
 
foreach ($data as $k => $v) {
 
 
$tmpData = [];
foreach ($v as $key => $val) {
 
$totalNum = gd_count($data);
 
 
 
 
if ($this->excelPageNum) $data = array_chunk($data, $this->excelPageNum, true);
else $data = array_chunk($data, $totalNum, true);
 
$setHedData[] = "<tr>";
 
foreach ($data as $k => $v) {
 
 
$tmpData = [];
foreach ($v as $key => $val) {
$orderList = $orderData['orderList'];
}
 
 
 
 
//값이 입력되지 않은 것으로 간주하고 전체 다운로드.
if ($this->excelPageNum == 0) {
$pageNum = 0;
} else {
$data = $orderList[$i];
}
 
foreach ($data as $key => $val) {
$progress = ($totalNum - 1) > 0 ? round((100 / ($totalNum - 1)) * ($key + ($i * $this->excelPageNum))) : 100;
if ($progress % 20 == 0 || $progress == '100') {
}
 
fwrite($fh, gd_implode(chr(10), $tmpData));
 
unset($tmpData);
}
 
fclose($fh);
 
$this->fileConfig['fileName'][] = $fileName . ".xls";
 
}
 
return true;
$setData = [];
$setHedData[] = "<tr>";
foreach ($data as $k => $v) {
 
$tmpData = [];
foreach ($v as $key => $val) {
if (($key % 20 == 0 && $key != '0') || $totalNum - 1 == $key) {
$setData[] = gd_array_merge($setHedData, $tmpData);
}
 
return ['getData' => $setData, 'totalCount' => '$totalNum'];
}
}
 
변경 후ExcelRequest.php
*/
}
 
/**
* @param array $fileInfo 엑셀 요청의 menu, fileName, whereCondition, totalCount
* @param int|string $excelKey 선택한 파일 순번
* @return int|string|null 파일별 처리건수 또는 미집계
*/
public function getDownloadTotalCount(array $fileInfo, $excelKey)
{
if (!in_array($fileInfo['menu'] ?? '', ['order', 'orderDraft', 'member'], true)) {
return $fileInfo['totalCount'] ?? null;
}
 
$fileNames = explode(STR_DIVISION, $fileInfo['fileName'] ?? '');
if ((!is_int($excelKey) && !is_string($excelKey))
|| (string) (int) $excelKey !== (string) $excelKey
|| !isset($fileNames[$excelKey])
|| empty($fileNames[$excelKey])) {
return null;
}
 
$whereCondition = [];
if (!empty($fileInfo['whereCondition'])) {
if (!is_string($fileInfo['whereCondition'])) {
return null;
}
$whereCondition = @unserialize($fileInfo['whereCondition'], ['allowed_classes' => false]);
if (!is_array($whereCondition)) {
return null;
}
}
 
if (array_key_exists('excelFileCounts', $whereCondition)) {
$fileCounts = $whereCondition['excelFileCounts'];
if (!is_array($fileCounts) || array_keys($fileCounts) !== $fileNames) {
return null;
}
foreach ($fileCounts as $fileCount) {
if (!is_int($fileCount) || $fileCount < 0) {
return null;
}
}
return $fileCounts[$fileNames[$excelKey]];
}
 
// 파일별 집계가 없는 이전 요청과 튜닝 사본은 기존 건수 표시를 유지한다.
return $fileInfo['totalCount'] ?? null;
}
 
public function makeExcelFile(&$arrData)
{
$excleForm = \App::load('\\Component\\Excel\\ExcelForm');
$this->fileConfig['menu'] = $formData['menu'];
$this->fileConfig['location'] = $formData['location'];
 
// 미집계와 실제 0건을 구분하고 재사용 시 직전 요청 값을 제거한다.
$this->fileConfig['totalCount'] = null;
$this->fileConfig['excelFileCounts'] = [];
$tracksFileCount = in_array($formData['menu'], ['order', 'member'], true) || $arrData['menu'] === 'orderDraft';
if ($tracksFileCount) {
$this->fileConfig['fileName'] = [];
$logWhereCondition = unserialize($arrData['whereCondition'], ['allowed_classes' => false]);
if (is_array($logWhereCondition)) {
// 요청에서 전달되거나 이전 생성 때 저장한 건수는 재집계한다.
unset($logWhereCondition['excelFileCounts']);
$arrData['whereCondition'] = serialize($logWhereCondition);
}
}
 
if (!is_dir(UserFilePath::data('excel', $formData['menu'])->getPathName())) {
mkdir(UserFilePath::data('excel', $formData['menu'])->getPathName(), 0707);
}
$tmpGetData = $this->getMemberMemberList(unserialize($arrData['whereCondition']), $formData['excelField'], $excelFieldName);
}
$getData = $tmpGetData['getData'];
$this->fileConfig['totalCount'] = $tmpGetData['totalCount'];
} else if ($formData['menu'] == 'promotion' && $formData['location'] == 'coupon_manage') {
$getData = $this->getPromotionCouponManage($arrData, $formData['excelField'], $excelFieldName);
} else if ($formData['menu'] == 'promotion' && $formData['location'] == 'coupon_offline_manage') {
}
 
if ($getData) {
$generatedAllFiles = true;
if (\is_array($getData)) {
foreach ($getData as $k => $v) {
if ($this->genarateFile($v) === false) {
$generatedAllFiles = false;
}
}
} else {
if (gd_isset($this->fileConfig['password'])) {
$arrData['filePath'] = "excel" . DS . $formData['menu'];
$arrData['fileName'] = gd_implode(STR_DIVISION, $this->fileConfig['fileName']);
 
if ($tracksFileCount) {
$fileNames = $this->fileConfig['fileName'];
$fileCounts = $this->fileConfig['excelFileCounts'];
if (empty($fileCounts) && count($fileNames) === 1 && isset($this->fileConfig['totalCount'])) {
$fileCounts = [(int) $this->fileConfig['totalCount']];
}
$logWhereCondition = unserialize($arrData['whereCondition'], ['allowed_classes' => false]);
$logWhereCondition = is_array($logWhereCondition) ? $logWhereCondition : [];
$logWhereCondition['excelFileCounts'] = [];
if ($generatedAllFiles
&& (!is_array($getData) || count($getData) === count($fileNames))
&& !empty($fileNames)
&& count($fileNames) === count(array_unique($fileNames))
&& empty($fileCounts)) {
unset($logWhereCondition['excelFileCounts']);
}
if ($generatedAllFiles
&& (!is_array($getData) || count($getData) === count($fileNames))
&& !empty($fileNames)
&& count($fileNames) === count(array_unique($fileNames))
&& count($fileNames) === count($fileCounts)
&& array_keys($fileCounts) === range(0, count($fileNames) - 1)) {
$logWhereCondition['excelFileCounts'] = array_combine($fileNames, $fileCounts);
}
$arrData['whereCondition'] = serialize($logWhereCondition);
}
 
if (isset($this->fileConfig['totalCount'])) {
// DBTool의 느슨한 null 비교에서 정수 0이 기본값으로 바뀌므로 문자열로 전달한다.
$arrData['totalCount'] = $this->fileConfig['totalCount'] === 0 ? '0' : $this->fileConfig['totalCount'];
}
 
$arrData['state'] = "y";
$arrData['expiryDate'] = date("Y-m-d", strtotime("+7 day"));
 
$setData = $setHedData = [];
$setHedData[] = '<tr>';
foreach ($data as $k => $v) {
$this->fileConfig['excelFileCounts'][] = count($v);
$tmpData = [];
foreach ($v as $key => $val) {
if (($key % 20 == 0 && $key != '0') || $totalNum - 1 == $key) {
$orderData = $orderAdmin->getOrderListForAdminExcel($whereCondition, $whereCondition['periodFl'], $isUserHandle, $orderType, $excelField, 0, $this->excelPageNum);
 
//튜닝한 업체를 위해 데이터 맞춤
if (!isset($orderData['totalCount'], $orderData['orderList'])) {
$isGenerator = false;
$totalNum = gd_count($orderData);
if ($this->excelPageNum) $orderList = array_chunk($orderData, $this->excelPageNum, true);
$totalNum = gd_count($orderData['totalCount']);
$orderList = $orderData['orderList'];
if (gd_is_provider() && $orderType == 'goods') {
$totalScmInfo = $orderData['totalScmInfo'] ?? [];
}
}
 
// 개인정보 접속기록의 '처리건수' 로 남길 실제 산출 건수
$this->fileConfig['totalCount'] = $totalNum;
 
//값이 입력되지 않은 것으로 간주하고 전체 다운로드.
if ($this->excelPageNum == 0) {
$pageNum = 0;
$data = $orderList[$i];
}
 
$fileCount = 0;
foreach ($data as $key => $val) {
$progress = ($totalNum == 1) ? 100 : round((100 / ($totalNum - 1)) * ($key + ($i * $this->excelPageNum)));
if ($progress % 20 == 0 || $progress == '100') {
} else {
fwrite($fh, gd_implode(chr(10), $tmpData));
}
$fileCount++;
unset($tmpData);
}
//exit;
fclose($fh);
 
$this->fileConfig['fileName'][] = $fileName . ".xls";
$this->fileConfig['excelFileCounts'][] = $fileCount;
}
 
 
 
$totalNum = gd_count($data);
 
// 개인정보 접속기록의 '처리건수' 로 남길 실제 산출 건수
$this->fileConfig['totalCount'] = $totalNum;
 
if ($this->excelPageNum) $data = array_chunk($data, $this->excelPageNum, true);
else $data = array_chunk($data, $totalNum, true);
 
$setHedData[] = "<tr>";
 
foreach ($data as $k => $v) {
$this->fileConfig['excelFileCounts'][] = count($v);
 
$tmpData = [];
foreach ($v as $key => $val) {
 
$totalNum = gd_count($data);
 
// 개인정보 접속기록의 '처리건수' 로 남길 실제 산출 건수
$this->fileConfig['totalCount'] = $totalNum;
 
if ($this->excelPageNum) $data = array_chunk($data, $this->excelPageNum, true);
else $data = array_chunk($data, $totalNum, true);
 
$setHedData[] = "<tr>";
 
foreach ($data as $k => $v) {
$this->fileConfig['excelFileCounts'][] = count($v);
 
$tmpData = [];
foreach ($v as $key => $val) {
$orderList = $orderData['orderList'];
}
 
// 개인정보 접속기록의 '처리건수' 로 남길 실제 산출 건수
$this->fileConfig['totalCount'] = $totalNum;
 
//값이 입력되지 않은 것으로 간주하고 전체 다운로드.
if ($this->excelPageNum == 0) {
$pageNum = 0;
} else {
$data = $orderList[$i];
}
$fileCount = 0;
foreach ($data as $key => $val) {
$progress = ($totalNum - 1) > 0 ? round((100 / ($totalNum - 1)) * ($key + ($i * $this->excelPageNum))) : 100;
if ($progress % 20 == 0 || $progress == '100') {
}
 
fwrite($fh, gd_implode(chr(10), $tmpData));
$fileCount++;
unset($tmpData);
}
 
fclose($fh);
 
$this->fileConfig['fileName'][] = $fileName . ".xls";
$this->fileConfig['excelFileCounts'][] = $fileCount;
}
 
return true;
$setData = [];
$setHedData[] = "<tr>";
foreach ($data as $k => $v) {
$this->fileConfig['excelFileCounts'][] = count($v);
$tmpData = [];
foreach ($v as $key => $val) {
if (($key % 20 == 0 && $key != '0') || $totalNum - 1 == $key) {
$setData[] = gd_array_merge($setHedData, $tmpData);
}
 
return ['getData' => $setData, 'totalCount' => $totalNum];
}
}
 
Component/Order/OrderAdminNew.php+19
변경 전OrderAdminNew.php
/** @var array 현재 자동취소 주문건 */
protected $targetOrderGoodsNoArr;
protected $targetOrderGoodsNo;
 
 
 
 
public $userHandleText = [
*/
public function saveOrderInvoice($arrData, $searchPeriod = '7')
{
 
parse_str($arrData['whereDetail'], $arrData['whereDetail']);
 
$arrData['whereDetail']['statusMode'] = "p,g";
}
 
$this->db->set_insert_db(DB_ORDER_GODO_POST, 'invoiceNo', array('s', $invoiceNo,), 'y');
 
 
unset($arrUpdate);
unset($arrBind);
*
* @param $arrData
*
 
* @throws Exception
* @internal param string $getValue 파라미터
*/
}
 
$resultData = $godoPost->sendInvoiceInfo($setData);
 
 
if ($resultData) {
 
$this->db->set_update_db(DB_ORDER_GODO_POST, $arrUpdate, 'invoiceNo = ?', $arrBind);
unset($arrUpdate);
unset($arrBind);
 
 
 
//예약완료시 입금상태의 주문건일 경우 상품준비중으로 변경
} else {
throw new \Exception(__('우체국 택배 연동하기가 실패하였습니다.'));
}
 
 
 
 
 
 
 
 
 
 
 
 
}
 
 
 
변경 후OrderAdminNew.php
/** @var array 현재 자동취소 주문건 */
protected $targetOrderGoodsNoArr;
protected $targetOrderGoodsNo;
/** @var array 우체국택배 송장번호를 발급한 주문번호 (saveOrderInvoice) */
protected $issuedInvoiceOrderNos = [];
 
 
public $userHandleText = [
*/
public function saveOrderInvoice($arrData, $searchPeriod = '7')
{
$this->issuedInvoiceOrderNos = [];
parse_str($arrData['whereDetail'], $arrData['whereDetail']);
 
$arrData['whereDetail']['statusMode'] = "p,g";
}
 
$this->db->set_insert_db(DB_ORDER_GODO_POST, 'invoiceNo', array('s', $invoiceNo,), 'y');
$this->issuedInvoiceOrderNos[] = $v['orderNo'];
 
unset($arrUpdate);
unset($arrBind);
*
* @param $arrData
*
* @return array 예약된 주문번호 목록
* @throws Exception
* @internal param string $getValue 파라미터
*/
}
 
$resultData = $godoPost->sendInvoiceInfo($setData);
$reservedOrderNos = [];
 
if ($resultData) {
 
$this->db->set_update_db(DB_ORDER_GODO_POST, $arrUpdate, 'invoiceNo = ?', $arrBind);
unset($arrUpdate);
unset($arrBind);
$reservedOrderNos[] = $updateData[$v]['orderNo'];
 
 
//예약완료시 입금상태의 주문건일 경우 상품준비중으로 변경
} else {
throw new \Exception(__('우체국 택배 연동하기가 실패하였습니다.'));
}
 
return array_values(array_unique($reservedOrderNos));
}
 
/**
* 우체국택배 송장번호를 발급한 주문번호 — 직전 saveOrderInvoice 호출 기준
*
* @return array
*/
public function getIssuedInvoiceOrderNos()
{
return array_values(array_unique($this->issuedInvoiceOrderNos));
}
 
 
 
Component/Order/OrderAdmin.php+19
변경 전OrderAdmin.php
protected $cancelOrderlLimit = 500;
/** @var array 현재 자동취소 주문건 */
protected $targetOrderGoodsNoArr;
 
 
protected $targetOrderGoodsNo;
 
public $userHandleText = [
*/
public function saveOrderInvoice($arrData, $searchPeriod = '7')
{
 
parse_str($arrData['whereDetail'], $arrData['whereDetail']);
 
$arrData['whereDetail']['statusMode'] = "p,g";
}
 
$this->db->set_insert_db(DB_ORDER_GODO_POST, 'invoiceNo', array('s', $invoiceNo,), 'y');
 
 
unset($arrUpdate);
unset($arrBind);
*
* @param $arrData
*
 
* @throws Exception
* @internal param string $getValue 파라미터
*/
}
 
$resultData = $godoPost->sendInvoiceInfo($setData);
 
 
if ($resultData) {
 
$this->db->set_update_db(DB_ORDER_GODO_POST, $arrUpdate, 'invoiceNo = ?', $arrBind);
unset($arrUpdate);
unset($arrBind);
 
 
 
//예약완료시 입금상태의 주문건일 경우 상품준비중으로 변경
} else {
throw new \Exception(__('우체국 택배 연동하기가 실패하였습니다.'));
}
 
 
 
 
 
 
 
 
 
 
 
 
}
 
 
 
변경 후OrderAdmin.php
protected $cancelOrderlLimit = 500;
/** @var array 현재 자동취소 주문건 */
protected $targetOrderGoodsNoArr;
/** @var array 우체국택배 송장번호를 발급한 주문번호 (saveOrderInvoice) */
protected $issuedInvoiceOrderNos = [];
protected $targetOrderGoodsNo;
 
public $userHandleText = [
*/
public function saveOrderInvoice($arrData, $searchPeriod = '7')
{
$this->issuedInvoiceOrderNos = [];
parse_str($arrData['whereDetail'], $arrData['whereDetail']);
 
$arrData['whereDetail']['statusMode'] = "p,g";
}
 
$this->db->set_insert_db(DB_ORDER_GODO_POST, 'invoiceNo', array('s', $invoiceNo,), 'y');
$this->issuedInvoiceOrderNos[] = $v['orderNo'];
 
unset($arrUpdate);
unset($arrBind);
*
* @param $arrData
*
* @return array 예약된 주문번호 목록
* @throws Exception
* @internal param string $getValue 파라미터
*/
}
 
$resultData = $godoPost->sendInvoiceInfo($setData);
$reservedOrderNos = [];
 
if ($resultData) {
 
$this->db->set_update_db(DB_ORDER_GODO_POST, $arrUpdate, 'invoiceNo = ?', $arrBind);
unset($arrUpdate);
unset($arrBind);
$reservedOrderNos[] = $updateData[$v]['orderNo'];
 
 
//예약완료시 입금상태의 주문건일 경우 상품준비중으로 변경
} else {
throw new \Exception(__('우체국 택배 연동하기가 실패하였습니다.'));
}
 
return array_values(array_unique($reservedOrderNos));
}
 
/**
* 우체국택배 송장번호를 발급한 주문번호 — 직전 saveOrderInvoice 호출 기준
*
* @return array
*/
public function getIssuedInvoiceOrderNos()
{
return array_values(array_unique($this->issuedInvoiceOrderNos));
}
 
 
 
Controller/Admin/Order/BankdaMatchPsController.php+58
변경 전BankdaMatchPsController.php
case 'accountList':
$bk = new Bankda();
$res = $bk->accountList(Request::get()->toArray());
 
 
 
 
 
echo $res;
exit();
break;
try {
$bk = new Bankda();
$res = $bk->bankMatching(Request::get()->toArray());
 
echo $res;
exit();
} catch (\Exception $e) {
$bk = new Bankda();
$getValue = Request::get()->toArray();
$res = $bk->bankManualOrderList($getValue);
 
if($res) {
echo json_encode($res, JSON_UNESCAPED_UNICODE);
}
throw new HttpException($e->ectMessage, 500);
}
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
변경 후BankdaMatchPsController.php
case 'accountList':
$bk = new Bankda();
$res = $bk->accountList(Request::get()->toArray());
$accountList = json_decode($res, true);
$this->attachPrivacyLogResult(
$this->extractListTargets($accountList, 'bkcode'),
$this->extractListTotalCount($accountList)
);
echo $res;
exit();
break;
try {
$bk = new Bankda();
$res = $bk->bankMatching(Request::get()->toArray());
$this->attachPrivacyLogResult($this->extractMatchedOrderNos($res));
echo $res;
exit();
} catch (\Exception $e) {
$bk = new Bankda();
$getValue = Request::get()->toArray();
$res = $bk->bankManualOrderList($getValue);
$this->attachPrivacyLogResult($this->extractListTargets($res, 'orderNo'), $this->extractListTotalCount($res));
if($res) {
echo json_encode($res, JSON_UNESCAPED_UNICODE);
}
throw new HttpException($e->ectMessage, 500);
}
}
 
/**
* 조회 결과 행의 식별자 — 결과 검증에서 누락을 감지하도록 응답과 식별자의 null 을 보존한다
*
* 통장입금내역은 입금내역 코드(뱅크다 TBLBANK.bkcode), 입금대기 주문은 주문번호를 처리대상으로 남긴다.
* 입금대기 주문은 결과가 없으면 lists 없이 page 만 내려준다
*
* @param mixed $response 조회 응답 (lists: 조회 행 목록, page: 페이징 정보)
* @param string $field 행의 식별자 필드 (bkcode, orderNo)
* @return array|null 응답 형식이 아니면 null
*/
protected function extractListTargets(mixed $response, string $field): ?array
{
if (!is_array($response) || !is_array($response['page'] ?? null)) {
return null;
}
$lists = $response['lists'] ?? [];
 
return is_array($lists)
? array_map(static fn(mixed $row): mixed => is_array($row) ? ($row[$field] ?? null) : null, $lists)
: null;
}
 
/**
* 조회 결과의 검색 건수
*
* @param mixed $response 조회 응답 (page.recode: 검색 건수)
* @return int|null
*/
protected function extractListTotalCount(mixed $response): ?int
{
$totalCount = is_array($response) ? ($response['page']['recode'] ?? null) : null;
 
return is_numeric($totalCount) ? (int) $totalCount : null;
}
 
/**
* 실시간입금확인으로 입금확인된 주문번호 — 화면 결과 레이어와 같이 '^' 뒤를 '|' 로 나눈다
*
* @param mixed $result 매칭 결과 (결과 메시지^주문번호|주문번호)
* @return array|null 입금확인된 주문이 없으면 빈 배열
*/
protected function extractMatchedOrderNos(mixed $result): ?array
{
if (!is_string($result)) {
return null;
}
$orderNos = explode('^', $result, 2)[1] ?? '';
 
return $orderNos === '' ? [] : explode('|', $orderNos);
}
}
 
Controller/Admin/Order/BankdaNoMatchPsController.php+21-1
변경 전BankdaNoMatchPsController.php
// --- 미확인 입금자 등록
case 'insert':
$ghostDepositor->registerGhostDepositor($requestPostParams);
 
 
 
 
$rs['result'] = true;
$this->json($rs);
case 'load':
$res = $ghostDepositor->loadGhostDepositor($requestPostParams);
 
$this->json($res);
break;
case 'download':
$res = $ghostDepositor->loadGhostDepositor($requestPostParams);
 
 
$ghostDepositor->downloadGhostDepositor($res['body']);
default:
exit;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
변경 후BankdaNoMatchPsController.php
// --- 미확인 입금자 등록
case 'insert':
$sno = $ghostDepositor->registerGhostDepositor($requestPostParams);
// 등록 번호를 돌려받지 못하면 처리 전 기록만 남긴다
if (!empty($sno)) {
$this->attachPrivacyLogResult([$sno]);
}
$rs['result'] = true;
$this->json($rs);
case 'load':
$res = $ghostDepositor->loadGhostDepositor($requestPostParams);
$this->attachPrivacyLogResult($this->extractPrivacyLogTargets($res['body'] ?? null));
$this->json($res);
break;
case 'download':
$res = $ghostDepositor->loadGhostDepositor($requestPostParams);
// 엑셀 다운로드는 다른 엑셀과 같이 처리건수만 남긴다
$this->attachPrivacyLogResult([], is_array($res['body'] ?? null) ? count($res['body']) : null);
$ghostDepositor->downloadGhostDepositor($res['body']);
default:
exit;
}
/**
* 조회 결과의 입금자 번호 — 결과 검증에서 누락을 감지하도록 본문과 번호의 null 을 보존한다
*
* @param mixed $body 조회 결과 행 목록
* @return array|null
*/
protected function extractPrivacyLogTargets(mixed $body): ?array
{
return is_array($body)
? array_map(static fn(mixed $row): mixed => is_array($row) ? ($row['sno'] ?? null) : null, $body)
: null;
}
}
 
Controller/Admin/Order/CashReceiptPsController.php+11-2
변경 전CashReceiptPsController.php
// --- 현금영수증 개별 발급 요청 저장
case 'cash_receipt_register':
try {
// 개별 발급 요청 저장
$cashReceipt->saveCashReceiptEach($postValue);
 
 
 
 
 
 
 
 
 
 
$this->layer(__('저장이 완료되었습니다.'));
} catch (\Exception $e) {
 
변경 후CashReceiptPsController.php
// --- 현금영수증 개별 발급 요청 저장
case 'cash_receipt_register':
try {
// 개별 발급 요청 저장 — 주문번호 없이 발급하면 저장 시 생성되므로 저장 후 접속기록에 채운다
$saved = false;
try {
$cashReceipt->saveCashReceiptEach($postValue);
$saved = true;
} finally {
$savedOrderNo = $cashReceipt->getSavedOrderNo();
if ($saved || !empty($savedOrderNo)) {
$this->attachPrivacyLogResult([$savedOrderNo]);
}
}
 
$this->layer(__('저장이 완료되었습니다.'));
} catch (\Exception $e) {
 
Controller/Admin/Order/OrderPsController.php+12-1
변경 전OrderPsController.php
try {
$excelOrderConvert = App::load('Component\\Excel\\ExcelOrderConvert');
$result = $excelOrderConvert->updateOrderInvoiceExcel(Request::files()->toArray());
 
 
 
 
$this->json($result);
exit;
} catch (Exception $e) {
case 'register_frequency':
try {
$postValue = StringUtils::xssArrayClean(Request::request()->toArray());
$order->registerFrequencyAddress($postValue);
 
 
 
 
 
throw new LayerException();
 
} catch (Exception $e) {
 
// 주문 저장 후 처리
if ($result) {
 
 
// Kafka MQ처리
$mqData = [
'cartInfo' => ['cartSnos' => is_array($cart->cartSno) ? $cart->cartSno : [$cart->cartSno]],
 
변경 후OrderPsController.php
try {
$excelOrderConvert = App::load('Component\\Excel\\ExcelOrderConvert');
$result = $excelOrderConvert->updateOrderInvoiceExcel(Request::files()->toArray());
// 그룹코드를 돌려받지 못하면 처리 전 기록만 남긴다
if (is_array($result) && !empty($result['groupCd'])) {
$this->attachPrivacyLogResult([$result['groupCd']], $result['total'] ?? null);
}
$this->json($result);
exit;
} catch (Exception $e) {
case 'register_frequency':
try {
$postValue = StringUtils::xssArrayClean(Request::request()->toArray());
$result = $order->registerFrequencyAddress($postValue);
// 등록은 새로 생긴 주소 번호, 수정은 요청한 주소 번호를 남기고, 번호를 받지 못하면 처리 전 기록만 남긴다
$frequencySno = empty($postValue['sno']) ? $result : $postValue['sno'];
if (is_numeric($frequencySno)) {
$this->attachPrivacyLogResult([(string) $frequencySno]);
}
throw new LayerException();
 
} catch (Exception $e) {
 
// 주문 저장 후 처리
if ($result) {
$this->attachPrivacyLogResult([$order->orderNo]);
 
// Kafka MQ처리
$mqData = [
'cartInfo' => ['cartSnos' => is_array($cart->cartSno) ? $cart->cartSno : [$cart->cartSno]],
 
Controller/Admin/Order/PostPsController.php+12-1
변경 전PostPsController.php
}
$result = $orderAdmin->saveOrderInvoice($postValue);
 
 
 
 
 
 
 
if(gd_count($result) > 0 ) {
throw new LayerException(sprintf(__("필수 정보(수령자명,수령자 핸드폰번호,수령자 주소,수령자 우편번호,주문자명) 가 누락된 주문(%s) 외 우체국 택배 송장번호가 발급되었습니다."), gd_implode(",",$result)),null,null,null,6000);
throw new LayerException(__('우체국택배 서비스 신청 후 이용 가능합니다.'));
}
$orderAdmin->reserveOrderInvoice($postValue);
 
 
 
 
throw new LayerException(__("우체국택배로 예약되었습니다."));
break;
// 우체국택배 취소
 
변경 후PostPsController.php
}
$result = $orderAdmin->saveOrderInvoice($postValue);
// 발급한 주문번호를 돌려받지 못하면 처리 전 기록만 남긴다
$issuedOrderNos = method_exists($orderAdmin, 'getIssuedInvoiceOrderNos')
? $orderAdmin->getIssuedInvoiceOrderNos()
: [];
if (!empty($issuedOrderNos)) {
$this->attachPrivacyLogResult($issuedOrderNos);
}
if(gd_count($result) > 0 ) {
throw new LayerException(sprintf(__("필수 정보(수령자명,수령자 핸드폰번호,수령자 주소,수령자 우편번호,주문자명) 가 누락된 주문(%s) 외 우체국 택배 송장번호가 발급되었습니다."), gd_implode(",",$result)),null,null,null,6000);
throw new LayerException(__('우체국택배 서비스 신청 후 이용 가능합니다.'));
}
$reservedOrderNos = $orderAdmin->reserveOrderInvoice($postValue);
// 예약한 주문번호를 돌려받지 못하면 처리 전 기록만 남긴다
if (!empty($reservedOrderNos)) {
$this->attachPrivacyLogResult($reservedOrderNos);
}
throw new LayerException(__("우체국택배로 예약되었습니다."));
break;
// 우체국택배 취소
 
Controller/Admin/Share/LayerExcelPsController.php+5-1
변경 전LayerExcelPsController.php
$request->request()->set($fileInfo['menu'] . 'Log', true);
$request->post()->set('fileName', $fileName[$postValue['excelKey']]);
$request->post()->set('downloadFileName', $fileInfo['downloadFileName']);
$request->post()->set('totalCount', $fileInfo['totalCount']);
 
 
 
 
$logAction = \App::load('Component\\Admin\\AdminLogDAO');
$logAction->setAdminLog();
}
 
변경 후LayerExcelPsController.php
$request->request()->set($fileInfo['menu'] . 'Log', true);
$request->post()->set('fileName', $fileName[$postValue['excelKey']]);
$request->post()->set('downloadFileName', $fileInfo['downloadFileName']);
$downloadTotalCount = $fileInfo['totalCount'] ?? null;
if (method_exists($excelRequest, 'getDownloadTotalCount')) {
$downloadTotalCount = $excelRequest->getDownloadTotalCount($fileInfo, $postValue['excelKey']);
}
$request->post()->set('totalCount', $downloadTotalCount);
$logAction = \App::load('Component\\Admin\\AdminLogDAO');
$logAction->setAdminLog();
}
 
공급사 계정 다른상품교환 처리 개선
Admin/order/layout_order_view_status_exchange.php+2-1
변경 전layout_order_view_status_exchange.php
//다른상품 교환
$.each($("input[name*='bundle[statusCheck]']"), function () {
var enurikey = $(this).val().concat($(this).attr("data-goods-no"));
var enuriVal = $(this).closest('tr').find("input[name='enuri[]']").val();
 
$('#exchangeForm').append("<input type='hidden' name='enuri["+enurikey+"]' value='"+enuriVal+"' />");
});
}
 
변경 후layout_order_view_status_exchange.php
//다른상품 교환
$.each($("input[name*='bundle[statusCheck]']"), function () {
var enurikey = $(this).val().concat($(this).attr("data-goods-no"));
var enuriInput = $(this).closest('tr').find("input[name='enuri[]']");
var enuriVal = enuriInput.length > 0 ? enuriInput.val() : '0';
$('#exchangeForm').append("<input type='hidden' name='enuri["+enurikey+"]' value='"+enuriVal+"' />");
});
}
 
Component/Order/ReOrderCalculation.php+7-1
변경 전ReOrderCalculation.php
$deliveryMethodFl = '';
foreach ($dVal as $gKey => $gVal) {
$gVal['orderNo'] = $data['orderNo'];
$gVal['enuri'] = $data['enuri'][$gVal['sno'] . $gVal['goodsNo']];
 
 
 
 
 
 
$gVal['mallSno'] = $orderData['mallSno'];
$gVal['orderCd'] = ++$orderCd;
$gVal['orderStatus'] = $changeStatus;
 
변경 후ReOrderCalculation.php
$deliveryMethodFl = '';
foreach ($dVal as $gKey => $gVal) {
$gVal['orderNo'] = $data['orderNo'];
$gVal['enuri'] = Manager::isProvider() ? 0 : (int)$data['enuri'][$gVal['sno'] . $gVal['goodsNo']];
if ($gVal['enuri'] < 0) {
throw new Exception(__('운영자 추가 할인 실행을 실패하였습니다.[금액이 0보다 작음]'));
}
if ($gVal['enuri'] > $gVal['price']['goodsPriceSubtotal']) {
throw new Exception(__('운영자 추가 할인 실행을 실패하였습니다.[상품결제가보다 금액이 큼]'));
}
$gVal['mallSno'] = $orderData['mallSno'];
$gVal['orderCd'] = ++$orderCd;
$gVal['orderStatus'] = $changeStatus;
 
네이버 판매지수 집계 정확도 개선
Component/Worker/NaverDbUrl.php+1
변경 전NaverDbUrl.php
$data = [];
 
foreach ($getData as $val) {
 
if ($val['regDt'] == $val['handleDt']) {
$goodsPrice = $val['goodsPrice'] - $val['refundPrice'];
$goodsCnt = $val['goodsCnt'] - $val['goodsHandleCnt'];
 
변경 후NaverDbUrl.php
$data = [];
 
foreach ($getData as $val) {
$goodsPrice = $goodsCnt = $orderCnt = 0;
if ($val['regDt'] == $val['handleDt']) {
$goodsPrice = $val['goodsPrice'] - $val['refundPrice'];
$goodsCnt = $val['goodsCnt'] - $val['goodsHandleCnt'];
 
상품 수정시 정가/매입가/판매가 입력 안정성 개선
Component/Goods/GoodsAdmin.php+10-2
변경 전GoodsAdmin.php
 
const ECT_INVALID_ARG = 'GoodsAdmin.ECT_INVALID_ARG';
 
 
 
 
const TEXT_REQUIRE_VALUE = '%s은(는) 필수 항목 입니다.';
 
const TEXT_USELESS_VALUE = '%s은(는) 사용할 수 없습니다.';
*/
 
//
 
 
$arrData['mileageGroupMemberInfo'] = str_replace('\'', '', json_encode($arrData['mileageGroupMemberInfo'], JSON_UNESCAPED_UNICODE));
$arrData['mileageGroupInfo'] = @gd_implode(INT_DIVISION, $arrData['mileageGroupInfo']);
$arrData['fixedGoodsDiscount'] = @gd_implode(STR_DIVISION, $arrData['fixedGoodsDiscount']);
// 할인값의 천 단위 콤마 제거 (미제거 시 할인가 숫자 연산이 깨짐)
$arrData = NumberUtils::removeCommaByField($arrData, 'goodsDiscount');
 
 
 
$arrData['goodsDiscountGroupMemberInfo'] = NumberUtils::removeCommaByField($arrData['goodsDiscountGroupMemberInfo'], 'goodsDiscount');
$arrData['goodsDiscountGroupMemberInfo'] = str_replace('\'', '', json_encode($arrData['goodsDiscountGroupMemberInfo'], JSON_UNESCAPED_UNICODE));
$arrData['exceptBenefit'] = @gd_implode(STR_DIVISION, $arrData['exceptBenefit']);
 
변경 후GoodsAdmin.php
 
const ECT_INVALID_ARG = 'GoodsAdmin.ECT_INVALID_ARG';
 
/** @var string[] 천 단위 콤마 입력이 허용되어 저장 전 정제가 필요한 금액 필드 */
protected const COMMA_REMOVABLE_AMOUNT_FIELDS = ['goodsPrice', 'fixedPrice', 'costPrice', 'goodsDiscount', 'mileageGoods'];
 
const TEXT_REQUIRE_VALUE = '%s은(는) 필수 항목 입니다.';
 
const TEXT_USELESS_VALUE = '%s은(는) 사용할 수 없습니다.';
*/
 
//
// 회원등급별 마일리지도 회원등급별 할인과 같이 별도 배열이라, 인코딩 전에 정제해야 한다
$arrData['mileageGroupMemberInfo'] = NumberUtils::removeCommaByField($arrData['mileageGroupMemberInfo'], 'mileageGoods');
$arrData['mileageGroupMemberInfo'] = str_replace('\'', '', json_encode($arrData['mileageGroupMemberInfo'], JSON_UNESCAPED_UNICODE));
$arrData['mileageGroupInfo'] = @gd_implode(INT_DIVISION, $arrData['mileageGroupInfo']);
$arrData['fixedGoodsDiscount'] = @gd_implode(STR_DIVISION, $arrData['fixedGoodsDiscount']);
// 금액값의 천 단위 콤마 제거 (미제거 시 DB 저장 과정에서 콤마 앞자리만 남고, 할인가 숫자 연산도 깨짐)
foreach (self::COMMA_REMOVABLE_AMOUNT_FIELDS as $amountField) {
$arrData = NumberUtils::removeCommaByField($arrData, $amountField);
}
// 회원등급별 할인은 별도 배열에 담겨 와 위 루프 대상이 아니다
$arrData['goodsDiscountGroupMemberInfo'] = NumberUtils::removeCommaByField($arrData['goodsDiscountGroupMemberInfo'], 'goodsDiscount');
$arrData['goodsDiscountGroupMemberInfo'] = str_replace('\'', '', json_encode($arrData['goodsDiscountGroupMemberInfo'], JSON_UNESCAPED_UNICODE));
$arrData['exceptBenefit'] = @gd_implode(STR_DIVISION, $arrData['exceptBenefit']);
 
Component/Goods/GoodsBenefit.php+3-1
변경 전GoodsBenefit.php
// 상품할인금액
$goodsDcPrice = $goodsData['goodsPrice'] - gd_number_figure(($goodsData['goodsPrice'] * $discountPercent), $goodsConfigTrunc['unitPrecision'], $goodsConfigTrunc['unitRound']);
} else {
 
 
// 상품금액보다 상품할인금액이 클 경우 상품금액으로 변경
if ($goodsData['goodsDiscount'] > $goodsData['goodsPrice']) $goodsDiscount = $goodsData['goodsPrice'];
// 상품할인금액 (정액인 경우 해당 설정된 금액으로)
$goodsDcPrice = $goodsData['goodsPrice'] - $goodsDiscount;
}
 
변경 후GoodsBenefit.php
// 상품할인금액
$goodsDcPrice = $goodsData['goodsPrice'] - gd_number_figure(($goodsData['goodsPrice'] * $discountPercent), $goodsConfigTrunc['unitPrecision'], $goodsConfigTrunc['unitRound']);
} else {
// 할인금액 초기화 (미초기화 시 null 이라 할인이 반영되지 않음)
$goodsDiscount = NumberUtils::numberFormatToFloat($goodsData['goodsDiscount']) ?: 0;
// 상품금액보다 상품할인금액이 클 경우 상품금액으로 변경
if ($goodsDiscount > $goodsData['goodsPrice']) $goodsDiscount = $goodsData['goodsPrice'];
// 상품할인금액 (정액인 경우 해당 설정된 금액으로)
$goodsDcPrice = $goodsData['goodsPrice'] - $goodsDiscount;
}
 
상품 엑셀 업로드 시 단위가격 반영 개선
Component/Excel/ExcelGoodsConvert.php+22-1
변경 전ExcelGoodsConvert.php
use Component\Database\DBTableField;
use Framework\Utility\ArrayUtils;
use Framework\Utility\ComponentUtils;
 
use Framework\Utility\ProducerUtils;
use Framework\Utility\StringUtils;
use Framework\Http\Parameter;
$goodsData['goodsNmFl'] = 'e';
}
switch ($dbKey) {
 
 
 
 
 
 
 
 
case 'kcmarkFl':
case 'kcmarkDivFl':
case 'kcmarkNo':
}
 
// 단위 가격 자동 계산 (올림)
$goodsPrice = floatval($goodsData['goodsPrice']);
 
 
 
 
 
 
 
 
 
 
 
 
$calcUnitPrice = ($goodsPrice > 0 && floatval($unitQuantity) > 0)
? ceil(($goodsPrice / floatval($unitQuantity)) * floatval($unitBaseQuantity))
: 0;
 
변경 후ExcelGoodsConvert.php
use Component\Database\DBTableField;
use Framework\Utility\ArrayUtils;
use Framework\Utility\ComponentUtils;
use Framework\Utility\NumberUtils;
use Framework\Utility\ProducerUtils;
use Framework\Utility\StringUtils;
use Framework\Http\Parameter;
$goodsData['goodsNmFl'] = 'e';
}
switch ($dbKey) {
case 'goodsPrice':
// 엑셀 셀이 텍스트 서식이면 '10,000' 처럼 콤마가 섞여 들어온다. 콤마를 둔 채 숫자 컬럼에 저장하면
// 앞자리만 남고 잘리므로, 저장과 단위가격 계산이 같은 값을 보도록 여기서 정규화한다
$goodsPrice = NumberUtils::numberFormatToFloat($goodsData[$dbKey]);
if ($goodsPrice !== false) {
$goodsData[$dbKey] = $goodsPrice;
}
break;
case 'kcmarkFl':
case 'kcmarkDivFl':
case 'kcmarkNo':
}
 
// 단위 가격 자동 계산 (올림)
// 판매가는 엑셀 값을 우선 사용하고, 컬럼 누락·권한 제외 등으로 쓸 수 없는 행만 저장이 끝난 DB 값으로 보완한다
$goodsPrice = $this->hasGoodsPriceAuth
? NumberUtils::numberFormatToFloat($goodsData['goodsPrice'] ?? null)
: false;
if ($goodsPrice === false) {
$arrBind = [];
$this->db->bind_param_push($arrBind, 'i', $goodsData['goodsNo']);
$strSQL = 'SELECT goodsPrice FROM ' . DB_GOODS . ' WHERE goodsNo = ?';
$goodsRow = $this->db->query_fetch($strSQL, $arrBind, false);
unset($arrBind);
$goodsPrice = floatval($goodsRow['goodsPrice'] ?? 0);
}
 
$calcUnitPrice = ($goodsPrice > 0 && floatval($unitQuantity) > 0)
? ceil(($goodsPrice / floatval($unitQuantity)) * floatval($unitBaseQuantity))
: 0;
 
엑셀 다운로드 시 자체상품코드 텍스트 서식 적용
Component/Excel/ExcelDataConvert.php+2-2
변경 전ExcelDataConvert.php
$this->excelBody[] = '<td>' . ($key+1) . '</td>' . chr(10);
$this->excelBody[] = '<td class="xl24">' . $resultValue['orderNo'] . '</td>' . chr(10);
$this->excelBody[] = '<td>' . $resultValue['orderGroup'] . '</td>' . chr(10);
$this->excelBody[] = '<td>' . $resultValue['goodsCd'] . '</td>' . chr(10);
$this->excelBody[] = '<td>' . $resultValue['optionCode'] . '</td>' . chr(10);
$this->excelBody[] = '<td>' . $resultValue['result'] . '</td>' . chr(10);
$this->excelBody[] = '<td>' . $resultValue['message'] . '</td>' . chr(10);
$this->excelBody[] = '</tr>' . chr(10);
 
변경 후ExcelDataConvert.php
$this->excelBody[] = '<td>' . ($key+1) . '</td>' . chr(10);
$this->excelBody[] = '<td class="xl24">' . $resultValue['orderNo'] . '</td>' . chr(10);
$this->excelBody[] = '<td>' . $resultValue['orderGroup'] . '</td>' . chr(10);
$this->excelBody[] = '<td class="xl24">' . $resultValue['goodsCd'] . '</td>' . chr(10);
$this->excelBody[] = '<td class="xl24">' . $resultValue['optionCode'] . '</td>' . chr(10);
$this->excelBody[] = '<td>' . $resultValue['result'] . '</td>' . chr(10);
$this->excelBody[] = '<td>' . $resultValue['message'] . '</td>' . chr(10);
$this->excelBody[] = '</tr>' . chr(10);
 
Component/Excel/ExcelRequest.php+7-2
변경 전ExcelRequest.php
$tmpData[] = "<td></td>";
}
 
 
 
 
break;
default :
if ($excelFieldName[$excelValue]['type'] == 'mileage' && $val[$excelValue] != '') {
}
$tmpData[] = "<td>" . $settleKind . "</td>";
break;
// 숫자 처리 - 주문 번호 및 우편번호(5자리) 숫자에 대한 처리
 
case 'orderNo':
case 'apiOrderNo':
case 'apiOrderGoodsNo':
case 'settleKind':
$tmpData[] = "<td>" . $orderDelete->printSettleKind($val[$excelValue]) . "</td>";
break;
// 숫자 처리 - 주문 번호 및 우편번호(5자리) 숫자에 대한 처리
 
case 'orderNo':
case 'apiOrderNo':
case 'apiOrderGoodsNo':
 
변경 후ExcelRequest.php
$tmpData[] = "<td></td>";
}
 
break;
case 'goodsCd':
$tmpData[] = "<td class=\"xl24\">" . $val[$excelValue] . "</td>";
break;
default :
if ($excelFieldName[$excelValue]['type'] == 'mileage' && $val[$excelValue] != '') {
}
$tmpData[] = "<td>" . $settleKind . "</td>";
break;
// 숫자 처리 - 주문 번호, 우편번호(5자리), 자체상품코드 등 숫자로 인식되면 안 되는 값
case 'goodsCd':
case 'orderNo':
case 'apiOrderNo':
case 'apiOrderGoodsNo':
case 'settleKind':
$tmpData[] = "<td>" . $orderDelete->printSettleKind($val[$excelValue]) . "</td>";
break;
// 숫자 처리 - 주문 번호, 우편번호(5자리), 자체상품코드 등 숫자로 인식되면 안 되는 값
case 'goodsCd':
case 'orderNo':
case 'apiOrderNo':
case 'apiOrderGoodsNo':
 
Component/Excel/ExcelSample.php+9
변경 전ExcelSample.php
use Framework\Utility\ImageUtils;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Helper\Html;
 
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Fill;
 
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
 
$this->setHeaderCellStyle($headerLastRow);
$this->setAllCellStyle();
 
 
 
 
 
 
 
 
return $this->spreadsheet;
}
 
 
변경 후ExcelSample.php
use Framework\Utility\ImageUtils;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Helper\Html;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
 
$this->setHeaderCellStyle($headerLastRow);
$this->setAllCellStyle();
 
// 샘플에 새로 입력하는 자체상품코드의 앞자리 0 이 잘리지 않도록 열 서식을 텍스트로 지정한다
$goodsCdIndex = array_search('goodsCd', array_column($excelGoodsField, 'dbKey'), true);
if ($goodsCdIndex !== false) {
$goodsCdColumn = Coordinate::stringFromColumnIndex($goodsCdIndex + 1);
$this->worksheet->getStyle("{$goodsCdColumn}:{$goodsCdColumn}")->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_TEXT);
}
 
return $this->spreadsheet;
}
 
 
판매채널/설정 메뉴 안내 링크 변경
Admin/marketing/marketing_info.php-3
변경 전marketing_info.php
<?php } else { ?>
<div class="page-header js-affix">
<h3><?php echo end($naviMenu->location);?> <small></small></h3>
<div class="btn-group">
<a href="https://marketing.godo.co.kr/board/list.gd" target="_blank" class="btn btn-white" style="background: url(<?=PATH_ADMIN_GD_SHARE?>img/marketing_notice.png) no-repeat 5% 70%; padding-left:35px;">마케팅 공지사항</a>
</div>
</div>
 
<iframe name='introduce' src='/share/iframe_godo_page.php?menu=<?=$menu?>' frameborder='0' marginwidth='0' marginheight='0' width='100%' height='2100'></iframe>
 
변경 후marketing_info.php
<?php } else { ?>
<div class="page-header js-affix">
<h3><?php echo end($naviMenu->location);?> <small></small></h3>
 
 
 
</div>
 
<iframe name='introduce' src='/share/iframe_godo_page.php?menu=<?=$menu?>' frameborder='0' marginwidth='0' marginheight='0' width='100%' height='2100'></iframe>
 
Admin/policy/naver_pay_config_order.php+2-2
변경 전naver_pay_config_order.php
<div class="table-title gd-help-manual">
<span class="mgt10">네이버페이 주문형 설정/관리</span>
<span class="flo-right">
<a href="https://marketing.godo.co.kr/board/view.gd?postNo=230&tab=3" target="_blank" class="btn btn-red-box js-manage-inform">네이버페이 주문형 연동 방법</a>
</span>
<!--*필독* 네이버페이 버전 설정 안내입니다.
네이버페이 버전을 2.1로 업그레이드 하실 수 있습니다.
<label class="radio-inline"><input type="radio" class="form-control" name="useYn" value="y" <?= gd_isset($naverPayData['checked']['useYn']['y']) ?>/>사용함</label>
<label class="radio-inline"><input type="radio" class="form-control" name="useYn" value="n" <?= gd_isset($naverPayData['checked']['useYn']['n']) ?>/>사용안함</label>
<div class="notice-info">네이버페이 주문형을 아직 신청하지 않은 경우 먼저 신청을 진행해주시기 바랍니다. <a href="https://admin.pay.naver.com/join/step1" target="_blank">바로가기></a></div>
<div class="notice-info">시스템 연동 단계일 경우, 공지사항 참고 부탁드립니다. <a href="https://marketing.nhn-commerce.com/board/view.gd?postNo=230" target="_blank">공지사항 바로가기></a> </div>
</td>
</tr>
<tr>
 
변경 후naver_pay_config_order.php
<div class="table-title gd-help-manual">
<span class="mgt10">네이버페이 주문형 설정/관리</span>
<span class="flo-right">
<a href="https://marketing-help.nhn-commerce.com/ad-channel-guide/naverpay/godomall-enamu-service-integration" target="_blank" class="btn btn-red-box js-manage-inform">네이버페이 주문형 연동 방법</a>
</span>
<!--*필독* 네이버페이 버전 설정 안내입니다.
네이버페이 버전을 2.1로 업그레이드 하실 수 있습니다.
<label class="radio-inline"><input type="radio" class="form-control" name="useYn" value="y" <?= gd_isset($naverPayData['checked']['useYn']['y']) ?>/>사용함</label>
<label class="radio-inline"><input type="radio" class="form-control" name="useYn" value="n" <?= gd_isset($naverPayData['checked']['useYn']['n']) ?>/>사용안함</label>
<div class="notice-info">네이버페이 주문형을 아직 신청하지 않은 경우 먼저 신청을 진행해주시기 바랍니다. <a href="https://admin.pay.naver.com/join/step1" target="_blank">바로가기></a></div>
<div class="notice-info">시스템 연동 단계일 경우, 공지사항 참고 부탁드립니다. <a href="https://marketing-help.nhn-commerce.com/ad-channel-guide/naverpay/godomall-enamu-service-integration" target="_blank">공지사항 바로가기></a> </div>
</td>
</tr>
<tr>
 
엑셀 다운로드 성능 개선 및 통계 기록 확대
Component/Excel/ExcelDataConvert.php+3
변경 전ExcelDataConvert.php
* 상품 엑셀 다운
*
* @author artherot
 
 
*/
public function setExcelGoodsDown($setData)
{
// 엑셀 하단
$this->excelFooter;
 
 
}
 
/**
 
변경 후ExcelDataConvert.php
* 상품 엑셀 다운
*
* @author artherot
* @param array $setData 엑셀 다운로드 요청 데이터 (fieldCheck, downType, downRange 등)
* @return bool 다운로드 대상 필드가 없으면 false
*/
public function setExcelGoodsDown($setData)
{
// 엑셀 하단
$this->excelFooter;
 
return true;
}
 
/**
 
Component/Excel/ExcelRequest.php+2-74
변경 전ExcelRequest.php
use Framework\Utility\ComponentUtils;
use Framework\Utility\ArrayUtils;
use Framework\Utility\DateTimeUtils;
use Framework\Utility\ProducerUtils;
use Framework\Utility\StringUtils;
use Framework\Utility\NumberUtils;
use Framework\Security\Token;
use Framework\Debug\Exception\MissingRequiredFieldException;
use LogHandler;
use Origin\DTO\Kafka\ShopDataExtractLogDTO;
use Origin\Enum\Excel\ShopDataExtractTarget;
use Request;
use Session;
use UserFilePath;
$orderDelete->deleteLapseOrderExcelFormUpdate($arrData['requestSno'], $arrData['sno']);
$this->_logger->channel('orderDelete')->info(__METHOD__ . ' ORDER DELETE EXCEL FORM SNO SAVE, DB_EXCEL_REQUEST INSERT NO : ' . $arrData['requestSno'] . ', EXCEL FORM SNO : ', [$arrData['formSno']]);
 
$this->publishExtractLog($formData, true, ShopDataExtractLogDTO::EXTRACT_TYPE_EXCEL);
return $arrData['requestSno'];
}
 
unset($arrBind);
 
$this->publishExtractLog($formData, true, ShopDataExtractLogDTO::EXTRACT_TYPE_EXCEL);
return true;
} else {
$this->publishExtractLog($formData, false, ShopDataExtractLogDTO::EXTRACT_TYPE_EXCEL);
return false;
}
 
 
 
//특정 갯수 이하인 경우 바로 생성
/*
if($arrData[ $arrData['whereFl'].'Count'] <= self::EXCEL_PAGE_NUM ) {
return true;
}
*/
 
}
 
public function makeExcelFile(&$arrData)
 
return ['getData' => $setData, 'totalCount' => '$totalNum'];
}
 
/**
* 상점 데이터 추출 완료 결과를 카프카 토픽으로 발행한다.
*
* @param ?array $formData 엑셀 양식 데이터 (es_excelForm, menu 포함)
* @param bool $isSuccess 추출 성공 여부
* @param string $extractType 추출 유형 (ShopDataExtractLogDTO::EXTRACT_TYPE_* 상수)
* @return void
*/
protected function publishExtractLog(?array $formData, bool $isSuccess, string $extractType): void
{
//10월 정기배포 전까지 발행되지 않도록 임시조치
return;
try {
$godosno = Globals::get('gLicense.godosno');
if (empty($godosno)) {
throw new MissingRequiredFieldException('상점 데이터 추출 로그 발행 실패: 라이선스 상점번호(godosno)가 없습니다.');
}
 
$menu = $formData['menu'] ?? null;
if (empty($menu)) {
throw new MissingRequiredFieldException('상점 데이터 추출 로그 발행 실패: 엑셀 양식 메뉴(menu)가 없습니다.');
}
 
$extractTarget = ShopDataExtractTarget::fromMenu($menu);
// 매핑 미확정 메뉴(orderDraft, plusreview, adminLog)는 발행하지 않고 건너뛴다. (9월 배포 추가작업 예정)
if ($extractTarget === null) {
$this->_logger->channel('excel')->info(
'상점 데이터 추출 로그 발행 생략: 매핑되지 않은 엑셀 양식 메뉴',
[
'godoSno' => (int)$godosno,
'extractType' => $extractType,
'extractTarget' => $extractTarget->value,
'isSuccess' => $isSuccess
]
);
return;
}
 
$producer = new ProducerUtils();
$shopDataExtractLogDto = new ShopDataExtractLogDTO(
[(int)$godosno],
$extractType,
$extractTarget->value,
$isSuccess
);
 
$producer->send(
$producer::TOPIC_SHOP_DATA_EXTRACT_LOG_CREATE,
json_encode($shopDataExtractLogDto->toArray()),
$producer::MODE_RESULT_CALLLBACK
);
} catch (\Throwable $e) {
$this->_logger->channel('excel')->warning(
'상점 데이터 추출 로그 카프카 메시지 발송 실패',
[
'exception' => $e,
'extractType' => $extractType,
'menu' => $formData['menu'] ?? null
]
);
}
}
}
 
변경 후ExcelRequest.php
use Framework\Utility\ComponentUtils;
use Framework\Utility\ArrayUtils;
use Framework\Utility\DateTimeUtils;
 
use Framework\Utility\StringUtils;
use Framework\Utility\NumberUtils;
use Framework\Security\Token;
 
use LogHandler;
 
 
use Request;
use Session;
use UserFilePath;
$orderDelete->deleteLapseOrderExcelFormUpdate($arrData['requestSno'], $arrData['sno']);
$this->_logger->channel('orderDelete')->info(__METHOD__ . ' ORDER DELETE EXCEL FORM SNO SAVE, DB_EXCEL_REQUEST INSERT NO : ' . $arrData['requestSno'] . ', EXCEL FORM SNO : ', [$arrData['formSno']]);
 
 
return $arrData['requestSno'];
}
 
unset($arrBind);
 
 
return true;
 
 
 
}
 
return false;
 
//특정 갯수 이하인 경우 바로 생성
/*
if($arrData[ $arrData['whereFl'].'Count'] <= self::EXCEL_PAGE_NUM ) {
return true;
}
*/
 
}
 
public function makeExcelFile(&$arrData)
 
return ['getData' => $setData, 'totalCount' => '$totalNum'];
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
Controller/Admin/Goods/ExcelGoodsPsController.php+20-3
변경 전ExcelGoodsPsController.php
// 상품 엑셀 다운로드
case 'excel_down':
$this->streamedDownload('상품다운로드.xls');
$excel->setExcelGoodsDown($postValue);
// 상품 엑셀 다운로드 본사 & 전체 일 떄 로깅 처리
if ($postValue['downType'] === 'all' && $postValue['scmFl'] === 'n') {
Churn::detectExcelDownloadTotal('goods');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
exit;
break;
 
변경 후ExcelGoodsPsController.php
// 상품 엑셀 다운로드
case 'excel_down':
$this->streamedDownload('상품다운로드.xls');
 
// 상품 엑셀 다운로드 본사 & 전체 일 떄 로깅 처리
$isTotalDownload = $postValue['downType'] === 'all' && $postValue['scmFl'] === 'n';
try {
$isDownloadSuccess = $excel->setExcelGoodsDown($postValue);
} catch (\Throwable $e) {
// 권한 없음·쿼리 오류 등으로 중단된 경우도 추출 실패로 남긴다
if ($isTotalDownload) {
Churn::detectExcelDownloadFail('goods');
}
throw $e;
}
if ($isTotalDownload) {
// 튜닝 소스가 반환값 없이 오버라이드한 경우(null)를 실패로 오인하지 않도록 명시적 false 만 실패 처리한다.
if ($isDownloadSuccess === false) {
Churn::detectExcelDownloadFail('goods');
} else {
Churn::detectExcelDownloadTotal('goods');
}
}
exit;
break;
 
Controller/Admin/Share/LayerExcelPsController.php+25-3
변경 전LayerExcelPsController.php
$postValue = $request->post()->toArray();
$excelRequest = \App::load('Component\\Excel\\ExcelRequest');
$logger->info(__METHOD__, $postValue);
 
try {
switch ($postValue['mode']) {
case 'excel':
$data = $excelRequest->saveInfoExcelRequest($postValue);
 
 
 
 
 
 
if ($data === true) {
if ($postValue['whereFl'] == 'total' && ($postValue['menu'] == 'member' || $postValue['menu'] == 'goods')) {
Churn::detectExcelDownloadTotal($postValue['menu']);
}
echo "<script> parent.set_excel_list('" . __('다운로드할 엑셀파일 생성이 완료되었습니다. 파일을 선택하여 다운로드하시기 바랍니다.') . "'); </script>";
} else {
echo "<script> parent.hide_process(); </script>";
}
}
} catch (\Exception $e) {
 
 
 
 
 
$logger->info($e->getMessage(), $e->getTrace());
throw new LayerException($e->getMessage());
}
exit();
}
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
변경 후LayerExcelPsController.php
$postValue = $request->post()->toArray();
$excelRequest = \App::load('Component\\Excel\\ExcelRequest');
$logger->info(__METHOD__, $postValue);
$isExtractLogPublished = false;
try {
switch ($postValue['mode']) {
case 'excel':
$data = $excelRequest->saveInfoExcelRequest($postValue);
// 조회 결과 0건도 추출 처리 자체는 성공이므로 상품 즉시 다운로드 경로와 같은 기준으로 성공 발행한다
if ($this->isTotalExtractTarget($postValue)) {
Churn::detectExcelDownloadTotal($postValue['menu']);
$isExtractLogPublished = true;
}
 
if ($data === true) {
 
 
 
echo "<script> parent.set_excel_list('" . __('다운로드할 엑셀파일 생성이 완료되었습니다. 파일을 선택하여 다운로드하시기 바랍니다.') . "'); </script>";
} else {
echo "<script> parent.hide_process(); </script>";
}
}
} catch (\Exception $e) {
// 권한 없음·DB 오류로 추출이 중단된 경우도 실패로 남긴다. 성공을 이미 발행했으면 중복으로 보내지 않는다
if (!$isExtractLogPublished && ($postValue['mode'] ?? '') === 'excel' && $this->isTotalExtractTarget($postValue)) {
Churn::detectExcelDownloadFail($postValue['menu']);
}
 
$logger->info($e->getMessage(), $e->getTrace());
throw new LayerException($e->getMessage());
}
exit();
}
 
/**
* 전체 범위 추출 로그 발행 대상인지 여부. 성공·실패 양쪽 호출부가 같은 조건을 쓰도록 묶는다.
*
* @param array $postValue whereFl, menu
*
* @return bool
*/
protected function isTotalExtractTarget(array $postValue): bool
{
return ($postValue['whereFl'] ?? '') == 'total'
&& in_array($postValue['menu'] ?? '', ['member', 'goods'], true);
}
}
 
로그인·카카오싱크 보안 강화.
Component/Member/Member.php+1-1
변경 전Member.php
{
$data['PAGE_URL'] = Request::getDomainUrl() . Request::getRequestUri();
$data['POST'] = Request::post()->toArray();
unset($data['POST']['loginPwd']);
$data['GET'] = Request::get()->toArray();
$data['USER_AGENT'] = Request::getUserAgent();
$data['SESSION'] = \Session::get('member');
 
변경 후Member.php
{
$data['PAGE_URL'] = Request::getDomainUrl() . Request::getRequestUri();
$data['POST'] = Request::post()->toArray();
unset($data['POST']['loginPwd'], $data['POST']['secretKey']);
$data['GET'] = Request::get()->toArray();
$data['USER_AGENT'] = Request::getUserAgent();
$data['SESSION'] = \Session::get('member');
 
Component/Member/Util/MemberUtil.php+14-2
변경 전MemberUtil.php
* @param string $encryptedString 암호화된 로그인 정보
* @param string $key 암호화 키
*
* @return String
* @throws Exception
*/
public function jsDecrypt($encryptedString, $key= self::SECRET_KEY)
{
$json = json_decode(base64_decode($encryptedString), true);
 
 
 
 
 
 
 
 
 
 
 
 
 
try {
$salt = hex2bin($json["salt"]);
$iv = hex2bin($json["iv"]);
}
 
$cipherText = base64_decode($json['ciphertext']);
$iterations = (int)abs($json['iterations']);
if ($iterations <= 0) {
$iterations = 999;
}
 
변경 후MemberUtil.php
* @param string $encryptedString 암호화된 로그인 정보
* @param string $key 암호화 키
*
* @return string|null
* @throws Exception
*/
public function jsDecrypt($encryptedString, $key= self::SECRET_KEY)
{
$json = json_decode(base64_decode($encryptedString), true);
 
// 평문 전송 전환기: 암호문 구조가 아닌 입력은 복호화 불가로 간주 (Warning 방지)
if (!is_array($json) || !isset($json['salt'], $json['iv'], $json['ciphertext'])) {
return null;
}
 
// hex2bin() E_WARNING 방지: salt·iv 가 짝수 길이 16진수 문자열이 아니면 복호화 불가로 간주
foreach (['salt', 'iv'] as $hexKey) {
if (!is_string($json[$hexKey]) || !ctype_xdigit($json[$hexKey]) || strlen($json[$hexKey]) % 2 !== 0) {
return null;
}
}
 
try {
$salt = hex2bin($json["salt"]);
$iv = hex2bin($json["iv"]);
}
 
$cipherText = base64_decode($json['ciphertext']);
$iterations = (int)abs($json['iterations'] ?? 0);
if ($iterations <= 0) {
$iterations = 999;
}
 
Controller/Front/Member/LoginPsController.php+6
변경 전LoginPsController.php
$decryptLoginPwd = $memberUtil->jsDecrypt($request->post()->get('loginPwd'), self::SECRET_KEY);
 
if (empty($decryptLoginPwd) === false) {
 
 
$request->post()->set('loginId', trim($decryptLoginId));
$request->post()->set('loginPwd', trim($decryptLoginPwd));
 
 
 
 
}
 
//카카오 계정탈퇴 혹은 연결해제시 카카오에서 연결끊기 콜백 url 받아 카카오 연결 정보 삭제
 
변경 후LoginPsController.php
$decryptLoginPwd = $memberUtil->jsDecrypt($request->post()->get('loginPwd'), self::SECRET_KEY);
 
if (empty($decryptLoginPwd) === false) {
// 클라이언트 암호화 제거 전환기: 암호문을 보내는 구스킨 잔존 상점 실측용
$logger->channel('userLogin')->info('로그인 암호문 수신', ['referer' => $request->getReferer()]);
$request->post()->set('loginId', trim($decryptLoginId));
$request->post()->set('loginPwd', trim($decryptLoginPwd));
} else {
// 평문 전송 스킨: 암호문 경로와 동일하게 loginId/loginPwd trim 정합
$request->post()->set('loginId', trim($request->post()->get('loginId') ?? ''));
$request->post()->set('loginPwd', trim($request->post()->get('loginPwd') ?? ''));
}
 
//카카오 계정탈퇴 혹은 연결해제시 카카오에서 연결끊기 콜백 url 받아 카카오 연결 정보 삭제
 
data/skin/front/moment/member/kakao_connect.html+2-40
변경 전kakao_connect.html
<!-- //member_tit -->
<div class="member_cont kakao_connect">
<input type="hidden" id="token" name="token" value="{token}" />
<input type="hidden" id="secretKey" name="secretKey" value="{secretKey}" />
<div class="kakao_connect_header">
<h3><b>{kakaoEmail}</b>{=__('으로 가입된 회원정보가 있습니다.')}</h3>
</div>
location.href = "../member/login.php";
}
 
/**
* 로그인 정보 암호화 처리
*/
let Encryption = {
get encryptMethod() {
return "AES-256-CBC";
},
get encryptMethodLength() {
let encryptMethod = this.encryptMethod;
let aesNumber = encryptMethod.match(/\d+/)[0];
return parseInt(aesNumber);
},
encrypt: function (string, key) {
let iv = CryptoJS.lib.WordArray.random(16);
let salt = CryptoJS.lib.WordArray.random(256);
let iterations = 999;
let encryptMethodLength = this.encryptMethodLength / 4;
let hashKey = CryptoJS.PBKDF2(key, salt, { hasher: CryptoJS.algo.SHA512, keySize: encryptMethodLength / 8, iterations: iterations });
let encrypted = CryptoJS.AES.encrypt(string, hashKey, { mode: CryptoJS.mode.CBC, iv: iv });
let encryptedString = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
 
let output = {
ciphertext: encryptedString,
iv: CryptoJS.enc.Hex.stringify(iv),
salt: CryptoJS.enc.Hex.stringify(salt),
iterations: iterations
};
 
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(output)));
}
};
 
 
function connectToKakao() {
let memNo = $("input[name='memNo']:checked").val();
if (!memNo) {
let loginId = $("#loginId").val();
let loginPwd = $("#loginPwd").val();
let token = $("#token").val();
let secretKey = $("#secretKey").val();
 
if (!loginId) {
alert('{=__("아이디를 입력해주세요.")}');
return;
}
 
let encryptLoginId = Encryption.encrypt(loginId, secretKey);
let encryptLoginPwd = Encryption.encrypt(loginPwd, secretKey);
 
$("#connectToKakaoBtn").prop("disabled", true);
 
$.ajax({
url: "../member/kakao_connect_ps.php",
data: {
memNo: memNo,
loginId: encryptLoginId,
loginPwd: encryptLoginPwd,
token: token
},
success: function (data) {
 
변경 후kakao_connect.html
<!-- //member_tit -->
<div class="member_cont kakao_connect">
<input type="hidden" id="token" name="token" value="{token}" />
 
<div class="kakao_connect_header">
<h3><b>{kakaoEmail}</b>{=__('으로 가입된 회원정보가 있습니다.')}</h3>
</div>
location.href = "../member/login.php";
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
function connectToKakao() {
let memNo = $("input[name='memNo']:checked").val();
if (!memNo) {
let loginId = $("#loginId").val();
let loginPwd = $("#loginPwd").val();
let token = $("#token").val();
 
 
if (!loginId) {
alert('{=__("아이디를 입력해주세요.")}');
return;
}
 
 
 
 
$("#connectToKakaoBtn").prop("disabled", true);
 
$.ajax({
url: "../member/kakao_connect_ps.php",
data: {
memNo: memNo,
loginId: loginId,
loginPwd: loginPwd,
token: token
},
success: function (data) {
 
data/skin/front/moment/member/login.html-62
변경 전login.html
<form id="formLogin" method="post" action="{loginActionUrl}">
<input type="hidden" id="mode" name="mode" value="{modeLogin}"/>
<input type="hidden" id="returnUrl" name="returnUrl" value="{returnUrl}"/>
<input type="hidden" id="secretKey" name="secretKey" value="{secretKey}"/>
<input type="hidden" id="encryptFl" name="encryptFl" value="Y"/>
<div class="member_login_box">
<h3>{=__('회원 로그인')}</h3>
<div class="login_input_sec">
<script type="text/javascript">
var $formLogin;
 
/**
* 로그인 정보 암호화 처리
*/
var Encryption = {
get encryptMethod() {
return 'AES-256-CBC';
},
get encryptMethodLength() {
var encryptMethod = this.encryptMethod;
var aesNumber = encryptMethod.match(/\d+/)[0];
return parseInt(aesNumber);
},
encrypt : function (string, key) {
var iv = CryptoJS.lib.WordArray.random(16);
var salt = CryptoJS.lib.WordArray.random(256);
var iterations = 999;
var encryptMethodLength = (this.encryptMethodLength/4);
var hashKey = CryptoJS.PBKDF2(key, salt, {'hasher': CryptoJS.algo.SHA512, 'keySize': (encryptMethodLength/8), 'iterations': iterations});
var encrypted = CryptoJS.AES.encrypt(string, hashKey, {'mode': CryptoJS.mode.CBC, 'iv': iv});
var encryptedString = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
 
var output = {
'ciphertext': encryptedString,
'iv': CryptoJS.enc.Hex.stringify(iv),
'salt': CryptoJS.enc.Hex.stringify(salt),
'iterations': iterations
};
 
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(output)));
}
}
 
/**
* form serialize 값 변경
*
* @param values 폼명
* @param k 변경할 inputName
* @param v 변경할 inputValue
*/
function changeSerialize(values, k, v) {
var found = false;
for (i = 0; i < values.length && !found; i++) {
if (values[i].name == k) {
values[i].value = v;
found = true;
}
}
 
if (!found) {
values.push({name: k,value: v});
}
return values;
}
 
$(document).ready(function () {
var order_no_max_length = $('input[name=orderNo]').data('max-length');
$('#btnJoinMember').click(function (e) {
}
}
 
// 로그인 정보 암호화 처리 (보안이슈)
var encryptLoginId = Encryption.encrypt($('#loginId').val(),$('#secretKey').val());
var encryptLoginPwd = Encryption.encrypt($('#loginPwd').val(),$('#secretKey').val());
 
var params = $(form).serializeArray();
params = changeSerialize(params, 'loginId', encryptLoginId); // 암호화 된 아이디로 변경
params = changeSerialize(params, 'loginPwd', encryptLoginPwd); // 암호화 된 패스워드로 변경
$.post('../member/login_ps.php', params).done(function (data) {
var code = data.code;
var message = data.message;
 
변경 후login.html
<form id="formLogin" method="post" action="{loginActionUrl}">
<input type="hidden" id="mode" name="mode" value="{modeLogin}"/>
<input type="hidden" id="returnUrl" name="returnUrl" value="{returnUrl}"/>
 
 
<div class="member_login_box">
<h3>{=__('회원 로그인')}</h3>
<div class="login_input_sec">
<script type="text/javascript">
var $formLogin;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$(document).ready(function () {
var order_no_max_length = $('input[name=orderNo]').data('max-length');
$('#btnJoinMember').click(function (e) {
}
}
 
 
 
 
 
var params = $(form).serializeArray();
 
 
$.post('../member/login_ps.php', params).done(function (data) {
var code = data.code;
var message = data.message;
 
data/skin/front/mygreek/member/kakao_connect.html+2-40
변경 전kakao_connect.html
<!-- //member_tit -->
<div class="member_cont kakao_connect">
<input type="hidden" id="token" name="token" value="{token}" />
<input type="hidden" id="secretKey" name="secretKey" value="{secretKey}" />
<div class="kakao_connect_header">
<h3><b>{kakaoEmail}</b>{=__('으로 가입된 회원정보가 있습니다.')}</h3>
</div>
location.href = "../member/login.php";
}
 
/**
* 로그인 정보 암호화 처리
*/
let Encryption = {
get encryptMethod() {
return "AES-256-CBC";
},
get encryptMethodLength() {
let encryptMethod = this.encryptMethod;
let aesNumber = encryptMethod.match(/\d+/)[0];
return parseInt(aesNumber);
},
encrypt: function (string, key) {
let iv = CryptoJS.lib.WordArray.random(16);
let salt = CryptoJS.lib.WordArray.random(256);
let iterations = 999;
let encryptMethodLength = this.encryptMethodLength / 4;
let hashKey = CryptoJS.PBKDF2(key, salt, { hasher: CryptoJS.algo.SHA512, keySize: encryptMethodLength / 8, iterations: iterations });
let encrypted = CryptoJS.AES.encrypt(string, hashKey, { mode: CryptoJS.mode.CBC, iv: iv });
let encryptedString = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
 
let output = {
ciphertext: encryptedString,
iv: CryptoJS.enc.Hex.stringify(iv),
salt: CryptoJS.enc.Hex.stringify(salt),
iterations: iterations
};
 
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(output)));
}
};
 
 
function connectToKakao() {
let memNo = $("input[name='memNo']:checked").val();
if (!memNo) {
let loginId = $("#loginId").val();
let loginPwd = $("#loginPwd").val();
let token = $("#token").val();
let secretKey = $("#secretKey").val();
 
if (!loginId) {
alert('{=__("아이디를 입력해주세요.")}');
return;
}
 
let encryptLoginId = Encryption.encrypt(loginId, secretKey);
let encryptLoginPwd = Encryption.encrypt(loginPwd, secretKey);
 
$("#connectToKakaoBtn").prop("disabled", true);
 
$.ajax({
url: "../member/kakao_connect_ps.php",
data: {
memNo: memNo,
loginId: encryptLoginId,
loginPwd: encryptLoginPwd,
token: token
},
success: function (data) {
 
변경 후kakao_connect.html
<!-- //member_tit -->
<div class="member_cont kakao_connect">
<input type="hidden" id="token" name="token" value="{token}" />
 
<div class="kakao_connect_header">
<h3><b>{kakaoEmail}</b>{=__('으로 가입된 회원정보가 있습니다.')}</h3>
</div>
location.href = "../member/login.php";
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
function connectToKakao() {
let memNo = $("input[name='memNo']:checked").val();
if (!memNo) {
let loginId = $("#loginId").val();
let loginPwd = $("#loginPwd").val();
let token = $("#token").val();
 
 
if (!loginId) {
alert('{=__("아이디를 입력해주세요.")}');
return;
}
 
 
 
 
$("#connectToKakaoBtn").prop("disabled", true);
 
$.ajax({
url: "../member/kakao_connect_ps.php",
data: {
memNo: memNo,
loginId: loginId,
loginPwd: loginPwd,
token: token
},
success: function (data) {
 
data/skin/front/mygreek/member/login.html-62
변경 전login.html
<form id="formLogin" method="post" action="{loginActionUrl}">
<input type="hidden" id="mode" name="mode" value="{modeLogin}"/>
<input type="hidden" id="returnUrl" name="returnUrl" value="{returnUrl}"/>
<input type="hidden" id="secretKey" name="secretKey" value="{secretKey}"/>
<input type="hidden" id="encryptFl" name="encryptFl" value="Y"/>
<div class="member_login_box">
<h3>{=__('회원 로그인')}</h3>
<div class="login_input_sec">
<script type="text/javascript">
var $formLogin;
 
/**
* 로그인 정보 암호화 처리
*/
var Encryption = {
get encryptMethod() {
return 'AES-256-CBC';
},
get encryptMethodLength() {
var encryptMethod = this.encryptMethod;
var aesNumber = encryptMethod.match(/\d+/)[0];
return parseInt(aesNumber);
},
encrypt : function (string, key) {
var iv = CryptoJS.lib.WordArray.random(16);
var salt = CryptoJS.lib.WordArray.random(256);
var iterations = 999;
var encryptMethodLength = (this.encryptMethodLength/4);
var hashKey = CryptoJS.PBKDF2(key, salt, {'hasher': CryptoJS.algo.SHA512, 'keySize': (encryptMethodLength/8), 'iterations': iterations});
var encrypted = CryptoJS.AES.encrypt(string, hashKey, {'mode': CryptoJS.mode.CBC, 'iv': iv});
var encryptedString = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
 
var output = {
'ciphertext': encryptedString,
'iv': CryptoJS.enc.Hex.stringify(iv),
'salt': CryptoJS.enc.Hex.stringify(salt),
'iterations': iterations
};
 
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(output)));
}
}
 
/**
* form serialize 값 변경
*
* @param values 폼명
* @param k 변경할 inputName
* @param v 변경할 inputValue
*/
function changeSerialize(values, k, v) {
var found = false;
for (i = 0; i < values.length && !found; i++) {
if (values[i].name == k) {
values[i].value = v;
found = true;
}
}
 
if (!found) {
values.push({name: k,value: v});
}
return values;
}
 
$(document).ready(function () {
var order_no_max_length = $('input[name=orderNo]').data('max-length');
$('#btnJoinMember').click(function (e) {
}
}
 
// 로그인 정보 암호화 처리 (보안이슈)
var encryptLoginId = Encryption.encrypt($('#loginId').val(),$('#secretKey').val());
var encryptLoginPwd = Encryption.encrypt($('#loginPwd').val(),$('#secretKey').val());
 
var params = $(form).serializeArray();
params = changeSerialize(params, 'loginId', encryptLoginId); // 암호화 된 아이디로 변경
params = changeSerialize(params, 'loginPwd', encryptLoginPwd); // 암호화 된 패스워드로 변경
$.post('../member/login_ps.php', params).done(function (data) {
var code = data.code;
var message = data.message;
 
변경 후login.html
<form id="formLogin" method="post" action="{loginActionUrl}">
<input type="hidden" id="mode" name="mode" value="{modeLogin}"/>
<input type="hidden" id="returnUrl" name="returnUrl" value="{returnUrl}"/>
 
 
<div class="member_login_box">
<h3>{=__('회원 로그인')}</h3>
<div class="login_input_sec">
<script type="text/javascript">
var $formLogin;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$(document).ready(function () {
var order_no_max_length = $('input[name=orderNo]').data('max-length');
$('#btnJoinMember').click(function (e) {
}
}
 
 
 
 
 
var params = $(form).serializeArray();
 
 
$.post('../member/login_ps.php', params).done(function (data) {
var code = data.code;
var message = data.message;
 
data/skin/front/story_g/member/kakao_connect.html+2-40
변경 전kakao_connect.html
<h2>{=__('회원 정보 확인')}</h2>
<div class="box kakao_connect">
<input type="hidden" id="token" name="token" value="{token}" />
<input type="hidden" id="secretKey" name="secretKey" value="{secretKey}" />
<div class="kakao_connect_header">
<h3><b>{kakaoEmail}</b>{=__('으로 가입된 회원정보가 있습니다.')}</h3>
</div>
location.href = "../member/login.php";
}
 
/**
* 로그인 정보 암호화 처리
*/
let Encryption = {
get encryptMethod() {
return "AES-256-CBC";
},
get encryptMethodLength() {
let encryptMethod = this.encryptMethod;
let aesNumber = encryptMethod.match(/\d+/)[0];
return parseInt(aesNumber);
},
encrypt: function (string, key) {
let iv = CryptoJS.lib.WordArray.random(16);
let salt = CryptoJS.lib.WordArray.random(256);
let iterations = 999;
let encryptMethodLength = this.encryptMethodLength / 4;
let hashKey = CryptoJS.PBKDF2(key, salt, { hasher: CryptoJS.algo.SHA512, keySize: encryptMethodLength / 8, iterations: iterations });
let encrypted = CryptoJS.AES.encrypt(string, hashKey, { mode: CryptoJS.mode.CBC, iv: iv });
let encryptedString = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
 
let output = {
ciphertext: encryptedString,
iv: CryptoJS.enc.Hex.stringify(iv),
salt: CryptoJS.enc.Hex.stringify(salt),
iterations: iterations
};
 
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(output)));
}
};
 
 
function connectToKakao() {
let memNo = $("input[name='memNo']:checked").val();
if (!memNo) {
let loginId = $("#loginId").val();
let loginPwd = $("#loginPwd").val();
let token = $("#token").val();
let secretKey = $("#secretKey").val();
 
if (!loginId) {
alert('{=__("아이디를 입력해주세요.")}');
return;
}
 
let encryptLoginId = Encryption.encrypt(loginId, secretKey);
let encryptLoginPwd = Encryption.encrypt(loginPwd, secretKey);
 
$("#connectToKakaoBtn").prop("disabled", true);
 
$.ajax({
url: "../member/kakao_connect_ps.php",
data: {
memNo: memNo,
loginId: encryptLoginId,
loginPwd: encryptLoginPwd,
token: token
},
success: function (data) {
 
변경 후kakao_connect.html
<h2>{=__('회원 정보 확인')}</h2>
<div class="box kakao_connect">
<input type="hidden" id="token" name="token" value="{token}" />
 
<div class="kakao_connect_header">
<h3><b>{kakaoEmail}</b>{=__('으로 가입된 회원정보가 있습니다.')}</h3>
</div>
location.href = "../member/login.php";
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
function connectToKakao() {
let memNo = $("input[name='memNo']:checked").val();
if (!memNo) {
let loginId = $("#loginId").val();
let loginPwd = $("#loginPwd").val();
let token = $("#token").val();
 
 
if (!loginId) {
alert('{=__("아이디를 입력해주세요.")}');
return;
}
 
 
 
 
$("#connectToKakaoBtn").prop("disabled", true);
 
$.ajax({
url: "../member/kakao_connect_ps.php",
data: {
memNo: memNo,
loginId: loginId,
loginPwd: loginPwd,
token: token
},
success: function (data) {
 
data/skin/front/story_g/member/login.html-62
변경 전login.html
<form id="formLogin" method="post" action="{loginActionUrl}">
<input type="hidden" id="mode" name="mode" value="{modeLogin}"/>
<input type="hidden" id="returnUrl" name="returnUrl" value="{returnUrl}"/>
<input type="hidden" id="secretKey" name="secretKey" value="{secretKey}"/>
<input type="hidden" id="encryptFl" name="encryptFl" value="Y"/>
<div class="login">
<div class="input-info">
<div>
<script type="text/javascript">
var $formLogin;
 
/**
* 로그인 정보 암호화 처리
*/
var Encryption = {
get encryptMethod() {
return 'AES-256-CBC';
},
get encryptMethodLength() {
var encryptMethod = this.encryptMethod;
var aesNumber = encryptMethod.match(/\d+/)[0];
return parseInt(aesNumber);
},
encrypt : function (string, key) {
var iv = CryptoJS.lib.WordArray.random(16);
var salt = CryptoJS.lib.WordArray.random(256);
var iterations = 999;
var encryptMethodLength = (this.encryptMethodLength/4);
var hashKey = CryptoJS.PBKDF2(key, salt, {'hasher': CryptoJS.algo.SHA512, 'keySize': (encryptMethodLength/8), 'iterations': iterations});
var encrypted = CryptoJS.AES.encrypt(string, hashKey, {'mode': CryptoJS.mode.CBC, 'iv': iv});
var encryptedString = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
 
var output = {
'ciphertext': encryptedString,
'iv': CryptoJS.enc.Hex.stringify(iv),
'salt': CryptoJS.enc.Hex.stringify(salt),
'iterations': iterations
};
 
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(output)));
}
}
 
/**
* form serialize 값 변경
*
* @param values 폼명
* @param k 변경할 inputName
* @param v 변경할 inputValue
*/
function changeSerialize(values, k, v) {
var found = false;
for (i = 0; i < values.length && !found; i++) {
if (values[i].name == k) {
values[i].value = v;
found = true;
}
}
 
if (!found) {
values.push({name: k,value: v});
}
return values;
}
 
function login_fail(url, message) {
$formLogin.find('.caution-msg1').removeClass('dn').text(message);
setTimeout(function () {
}
}
 
// 로그인 정보 암호화 처리 (보안이슈)
var encryptLoginId = Encryption.encrypt($('#loginId').val(),$('#secretKey').val());
var encryptLoginPwd = Encryption.encrypt($('#loginPwd').val(),$('#secretKey').val());
 
var params = $(form).serializeArray();
params = changeSerialize(params, 'loginId', encryptLoginId); // 암호화 된 아이디로 변경
params = changeSerialize(params, 'loginPwd', encryptLoginPwd); // 암호화 된 패스워드로 변경
$.post('../member/login_ps.php', params).done(function (data) {
var code = data.code;
var message = data.message;
 
변경 후login.html
<form id="formLogin" method="post" action="{loginActionUrl}">
<input type="hidden" id="mode" name="mode" value="{modeLogin}"/>
<input type="hidden" id="returnUrl" name="returnUrl" value="{returnUrl}"/>
 
 
<div class="login">
<div class="input-info">
<div>
<script type="text/javascript">
var $formLogin;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
function login_fail(url, message) {
$formLogin.find('.caution-msg1').removeClass('dn').text(message);
setTimeout(function () {
}
}
 
 
 
 
 
var params = $(form).serializeArray();
 
 
$.post('../member/login_ps.php', params).done(function (data) {
var code = data.code;
var message = data.message;
 
data/skin/mobile/moment/member/kakao_connect.html+2-40
변경 전kakao_connect.html
<!-- //member_tit -->
<div class="member_cont kakao_connect">
<input type="hidden" id="token" name="token" value="{token}" />
<input type="hidden" id="secretKey" name="secretKey" value="{secretKey}" />
<div class="kakao_connect_header">
<h3><b>{kakaoEmail}</b>{=__('으로 가입된 회원정보가 있습니다.')}</h3>
</div>
location.href = "../member/login.php";
}
 
/**
* 로그인 정보 암호화 처리
*/
let Encryption = {
get encryptMethod() {
return "AES-256-CBC";
},
get encryptMethodLength() {
let encryptMethod = this.encryptMethod;
let aesNumber = encryptMethod.match(/\d+/)[0];
return parseInt(aesNumber);
},
encrypt: function (string, key) {
let iv = CryptoJS.lib.WordArray.random(16);
let salt = CryptoJS.lib.WordArray.random(256);
let iterations = 999;
let encryptMethodLength = this.encryptMethodLength / 4;
let hashKey = CryptoJS.PBKDF2(key, salt, { hasher: CryptoJS.algo.SHA512, keySize: encryptMethodLength / 8, iterations: iterations });
let encrypted = CryptoJS.AES.encrypt(string, hashKey, { mode: CryptoJS.mode.CBC, iv: iv });
let encryptedString = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
 
let output = {
ciphertext: encryptedString,
iv: CryptoJS.enc.Hex.stringify(iv),
salt: CryptoJS.enc.Hex.stringify(salt),
iterations: iterations
};
 
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(output)));
}
};
 
 
function connectToKakao() {
let memNo = $("input[name='memNo']:checked").val();
if (!memNo) {
let loginId = $("#loginId").val();
let loginPwd = $("#loginPwd").val();
let token = $("#token").val();
let secretKey = $("#secretKey").val();
 
if (!loginId) {
alert('{=__("아이디를 입력해주세요.")}');
return;
}
 
let encryptLoginId = Encryption.encrypt(loginId, secretKey);
let encryptLoginPwd = Encryption.encrypt(loginPwd, secretKey);
 
$("#connectToKakaoBtn").prop("disabled", true);
 
$.ajax({
url: "../member/kakao_connect_ps.php",
data: {
memNo: memNo,
loginId: encryptLoginId,
loginPwd: encryptLoginPwd,
token: token
},
success: function (data) {
 
변경 후kakao_connect.html
<!-- //member_tit -->
<div class="member_cont kakao_connect">
<input type="hidden" id="token" name="token" value="{token}" />
 
<div class="kakao_connect_header">
<h3><b>{kakaoEmail}</b>{=__('으로 가입된 회원정보가 있습니다.')}</h3>
</div>
location.href = "../member/login.php";
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
function connectToKakao() {
let memNo = $("input[name='memNo']:checked").val();
if (!memNo) {
let loginId = $("#loginId").val();
let loginPwd = $("#loginPwd").val();
let token = $("#token").val();
 
 
if (!loginId) {
alert('{=__("아이디를 입력해주세요.")}');
return;
}
 
 
 
 
$("#connectToKakaoBtn").prop("disabled", true);
 
$.ajax({
url: "../member/kakao_connect_ps.php",
data: {
memNo: memNo,
loginId: loginId,
loginPwd: loginPwd,
token: token
},
success: function (data) {
 
data/skin/mobile/moment/member/login.html-66
변경 전login.html
<input type="hidden" name="saveFlag" value="{data.saveFlag}"/>
<input type="hidden" id="mode" name="mode" value="{modeLogin}"/>
<input type="hidden" id="isMyapp" name="isMyapp" value="{isMyapp}"/>
<input type="hidden" id="secretKey" name="secretKey" value="{secretKey}"/>
<input type="hidden" id="encryptFl" name="encryptFl" value="Y"/>
<input type="hidden" id="encryptLoginId" name="encryptLoginId"/>
<input type="hidden" id="encryptLoginPwd" name="encryptLoginPwd"/>
<dl>
<dt><label for="loginId">{=__('아이디')}</label></dt>
<dd><input type="text" id="loginId" name="loginId" value="{data.loginId}" placeholder="{=__('아이디')}"/></dd>
var $formLogin;
var isMyapp = $('#isMyapp').val();
 
/**
* 로그인 정보 암호화 처리
*/
var Encryption = {
get encryptMethod() {
return 'AES-256-CBC';
},
get encryptMethodLength() {
var encryptMethod = this.encryptMethod;
var aesNumber = encryptMethod.match(/\d+/)[0];
return parseInt(aesNumber);
},
encrypt : function (string, key) {
var iv = CryptoJS.lib.WordArray.random(16);
var salt = CryptoJS.lib.WordArray.random(256);
var iterations = 999;
var encryptMethodLength = (this.encryptMethodLength/4);
var hashKey = CryptoJS.PBKDF2(key, salt, {'hasher': CryptoJS.algo.SHA512, 'keySize': (encryptMethodLength/8), 'iterations': iterations});
var encrypted = CryptoJS.AES.encrypt(string, hashKey, {'mode': CryptoJS.mode.CBC, 'iv': iv});
var encryptedString = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
 
var output = {
'ciphertext': encryptedString,
'iv': CryptoJS.enc.Hex.stringify(iv),
'salt': CryptoJS.enc.Hex.stringify(salt),
'iterations': iterations
};
 
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(output)));
}
}
 
/**
* form serialize 값 변경
*
* @param values 폼명
* @param k 변경할 inputName
* @param v 변경할 inputValue
*/
function changeSerialize(values, k, v) {
var found = false;
for (i = 0; i < values.length && !found; i++) {
if (values[i].name == k) {
values[i].value = v;
found = true;
}
}
 
if (!found) {
values.push({name: k,value: v});
}
return values;
}
 
$(document).ready(function () {
var order_no_max_length = $('input[name=orderNo]').data('max-length');
$formLogin = $('#formLogin');
required: "{=__('패스워드를 입력해주세요')}"
}
}, submitHandler: function (form) {
// 로그인 정보 암호화 처리 (보안이슈)
var encryptLoginId = Encryption.encrypt($('#loginId').val(),$('#secretKey').val());
var encryptLoginPwd = Encryption.encrypt($('#loginPwd').val(),$('#secretKey').val());
 
if (isMyapp) {
form.encryptLoginId.value = encryptLoginId;
form.encryptLoginPwd.value = encryptLoginPwd;
form.target = 'ifrmProcess';
form.submit();
} else {
}
 
var params = $(form).serializeArray();
params = changeSerialize(params, 'loginId', encryptLoginId); // 암호화 된 아이디로 변경
params = changeSerialize(params, 'loginPwd', encryptLoginPwd); // 암호화 된 패스워드로 변경
$.post('../member/login_ps.php', params).done(function (data) {
var code = data.code;
var message = data.message;
 
변경 후login.html
<input type="hidden" name="saveFlag" value="{data.saveFlag}"/>
<input type="hidden" id="mode" name="mode" value="{modeLogin}"/>
<input type="hidden" id="isMyapp" name="isMyapp" value="{isMyapp}"/>
 
 
 
 
<dl>
<dt><label for="loginId">{=__('아이디')}</label></dt>
<dd><input type="text" id="loginId" name="loginId" value="{data.loginId}" placeholder="{=__('아이디')}"/></dd>
var $formLogin;
var isMyapp = $('#isMyapp').val();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$(document).ready(function () {
var order_no_max_length = $('input[name=orderNo]').data('max-length');
$formLogin = $('#formLogin');
required: "{=__('패스워드를 입력해주세요')}"
}
}, submitHandler: function (form) {
 
 
 
 
if (isMyapp) {
 
 
form.target = 'ifrmProcess';
form.submit();
} else {
}
 
var params = $(form).serializeArray();
 
 
$.post('../member/login_ps.php', params).done(function (data) {
var code = data.code;
var message = data.message;
 
data/skin/mobile/mygreek/member/kakao_connect.html+2-39
변경 전kakao_connect.html
<!-- //member_tit -->
<div class="member_cont kakao_connect">
<input type="hidden" id="token" name="token" value="{token}" />
<input type="hidden" id="secretKey" name="secretKey" value="{secretKey}" />
<div class="kakao_connect_header">
<h3><b>{kakaoEmail}</b>{=__('으로 가입된 회원정보가 있습니다.')}</h3>
</div>
location.href = "../member/login.php";
}
 
/**
* 로그인 정보 암호화 처리
*/
let Encryption = {
get encryptMethod() {
return "AES-256-CBC";
},
get encryptMethodLength() {
let encryptMethod = this.encryptMethod;
let aesNumber = encryptMethod.match(/\d+/)[0];
return parseInt(aesNumber);
},
encrypt: function (string, key) {
let iv = CryptoJS.lib.WordArray.random(16);
let salt = CryptoJS.lib.WordArray.random(256);
let iterations = 999;
let encryptMethodLength = this.encryptMethodLength / 4;
let hashKey = CryptoJS.PBKDF2(key, salt, { hasher: CryptoJS.algo.SHA512, keySize: encryptMethodLength / 8, iterations: iterations });
let encrypted = CryptoJS.AES.encrypt(string, hashKey, { mode: CryptoJS.mode.CBC, iv: iv });
let encryptedString = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
 
let output = {
ciphertext: encryptedString,
iv: CryptoJS.enc.Hex.stringify(iv),
salt: CryptoJS.enc.Hex.stringify(salt),
iterations: iterations
};
 
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(output)));
}
};
 
function connectToKakao() {
let memNo = $("input[name='memNo']:checked").val();
if (!memNo) {
let loginId = $("#loginId").val();
let loginPwd = $("#loginPwd").val();
let token = $("#token").val();
let secretKey = $("#secretKey").val();
 
if (!loginId) {
alert('{=__("아이디를 입력해주세요.")}');
return;
}
 
let encryptLoginId = Encryption.encrypt(loginId, secretKey);
let encryptLoginPwd = Encryption.encrypt(loginPwd, secretKey);
 
$("#connectToKakaoBtn").prop("disabled", true);
 
$.ajax({
url: "../member/kakao_connect_ps.php",
data: {
memNo: memNo,
loginId: encryptLoginId,
loginPwd: encryptLoginPwd,
token: token
},
success: function (data) {
 
변경 후kakao_connect.html
<!-- //member_tit -->
<div class="member_cont kakao_connect">
<input type="hidden" id="token" name="token" value="{token}" />
 
<div class="kakao_connect_header">
<h3><b>{kakaoEmail}</b>{=__('으로 가입된 회원정보가 있습니다.')}</h3>
</div>
location.href = "../member/login.php";
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
function connectToKakao() {
let memNo = $("input[name='memNo']:checked").val();
if (!memNo) {
let loginId = $("#loginId").val();
let loginPwd = $("#loginPwd").val();
let token = $("#token").val();
 
 
if (!loginId) {
alert('{=__("아이디를 입력해주세요.")}');
return;
}
 
 
 
 
$("#connectToKakaoBtn").prop("disabled", true);
 
$.ajax({
url: "../member/kakao_connect_ps.php",
data: {
memNo: memNo,
loginId: loginId,
loginPwd: loginPwd,
token: token
},
success: function (data) {
 
data/skin/mobile/mygreek/member/login.html-66
변경 전login.html
<input type="hidden" name="saveFlag" value="{data.saveFlag}"/>
<input type="hidden" id="mode" name="mode" value="{modeLogin}"/>
<input type="hidden" id="isMyapp" name="isMyapp" value="{isMyapp}"/>
<input type="hidden" id="secretKey" name="secretKey" value="{secretKey}"/>
<input type="hidden" id="encryptFl" name="encryptFl" value="Y"/>
<input type="hidden" id="encryptLoginId" name="encryptLoginId"/>
<input type="hidden" id="encryptLoginPwd" name="encryptLoginPwd"/>
<dl>
<dt><label for="loginId">{=__('아이디')}</label></dt>
<dd><input type="text" id="loginId" name="loginId" value="{data.loginId}" placeholder="{=__('아이디')}"/></dd>
var $formLogin;
var isMyapp = $('#isMyapp').val();
 
/**
* 로그인 정보 암호화 처리
*/
var Encryption = {
get encryptMethod() {
return 'AES-256-CBC';
},
get encryptMethodLength() {
var encryptMethod = this.encryptMethod;
var aesNumber = encryptMethod.match(/\d+/)[0];
return parseInt(aesNumber);
},
encrypt : function (string, key) {
var iv = CryptoJS.lib.WordArray.random(16);
var salt = CryptoJS.lib.WordArray.random(256);
var iterations = 999;
var encryptMethodLength = (this.encryptMethodLength/4);
var hashKey = CryptoJS.PBKDF2(key, salt, {'hasher': CryptoJS.algo.SHA512, 'keySize': (encryptMethodLength/8), 'iterations': iterations});
var encrypted = CryptoJS.AES.encrypt(string, hashKey, {'mode': CryptoJS.mode.CBC, 'iv': iv});
var encryptedString = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
 
var output = {
'ciphertext': encryptedString,
'iv': CryptoJS.enc.Hex.stringify(iv),
'salt': CryptoJS.enc.Hex.stringify(salt),
'iterations': iterations
};
 
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(output)));
}
}
 
/**
* form serialize 값 변경
*
* @param values 폼명
* @param k 변경할 inputName
* @param v 변경할 inputValue
*/
function changeSerialize(values, k, v) {
var found = false;
for (i = 0; i < values.length && !found; i++) {
if (values[i].name == k) {
values[i].value = v;
found = true;
}
}
 
if (!found) {
values.push({name: k,value: v});
}
return values;
}
 
$(document).ready(function () {
var order_no_max_length = $('input[name=orderNo]').data('max-length');
$formLogin = $('#formLogin');
required: "{=__('패스워드를 입력해주세요')}"
}
}, submitHandler: function (form) {
// 로그인 정보 암호화 처리 (보안이슈)
var encryptLoginId = Encryption.encrypt($('#loginId').val(),$('#secretKey').val());
var encryptLoginPwd = Encryption.encrypt($('#loginPwd').val(),$('#secretKey').val());
 
if (isMyapp) {
form.encryptLoginId.value = encryptLoginId;
form.encryptLoginPwd.value = encryptLoginPwd;
form.target = 'ifrmProcess';
form.submit();
} else {
}
 
var params = $(form).serializeArray();
params = changeSerialize(params, 'loginId', encryptLoginId); // 암호화 된 아이디로 변경
params = changeSerialize(params, 'loginPwd', encryptLoginPwd); // 암호화 된 패스워드로 변경
$.post('../member/login_ps.php', params).done(function (data) {
var code = data.code;
var message = data.message;
 
변경 후login.html
<input type="hidden" name="saveFlag" value="{data.saveFlag}"/>
<input type="hidden" id="mode" name="mode" value="{modeLogin}"/>
<input type="hidden" id="isMyapp" name="isMyapp" value="{isMyapp}"/>
 
 
 
 
<dl>
<dt><label for="loginId">{=__('아이디')}</label></dt>
<dd><input type="text" id="loginId" name="loginId" value="{data.loginId}" placeholder="{=__('아이디')}"/></dd>
var $formLogin;
var isMyapp = $('#isMyapp').val();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$(document).ready(function () {
var order_no_max_length = $('input[name=orderNo]').data('max-length');
$formLogin = $('#formLogin');
required: "{=__('패스워드를 입력해주세요')}"
}
}, submitHandler: function (form) {
 
 
 
 
if (isMyapp) {
 
 
form.target = 'ifrmProcess';
form.submit();
} else {
}
 
var params = $(form).serializeArray();
 
 
$.post('../member/login_ps.php', params).done(function (data) {
var code = data.code;
var message = data.message;
 
data/skin/mobile/story_g/member/kakao_connect.html+2-39
변경 전kakao_connect.html
<!-- //member_tit -->
<div class="member_cont kakao_connect">
<input type="hidden" id="token" name="token" value="{token}" />
<input type="hidden" id="secretKey" name="secretKey" value="{secretKey}" />
<div class="kakao_connect_header">
<h3><b>{kakaoEmail}</b>{=__('으로 가입된 회원정보가 있습니다.')}</h3>
</div>
location.href = "../member/login.php";
}
 
/**
* 로그인 정보 암호화 처리
*/
let Encryption = {
get encryptMethod() {
return "AES-256-CBC";
},
get encryptMethodLength() {
let encryptMethod = this.encryptMethod;
let aesNumber = encryptMethod.match(/\d+/)[0];
return parseInt(aesNumber);
},
encrypt: function (string, key) {
let iv = CryptoJS.lib.WordArray.random(16);
let salt = CryptoJS.lib.WordArray.random(256);
let iterations = 999;
let encryptMethodLength = this.encryptMethodLength / 4;
let hashKey = CryptoJS.PBKDF2(key, salt, { hasher: CryptoJS.algo.SHA512, keySize: encryptMethodLength / 8, iterations: iterations });
let encrypted = CryptoJS.AES.encrypt(string, hashKey, { mode: CryptoJS.mode.CBC, iv: iv });
let encryptedString = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
 
let output = {
ciphertext: encryptedString,
iv: CryptoJS.enc.Hex.stringify(iv),
salt: CryptoJS.enc.Hex.stringify(salt),
iterations: iterations
};
 
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(output)));
}
};
 
function connectToKakao() {
let memNo = $("input[name='memNo']:checked").val();
if (!memNo) {
let loginId = $("#loginId").val();
let loginPwd = $("#loginPwd").val();
let token = $("#token").val();
let secretKey = $("#secretKey").val();
 
if (!loginId) {
alert('{=__("아이디를 입력해주세요.")}');
return;
}
 
let encryptLoginId = Encryption.encrypt(loginId, secretKey);
let encryptLoginPwd = Encryption.encrypt(loginPwd, secretKey);
 
$("#connectToKakaoBtn").prop("disabled", true);
 
$.ajax({
url: "../member/kakao_connect_ps.php",
data: {
memNo: memNo,
loginId: encryptLoginId,
loginPwd: encryptLoginPwd,
token: token
},
success: function (data) {
 
변경 후kakao_connect.html
<!-- //member_tit -->
<div class="member_cont kakao_connect">
<input type="hidden" id="token" name="token" value="{token}" />
 
<div class="kakao_connect_header">
<h3><b>{kakaoEmail}</b>{=__('으로 가입된 회원정보가 있습니다.')}</h3>
</div>
location.href = "../member/login.php";
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
function connectToKakao() {
let memNo = $("input[name='memNo']:checked").val();
if (!memNo) {
let loginId = $("#loginId").val();
let loginPwd = $("#loginPwd").val();
let token = $("#token").val();
 
 
if (!loginId) {
alert('{=__("아이디를 입력해주세요.")}');
return;
}
 
 
 
 
$("#connectToKakaoBtn").prop("disabled", true);
 
$.ajax({
url: "../member/kakao_connect_ps.php",
data: {
memNo: memNo,
loginId: loginId,
loginPwd: loginPwd,
token: token
},
success: function (data) {
 
data/skin/mobile/story_g/member/login.html-66
변경 전login.html
<input type="hidden" name="saveFlag" value="{data.saveFlag}"/>
<input type="hidden" id="mode" name="mode" value="{modeLogin}"/>
<input type="hidden" id="isMyapp" name="isMyapp" value="{isMyapp}"/>
<input type="hidden" id="secretKey" name="secretKey" value="{secretKey}"/>
<input type="hidden" id="encryptFl" name="encryptFl" value="Y"/>
<input type="hidden" id="encryptLoginId" name="encryptLoginId"/>
<input type="hidden" id="encryptLoginPwd" name="encryptLoginPwd"/>
<div class="inp_tx">
<label for="loginId" class="blind">{=__('아이디')}</label>
<input type="text" id="loginId" name="loginId" value="{data.loginId}" placeholder="{=__('아이디')}">
var $formLogin;
var isMyapp = $('#isMyapp').val();
 
/**
* 로그인 정보 암호화 처리
*/
var Encryption = {
get encryptMethod() {
return 'AES-256-CBC';
},
get encryptMethodLength() {
var encryptMethod = this.encryptMethod;
var aesNumber = encryptMethod.match(/\d+/)[0];
return parseInt(aesNumber);
},
encrypt : function (string, key) {
var iv = CryptoJS.lib.WordArray.random(16);
var salt = CryptoJS.lib.WordArray.random(256);
var iterations = 999;
var encryptMethodLength = (this.encryptMethodLength/4);
var hashKey = CryptoJS.PBKDF2(key, salt, {'hasher': CryptoJS.algo.SHA512, 'keySize': (encryptMethodLength/8), 'iterations': iterations});
var encrypted = CryptoJS.AES.encrypt(string, hashKey, {'mode': CryptoJS.mode.CBC, 'iv': iv});
var encryptedString = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
 
var output = {
'ciphertext': encryptedString,
'iv': CryptoJS.enc.Hex.stringify(iv),
'salt': CryptoJS.enc.Hex.stringify(salt),
'iterations': iterations
};
 
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(output)));
}
}
 
/**
* form serialize 값 변경
*
* @param values 폼명
* @param k 변경할 inputName
* @param v 변경할 inputValue
*/
function changeSerialize(values, k, v) {
var found = false;
for (i = 0; i < values.length && !found; i++) {
if (values[i].name == k) {
values[i].value = v;
found = true;
}
}
 
if (!found) {
values.push({name: k,value: v});
}
return values;
}
 
$(document).ready(function () {
$formLogin = $('#formLogin');
$formLogin.validate({
required: "{=__('패스워드를 입력해주세요')}"
}
}, submitHandler: function (form) {
// 로그인 정보 암호화 처리 (보안이슈)
var encryptLoginId = Encryption.encrypt($('#loginId').val(),$('#secretKey').val());
var encryptLoginPwd = Encryption.encrypt($('#loginPwd').val(),$('#secretKey').val());
 
if (isMyapp) {
form.encryptLoginId.value = encryptLoginId;
form.encryptLoginPwd.value = encryptLoginPwd;
form.target = 'ifrmProcess';
form.submit();
} else {
}
 
var params = $(form).serializeArray();
params = changeSerialize(params, 'loginId', encryptLoginId); // 암호화 된 아이디로 변경
params = changeSerialize(params, 'loginPwd', encryptLoginPwd); // 암호화 된 패스워드로 변경
$.post('../member/login_ps.php', params).done(function (data) {
var code = data.code;
var message = data.message;
 
변경 후login.html
<input type="hidden" name="saveFlag" value="{data.saveFlag}"/>
<input type="hidden" id="mode" name="mode" value="{modeLogin}"/>
<input type="hidden" id="isMyapp" name="isMyapp" value="{isMyapp}"/>
 
 
 
 
<div class="inp_tx">
<label for="loginId" class="blind">{=__('아이디')}</label>
<input type="text" id="loginId" name="loginId" value="{data.loginId}" placeholder="{=__('아이디')}">
var $formLogin;
var isMyapp = $('#isMyapp').val();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$(document).ready(function () {
$formLogin = $('#formLogin');
$formLogin.validate({
required: "{=__('패스워드를 입력해주세요')}"
}
}, submitHandler: function (form) {
 
 
 
 
if (isMyapp) {
 
 
form.target = 'ifrmProcess';
form.submit();
} else {
}
 
var params = $(form).serializeArray();
 
 
$.post('../member/login_ps.php', params).done(function (data) {
var code = data.code;
var message = data.message;
 
보안서버 HTTPS 리다이렉트 처리 개선
Component/SiteLink/SiteLink.php+1-1
변경 전SiteLink.php
\Cookie::del('GD5SESSID');
}
$refreshUrl = $this->getFullUrl('https', $this->_sslDomain, $this->_sslPort, Request::getRequestUri());
http_response_code(Response::HTTP_TEMPORARY_REDIRECT);
header('Location: ' . $refreshUrl);
exit();
} else {
 
변경 후SiteLink.php
\Cookie::del('GD5SESSID');
}
$refreshUrl = $this->getFullUrl('https', $this->_sslDomain, $this->_sslPort, Request::getRequestUri());
http_response_code(Response::HTTP_PERMANENTLY_REDIRECT);
header('Location: ' . $refreshUrl);
exit();
} else {
 
SMS 발송담당자 지정 인원 제한 해제
Admin/policy/_manage_permission_menu_list.php+1-1
변경 전_manage_permission_menu_list.php
?>
</table>
</div>
<input type="hidden" id="messageSenderMeta" data-editor-approver="<?= !empty($isEditorMessageApprover) ? 'y' : 'n'; ?>" data-editor-representative="<?= !empty($isEditorMessageRepresentative) ? 'y' : 'n'; ?>" data-caller-blocked="<?= !empty($isCallerBlocked) ? 'y' : 'n'; ?>" data-caller-uncertified-delegate="<?= !empty($isCallerUncertifiedDelegate) ? 'y' : 'n'; ?>" data-sender-count="<?= (int)(gd_isset($messageSenderCount, 0)); ?>" data-sender-limit="<?= (int)(gd_isset($messageSenderLimit, 0)); ?>"/>
<div class="access-control-reason <?=(!empty($sno) || $changeType == 'init') ? '' : 'display-none'?>" style="clear: both;">
<div class="table-action-dropdown">
<div class="table-action mgt0 mgb15">
 
변경 후_manage_permission_menu_list.php
?>
</table>
</div>
<input type="hidden" id="messageSenderMeta" data-editor-approver="<?= !empty($isEditorMessageApprover) ? 'y' : 'n'; ?>" data-editor-representative="<?= !empty($isEditorMessageRepresentative) ? 'y' : 'n'; ?>" data-caller-blocked="<?= !empty($isCallerBlocked) ? 'y' : 'n'; ?>" data-caller-uncertified-delegate="<?= !empty($isCallerUncertifiedDelegate) ? 'y' : 'n'; ?>"/>
<div class="access-control-reason <?=(!empty($sno) || $changeType == 'init') ? '' : 'display-none'?>" style="clear: both;">
<div class="table-action-dropdown">
<div class="table-action mgt0 mgb15">
 
Admin/policy/manage_permission.php+1-12
변경 전manage_permission.php
var $smsSetBox = $('#menuList input:checkbox[data-value="messageSendSms"]:not(:disabled)');
if ($smsSetBox.length > 0) {
var smsSetGranted = $smsSetBox.is(':checked');
var smsChanged = false, smsNewSenderCount = 0;
$smsCheckedRows.each(function () {
var smsRole = $(this).data('smsRole');
// 잠금 판정은 서버가 행마다 내려준다 — 미등록 최고운영자는 smsRole 이 비어 있어 역할값만으로는 걸러지지 않는다
if (nowSender !== smsSetGranted) {
smsChanged = true;
}
if (smsSetGranted && !nowSender) {
smsNewSenderCount++;
}
});
if (smsChanged) {
var $smsMeta = $('#messageSenderMeta');
dialog_alert('SMS 발송 메뉴 접근이 제한되었습니다.<br>스팸 또는 부정 사용으로 차단되어 접근할 수 없습니다.<br>자세한 사항은 1:1문의로 문의하시기 바랍니다.', '경고');
return false;
}
if (smsSetGranted) {
var smsSenderCount = parseInt($smsMeta.data('senderCount'), 10) || 0;
var smsSenderLimit = parseInt($smsMeta.data('senderLimit'), 10) || 0;
if (smsSenderCount + smsNewSenderCount > smsSenderLimit) {
dialog_alert('발송담당자는 최대 ' + smsSenderLimit + '명까지 지정 가능합니다.', '경고');
return false;
}
}
if ($.trim($('#accessControlReason').val()) === '') {
dialog_alert('발송담당자 권한 변경 사유를 작성해주세요.', '경고');
return false;
 
변경 후manage_permission.php
var $smsSetBox = $('#menuList input:checkbox[data-value="messageSendSms"]:not(:disabled)');
if ($smsSetBox.length > 0) {
var smsSetGranted = $smsSetBox.is(':checked');
var smsChanged = false;
$smsCheckedRows.each(function () {
var smsRole = $(this).data('smsRole');
// 잠금 판정은 서버가 행마다 내려준다 — 미등록 최고운영자는 smsRole 이 비어 있어 역할값만으로는 걸러지지 않는다
if (nowSender !== smsSetGranted) {
smsChanged = true;
}
 
 
 
});
if (smsChanged) {
var $smsMeta = $('#messageSenderMeta');
dialog_alert('SMS 발송 메뉴 접근이 제한되었습니다.<br>스팸 또는 부정 사용으로 차단되어 접근할 수 없습니다.<br>자세한 사항은 1:1문의로 문의하시기 바랍니다.', '경고');
return false;
}
 
 
 
 
 
 
 
 
if ($.trim($('#accessControlReason').val()) === '') {
dialog_alert('발송담당자 권한 변경 사유를 작성해주세요.', '경고');
return false;
 
Component/Member/Manager.php-7
변경 전Manager.php
$smsRoleGuard = \App::getInstance(MessageOperatorRoleGuard::class);
$smsGranted = is_array($arrData['functionAuth']) && (($arrData['functionAuth'][MessageOperatorRoleService::SEND_SMS_FUNCTION_AUTH] ?? '') === 'y');
$smsChanged = false;
$smsNewSenderCount = 0;
foreach ($managersData as $smsTarget) {
// 최고운영자(sno=1)/위임자는 messageSendSms 강제(잠금)라 변경 대상 아님
if ($smsRoleService->isSenderPermissionLocked((int)$smsTarget['sno'])) {
if ($smsNowGranted !== $smsGranted) {
$smsChanged = true;
}
if ($smsGranted && $smsNowGranted === false) {
$smsNewSenderCount++; // 신규로 발송담당자가 되는 대상
}
}
if ($smsChanged) {
if ($smsRoleGuard->isDelegateOrHigher() === false) {
if ($smsRoleGuard->isRepresentative() && $smsRoleService->isBlockedRepresentative()) {
throw new Exception(__('SMS 발송 메뉴 접근이 제한되었습니다.<br>스팸 또는 부정 사용으로 차단되어 접근할 수 없습니다.<br>자세한 사항은 1:1문의로 문의하시기 바랍니다.'));
}
if ($smsGranted && ($smsRoleService->countSenders() + $smsNewSenderCount) > MessageOperatorRoleService::MAX_SENDER_COUNT) {
throw new Exception(__('발송담당자는 최대 %d명까지 지정 가능합니다.', MessageOperatorRoleService::MAX_SENDER_COUNT));
}
if (trim((string)($arrData['accessControlReason'] ?? '')) === '') {
throw new Exception(__('발송담당자 권한 변경 사유를 작성해주세요.'));
}
 
변경 후Manager.php
$smsRoleGuard = \App::getInstance(MessageOperatorRoleGuard::class);
$smsGranted = is_array($arrData['functionAuth']) && (($arrData['functionAuth'][MessageOperatorRoleService::SEND_SMS_FUNCTION_AUTH] ?? '') === 'y');
$smsChanged = false;
 
foreach ($managersData as $smsTarget) {
// 최고운영자(sno=1)/위임자는 messageSendSms 강제(잠금)라 변경 대상 아님
if ($smsRoleService->isSenderPermissionLocked((int)$smsTarget['sno'])) {
if ($smsNowGranted !== $smsGranted) {
$smsChanged = true;
}
 
 
 
}
if ($smsChanged) {
if ($smsRoleGuard->isDelegateOrHigher() === false) {
if ($smsRoleGuard->isRepresentative() && $smsRoleService->isBlockedRepresentative()) {
throw new Exception(__('SMS 발송 메뉴 접근이 제한되었습니다.<br>스팸 또는 부정 사용으로 차단되어 접근할 수 없습니다.<br>자세한 사항은 1:1문의로 문의하시기 바랍니다.'));
}
 
 
 
if (trim((string)($arrData['accessControlReason'] ?? '')) === '') {
throw new Exception(__('발송담당자 권한 변경 사유를 작성해주세요.'));
}
 
Controller/Admin/Policy/ManagePsController.php-2
변경 전ManagePsController.php
$this->setData('isCallerBlocked', $isEditorMessageRepresentative && $messageOperatorRoleService->isBlockedRepresentative());
// 위임자 아님 안내가 우선이라 위임자 이상일 때만 판정한다 — isUncertifiedDelegateActor 는 위임자가 아닌 운영자도 DI 가 없으면 true 다
$this->setData('isCallerUncertifiedDelegate', $messageOperatorRoleGuard->isDelegateOrHigher() && $messageOperatorRoleService->isUncertifiedDelegateActor());
$this->setData('messageSenderCount', $messageOperatorRoleService->countSenders());
$this->setData('messageSenderLimit', MessageOperatorRoleService::MAX_SENDER_COUNT);
break;
 
// --- 운영자 권한 설정> 운영자 검색
 
변경 후ManagePsController.php
$this->setData('isCallerBlocked', $isEditorMessageRepresentative && $messageOperatorRoleService->isBlockedRepresentative());
// 위임자 아님 안내가 우선이라 위임자 이상일 때만 판정한다 — isUncertifiedDelegateActor 는 위임자가 아닌 운영자도 DI 가 없으면 true 다
$this->setData('isCallerUncertifiedDelegate', $messageOperatorRoleGuard->isDelegateOrHigher() && $messageOperatorRoleService->isUncertifiedDelegateActor());
 
 
break;
 
// --- 운영자 권한 설정> 운영자 검색
 
Controller/Admin/Share/LayerManagePermissionController.php-2
변경 전LayerManagePermissionController.php
$this->setData('isCallerBlocked', $isEditorMessageRepresentative && $messageOperatorRoleService->isBlockedRepresentative());
// 위임자 아님 안내가 우선이라 위임자 이상일 때만 판정한다 — isUncertifiedDelegateActor 는 위임자가 아닌 운영자도 DI 가 없으면 true 다
$this->setData('isCallerUncertifiedDelegate', $messageOperatorRoleGuard->isDelegateOrHigher() && $messageOperatorRoleService->isUncertifiedDelegateActor());
$this->setData('messageSenderCount', $messageOperatorRoleService->countSenders());
$this->setData('messageSenderLimit', MessageOperatorRoleService::MAX_SENDER_COUNT);
$this->setData('scmFl', $scmFl);
$this->setData('scmNo', $scmNo);
$this->setData('viewMemuDepth', $viewMemuDepth);
 
변경 후LayerManagePermissionController.php
$this->setData('isCallerBlocked', $isEditorMessageRepresentative && $messageOperatorRoleService->isBlockedRepresentative());
// 위임자 아님 안내가 우선이라 위임자 이상일 때만 판정한다 — isUncertifiedDelegateActor 는 위임자가 아닌 운영자도 DI 가 없으면 true 다
$this->setData('isCallerUncertifiedDelegate', $messageOperatorRoleGuard->isDelegateOrHigher() && $messageOperatorRoleService->isUncertifiedDelegateActor());
 
 
$this->setData('scmFl', $scmFl);
$this->setData('scmNo', $scmNo);
$this->setData('viewMemuDepth', $viewMemuDepth);