본문으로 건너뛰기

소스 변경 전체 보기

PHP 7 · GODO25
변경 파일 수: 144개
변경 파일 목록
총 144개
엑셀 다운로드 시 다운로드 기록 수집
ExcelRequest.phpComponent/Excel/
개인정보 수집 및 이용 동의 템플릿 개정
excel_member_up.phpAdmin/member/member_detail_search.phpAdmin/member/member_joinitem.phpAdmin/member/_member_view_other.phpAdmin/member/_member_view.phpAdmin/member/base_agreement_with_private.phpAdmin/policy/BuyerInformCode.phpComponent/Agreement/BuyerInform.phpComponent/Agreement/BuyerInformVo.phpComponent/Agreement/DBTableField.phpComponent/Database/MemberTableField.phpComponent/Database/ExcelMember.phpComponent/Excel/History.phpComponent/Member/MemberAdmin.phpComponent/Member/MemberDAO.phpComponent/Member/Member.phpComponent/Member/MemberVO.phpComponent/Member/MyPage.phpComponent/Member/MemberUtil.phpComponent/Member/Util/MemberModifyController.phpController/Admin/Member/MemberPsController.phpController/Admin/Member/MemberRegisterController.phpController/Admin/Member/BaseAgreementWithPrivateController.phpController/Admin/Policy/BaseAgreementWithPrivatePsController.phpController/Admin/Policy/MemberCrmDetailController.phpController/Admin/Share/JoinAgreementController.phpController/Front/Member/LoginPsController.phpController/Front/Member/MyPageController.phpController/Front/Mypage/AgreementController.phpController/Front/Service/icon_reset.pngdata/skin/front/moment/img/icon/board/join_agreement.htmldata/skin/front/moment/member/_join_view.htmldata/skin/front/moment/member/_join_view_other.htmldata/skin/front/moment/member/my_page.htmldata/skin/front/moment/mypage/join_agreement.htmldata/skin/front/mygreek/member/_join_view.htmldata/skin/front/mygreek/member/_join_view_other.htmldata/skin/front/mygreek/member/my_page.htmldata/skin/front/mygreek/mypage/join_agreement.htmldata/skin/front/story_g/member/_join_view.htmldata/skin/front/story_g/member/_join_view_other.htmldata/skin/front/story_g/member/my_page.htmldata/skin/front/story_g/mypage/join_agreement.htmldata/skin/mobile/moment/member/_join_view.htmldata/skin/mobile/moment/member/_join_view_other.htmldata/skin/mobile/moment/member/my_page.htmldata/skin/mobile/moment/mypage/join_agreement.htmldata/skin/mobile/mygreek/member/_join_view.htmldata/skin/mobile/mygreek/member/_join_view_other.htmldata/skin/mobile/mygreek/member/my_page.htmldata/skin/mobile/mygreek/mypage/join_agreement.htmldata/skin/mobile/story_g/member/_join_view.htmldata/skin/mobile/story_g/member/_join_view_other.htmldata/skin/mobile/story_g/member/my_page.htmldata/skin/mobile/story_g/mypage/
지역별 추가배송비 구간별 반복 부과 옵션 추가
delivery_regist.phpAdmin/policy/delivery_regist.phpAdmin/provider/policy/Cart.phpComponent/Cart/DBTableField.phpComponent/Database/DeliveryCart.phpComponent/Delivery/Delivery.phpComponent/Delivery/DeliveryRegistController.phpController/Admin/Policy/layer.cssdata/skin/front/moment/css/common/layer/goods_view.htmldata/skin/front/moment/goods/layer_option.htmldata/skin/front/moment/goods/layer.cssdata/skin/front/mygreek/css/common/layer/goods_view.htmldata/skin/front/mygreek/goods/layer_option.htmldata/skin/front/mygreek/goods/icon_warning_green.svgdata/skin/front/mygreek/img/icon/etc/gd_share.cssdata/skin/front/story_g/css/goods_view.htmldata/skin/front/story_g/goods/layer_option.htmldata/skin/front/story_g/goods/goods_view.htmldata/skin/mobile/moment/goods/goods_view.htmldata/skin/mobile/mygreek/goods/goods_view.htmldata/skin/mobile/story_g/goods/
- [게시판] 비회원 글쓰기 보안 강화
Board.phpComponent/Board/BoardPsController.phpController/Mobile/Board/
LMS 메시지 발송 시 제목 입력 기능
sms_auto.phpAdmin/member/sms_log.phpAdmin/member/sms_send.phpAdmin/member/cart_remind_regist.phpAdmin/promotion/comeback_coupon_regist.phpAdmin/promotion/layer_cart_remind_message.phpAdmin/promotion/layer_comeback_coupon_sms.phpAdmin/share/layer_standby_sms.phpAdmin/share/member_crm_sms.phpAdmin/share/CartRemind.phpComponent/CartRemind/CouponAdmin.phpComponent/Coupon/DBTableField.phpComponent/Database/SmsAdmin.phpComponent/Sms/SmsAuto.phpComponent/Sms/SmsSender.phpComponent/Sms/SmsAutoController.phpController/Admin/Member/SmsLogPsController.phpController/Admin/Member/SmsSendController.phpController/Admin/Member/CartRemindRegistController.phpController/Admin/Promotion/ComebackCouponRegistController.phpController/Admin/Promotion/LayerCartRemindMessageController.phpController/Admin/Promotion/LayerStandbySmsController.phpController/Admin/Share/
무료보안 관리자 화면 안정성 개선
SecureSocketLayer.phpComponent/SiteLink/
본인인증(아이핀) 페이지 보안 강화
IpinMainController.phpController/Front/Member/Ipin/
상품 검색 보안 강화.
Goods.phpComponent/Goods/
구매평 연동 플러스리뷰 설정 안정성 개선
Policy.phpComponent/Policy/
관리자-유저 세션 격리 강화
MemberSnsDAO.phpComponent/Member/
변경 파일 코드
추가삭제
엑셀 다운로드 시 다운로드 기록 수집
Component/Excel/ExcelRequest.php+116
변경 전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;
} else {
 
return false;
}
 
 
return ['getData' => $setData, 'totalCount' => '$totalNum'];
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
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;
} else {
 
return false;
}
 
 
return ['getData' => $setData, 'totalCount' => '$totalNum'];
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
변경 후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;
}
 
 
return ['getData' => $setData, 'totalCount' => '$totalNum'];
}
 
/**
* 상점 데이터 추출 완료 결과를 카프카 토픽으로 발행한다.
*
* @param array|null $formData 엑셀 양식 데이터 (es_excelForm, menu 포함)
* @param bool $isSuccess 추출 성공 여부
* @param string $extractType 추출 유형 (ShopDataExtractLogDTO::EXTRACT_TYPE_* 상수)
* @return void
*/
protected function publishExtractLog($formData, bool $isSuccess, string $extractType)
{
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,
$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
]
);
}
}
}
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 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($arrData, true, ShopDataExtractLogDTO::EXTRACT_TYPE_EXCEL);
return $arrData['requestSno'];
}
 
unset($arrBind);
 
$this->publishExtractLog($arrData, true, ShopDataExtractLogDTO::EXTRACT_TYPE_EXCEL);
return true;
} else {
$this->publishExtractLog($arrData, false, ShopDataExtractLogDTO::EXTRACT_TYPE_EXCEL);
return false;
}
 
 
return ['getData' => $setData, 'totalCount' => '$totalNum'];
}
 
/**
* 상점 데이터 추출 완료 결과를 카프카 토픽으로 발행한다.
*
* @param array $arrData 추출 요청 데이터 (menu 포함)
* @param bool $isSuccess 추출 성공 여부
* @param string $extractType 추출 유형 (ShopDataExtractLogDTO::EXTRACT_TYPE_* 상수)
* @return void
*/
protected function publishExtractLog(array $arrData, bool $isSuccess, string $extractType)
{
try {
$godosno = Globals::get('gLicense.godosno');
if (empty($godosno)) {
throw new MissingRequiredFieldException('상점 데이터 추출 로그 발행 실패: 라이선스 상점번호(godosno)가 없습니다.');
}
 
$extractTarget = $arrData['menu'] ? strtoupper($arrData['menu']) : null;
$producer = new ProducerUtils();
$shopDataExtractLogDto = new ShopDataExtractLogDTO(
[(int)$godosno],
$extractType,
$extractTarget,
$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,
'extractTarget' => $arrData['menu'] ?? null
]
);
}
}
}
 
애널리틱스 세션 분석 기능 고도화
Component/Cart/Cart.php+12
변경 전Cart.php
use Framework\Utility\ArrayUtils;
use Framework\Utility\NumberUtils;
use Framework\Utility\ProducerUtils;
 
use Framework\Utility\SkinUtils;
use Framework\Utility\StringUtils;
use Globals;
$result = $kafka->send($kafka::TOPIC_CART_ADD_STATISTICS, $kafka->makeData([$cartStatistics], 'cas'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', $result);
}
 
 
 
 
 
 
 
 
 
 
 
// 장바구니 변경 갯수 상품 업데이트
$goods = \App::load(\Component\Goods\Goods::class);
$goods->setCartGoodsCount($arrData['goodsNo']);
 
변경 후Cart.php
use Framework\Utility\ArrayUtils;
use Framework\Utility\NumberUtils;
use Framework\Utility\ProducerUtils;
use Origin\Service\Statistics\Analytics\Cart\CartAddHistoryAnalyticsCollectorService;
use Framework\Utility\SkinUtils;
use Framework\Utility\StringUtils;
use Globals;
$result = $kafka->send($kafka::TOPIC_CART_ADD_STATISTICS, $kafka->makeData([$cartStatistics], 'cas'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', $result);
}
 
// 장바구니 추가 통계 수집 (수기주문 제외)
try {
$cartAddHistoryAnalyticsCollectorService = \App::getInstance(CartAddHistoryAnalyticsCollectorService::class);
if ($cartAddHistoryAnalyticsCollectorService->isCollectableCart($this->isWrite)) {
$cartAddHistoryAnalyticsCollectorService->collectAnalytics($arrData);
}
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analytics 수집 실패', ['exception' => $e, 'errorMessage' => $e->getMessage()]);
}
 
// 장바구니 변경 갯수 상품 업데이트
$goods = \App::load(\Component\Goods\Goods::class);
$goods->setCartGoodsCount($arrData['goodsNo']);
 
Component/Database/DBTableField.php+19
변경 전DBTableField.php
 
return $arrField;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
변경 후DBTableField.php
 
return $arrField;
}
 
/**
* [주문] analyticsOrder 필드 기본값
*
* @return array analyticsOrder 테이블 필드 정보
*/
public static function tableAnalyticsOrder()
{
// @formatter:off
$arrField = [
['val' => 'orderNo', 'typ' => 's', 'def' => null], // 주문번호
['val' => 'clientId', 'typ' => 's', 'def' => null], // 애널리틱스 클라이언트 ID
['val' => 'sessionId', 'typ' => 's', 'def' => null], // 애널리틱스 세션 ID
['val' => 'regDt', 'typ' => 's', 'def' => null], // 등록일
];
// @formatter:on
 
return $arrField;
}
}
 
Component/Order/ExternalOrder.php+12
변경 전ExternalOrder.php
use Session;
use Framework\Utility\ArrayUtils;
use Framework\Utility\StringUtils;
 
 
/**
* 외부채널 주문 관련 class
}
 
unset($arrBind);
 
 
 
 
 
 
 
 
 
 
 
}
 
/*
 
변경 후ExternalOrder.php
use Session;
use Framework\Utility\ArrayUtils;
use Framework\Utility\StringUtils;
use Origin\Service\Statistics\Analytics\Order\AnalyticsOrderService;
 
/**
* 외부채널 주문 관련 class
}
 
unset($arrBind);
 
// 애널리틱스 주문 추적값 저장
try {
if (empty($insertDataOrder['orderNo'])) {
throw new Exception('orderNo가 비어있습니다');
}
$analyticsOrderService = \App::getInstance(AnalyticsOrderService::class);
$analyticsOrderService->saveAnalyticsOrder($insertDataOrder['orderNo']);
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analyticsOrder 저장 실패', ['exception' => $e, 'errorMessage' => $e->getMessage(), 'orderNo' => $insertDataOrder['orderNo']]);
}
}
 
/*
 
Component/Order/OrderAdminNew.php+33-20
변경 전OrderAdminNew.php
use Framework\Utility\StringUtils;
use Globals;
use LogHandler;
use Origin\Enum\Order\OrderSettleKind;
use Origin\Enum\Order\OrderHandleMode;
use Origin\Enum\Order\OrderStatusCode;
use Origin\Enum\Order\OrderStatusGroup;
 
 
use Origin\Service\Statistics\Analytics\Order\OrderCompleteAnalyticsCollectorService;
use Origin\Service\WebHook\OrderWebHookService;
use Repository\Order\OrderDeliveryOriginalRepository;
break;
}
 
// 주문 완료 통계 수집
try {
$isOrderAnalyticsCollectAvailable = false;
$analyticsCheckChangeStatus = substr($changeStatus, 0, 1);
if (in_array($analyticsCheckChangeStatus, ['p', 'o'])) { // 결제완료, 입금대기일때
if ($analyticsCheckChangeStatus === 'o' && in_array($orderData['settleKind'], OrderSettleKind::getVirtualAccountKinds())) { // 입금 대기중인 가상계좌는 수집
$isOrderAnalyticsCollectAvailable = true;
}
 
if ($analyticsCheckChangeStatus === 'p' && !in_array($orderData['settleKind'], OrderSettleKind::getBankAndVirtualAccountKinds())) { // 결제 완료된 무통장/가상계좌는 수집 하지 않음
$isOrderAnalyticsCollectAvailable = true;
}
}
 
if ($isOrderAnalyticsCollectAvailable) {
$orderCompleteStatisticsCollectorService = \App::getInstance(OrderCompleteAnalyticsCollectorService::class);
$orderAnalyticsData = [
'orderNo' => $orderNo,
'order' => $orderData,
];
$orderCompleteStatisticsCollectorService->collectAnalytics($orderAnalyticsData);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
} catch (\Throwable $e) {
\Logger::channel('global')->error(__METHOD__ . ' analytics 수집 실패: ' . $e->getMessage(), [$e->getTraceAsString()]);
}
 
// 고도몰 주문 웹훅 발송
 
변경 후OrderAdminNew.php
use Framework\Utility\StringUtils;
use Globals;
use LogHandler;
 
use Origin\Enum\Order\OrderHandleMode;
use Origin\Enum\Order\OrderStatusCode;
use Origin\Enum\Order\OrderStatusGroup;
use Origin\Enum\Statistics\Analytics\Order\ClaimType;
use Origin\Service\Statistics\Analytics\Order\ClaimCompleteAnalyticsCollectorService;
use Origin\Service\Statistics\Analytics\Order\OrderCompleteAnalyticsCollectorService;
use Origin\Service\WebHook\OrderWebHookService;
use Repository\Order\OrderDeliveryOriginalRepository;
break;
}
 
 
try {
$orderCompleteStatisticsCollectorService = \App::getInstance(OrderCompleteAnalyticsCollectorService::class);
$claimCompleteStatisticsCollectorService = \App::getInstance(ClaimCompleteAnalyticsCollectorService::class);
 
// 결제완료 묶음에 교환추가(z)가 섞이면 통째로 claim, 아니면 일반 결제완료(order_complete)
$exchangeExtraPaymentAmount = $claimCompleteStatisticsCollectorService->getCollectibleExchangeExtraPaymentAmount($changeStatus, $orderNo, $bundleData['sno'] ?? []);
if (!empty($exchangeExtraPaymentAmount)) {
// 교환추가가 섞인 결제완료 → claim_complete 수집 (일반상품 결제금액 + 교환 차액)
$claimCompleteStatisticsCollectorService->collectAnalytics([
'orderNo' => $orderNo,
'claimType' => ClaimType::EXCHANGE,
'claimAmount' => $exchangeExtraPaymentAmount,
]);
} elseif ($orderCompleteStatisticsCollectorService->isOrderCompleteCollectible($changeStatus)) {
$orderCompleteStatisticsCollectorService->collectAnalytics([
 
'orderNo' => $orderNo,
'order' => $orderData,
]);
}
// 결제완료 → 입금대기 되돌림 시점 통계 수집
// 되돌림은 주문 묶음 전체 단위로만 일어나므로(부분 되돌림 없음) 대표로 첫 상품 상태만 확인
$prevStatus = array_values($goodsData)[0]['orderStatus'] ?? '';
$claimAmount = $orderData['settlePrice'] ?? 0;
$mileageClaimAmount = $orderData['useMileage'] ?? 0;
$depositClaimAmount = $orderData['useDeposit'] ?? 0;
if ($claimCompleteStatisticsCollectorService->isReversalToWaitDepositCollectible($changeStatus, $prevStatus, (float)$claimAmount, (float)$mileageClaimAmount, (float)$depositClaimAmount)) {
$claimCompleteStatisticsCollectorService->collectAnalytics([
'orderNo' => $orderNo,
'claimType' => ClaimType::REVERSAL,
'claimAmount' => $claimAmount,
'mileageClaimAmount' => $mileageClaimAmount,
'depositClaimAmount' => $depositClaimAmount,
]);
}
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analytics 수집 실패', ['exception' => $e, 'errorMessage' => $e->getMessage()]);
}
 
// 고도몰 주문 웹훅 발송
 
Component/Order/OrderAdmin.php+33-20
변경 전OrderAdmin.php
use Framework\Utility\StringUtils;
use Globals;
use LogHandler;
use Origin\Enum\Order\OrderSettleKind;
use Origin\Enum\Order\OrderHandleMode;
use Origin\Enum\Order\OrderStatusCode;
use Origin\Enum\Order\OrderStatusGroup;
 
 
use Origin\Service\Statistics\Analytics\Order\OrderCompleteAnalyticsCollectorService;
use Origin\Service\WebHook\OrderWebHookService;
use Repository\Order\OrderDeliveryOriginalRepository;
break;
}
 
// 주문 완료 통계 수집
try {
$isOrderAnalyticsCollectAvailable = false;
$analyticsCheckChangeStatus = substr($changeStatus, 0, 1);
if (in_array($analyticsCheckChangeStatus, ['p', 'o'])) { // 결제완료, 입금대기일때
if ($analyticsCheckChangeStatus === 'o' && in_array($orderData['settleKind'], OrderSettleKind::getVirtualAccountKinds())) { // 입금 대기중인 가상계좌는 수집
$isOrderAnalyticsCollectAvailable = true;
}
 
if ($analyticsCheckChangeStatus === 'p' && !in_array($orderData['settleKind'], OrderSettleKind::getBankAndVirtualAccountKinds())) { // 결제 완료된 무통장/가상계좌는 수집 하지 않음
$isOrderAnalyticsCollectAvailable = true;
}
}
 
if ($isOrderAnalyticsCollectAvailable) {
$orderCompleteStatisticsCollectorService = \App::getInstance(OrderCompleteAnalyticsCollectorService::class);
$orderAnalyticsData = [
'orderNo' => $orderNo,
'order' => $orderData,
];
$orderCompleteStatisticsCollectorService->collectAnalytics($orderAnalyticsData);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
} catch (\Throwable $e) {
\Logger::channel('global')->error(__METHOD__ . ' analytics 수집 실패: ' . $e->getMessage(), [$e->getTraceAsString()]);
}
 
// 고도몰 주문 웹훅 발송
 
변경 후OrderAdmin.php
use Framework\Utility\StringUtils;
use Globals;
use LogHandler;
 
use Origin\Enum\Order\OrderHandleMode;
use Origin\Enum\Order\OrderStatusCode;
use Origin\Enum\Order\OrderStatusGroup;
use Origin\Enum\Statistics\Analytics\Order\ClaimType;
use Origin\Service\Statistics\Analytics\Order\ClaimCompleteAnalyticsCollectorService;
use Origin\Service\Statistics\Analytics\Order\OrderCompleteAnalyticsCollectorService;
use Origin\Service\WebHook\OrderWebHookService;
use Repository\Order\OrderDeliveryOriginalRepository;
break;
}
 
 
try {
$orderCompleteStatisticsCollectorService = \App::getInstance(OrderCompleteAnalyticsCollectorService::class);
$claimCompleteStatisticsCollectorService = \App::getInstance(ClaimCompleteAnalyticsCollectorService::class);
 
// 결제완료 묶음에 교환추가(z)가 섞이면 통째로 claim, 아니면 일반 결제완료(order_complete)
$exchangeExtraPaymentAmount = $claimCompleteStatisticsCollectorService->getCollectibleExchangeExtraPaymentAmount($changeStatus, $orderNo, $bundleData['sno'] ?? []);
if (!empty($exchangeExtraPaymentAmount)) {
// 교환추가가 섞인 결제완료 → claim_complete 수집 (일반상품 결제금액 + 교환 차액)
$claimCompleteStatisticsCollectorService->collectAnalytics([
'orderNo' => $orderNo,
'claimType' => ClaimType::EXCHANGE,
'claimAmount' => $exchangeExtraPaymentAmount,
]);
} elseif ($orderCompleteStatisticsCollectorService->isOrderCompleteCollectible($changeStatus)) {
$orderCompleteStatisticsCollectorService->collectAnalytics([
 
'orderNo' => $orderNo,
'order' => $orderData,
]);
}
// 결제완료 → 입금대기 되돌림 시점 통계 수집
// 되돌림은 주문 묶음 전체 단위로만 일어나므로(부분 되돌림 없음) 대표로 첫 상품 상태만 확인
$prevStatus = array_values($goodsData)[0]['orderStatus'] ?? '';
$claimAmount = $orderData['settlePrice'] ?? 0;
$mileageClaimAmount = $orderData['useMileage'] ?? 0;
$depositClaimAmount = $orderData['useDeposit'] ?? 0;
if ($claimCompleteStatisticsCollectorService->isReversalToWaitDepositCollectible($changeStatus, $prevStatus, (float)$claimAmount, (float)$mileageClaimAmount, (float)$depositClaimAmount)) {
$claimCompleteStatisticsCollectorService->collectAnalytics([
'orderNo' => $orderNo,
'claimType' => ClaimType::REVERSAL,
'claimAmount' => $claimAmount,
'mileageClaimAmount' => $mileageClaimAmount,
'depositClaimAmount' => $depositClaimAmount,
]);
}
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analytics 수집 실패', ['exception' => $e, 'errorMessage' => $e->getMessage()]);
}
 
// 고도몰 주문 웹훅 발송
 
Component/Order/OrderNew.php+15-3
변경 전OrderNew.php
use LogHandler;
use Origin\Constants\WebHookEventType;
use Origin\Service\Order\OrderInfoService;
 
use Origin\Service\Statistics\Analytics\Order\OrderCompleteAnalyticsCollectorService;
use Origin\Service\WebHook\OrderWebHookService;
use Request;
$this->db->set_insert_db(DB_ORDER, $arrBind['param'], $arrBind['bind'], 'y', false);
unset($arrBind);
 
 
 
 
 
 
 
 
 
 
 
 
$this->setPayHistory($history);
 
// 주문 사은품 정보 저장
}
}
 
// 주문 완료 통계 수집
try {
if ($orderInfo['settleKind'] == 'gb' || $orderInfo['settleKind'] == self::SETTLE_KIND_ZERO) {
$orderCompleteStatisticsCollectorService = \App::getInstance(OrderCompleteAnalyticsCollectorService::class);
$orderAnalyticsData = [
'orderNo' => $this->orderNo,
$orderCompleteStatisticsCollectorService->collectAnalytics($orderAnalyticsData);
}
} catch (\Throwable $e) {
\Logger::channel('global')->error(__METHOD__ . ' analytics 수집 실패: ' . $e->getMessage(), [$e->getTraceAsString()]);
}
 
// 주문서 저장 이후, channelType 세션 데이터 제거
 
변경 후OrderNew.php
use LogHandler;
use Origin\Constants\WebHookEventType;
use Origin\Service\Order\OrderInfoService;
use Origin\Service\Statistics\Analytics\Order\AnalyticsOrderService;
use Origin\Service\Statistics\Analytics\Order\OrderCompleteAnalyticsCollectorService;
use Origin\Service\WebHook\OrderWebHookService;
use Request;
$this->db->set_insert_db(DB_ORDER, $arrBind['param'], $arrBind['bind'], 'y', false);
unset($arrBind);
 
// 애널리틱스 주문 추적값 저장
try {
if (empty($this->orderNo)) {
throw new Exception('orderNo가 비어있습니다');
}
$analyticsOrderService = \App::getInstance(AnalyticsOrderService::class);
$analyticsOrderService->saveAnalyticsOrder($this->orderNo);
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analyticsOrder 저장 실패', ['exception' => $e, 'errorMessage' => $e->getMessage(), 'orderNo' => $this->orderNo]);
}
 
$this->setPayHistory($history);
 
// 주문 사은품 정보 저장
}
}
 
// 결제완료 시점 통계 수집
try {
if ($orderInfo['settleKind'] == self::SETTLE_KIND_ZERO) {
$orderCompleteStatisticsCollectorService = \App::getInstance(OrderCompleteAnalyticsCollectorService::class);
$orderAnalyticsData = [
'orderNo' => $this->orderNo,
$orderCompleteStatisticsCollectorService->collectAnalytics($orderAnalyticsData);
}
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analytics 수집 실패', ['exception' => $e, 'errorMessage' => $e->getMessage()]);
}
 
// 주문서 저장 이후, channelType 세션 데이터 제거
 
Component/Order/Order.php+15-3
변경 전Order.php
use LogHandler;
use Origin\Constants\WebHookEventType;
use Origin\Service\Order\OrderInfoService;
 
use Origin\Service\Statistics\Analytics\Order\OrderCompleteAnalyticsCollectorService;
use Origin\Service\WebHook\OrderWebHookService;
use Request;
$this->db->set_insert_db(DB_ORDER, $arrBind['param'], $arrBind['bind'], 'y', false);
unset($arrBind);
 
 
 
 
 
 
 
 
 
 
 
 
// 최초결제 결제히스토리 저장
$history = [
'orderNo' => $this->orderNo,// 주문번호
}
}
 
// 주문 완료 통계 수집
try {
if ($orderInfo['settleKind'] == 'gb' || $orderInfo['settleKind'] == self::SETTLE_KIND_ZERO) {
$orderCompleteStatisticsCollectorService = \App::getInstance(OrderCompleteAnalyticsCollectorService::class);
$orderAnalyticsData = [
'orderNo' => $this->orderNo,
$orderCompleteStatisticsCollectorService->collectAnalytics($orderAnalyticsData);
}
} catch (\Throwable $e) {
\Logger::channel('global')->error(__METHOD__ . ' analytics 수집 실패: ' . $e->getMessage(), [$e->getTraceAsString()]);
}
 
// 페이스북 FBE v2 pixelCookie 값 주문서 저장
 
변경 후Order.php
use LogHandler;
use Origin\Constants\WebHookEventType;
use Origin\Service\Order\OrderInfoService;
use Origin\Service\Statistics\Analytics\Order\AnalyticsOrderService;
use Origin\Service\Statistics\Analytics\Order\OrderCompleteAnalyticsCollectorService;
use Origin\Service\WebHook\OrderWebHookService;
use Request;
$this->db->set_insert_db(DB_ORDER, $arrBind['param'], $arrBind['bind'], 'y', false);
unset($arrBind);
 
// 애널리틱스 주문 추적값 저장
try {
if (empty($this->orderNo)) {
throw new Exception('orderNo가 비어있습니다');
}
$analyticsOrderService = \App::getInstance(AnalyticsOrderService::class);
$analyticsOrderService->saveAnalyticsOrder($this->orderNo);
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analyticsOrder 저장 실패', ['exception' => $e, 'errorMessage' => $e->getMessage(), 'orderNo' => $this->orderNo]);
}
 
// 최초결제 결제히스토리 저장
$history = [
'orderNo' => $this->orderNo,// 주문번호
}
}
 
// 결제완료 시점 통계 수집
try {
if ($orderInfo['settleKind'] == self::SETTLE_KIND_ZERO) {
$orderCompleteStatisticsCollectorService = \App::getInstance(OrderCompleteAnalyticsCollectorService::class);
$orderAnalyticsData = [
'orderNo' => $this->orderNo,
$orderCompleteStatisticsCollectorService->collectAnalytics($orderAnalyticsData);
}
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analytics 수집 실패', ['exception' => $e, 'errorMessage' => $e->getMessage()]);
}
 
// 페이스북 FBE v2 pixelCookie 값 주문서 저장
 
Component/Order/ReOrderCalculation.php+54
변경 전ReOrderCalculation.php
use Globals;
use Origin\Constants\WebHookEventType;
use Origin\Service\WebHook\OrderWebHookService;
 
 
use Session;
use Component\Member\Manager;
use Component\Order\OrderSalesStatistics;
// 바로 위의 updateStatusPreprocess 는 내부에 transaction 이 한번 더 있기 때문에 이 exception 롤백과 무관하게 commit 됨.
throw new Exception(__($returnError));
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
public function setRefundCompleteOrderGoodsNew($getData, $autoProcess, $userHandleFl = false)
// 바로 위의 updateStatusPreprocess 는 내부에 transaction 이 한번 더 있기 때문에 이 exception 롤백과 무관하게 commit 됨.
throw new Exception(__($returnError));
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
/**
$this->orderWebHookService->sendOrderGoodsWebHook($webhookOrderGoodsSnos, $claimStatus, $changeStatus);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
return true;
}
 
 
변경 후ReOrderCalculation.php
use Globals;
use Origin\Constants\WebHookEventType;
use Origin\Service\WebHook\OrderWebHookService;
use Origin\Enum\Statistics\Analytics\Order\ClaimType;
use Origin\Service\Statistics\Analytics\Order\ClaimCompleteAnalyticsCollectorService;
use Session;
use Component\Member\Manager;
use Component\Order\OrderSalesStatistics;
// 바로 위의 updateStatusPreprocess 는 내부에 transaction 이 한번 더 있기 때문에 이 exception 롤백과 무관하게 commit 됨.
throw new Exception(__($returnError));
}
 
// 환불완료 시점 통계 수집
try {
$claimCompleteStatisticsCollectorService = \App::getInstance(ClaimCompleteAnalyticsCollectorService::class);
$claimAmount = $getData['check']['totalRefundPrice'] ?? 0;
$mileageClaimAmount = gd_isset($getData['info']['refundGoodsUseMileage'], 0) + gd_isset($getData['info']['refundDeliveryUseMileage'], 0) - gd_isset($getData['info']['refundUseMileageCommission'], 0);
$depositClaimAmount = gd_isset($getData['info']['refundGoodsUseDeposit'], 0) + gd_isset($getData['info']['refundDeliveryUseDeposit'], 0) - gd_isset($getData['info']['refundUseDepositCommission'], 0);
if ($claimCompleteStatisticsCollectorService->isRefundAmountCollectible((float)$claimAmount, (float)$mileageClaimAmount, (float)$depositClaimAmount)) {
$claimCompleteStatisticsCollectorService->collectAnalytics([
'orderNo' => $getData['orderNo'],
'claimType' => ClaimType::REFUND,
'claimAmount' => $claimAmount,
'mileageClaimAmount' => $mileageClaimAmount,
'depositClaimAmount' => $depositClaimAmount,
]);
}
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analytics 수집 실패', ['exception' => $e, 'errorMessage' => $e->getMessage()]);
}
}
 
public function setRefundCompleteOrderGoodsNew($getData, $autoProcess, $userHandleFl = false)
// 바로 위의 updateStatusPreprocess 는 내부에 transaction 이 한번 더 있기 때문에 이 exception 롤백과 무관하게 commit 됨.
throw new Exception(__($returnError));
}
 
// 환불완료 시점 통계 수집
try {
$claimCompleteStatisticsCollectorService = \App::getInstance(ClaimCompleteAnalyticsCollectorService::class);
$claimAmount = $getData['check']['totalRefundPrice'] ?? 0;
$mileageClaimAmount = gd_isset($getData['info']['refundGoodsUseMileage'], 0) + gd_isset($getData['info']['refundDeliveryUseMileage'], 0) - gd_isset($getData['info']['refundUseMileageCommission'], 0);
$depositClaimAmount = gd_isset($getData['info']['refundGoodsUseDeposit'], 0) + gd_isset($getData['info']['refundDeliveryUseDeposit'], 0) - gd_isset($getData['info']['refundUseDepositCommission'], 0);
if ($claimCompleteStatisticsCollectorService->isRefundAmountCollectible((float)$claimAmount, (float)$mileageClaimAmount, (float)$depositClaimAmount)) {
$claimCompleteStatisticsCollectorService->collectAnalytics([
'orderNo' => $getData['orderNo'],
'claimType' => ClaimType::REFUND,
'claimAmount' => $claimAmount,
'mileageClaimAmount' => $mileageClaimAmount,
'depositClaimAmount' => $depositClaimAmount,
]);
}
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analytics 수집 실패', ['exception' => $e, 'errorMessage' => $e->getMessage()]);
}
}
 
/**
$this->orderWebHookService->sendOrderGoodsWebHook($webhookOrderGoodsSnos, $claimStatus, $changeStatus);
}
 
// 교환접수 시점 통계 수집
try {
$claimCompleteStatisticsCollectorService = \App::getInstance(ClaimCompleteAnalyticsCollectorService::class);
if ($postData['totalChangePrice'] > 0) {
$claimCompleteStatisticsCollectorService->collectAnalytics([
'orderNo' => $postData['orderNo'],
'claimType' => ClaimType::EXCHANGE,
'claimAmount' => $postData['totalChangePrice'],
]);
}
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analytics 수집 실패', ['exception' => $e, 'errorMessage' => $e->getMessage()]);
}
 
return true;
}
 
 
Component/Wish/Wish.php+17
변경 전Wish.php
use Exception;
use App;
use Origin\Service\WebHook\CartWebHookService;
 
 
 
class Wish
{
$result = $kafka->send($kafka::TOPIC_CART_ADD_STATISTICS, $kafka->makeData([$cartStatistics], 'cas'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', $result);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$cartInfo = gd_policy('order.cart');
if($cartInfo['moveWishPageFl'] =='n') {
//장바구니 저장 상품 삭제
 
변경 후Wish.php
use Exception;
use App;
use Origin\Service\WebHook\CartWebHookService;
use Origin\Service\Statistics\Analytics\Cart\CartAddHistoryAnalyticsCollectorService;
use Origin\Repository\Wish\WishRepository;
 
class Wish
{
$result = $kafka->send($kafka::TOPIC_CART_ADD_STATISTICS, $kafka->makeData([$cartStatistics], 'cas'), $kafka::MODE_RESULT_CALLLBACK, true);
\Logger::channel('kafka')->info('process sendMQ - return :', $result);
 
// 장바구니 추가 통계 수집
try {
// 다중 insert 시 insert_id는 첫 sno만 반환 → insert된 cart 특정 불가, 원본 위시(es_wish) 조회
$wishRepository = \App::getInstance(WishRepository::class);
$wishGoodsList = $wishRepository->findGoodsByWishSnosAndMemNo($sno, (int)Session::get('member.memNo'));
if (!empty($wishGoodsList)) {
$cartAddHistoryAnalyticsCollectorService = \App::getInstance(CartAddHistoryAnalyticsCollectorService::class);
foreach ($wishGoodsList as $wishGoods) {
$cartAddHistoryAnalyticsCollectorService->collectAnalytics($wishGoods);
}
}
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analytics 수집 실패', ['exception' => $e, 'errorMessage' => $e->getMessage()]);
}
 
$cartInfo = gd_policy('order.cart');
if($cartInfo['moveWishPageFl'] =='n') {
//장바구니 저장 상품 삭제
 
Controller/Front/Member/MemberPsController.php+2-2
변경 전MemberPsController.php
$memberStatisticsCollectorService = \App::getInstance(MemberJoinCompleteAnalyticsCollectorService::class);
$memberStatisticsCollectorService->collectAnalytics($memberVO->toArray());
} catch (\Throwable $e) {
\Logger::channel('global')->error(__METHOD__ . ' analytics 수집 실패: ' . $e->getMessage(), [$e->getTraceAsString()]);
}
 
// 평생회원 이벤트
$memberStatisticsCollectorService = \App::getInstance(MemberJoinCompleteAnalyticsCollectorService::class);
$memberStatisticsCollectorService->collectAnalytics($memberVO->toArray());
} catch (\Throwable $e) {
\Logger::channel('global')->error(__METHOD__ . ' analytics 수집 실패: ' . $e->getMessage(), [$e->getTraceAsString()]);
}
 
$memNo = $memberVO->getMemNo();
 
변경 후MemberPsController.php
$memberStatisticsCollectorService = \App::getInstance(MemberJoinCompleteAnalyticsCollectorService::class);
$memberStatisticsCollectorService->collectAnalytics($memberVO->toArray());
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analytics 수집 실패', ['exception' => $e, 'errorMessage' => $e->getMessage()]);
}
 
// 평생회원 이벤트
$memberStatisticsCollectorService = \App::getInstance(MemberJoinCompleteAnalyticsCollectorService::class);
$memberStatisticsCollectorService->collectAnalytics($memberVO->toArray());
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analytics 수집 실패', ['exception' => $e, 'errorMessage' => $e->getMessage()]);
}
 
$memNo = $memberVO->getMemNo();
 
Controller/Mobile/Member/MemberPsController.php+2-2
변경 전MemberPsController.php
$memberStatisticsCollectorService = \App::getInstance(MemberJoinCompleteAnalyticsCollectorService::class);
$memberStatisticsCollectorService->collectAnalytics($memberVO->toArray());
} catch (\Throwable $e) {
\Logger::channel('global')->error(__METHOD__ . ' analytics 수집 실패: ' . $e->getMessage(), [$e->getTraceAsString()]);
}
 
// request가 ajax일 때 (카카오 싱크)
$memberStatisticsCollectorService = \App::getInstance(MemberJoinCompleteAnalyticsCollectorService::class);
$memberStatisticsCollectorService->collectAnalytics($memberVO->toArray());
} catch (\Throwable $e) {
\Logger::channel('global')->error(__METHOD__ . ' analytics 수집 실패: ' . $e->getMessage(), [$e->getTraceAsString()]);
}
 
$memNo = $memberVO->getMemNo();
 
변경 후MemberPsController.php
$memberStatisticsCollectorService = \App::getInstance(MemberJoinCompleteAnalyticsCollectorService::class);
$memberStatisticsCollectorService->collectAnalytics($memberVO->toArray());
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analytics 수집 실패', ['exception' => $e, 'errorMessage' => $e->getMessage()]);
}
 
// request가 ajax일 때 (카카오 싱크)
$memberStatisticsCollectorService = \App::getInstance(MemberJoinCompleteAnalyticsCollectorService::class);
$memberStatisticsCollectorService->collectAnalytics($memberVO->toArray());
} catch (\Throwable $e) {
\Logger::channel('analytics')->warning('analytics 수집 실패', ['exception' => $e, 'errorMessage' => $e->getMessage()]);
}
 
$memNo = $memberVO->getMemNo();
 
개인정보 수집 및 이용 동의 템플릿 개정
Admin/member/excel_member_up.php+3
변경 전excel_member_up.php
<div class="notice-info">
엑셀업로드 전 회원가입 시 발송 가능한 항목(회원가입, 마일리지 지급, 회원가입 축하 쿠폰)의 발송설정을 확인해주시기 바랍니다. <a href="/member/sms_auto.php" target="_blank" class="btn-link">SMS설정&gt;</a>&nbsp;&nbsp;<a href="/member/mail_config_auto.php" target="_blank" class="btn-link">자동 메일 설정&gt;</a>
</div>
 
 
 
</td>
</tr>
</table>
 
변경 후excel_member_up.php
<div class="notice-info">
엑셀업로드 전 회원가입 시 발송 가능한 항목(회원가입, 마일리지 지급, 회원가입 축하 쿠폰)의 발송설정을 확인해주시기 바랍니다. <a href="/member/sms_auto.php" target="_blank" class="btn-link">SMS설정&gt;</a>&nbsp;&nbsp;<a href="/member/mail_config_auto.php" target="_blank" class="btn-link">자동 메일 설정&gt;</a>
</div>
<div class="notice-info">
마케팅 목적 개인정보 수집 및 이용 항목 업로드 시 반드시 고객으로부터 받은 별도의 개인정보 수집·이용 동의서를 보유하고 계셔야 하며, NHN COMMERCE는 수탁사로서 업로드되는 데이터에 대한 책임을 지지 않습니다.
</div>
</td>
</tr>
</table>
 
Admin/member/member_detail_search.php+21-1
변경 전member_detail_search.php
</td>
</tr>
<tr>
<th>SMS수신동의</th>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<td>
<label class="radio-inline">
<input type="radio" name="smsFl"
 
변경 후member_detail_search.php
</td>
</tr>
<tr>
<th>마케팅 목적 개인정보 수집 및 이용 동의</th>
<td colspan="3">
<label class="radio-inline">
<input type="radio" name="privateMarketingConsentOptionFl"
value="" <?= gd_isset($checked['privateMarketingConsentOptionFl']['']); ?>/>
전체
</label>
<label class="radio-inline">
<input type="radio" name="privateMarketingConsentOptionFl"
value="y" <?= gd_isset($checked['privateMarketingConsentOptionFl']['y']); ?>/>
동의
</label>
<label class="radio-inline">
<input type="radio" name="privateMarketingConsentOptionFl"
value="n" <?= gd_isset($checked['privateMarketingConsentOptionFl']['n']); ?>/>
미동의
</label>
</td>
</tr>
<tr>
<th>모바일 메시지 수신동의</th>
<td>
<label class="radio-inline">
<input type="radio" name="smsFl"
 
Admin/member/member_joinitem.php+2-34
변경 전member_joinitem.php
</tr>
<tr>
<th>이메일</th>
<td>
<?php if ($mall['mallSno'] == 1) { ?>
<label class="checkbox-inline" title="사용여부를 선택해주세요!">
<input type="checkbox" name="email[use]" value="y"/>
<input type="hidden" name="email[require]" value="y"/>
<?php } ?>
</td>
<td>
<label class="checkbox-inline" for="maillingFl">
<input type="checkbox" id="maillingFl" name="maillingFl[use]" value="y">
정보/이벤트 메일 수신 동의 사용
</label>
</td>
</tr>
<tr>
<th>휴대폰번호</th>
<td <?= $mall['mallSno'] == 1 ? '' : 'colspan=2' ?>>
<label class="checkbox-inline" title="사용여부를 선택해주세요!">
<input type="checkbox" name="cellPhone[use]" value="y"/>
사용
필수
</label>
</td>
<?php if ($mall['mallSno'] == 1) { ?>
<td>
<label class="checkbox-inline" for="smsFl">
<input type="checkbox" id="smsFl" name="smsFl[use]" value="y">
정보/이벤트 SMS 수신 동의 사용
</label>
</td>
<?php } ?>
</tr>
<?php if ($mall['mallSno'] == 1) { ?>
<tr>
}
});
 
$(':checkbox[name="maillingFl[use]"], :checkbox[name="smsFl[use]"]', '#frmSetup').on('change', function (e) {
var $target = $(e.target);
if ($target.prop('checked') === false) {
BootstrapDialog.confirm({
title: "정보/이벤트 메일(SMS)수신 동의 사용 체크 해제",
message: "정보통신망법에 따라 수신동의한 회원에게만 정보/이벤트 소식을 전송할 수 있습니다. 수신동의 사용을 해제하시겠습니까?",
btnCancelLabel: "취소",
btnOkLabel: "해제",
callback: function (result) {
if (result) {
$target.prop('checked', false);
} else {
$target.prop('checked', true);
}
}
});
}
});
$('.expiration_detail').on('click', function () {
var msg = "휴면회원 정책에서 휴면회원 ‘사용함’으로 설정할 경우, 일정 기간 동안 쇼핑몰을 이용하지 않는 회원은 휴면회원으로 전환되어 쇼핑몰의 이용이 제한되고, 쇼핑몰 운영자는 회원에게 정보/이벤트성 안내를 할 수 없습니다."+'<br>'+"-&nbsp;&nbsp;&nbsp;회원가입 항목에서 개인 정보 유효기간 미사용 시 1년간 쇼핑몰을 이용하지 않는 회원들을 "+'<br>'+"&nbsp;&nbsp;&nbsp;&nbsp;휴면회원으로 일괄 전환합니다."+'<br>'+"-&nbsp;&nbsp;&nbsp;개인 정보 유효기간 사용 시 회원에게 ‘휴면회원 방지기간’ 정보를 수집할 수 있으며, 각 회원이 "+'<br>'+"&nbsp;&nbsp;&nbsp;&nbsp;“1년(기본값)/3년/5년/탈퇴 시” 중 선택한 기간 동안 쇼핑몰을 이용하지 않는 경우 해당 회원의"+'<br>'+"&nbsp;&nbsp;&nbsp;&nbsp;정보를 휴면회원으로 전환합니다."+'<br><div><img src="../admin/gd_share/img/expirationFl_img.png" style="width:80%; height:100%; margin-top:20px; margin-left:50px;"></div>' +
'<br>'+"휴면회원 정책에서 휴면회원 ‘사용 안함’으로 설정할 경우, 각 회원별로 개인정보 유효기간이 만료되더라도 휴면회원으로 전환되지 않으며 계속 쇼핑몰을 이용할 수 있습니다."+'<br>';
 
변경 후member_joinitem.php
</tr>
<tr>
<th>이메일</th>
<td colspan="2">
<?php if ($mall['mallSno'] == 1) { ?>
<label class="checkbox-inline" title="사용여부를 선택해주세요!">
<input type="checkbox" name="email[use]" value="y"/>
<input type="hidden" name="email[require]" value="y"/>
<?php } ?>
</td>
 
 
 
 
 
 
</tr>
<tr>
<th>휴대폰번호</th>
<td colspan="2">
<label class="checkbox-inline" title="사용여부를 선택해주세요!">
<input type="checkbox" name="cellPhone[use]" value="y"/>
사용
필수
</label>
</td>
 
 
 
 
 
 
 
 
</tr>
<?php if ($mall['mallSno'] == 1) { ?>
<tr>
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$('.expiration_detail').on('click', function () {
var msg = "휴면회원 정책에서 휴면회원 ‘사용함’으로 설정할 경우, 일정 기간 동안 쇼핑몰을 이용하지 않는 회원은 휴면회원으로 전환되어 쇼핑몰의 이용이 제한되고, 쇼핑몰 운영자는 회원에게 정보/이벤트성 안내를 할 수 없습니다."+'<br>'+"-&nbsp;&nbsp;&nbsp;회원가입 항목에서 개인 정보 유효기간 미사용 시 1년간 쇼핑몰을 이용하지 않는 회원들을 "+'<br>'+"&nbsp;&nbsp;&nbsp;&nbsp;휴면회원으로 일괄 전환합니다."+'<br>'+"-&nbsp;&nbsp;&nbsp;개인 정보 유효기간 사용 시 회원에게 ‘휴면회원 방지기간’ 정보를 수집할 수 있으며, 각 회원이 "+'<br>'+"&nbsp;&nbsp;&nbsp;&nbsp;“1년(기본값)/3년/5년/탈퇴 시” 중 선택한 기간 동안 쇼핑몰을 이용하지 않는 경우 해당 회원의"+'<br>'+"&nbsp;&nbsp;&nbsp;&nbsp;정보를 휴면회원으로 전환합니다."+'<br><div><img src="../admin/gd_share/img/expirationFl_img.png" style="width:80%; height:100%; margin-top:20px; margin-left:50px;"></div>' +
'<br>'+"휴면회원 정책에서 휴면회원 ‘사용 안함’으로 설정할 경우, 각 회원별로 개인정보 유효기간이 만료되더라도 휴면회원으로 전환되지 않으며 계속 쇼핑몰을 이용할 수 있습니다."+'<br>';
 
Admin/member/_member_view_other.php+3-50
변경 전_member_view_other.php
<col class="width-sm"/>
<col/>
</colgroup>
 
<tr>
<th>개인정보<br/>수집&middot;이용</th>
<td>
<?php
if (isset($data['privateApprovalOptionFl']) && is_array($data['privateApprovalOptionFl']) && isset($privateApprovalOption)) {
foreach ($privateApprovalOption as $index2 => $item2) {
if($data['privateApprovalOptionFl'][$item2['sno']] == 'y'){
echo '<div>- ' . $item2['informNm'] . ' : 동의함</div>';
} elseif ($data['privateApprovalOptionFl'][$item2['sno']] == 'n') {
echo '<div>- ' . $item2['informNm'] . ' : 동의안함</div>';
}
}
} else {
echo '사용안함';
}
?>
</td>
</tr>
<tr>
<th>개인정보 취급위탁</th>
<td>
<?php
if (isset($data['privateConsignFl']) && is_array($data['privateConsignFl']) && isset($privateConsign)) {
foreach ($privateConsign as $index2 => $item2) {
if($data['privateConsignFl'][$item2['sno']] == 'y'){
echo '<div>- ' . $item2['informNm'] . ' : 동의함</div>';
} elseif ($data['privateConsignFl'][$item2['sno']] == 'n') {
echo '<div>- ' . $item2['informNm'] . ' : 동의안함</div>';
}
}
} else {
echo '사용안함';
}
?>
</td>
</tr>
<tr>
<th>개인정보<br/>제3자 제공</th>
<td>
<?php
if (isset($data['privateOfferFl']) && is_array($data['privateOfferFl']) && isset($privateOffer)) {
foreach ($privateOffer as $index2 => $item2) {
if($data['privateOfferFl'][$item2['sno']] == 'y'){
echo '<div>- ' . $item2['informNm'] . ' : 동의함</div>';
} elseif ($data['privateOfferFl'][$item2['sno']] == 'n') {
echo '<div>- ' . $item2['informNm'] . ' : 동의안함</div>';
}
}
} else {
echo '사용안함';
}
?>
</td>
</tr>
</table>
 
변경 후_member_view_other.php
<col class="width-sm"/>
<col/>
</colgroup>
<?= $privateAgreementHtml ?? '' ?>
<tr>
<th>광고성 수신 동의</th>
<td>
<?= $advertisingReceiveHtml ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</td>
</tr>
</table>
 
Admin/member/_member_view.php+21-6
변경 전_member_view.php
<td colspan="3"><?= $data['sleepWakeDt']; ?></td>
</tr>
<?php } ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<tr>
<th>이메일</th>
<td>
</div>
<div class="form-inline">
<label class="checkbox-inline">
<input type="checkbox" name="maillingFl" value="y" data-default="" <?= $checked['maillingFl']['y']; ?>/>
정보/이벤트 MAIL 수신에 동의합니다.
</label>
</div>
<p class="notice-danger notice-info">*수신동의설정 안내메일의 자동발송여부에 따라 회원정보의 수신동의설정 변경 시 해당 회원에게 안내메일이 자동 발송됩니다.</p>
$mailAgreementView .= '<br/>(수신동의여부 확인메일 발송<br/> : ' . $data['lastNotificationDt']['mail'] . ')';
}
?>
<?= $data['maillingFl'] == 'y' ? $mailAgreementView : '거부 : ' . gd_date_format('Y-m-d', $mailLastReceiveAgreementDt); ?>
</td>
</tr>
<tr>
<div class="form-inline">
<span id="cellPhoneMsg" class="input_error_msg"></span>
<label class="checkbox-inline">
<input type="checkbox" name="smsFl" value="y" <?= $checked['smsFl']['y']; ?>>
정보/이벤트 SMS 수신에 동의합니다.
</label>
</div>
<p class="notice-danger notice-info">*수신동의설정 안내메일의 자동발송여부에 따라 회원정보의 수신동의설정 변경 시 해당 회원에게 SMS가 자동 발송됩니다.</p>
$smsAgreementView .= '<br/>(수신동의여부 확인SMS 발송<br/> : ' . $data['lastNotificationDt']['sms'] . ')';
}
?>
<?= $data['smsFl'] == 'y' ? $smsAgreementView : '거부 : ' . gd_date_format('Y-m-d', $smsLastReceiveAgreementDt); ?>
</td>
</tr>
<tr>
 
변경 후_member_view.php
<td colspan="3"><?= $data['sleepWakeDt']; ?></td>
</tr>
<?php } ?>
<?php if ($privateMarketingMemberUse): ?>
<tr>
<th>마케팅 목적 개인정보 수집 및 이용 동의</th>
<td>
<label class="checkbox-inline">
<input type="checkbox" name="privateMarketingConsentOptionFl" value="y" <?= ($mode === 'register') ? 'disabled' : '' ?> <?= $checked['privateMarketingConsentOptionFl']['y']; ?>/>
마케팅 목적 개인정보 수집 및 이용 동의
</label>
</td>
<th>마케팅 목적 개인정보 수집 및 이용 동의/거부일</th>
<td>
<?= ($data['privateMarketingConsentOptionFl'] === 'y' ? '동의 : ' : '거부 : ') . $data['privateMktAgreementDt'] ?>
</td>
</tr>
<?php endif; ?>
<tr>
<th>이메일</th>
<td>
</div>
<div class="form-inline">
<label class="checkbox-inline">
<input type="checkbox" name="maillingFl" <?= ($mode === 'register') ? 'disabled' : '' ?> value="y" data-default="" <?= $checked['maillingFl']['y']; ?>/>
마케팅 이메일 수신 동의
</label>
</div>
<p class="notice-danger notice-info">*수신동의설정 안내메일의 자동발송여부에 따라 회원정보의 수신동의설정 변경 시 해당 회원에게 안내메일이 자동 발송됩니다.</p>
$mailAgreementView .= '<br/>(수신동의여부 확인메일 발송<br/> : ' . $data['lastNotificationDt']['mail'] . ')';
}
?>
<?= $data['maillingFl'] == 'y' ? $mailAgreementView : '거부 : ' . $mailLastReceiveAgreementDt; ?>
</td>
</tr>
<tr>
<div class="form-inline">
<span id="cellPhoneMsg" class="input_error_msg"></span>
<label class="checkbox-inline">
<input type="checkbox" <?= ($mode === 'register') ? 'disabled' : '' ?> name="smsFl" value="y" <?= $checked['smsFl']['y']; ?>>
마케팅 모바일 메시지 수신 동의
</label>
</div>
<p class="notice-danger notice-info">*수신동의설정 안내메일의 자동발송여부에 따라 회원정보의 수신동의설정 변경 시 해당 회원에게 SMS가 자동 발송됩니다.</p>
$smsAgreementView .= '<br/>(수신동의여부 확인SMS 발송<br/> : ' . $data['lastNotificationDt']['sms'] . ')';
}
?>
<?= $data['smsFl'] == 'y' ? $smsAgreementView : '거부 : ' . $smsLastReceiveAgreementDt; ?>
</td>
</tr>
<tr>
 
Admin/policy/base_agreement_with_private.php+98
변경 전base_agreement_with_private.php
<?= $privateApprovalTableOption ?>
<?= $privateConsignTable ?>
<?= $privateOfferTable ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<div class="table-title gd-help-manual mgt10">
비회원 대상 동의항목 설정
</div>
$(document).ready(function () {
var $formSetup = $('#formSetup');
 
 
 
 
 
 
 
 
 
 
$.validator.addMethod("year", function (value) {
var valid = moment(value, 'YYYY', true).isValid();
var checked = $('#agreementModeFlY').prop('checked');
 
변경 후base_agreement_with_private.php
<?= $privateApprovalTableOption ?>
<?= $privateConsignTable ?>
<?= $privateOfferTable ?>
<?php if (!empty($privateMarketingMember)): ?>
<table class="table table-cols">
<caption>
[선택] 마케팅 목적 개인정보 수집 및 이용 동의
</caption>
<colgroup>
<col class="width-md"/>
<col/>
</colgroup>
<tbody>
<tr>
<th>사용여부</th>
<td>
<label class="radio-inline" for="privateMarketingMemberFlY">
<input id="privateMarketingMemberFlY" type="radio" name="privateMarketingMemberFl" value="y" <?= $privateMarketingMember['modeFl'] == 'y' ? 'checked=checked' : ''; ?> />
사용
</label>
<label class="radio-inline" for="privateMarketingMemberFlN">
<input id="privateMarketingMemberFlN" type="radio" name="privateMarketingMemberFl" value="n" <?= $privateMarketingMember['modeFl'] != 'y' ? 'checked=checked' : ''; ?> />
사용하지 않음
</label>
<p class="notice notice-info js-marketing-use-notice">광고성 메시지를 보내려면 아래에 있는 [선택] 광고성 수신 동의 약관도 반드시 함께 사용해야 합니다.</p>
</td>
</tr>
<tr>
<th>안내 팝업 노출 여부</th>
<td>
<label class="radio-inline" for="privateMarketingMemberNoticePopupFlY">
<input id="privateMarketingMemberNoticePopupFlY" type="radio" name="privateMarketingMemberNoticePopupFl" value="y" <?= $privateMarketingMember['noticePopupFl'] == 'y' ? 'checked=checked' : ''; ?> />
사용
</label>
<label class="radio-inline" for="privateMarketingMemberNoticePopupFlN">
<input id="privateMarketingMemberNoticePopupFlN" type="radio" name="privateMarketingMemberNoticePopupFl" value="n" <?= $privateMarketingMember['noticePopupFl'] != 'y' ? 'checked=checked' : ''; ?> />
사용하지 않음
</label>
<p class="notice notice-info">안내 팝업 노출 여부를 ‘사용’으로 설정 시, 마케팅 목적의 개인정보 수집 및 이용 동의 이력이 없는 회원이 로그인 시 최초 1회에 한하여 팝업 안내가 출력됩니다.</p>
</td>
</tr>
<tr>
<th>내용입력</th>
<td>
<input type="text" class="form-control" id="privateMarketingMemberWriteTitle" name="privateMarketingMemberWriteTitle" value="<?= gd_htmlspecialchars($privateMarketingMember['informNm']) ?>">
<textarea id="privateMarketingMemberWriteWrite" name="privateMarketingMemberWriteWrite" rows="12" class="form-control mgt5"><?= gd_htmlspecialchars($privateMarketingMember['content']) ?></textarea>
</td>
</tr>
</tbody>
</table>
<?php endif; ?>
<?php if (!empty($advertisingReceive)): ?>
<table class="table table-cols">
<caption>
[선택] 광고성 수신 동의
</caption>
<colgroup>
<col class="width-md"/>
<col/>
</colgroup>
<tbody>
<tr>
<th>사용여부</th>
<td>
<label class="checkbox-inline" for="advertisingReceiveMailFl">
<input id="advertisingReceiveMailFl" type="checkbox" name="advertisingReceiveMailFl" value="y" <?= $advertisingReceiveMailUse == 'y' ? 'checked="checked"' : '' ?> <?= $joinItemEmailUse == 'y' ? '' : 'disabled="disabled"' ?> />
이메일 수신 동의
</label>
<label class="checkbox-inline" for="advertisingReceiveSmsFl">
<input id="advertisingReceiveSmsFl" type="checkbox" name="advertisingReceiveSmsFl" value="y" <?= $advertisingReceiveSmsUse == 'y' ? 'checked="checked"' : '' ?> <?= $joinItemCellPhoneUse == 'y' ? '' : 'disabled="disabled"' ?> />
모바일 메시지 수신 동의
</label>
<?php if ($joinItemEmailUse != 'y' || $joinItemCellPhoneUse != 'y'): ?>
<p class="notice notice-info">광고성 수신 동의는 회원가입 항목에서 이메일/휴대폰번호를 사용 중일 때만 설정 가능합니다.</p>
<?php endif; ?>
<p class="mgt5">
이메일 : <?php if ($joinItemEmailUse == 'y'): ?>사용
<?php else: ?>사용 안 함 <a href="../member/member_joinitem.php" class="btn-link-underline" target="_blank">설정 바로가기></a><?php endif; ?><br/>
휴대폰번호 : <?php if ($joinItemCellPhoneUse == 'y'): ?>사용<?php else: ?>사용 안 함 <a href="../member/member_joinitem.php" class="btn-link-underline" target="_blank">설정 바로가기></a><?php endif; ?>
</p>
</td>
</tr>
<tr>
<th>내용입력</th>
<td>
<input type="text" class="form-control" id="advertisingReceiveWriteTitle" name="advertisingReceiveWriteTitle" value="<?= gd_htmlspecialchars($advertisingReceive['informNm']) ?>">
<textarea id="advertisingReceiveWriteWrite" name="advertisingReceiveWriteWrite" rows="12" class="form-control mgt5"><?= gd_htmlspecialchars($advertisingReceive['content']) ?></textarea>
</td>
</tr>
</tbody>
</table>
<?php endif; ?>
<div class="table-title gd-help-manual mgt10">
비회원 대상 동의항목 설정
</div>
$(document).ready(function () {
var $formSetup = $('#formSetup');
 
// 안내 팝업 노출 여부 비활성화 + 광고성 수신 동의 관련 안내 문구 숨김
const toggleMarketingNoticePopup = function () {
const isUse = $('input[name=privateMarketingMemberFl]:checked').val() === 'y';
$('input[name=privateMarketingMemberNoticePopupFl]').prop('disabled', !isUse);
$('.js-marketing-use-notice').toggle(isUse);
};
$formSetup.on('change', 'input[name=privateMarketingMemberFl]', toggleMarketingNoticePopup);
toggleMarketingNoticePopup();
 
$.validator.addMethod("year", function (value) {
var valid = moment(value, 'YYYY', true).isValid();
var checked = $('#agreementModeFlY').prop('checked');
 
Component/Agreement/BuyerInformCode.php+37
변경 전BuyerInformCode.php
const PRIVATE_PROVIDER = '001010';
/** 마케팅 활용을 위한 개인정보 수집 · 이용 동의 (비회원 주문 시) */
const PRIVATE_MARKETING = '001011';
 
 
 
 
 
 
 
/** 이용안내 */
const BASE_GUIDE = '006001';
/** 탈퇴안내 */
case self::PRIVATE_MARKETING:
$this->initPrivateMarketing();
break;
 
 
 
 
 
 
}
}
 
$this->_groupCd = '001';
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 멤버 변수를 배열로 반환하는 함수
*
 
변경 후BuyerInformCode.php
const PRIVATE_PROVIDER = '001010';
/** 마케팅 활용을 위한 개인정보 수집 · 이용 동의 (비회원 주문 시) */
const PRIVATE_MARKETING = '001011';
 
/** 마케팅 목적 개인정보 수집 및 이용 동의 */
const PRIVATE_MARKETING_MEMBER = '001015';
 
/** 광고성 수신 동의 */
const ADVERTISING_RECEIVE = '001016';
 
/** 이용안내 */
const BASE_GUIDE = '006001';
/** 탈퇴안내 */
case self::PRIVATE_MARKETING:
$this->initPrivateMarketing();
break;
case self::PRIVATE_MARKETING_MEMBER:
$this->initPrivateMarketingMember();
break;
case self::ADVERTISING_RECEIVE:
$this->initAdvertisingReceive();
break;
}
}
 
$this->_groupCd = '001';
}
 
/**
* 멤버 변수에 마케팅 목적 개인정보 수집 및 이용 동의 관련 데이터베이스 조회 데이터 설정
*
* @return void
*/
public function initPrivateMarketingMember()
{
$this->_informCd = self::PRIVATE_MARKETING_MEMBER;
$this->_informNm = __('마케팅 목적 개인정보 수집 및 이용 동의');
$this->_groupCd = '001';
}
 
/**
* 멤버 변수에 광고성 수신 동의 관련 데이터베이스 조회 데이터 설정
*
* @return void
*/
public function initAdvertisingReceive()
{
$this->_informCd = self::ADVERTISING_RECEIVE;
$this->_informNm = __('광고성 수신 동의');
$this->_groupCd = '001';
}
 
/**
* 멤버 변수를 배열로 반환하는 함수
*
 
Component/Agreement/BuyerInform.php+104
변경 전BuyerInform.php
return $inform;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 사용자 정의 이용약관 데이터 반환 함수
*
if (empty($vo->getInformNm())) {
$excludeField .= ',informNm';
}
 
 
 
 
 
// 테이블명 반환
$tableName = $this->mall->getTableName(DB_BUYER_INFORM, $this->saveMallSno);
$this->db->set_insert_db($tableName, $arrBind['param'], $arrBind['bind'], 'y');
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 기본정책 약관, 개인정보관련 동의사항, 이용, 탈퇴 안내 저장 함수
*
$vo->setModeFl(gd_isset($postValue['privateMarketingFl'], 'n'));
}
 
 
 
 
 
 
 
 
 
 
 
 
 
$strSQL = "SELECT sno, displayShopFl FROM " . $tableName . " WHERE informCd='" . $code . "'";
if ($mallSno > DEFAULT_MALL_NUMBER) {
$strSQL .= " AND mallSno='" . $mallSno . "'";
 
변경 후BuyerInform.php
return $inform;
}
 
/**
* 광고성 수신 동의 정보 반환 - 단일 배열 (상점명 치환코드 {rc_mallNm} 적용)
*
* @param int $mallSno
*
* @return array
* @throws Exception
*/
public function getAdvertisingReceiveContentWithReplaceCode(int $mallSno = DEFAULT_MALL_NUMBER): array
{
/** @var \Bundle\Component\Design\ReplaceCode $replaceCode */
$replaceCode = App::load('\\Component\\Design\\ReplaceCode');
$replaceCode->initWithUnsetDiff(
[
'{rc_mallNm}',
]
);
$mallInfo = array_map(function ($value) {
return $value['val'];
}, $replaceCode->getDefinedCode());
 
$inform = $this->getInformData(BuyerInformCode::ADVERTISING_RECEIVE, $mallSno);
if (!empty($inform['content'])) {
$inform['content'] = str_replace(array_keys($mallInfo), array_values($mallInfo), $inform['content']);
}
 
return $inform;
}
 
/**
* 사용자 정의 이용약관 데이터 반환 함수
*
if (empty($vo->getInformNm())) {
$excludeField .= ',informNm';
}
// [선택] 마케팅 목적 개인정보 수집 및 이용 동의 / 광고성 수신 동의는 본문을 공백으로 저장하면 기존 내용 유지
if (in_array($vo->getInformCd(), [BuyerInformCode::PRIVATE_MARKETING_MEMBER, BuyerInformCode::ADVERTISING_RECEIVE], true) && empty($vo->getContent())) {
$excludeField .= ',content';
}
 
// 테이블명 반환
$tableName = $this->mall->getTableName(DB_BUYER_INFORM, $this->saveMallSno);
$this->db->set_insert_db($tableName, $arrBind['param'], $arrBind['bind'], 'y');
}
 
/**
* 광고성 수신 동의 채널(이메일/모바일) 저장값 확정.
* 가입항목(joinitem) 미사용 채널은 체크박스가 disabled 로 출력되어 POST 에 실리지 않으므로 이전 es_config 값을 보존한다.
* es_config(member.advertisingReceive) 저장과 es_buyerInform modeFl 파생이 동일 결과를 쓰도록 단일화한다.
*
* @param array $post 저장 요청 POST 배열 (advertisingReceiveMailFl / advertisingReceiveSmsFl 포함 가능)
* @param int $mallSno
*
* @return array ['email' => ['use' => 'y'|'n'], 'mobile' => ['use' => 'y'|'n']]
*/
public function resolveAdvertisingReceiveChannels(array $post, int $mallSno = DEFAULT_MALL_NUMBER): array
{
$joinItem = gd_policy('member.joinitem', $mallSno);
$prevAdvertisingReceive = gd_policy('member.advertisingReceive', $mallSno);
 
return [
'email' => ['use' => ($joinItem['email']['use'] ?? 'n') === 'y'
? gd_isset($post['advertisingReceiveMailFl'], 'n')
: ($prevAdvertisingReceive['email']['use'] ?? 'n')],
'mobile' => ['use' => ($joinItem['cellPhone']['use'] ?? 'n') === 'y'
? gd_isset($post['advertisingReceiveSmsFl'], 'n')
: ($prevAdvertisingReceive['mobile']['use'] ?? 'n')],
];
}
 
/**
* 광고성 수신 동의 채널(이메일/모바일)의 프론트 노출 여부.
* 노출 조건 = 가입항목(joinitem) 사용 AND 광고성 수신 동의(es_config) 사용. (가입항목 선검사 강제 → 호출부 누락 방지)
*
* @param int $mallSno
*
* @return array ['mail' => 'y'|'n', 'sms' => 'y'|'n']
*/
public function getAdvertisingReceiveChannelUse(int $mallSno = DEFAULT_MALL_NUMBER): array
{
$joinItem = gd_policy('member.joinitem', $mallSno);
$advertisingReceive = gd_policy('member.advertisingReceive', $mallSno);
 
return [
'mail' => (($joinItem['email']['use'] ?? 'n') === 'y' && ($advertisingReceive['email']['use'] ?? 'n') === 'y') ? 'y' : 'n',
'sms' => (($joinItem['cellPhone']['use'] ?? 'n') === 'y' && ($advertisingReceive['mobile']['use'] ?? 'n') === 'y') ? 'y' : 'n',
];
}
 
/**
* 광고성 수신 동의 사용 여부. 채널(이메일/모바일) 중 하나라도 노출 가능하면 사용(true), 둘 다 미사용이면 false.
* es_buyerInform modeFl 대신 이 값을 프론트 노출/사용 판정 기준으로 쓴다.
*
* @param int $mallSno
*
* @return bool
*/
public function isUseAdvertisingReceive(int $mallSno = DEFAULT_MALL_NUMBER): bool
{
$channelUse = $this->getAdvertisingReceiveChannelUse($mallSno);
 
return $channelUse['mail'] === 'y' || $channelUse['sms'] === 'y';
}
 
/**
* 기본정책 약관, 개인정보관련 동의사항, 이용, 탈퇴 안내 저장 함수
*
$vo->setModeFl(gd_isset($postValue['privateMarketingFl'], 'n'));
}
 
if ($code == BuyerInformCode::PRIVATE_MARKETING_MEMBER) {
$vo->setInformNm(strip_tags($postValue['privateMarketingMemberWriteTitle']));
$vo->setModeFl(gd_isset($postValue['privateMarketingMemberFl'], 'n'));
$vo->setNoticePopupFl(gd_isset($postValue['privateMarketingMemberNoticePopupFl'], 'n'));
}
 
if ($code == BuyerInformCode::ADVERTISING_RECEIVE) {
$advertisingReceiveChannels = $this->resolveAdvertisingReceiveChannels($postValue, (int)$mallSno);
$vo->setInformNm(strip_tags($postValue['advertisingReceiveWriteTitle']));
$vo->setModeFl(($advertisingReceiveChannels['email']['use'] === 'y' || $advertisingReceiveChannels['mobile']['use'] === 'y') ? 'y' : 'n');
}
 
$strSQL = "SELECT sno, displayShopFl FROM " . $tableName . " WHERE informCd='" . $code . "'";
if ($mallSno > DEFAULT_MALL_NUMBER) {
$strSQL .= " AND mallSno='" . $mallSno . "'";
 
Component/Agreement/BuyerInformVo.php+17
변경 전BuyerInformVo.php
private $regDt;
private $modDt;
private $displayShopFl;
 
function __construct($code = null)
{
$this->displayShopFl = $displayShopFl;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* object return array
*
 
변경 후BuyerInformVo.php
private $regDt;
private $modDt;
private $displayShopFl;
private $noticePopupFl = 'n';
function __construct($code = null)
{
$this->displayShopFl = $displayShopFl;
}
/**
* @return string
*/
public function getNoticePopupFl(): string
{
return $this->noticePopupFl;
}
/**
* @param string $noticePopupFl
*/
public function setNoticePopupFl(string $noticePopupFl)
{
$this->noticePopupFl = $noticePopupFl;
}
/**
* object return array
*
 
Component/Database/DBTableField.php+1
변경 전DBTableField.php
['val' => 'scmDisplayFl', 'typ' => 's', 'def' => 'n'], // 모드 사용여부
['val' => 'content', 'typ' => 's', 'def' => null], // 내용
['val' => 'displayShopFl', 'typ' => 's', 'def' => 'n'], // 약관 노출 여부
 
];
// @formatter:on
 
 
변경 후DBTableField.php
['val' => 'scmDisplayFl', 'typ' => 's', 'def' => 'n'], // 모드 사용여부
['val' => 'content', 'typ' => 's', 'def' => null], // 내용
['val' => 'displayShopFl', 'typ' => 's', 'def' => 'n'], // 약관 노출 여부
['val' => 'noticePopupFl', 'typ' => 's', 'def' => 'n'], // 마케팅 목적 개인정보 수집 동의 안내 팝업 노출 여부
];
// @formatter:on
 
 
Component/Database/MemberTableField.php+12
변경 전MemberTableField.php
'def' => null,
],
// 개인정보동의 취급업무 위탁
 
 
 
 
 
 
 
 
 
 
 
 
[
'val' => 'foreigner',
'typ' => 's',
 
변경 후MemberTableField.php
'def' => null,
],
// 개인정보동의 취급업무 위탁
[
'val' => 'privateMarketingConsentOptionFl',
'typ' => 's',
'def' => '', // 미응답(빈값) 상태 유지 - DB DEFAULT '' 와 동일
],
// 마케팅 목적 개인정보 수집 및 이용 동의
[
'val' => 'privateMarketingConsentNoticePopupDt',
'typ' => 's',
'def' => null,
],
// 마케팅 목적 개인정보 수집 및 이용 동의 안내 팝업 노출 일시 (NULL:미노출)
[
'val' => 'foreigner',
'typ' => 's',
 
Component/Excel/ExcelMember.php+10-1
변경 전ExcelMember.php
'dbName' => 'member',
'dbKey' => 'smsFl',
'excelKey' => 'sms_fl',
'text' => __('SMS수신동의'),
'sample' => 'y',
'comment' => sprintf('y:%s<br />n:%s', __('받음'), __('거부')),
'desc' => sprintf('y:%s, n:%s, %s', __('받음'), __('거부'), __('기본은 y(받음)입니다.')),
'comment' => sprintf('n:%s<br />y:%s', __('동의안함'), __('동의함')),
'desc' => sprintf('n:%s, y:%s, %s', __('동의안함'), __('동의함'), __('기본은 n(동의안함)입니다.')),
],
 
 
 
 
 
 
 
 
 
[
'dbName' => 'member',
'dbKey' => 'foreigner',
 
변경 후ExcelMember.php
'dbName' => 'member',
'dbKey' => 'smsFl',
'excelKey' => 'sms_fl',
'text' => __('모바일메시지수신동의'),
'sample' => 'y',
'comment' => sprintf('y:%s<br />n:%s', __('받음'), __('거부')),
'desc' => sprintf('y:%s, n:%s, %s', __('받음'), __('거부'), __('기본은 y(받음)입니다.')),
'comment' => sprintf('n:%s<br />y:%s', __('동의안함'), __('동의함')),
'desc' => sprintf('n:%s, y:%s, %s', __('동의안함'), __('동의함'), __('기본은 n(동의안함)입니다.')),
],
[
'dbName' => 'member',
'dbKey' => 'privateMarketingConsentOptionFl',
'excelKey' => 'private_marketing_consent_option_fl',
'text' => __('마케팅 목적 개인정보 수집 및 이용'),
'sample' => 'n',
'comment' => sprintf('n:%s<br />y:%s', __('동의안함'), __('동의함')),
'desc' => sprintf('n:%s, y:%s, %s', __('동의안함'), __('동의함'), __('기본은 n(동의안함)입니다.')),
],
[
'dbName' => 'member',
'dbKey' => 'foreigner',
 
Component/Member/History.php+108-19
변경 전History.php
//__('마일리지')
'deposit' => '예치금',
//__('예치금')
'maillingFl' => '메일수신동의',
//__('메일수신동의')
'smsFl' => 'SMS수신동의',
//__('SMS수신동의')
'marriFl' => '결혼여부',
//__('결혼여부')
'marriDate' => '결혼기념일',
//__('개인정보 수집 및 이용 필수')
'privateApprovalOptionFl' => '개인정보 수집 및 이용 선택',
//__('개인정보 수집 및 이용 선택')
 
 
'privateOfferFl' => '개인정보동의 제3자 제공',
//__('개인정보동의 제3자 제공')
'privateConsignFl' => '개인정보동의 취급업무 위탁',
$this->filters[] = 'maillingFl';
}
 
 
 
 
if (key_exists('privateApprovalOptionFl', $different)) {
$this->filters[] = 'privateApprovalOptionFl';
}
 
 
 
if (key_exists('privateOfferFl', $different)) {
$this->filters[] = 'privateOfferFl';
}
$beforeValue = $displayArray[$beforeValue];
$value = $displayArray[$value];
}
 
 
 
 
unset($displayArray);
$different[$key] = [
$beforeValue,
StringUtils::strIsSet($item['otherValue'], '{}');
$otherValue = json_decode($item['otherValue'], true);
StringUtils::strIsSet($otherValue['smsFl']['sms080']['regDt'], '');
if (!empty($otherValue['smsFl']['sms080']['regDt']) && $item['updateColumn'] == 'SMS수신동의') {
 
$item['displayOtherValue'] = sprintf(' (080 수신거부 : %s)', $otherValue['smsFl']['sms080']['regDt']);
}
if (!empty($otherValue['reflectApplyMemberInfo']['orderNo']) && empty($otherValue['simpleJoin'])) {
*/
public function selectLastReceiveAgreementByMember($memberNo)
{
// __('SMS수신동의')
// __('메일수신동의')
 
$this->db->strField = 'mh.memNo, mh.updateColumn, mh.afterValue, MAX(mh.regDt) AS lastUpdateDt';
$this->db->strWhere = 'mh.memNo=? AND mh.updateColumn IN (\'SMS수신동의\', \'메일수신동의\')';
 
$this->db->strGroup = 'mh.updateColumn';
$this->db->bind_param_push($bind, 'i', $memberNo);
$query = $this->db->query_complete();
*/
public function getLastReceiveAgreementByMember($memberNo)
{
// __('SMS수신동의')
// __('메일수신동의')
$history = $this->selectLastReceiveAgreementByMember($memberNo);
$result = [];
foreach ($history as $item) {
if ($item['updateColumn'] == 'SMS수신동의') {
$result['lastReceiveAgreementDt']['sms'] = DateTimeUtils::dateFormat('Y-m-d H:i:s', $item['lastUpdateDt']);
} elseif ($item['updateColumn'] == '메일수신동의') {
$result['lastReceiveAgreementDt']['mail'] = DateTimeUtils::dateFormat('Y-m-d H:i:s', $item['lastUpdateDt']);
 
 
 
 
 
 
 
 
 
 
}
}
 
return $result;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 회원의 마지막 수신동의 일자 조회
*
public function selectLastReceiveAgreementByMembers($memberNos)
{
$this->db->strField = 'mh.memNo, mh.updateColumn, MAX(mh.regDt) AS lastUpdateDt';
$this->db->strWhere = 'mh.memNo in ('.implode(',', $memberNos).') AND mh.updateColumn IN (\'SMS수신동의\', \'메일수신동의\')';
 
$this->db->strGroup = 'mh.memNo, mh.updateColumn';
$query = $this->db->query_complete();
$strSQL = 'SELECT ' . array_shift($query) . ' FROM ' . DB_MEMBER_HISTORY . ' AS mh' . implode(' ', $query);
if (is_array($memberNos)) {
$history = $this->selectLastReceiveAgreementByMembers($memberNos);
foreach ($history as $item) {
if ($item['updateColumn'] == 'SMS수신동의') {
$result[$item['memNo']]['lastReceiveAgreementDt']['sms'] = DateTimeUtils::dateFormat('Y-m-d H:i:s', $item['lastUpdateDt']);
} elseif ($item['updateColumn'] == '메일수신동의') {
$result[$item['memNo']]['lastReceiveAgreementDt']['mail'] = DateTimeUtils::dateFormat('Y-m-d H:i:s', $item['lastUpdateDt']);
 
 
 
 
 
 
 
 
}
}
}
 
변경 후History.php
//__('마일리지')
'deposit' => '예치금',
//__('예치금')
'maillingFl' => '이메일 수신 동의',
//__('이메일 수신 동의')
'smsFl' => '모바일 메시지 수신 동의',
//__('모바일 메시지 수신 동의')
'marriFl' => '결혼여부',
//__('결혼여부')
'marriDate' => '결혼기념일',
//__('개인정보 수집 및 이용 필수')
'privateApprovalOptionFl' => '개인정보 수집 및 이용 선택',
//__('개인정보 수집 및 이용 선택')
'privateMarketingConsentOptionFl' => '마케팅 목적 개인정보 수집 및 이용 동의',
//__('마케팅 목적 개인정보 수집 및 이용 동의')
'privateOfferFl' => '개인정보동의 제3자 제공',
//__('개인정보동의 제3자 제공')
'privateConsignFl' => '개인정보동의 취급업무 위탁',
$this->filters[] = 'maillingFl';
}
 
if (key_exists('privateApprovalFl', $different)) {
$this->filters[] = 'privateApprovalFl';
}
if (key_exists('privateApprovalOptionFl', $different)) {
$this->filters[] = 'privateApprovalOptionFl';
}
if (key_exists('privateMarketingConsentOptionFl', $different)) {
$this->filters[] = 'privateMarketingConsentOptionFl';
}
if (key_exists('privateOfferFl', $different)) {
$this->filters[] = 'privateOfferFl';
}
$beforeValue = $displayArray[$beforeValue];
$value = $displayArray[$value];
}
// 마케팅 목적 개인정보 수집 및 이용 동의: 미응답(빈값)은 미동의(n)로 표시 (비교는 원본이라 최초 응답도 이력에 남음)
if ('privateMarketingConsentOptionFl' == $key && '' === $beforeValue) {
$beforeValue = 'n';
}
unset($displayArray);
$different[$key] = [
$beforeValue,
StringUtils::strIsSet($item['otherValue'], '{}');
$otherValue = json_decode($item['otherValue'], true);
StringUtils::strIsSet($otherValue['smsFl']['sms080']['regDt'], '');
// 'SMS수신동의' 는 구 라벨 - 마이그레이션 미완 데이터 대비
if (!empty($otherValue['smsFl']['sms080']['regDt']) && in_array($item['updateColumn'], ['모바일 메시지 수신 동의', 'SMS수신동의'], true)) {
$item['displayOtherValue'] = sprintf(' (080 수신거부 : %s)', $otherValue['smsFl']['sms080']['regDt']);
}
if (!empty($otherValue['reflectApplyMemberInfo']['orderNo']) && empty($otherValue['simpleJoin'])) {
*/
public function selectLastReceiveAgreementByMember($memberNo)
{
// __('모바일 메시지 수신 동의')
// __('이메일 수신 동의')
// __('마케팅 목적 개인정보 수집 및 이용 동의')
$this->db->strField = 'mh.memNo, mh.updateColumn, mh.afterValue, MAX(mh.regDt) AS lastUpdateDt';
// 'SMS수신동의'/'메일수신동의' 는 구 라벨 - 마이그레이션 미완 데이터 대비
$this->db->strWhere = 'mh.memNo=? AND mh.updateColumn IN (\'모바일 메시지 수신 동의\', \'SMS수신동의\', \'이메일 수신 동의\', \'메일수신동의\', \'마케팅 목적 개인정보 수집 및 이용 동의\')';
$this->db->strGroup = 'mh.updateColumn';
$this->db->bind_param_push($bind, 'i', $memberNo);
$query = $this->db->query_complete();
*/
public function getLastReceiveAgreementByMember($memberNo)
{
// __('모바일 메시지 수신 동의')
// __('이메일 수신 동의')
$history = $this->selectLastReceiveAgreementByMember($memberNo);
$result = [];
foreach ($history as $item) {
$dt = DateTimeUtils::dateFormat('Y-m-d H:i:s', $item['lastUpdateDt']);
// 'SMS수신동의'/'메일수신동의' 는 구 라벨 - 마이그레이션 미완 데이터 대비
if (in_array($item['updateColumn'], ['모바일 메시지 수신 동의', 'SMS수신동의'], true)) {
$key = 'sms';
} elseif (in_array($item['updateColumn'], ['이메일 수신 동의', '메일수신동의'], true)) {
$key = 'mail';
} elseif ($item['updateColumn'] == '마케팅 목적 개인정보 수집 및 이용 동의') {
$key = 'privateMkt';
} else {
continue;
}
// 옛/새 라벨이 각각 그룹으로 나뉘어 올 수 있어 더 늦은 일자만 유지
if (empty($result['lastReceiveAgreementDt'][$key]) || $result['lastReceiveAgreementDt'][$key] < $dt) {
$result['lastReceiveAgreementDt'][$key] = $dt;
}
}
 
return $result;
}
 
/**
* 회원의 개인정보 동의 항목별 마지막 변경 일시 조회 (updateColumn 한글 라벨 그룹, MAX regDt)
*
* @param $memberNo
*
* @return array
*/
public function selectLastPrivateAgreementByMember($memberNo): array
{
// __('개인정보 수집 및 이용 필수')
// __('개인정보 수집 및 이용 선택')
// __('개인정보동의 제3자 제공')
// __('개인정보동의 취급업무 위탁')
// __('마케팅 목적 개인정보 수집 및 이용 동의')
$this->db->strField = 'mh.updateColumn, MAX(mh.regDt) AS lastUpdateDt';
$this->db->strWhere = 'mh.memNo=? AND mh.updateColumn IN (\'개인정보 수집 및 이용 필수\', \'개인정보 수집 및 이용 선택\', \'개인정보동의 제3자 제공\', \'개인정보동의 취급업무 위탁\', \'마케팅 목적 개인정보 수집 및 이용 동의\')';
$this->db->strGroup = 'mh.updateColumn';
$this->db->bind_param_push($bind, 'i', $memberNo);
$query = $this->db->query_complete();
$strSQL = 'SELECT ' . array_shift($query) . ' FROM ' . DB_MEMBER_HISTORY . ' AS mh' . implode(' ', $query);
$result = $this->db->query_fetch($strSQL, $bind);
 
return $result;
}
 
/**
* 회원의 개인정보 동의 항목별 마지막 변경 일시 (컬럼명 => 'Y-m-d H:i:s')
* 이력이 없는 항목은 키 자체가 없으므로 호출부에서 entryDt 등으로 폴백한다.
*
* @param int $memberNo
*
* @return array privateApprovalFl / privateApprovalOptionFl / privateOfferFl / privateConsignFl / privateMarketingConsentOptionFl 중 이력 있는 항목만
*/
public function getLastPrivateAgreementDateByMember(int $memberNo): array
{
$labelToColumn = [
'개인정보 수집 및 이용 필수' => 'privateApprovalFl',
'개인정보 수집 및 이용 선택' => 'privateApprovalOptionFl',
'개인정보동의 제3자 제공' => 'privateOfferFl',
'개인정보동의 취급업무 위탁' => 'privateConsignFl',
'마케팅 목적 개인정보 수집 및 이용 동의' => 'privateMarketingConsentOptionFl',
];
$history = $this->selectLastPrivateAgreementByMember($memberNo);
$result = [];
foreach ($history as $item) {
$column = $labelToColumn[$item['updateColumn']] ?? null;
if ($column === null) {
continue;
}
$result[$column] = DateTimeUtils::dateFormat('Y-m-d H:i:s', $item['lastUpdateDt']);
}
 
return $result;
}
 
/**
* 회원의 마지막 수신동의 일자 조회
*
public function selectLastReceiveAgreementByMembers($memberNos)
{
$this->db->strField = 'mh.memNo, mh.updateColumn, MAX(mh.regDt) AS lastUpdateDt';
// 'SMS수신동의'/'메일수신동의' 는 구 라벨 - 마이그레이션 미완 데이터 대비
$this->db->strWhere = 'mh.memNo in ('.implode(',', $memberNos).') AND mh.updateColumn IN (\'모바일 메시지 수신 동의\', \'SMS수신동의\', \'이메일 수신 동의\', \'메일수신동의\')';
$this->db->strGroup = 'mh.memNo, mh.updateColumn';
$query = $this->db->query_complete();
$strSQL = 'SELECT ' . array_shift($query) . ' FROM ' . DB_MEMBER_HISTORY . ' AS mh' . implode(' ', $query);
if (is_array($memberNos)) {
$history = $this->selectLastReceiveAgreementByMembers($memberNos);
foreach ($history as $item) {
$dt = DateTimeUtils::dateFormat('Y-m-d H:i:s', $item['lastUpdateDt']);
// 'SMS수신동의'/'메일수신동의' 는 구 라벨 - 마이그레이션 미완 데이터 대비
if (in_array($item['updateColumn'], ['모바일 메시지 수신 동의', 'SMS수신동의'], true)) {
$key = 'sms';
} elseif (in_array($item['updateColumn'], ['이메일 수신 동의', '메일수신동의'], true)) {
$key = 'mail';
} else {
continue;
}
// 옛/새 라벨이 각각 그룹으로 나뉘어 올 수 있어 더 늦은 일자만 유지
if (empty($result[$item['memNo']]['lastReceiveAgreementDt'][$key]) || $result[$item['memNo']]['lastReceiveAgreementDt'][$key] < $dt) {
$result[$item['memNo']]['lastReceiveAgreementDt'][$key] = $dt;
}
}
}
 
Component/Member/MemberAdmin.php+10-2
변경 전MemberAdmin.php
}
$this->db->strJoin = ' LEFT JOIN ' . DB_MEMBER_SNS . ' AS ms ON m.memNo = ms.memNo';
$this->db->strJoin .= ' LEFT JOIN ' . DB_MEMBER_GROUP . ' AS mg ON m.groupSno = mg.sno';
$this->db->strJoin .= ' LEFT JOIN ' . DB_MEMBER_HISTORY . ' AS mh ON (m.memNo=mh.memNo AND mh.updateColumn=\'SMS수신동의\')';
$this->db->strJoin .= ' LEFT JOIN ' . DB_MEMBER_HISTORY . ' AS mh2 ON (m.memNo=mh2.memNo AND mh2.updateColumn=\'메일수신동의\')';
$this->db->strGroup = 'm.memNo';
$arrQuery = $this->db->query_complete(true, true);
$strSQL = 'SELECT ' . array_shift($arrQuery) . ' FROM ' . DB_MEMBER . ' AS m ' . implode(' ', $arrQuery);
}
}
 
 
 
 
 
 
 
$arrData = $this->validateMemberByAdminModification($arrData);
 
foreach ($preservedFileKeys as $fileKey => $fileVal) {
\App::getInstance('session')->set(SESSION_GLOBAL_MALL, ['isAdminModify' => true]);
}
\Component\Member\MemberValidation::addValidateMember($v, $require);
 
 
$v->add('memNo', 'number', true);
if (!$this->isExcelUpload) {
if (gd_isset($params['memPw'], '') !== '') {
 
변경 후MemberAdmin.php
}
$this->db->strJoin = ' LEFT JOIN ' . DB_MEMBER_SNS . ' AS ms ON m.memNo = ms.memNo';
$this->db->strJoin .= ' LEFT JOIN ' . DB_MEMBER_GROUP . ' AS mg ON m.groupSno = mg.sno';
$this->db->strJoin .= ' LEFT JOIN ' . DB_MEMBER_HISTORY . ' AS mh ON (m.memNo=mh.memNo AND mh.updateColumn=\'모바일 메시지 수신 동의\')';
$this->db->strJoin .= ' LEFT JOIN ' . DB_MEMBER_HISTORY . ' AS mh2 ON (m.memNo=mh2.memNo AND mh2.updateColumn=\'이메일 수신 동의\')';
$this->db->strGroup = 'm.memNo';
$arrQuery = $this->db->query_complete(true, true);
$strSQL = 'SELECT ' . array_shift($arrQuery) . ' FROM ' . DB_MEMBER . ' AS m ' . implode(' ', $arrQuery);
}
}
 
// 마케팅 목적 개인정보 수집 및 이용 동의는 약관 사용 시에만 포함
$privateMarketingMemberData = (new \Component\Agreement\BuyerInform())->getInformDataArray(\Component\Agreement\BuyerInformCode::PRIVATE_MARKETING_MEMBER);
if (($privateMarketingMemberData[0]['modeFl'] ?? 'n') === 'y') {
StringUtils::strIsSet($arrData['privateMarketingConsentOptionFl'], 'n');
}
 
$arrData = $this->validateMemberByAdminModification($arrData);
 
foreach ($preservedFileKeys as $fileKey => $fileVal) {
\App::getInstance('session')->set(SESSION_GLOBAL_MALL, ['isAdminModify' => true]);
}
\Component\Member\MemberValidation::addValidateMember($v, $require);
// 마케팅 목적 개인정보 수집 및 이용 동의 (validator 미등록 시 act garbageDelete 로 제거되어 미저장)
$v->add('privateMarketingConsentOptionFl', 'yn', false, '{' . __('마케팅 목적 개인정보 수집 및 이용 동의') . '}');
$v->add('memNo', 'number', true);
if (!$this->isExcelUpload) {
if (gd_isset($params['memPw'], '') !== '') {
 
Component/Member/MemberDAO.php+14-2
변경 전MemberDAO.php
 
$this->db->strField = 'm.memNo, m.memId, m.memNm, m.groupSno, m.mileage, m.deposit, m.smsFl, m.maillingFl, m.cellPhone, m.email';
$this->db->strField .= ', ' . $strFieldBySmsAgreementDt . ', ' . $strFieldByMailAgreementDt;
$this->db->strJoin = ' LEFT JOIN (SELECT memNo, COUNT(*) AS cnt, MAX(regDt) AS maxRegDt FROM ' . DB_MEMBER_HISTORY . ' WHERE updateColumn=\'SMS수신동의\' GROUP BY memNo) AS mh_sms ON m.memNo = mh_sms.memNo';
$this->db->strJoin .= ' LEFT JOIN (SELECT memNo, COUNT(*) AS cnt, MAX(regDt) AS maxRegDt FROM ' . DB_MEMBER_HISTORY . ' WHERE updateColumn=\'메일수신동의\' GROUP BY memNo) AS mh_mail ON m.memNo = mh_mail.memNo';
 
 
$this->db->strJoin .= ' LEFT JOIN (SELECT DISTINCT memNo FROM ' . DB_MEMBER_NOTIFICATION_LOG . ' WHERE ReasonCode=\'' . MailMimeAuto::AGREEMENT2YPERIOD . '\' AND regDt >= \'' . $standardDt . ' 00:00:00\' AND regDt <= \'' . $nowDt . ' 23:59:59\') AS mnl ON m.memNo = mnl.memNo';
 
$this->db->strWhere = '';
$this->db->bindParameter('sexFl', $params, $arrBind, $arrWhere, 'tableMember', 'm');
$this->db->bindParameter('maillingFl', $params, $arrBind, $arrWhere, 'tableMember', 'm');
$this->db->bindParameter('smsFl', $params, $arrBind, $arrWhere, 'tableMember', 'm');
 
 
 
 
 
 
 
 
 
 
$this->db->bindParameter('calendarFl', $params, $arrBind, $arrWhere, 'tableMember', 'm');
$this->db->bindParameter('marriFl', $params, $arrBind, $arrWhere, 'tableMember', 'm');
$this->db->bindParameter('connectSns', $params, $arrBind, $arrWhere, 'tableMemberSns', 'ms', 'snsTypeFl');
 
변경 후MemberDAO.php
 
$this->db->strField = 'm.memNo, m.memId, m.memNm, m.groupSno, m.mileage, m.deposit, m.smsFl, m.maillingFl, m.cellPhone, m.email';
$this->db->strField .= ', ' . $strFieldBySmsAgreementDt . ', ' . $strFieldByMailAgreementDt;
// 'SMS수신동의' 는 구 라벨 - 마이그레이션 미완 데이터 대비
$this->db->strJoin = ' LEFT JOIN (SELECT memNo, COUNT(*) AS cnt, MAX(regDt) AS maxRegDt FROM ' . DB_MEMBER_HISTORY . ' WHERE updateColumn IN (\'모바일 메시지 수신 동의\', \'SMS수신동의\') GROUP BY memNo) AS mh_sms ON m.memNo = mh_sms.memNo';
// '메일수신동의' 는 구 라벨 - 마이그레이션 미완 데이터 대비
$this->db->strJoin .= ' LEFT JOIN (SELECT memNo, COUNT(*) AS cnt, MAX(regDt) AS maxRegDt FROM ' . DB_MEMBER_HISTORY . ' WHERE updateColumn IN (\'이메일 수신 동의\', \'메일수신동의\') GROUP BY memNo) AS mh_mail ON m.memNo = mh_mail.memNo';
$this->db->strJoin .= ' LEFT JOIN (SELECT DISTINCT memNo FROM ' . DB_MEMBER_NOTIFICATION_LOG . ' WHERE ReasonCode=\'' . MailMimeAuto::AGREEMENT2YPERIOD . '\' AND regDt >= \'' . $standardDt . ' 00:00:00\' AND regDt <= \'' . $nowDt . ' 23:59:59\') AS mnl ON m.memNo = mnl.memNo';
 
$this->db->strWhere = '';
$this->db->bindParameter('sexFl', $params, $arrBind, $arrWhere, 'tableMember', 'm');
$this->db->bindParameter('maillingFl', $params, $arrBind, $arrWhere, 'tableMember', 'm');
$this->db->bindParameter('smsFl', $params, $arrBind, $arrWhere, 'tableMember', 'm');
// 마케팅 목적 개인정보 수집 및 이용 동의 검색값 화이트리스트 정규화
if (!in_array($params['privateMarketingConsentOptionFl'] ?? '', ['', 'y', 'n'], true)) {
$params['privateMarketingConsentOptionFl'] = '';
}
// 마케팅 목적 개인정보 수집 및 이용 동의 (미동의는 동의여부 저장 안 한 디폴트('') 포함이라 != 'y')
if (!empty($params['privateMarketingConsentOptionFl'])) {
$arrWhere[] = $params['privateMarketingConsentOptionFl'] === 'y'
? "m.privateMarketingConsentOptionFl = 'y'"
: "m.privateMarketingConsentOptionFl != 'y'";
}
$this->db->bindParameter('calendarFl', $params, $arrBind, $arrWhere, 'tableMember', 'm');
$this->db->bindParameter('marriFl', $params, $arrBind, $arrWhere, 'tableMember', 'm');
$this->db->bindParameter('connectSns', $params, $arrBind, $arrWhere, 'tableMemberSns', 'ms', 'snsTypeFl');
 
Component/Member/Member.php+59
변경 전Member.php
}
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 로그인 비밀번호를 재검증 하는 함수
*
$v->add('privateApprovalOptionFl', '', false, '{' . __('개인정보 수집.이용 동의 선택사항') . '}'); // 개인정보동의 이용자 동의사항
$v->add('privateOfferFl', '', false, '{' . __('개인정보동의 제3자 제공') . '}'); // 개인정보동의 제3자 제공
$v->add('privateConsignFl', '', false, '{' . __('개인정보동의 취급업무 위탁') . '}'); // 개인정보동의 취급업무 위탁
 
 
 
$v->add('foreigner', '', false, '{' . __('내외국인구분') . '}'); // 내외국인구분
$v->add('dupeinfo', '', false, '{' . __('본인확인 중복가입확인정보') . '}'); // 본인확인 중복가입확인정보
$v->add('pakey', '', false, '{' . __('본인확인 번호') . '}'); // 본인확인 번호
$vo->setPrivateApprovalOptionFl(json_encode($joinSession->get('privateApprovalOptionFl'), JSON_UNESCAPED_SLASHES));
$vo->setPrivateOfferFl(json_encode($joinSession->get('privateOfferFl'), JSON_UNESCAPED_SLASHES));
$vo->setPrivateConsignFl(json_encode($joinSession->get('privateConsignFl'), JSON_UNESCAPED_SLASHES));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$vo->setForeigner($joinSession->get('foreigner'));
$vo->setDupeinfo($joinSession->get('dupeinfo'));
$vo->setPakey($joinSession->get('pakey'));
'sexFl',
'marriFl',
'expirationFl',
 
], $memberData
);
 
 
변경 후Member.php
}
}
 
/**
* 마케팅 목적 개인정보 수집 및 이용 동의 안내(alert) 노출 여부 판정 + 노출 이력 기록
* 조건 통과 시 노출 이력(privateMarketingConsentNoticePopupDt)에 노출시각을 기록해 계정당 1회만 노출
*
* @return bool 안내 노출 대상이면 true (동시에 노출 이력 기록)
* @throws Exception
*/
public function markPrivateMarketingConsentNoticeShown(): bool
{
if (!MemberUtil::isLogin()) {
return false;
}
 
// 마케팅 목적 개인정보 수집 및 이용 동의 약관(001015) 사용중(modeFl='y') + 안내 팝업 노출 사용(noticePopupFl='y')
/** @var \Bundle\Component\Agreement\BuyerInform $buyerInform */
$buyerInform = \App::load('\\Component\\Agreement\\BuyerInform');
$inform = $buyerInform->getInformDataArray(\Component\Agreement\BuyerInformCode::PRIVATE_MARKETING_MEMBER, 'modeFl, noticePopupFl');
if (($inform[0]['modeFl'] ?? 'n') !== 'y' || ($inform[0]['noticePopupFl'] ?? 'n') !== 'y') {
return false;
}
 
$member = MemberUtil::getMemberBySession('memNo, privateMarketingConsentOptionFl, privateMarketingConsentNoticePopupDt');
$noticeDt = $member['privateMarketingConsentNoticePopupDt'] ?? '';
$alreadyNoticed = !empty($noticeDt) && $noticeDt !== '0000-00-00 00:00:00';
// 동의('y'), 안내 노출 이력이 있으면 미노출
if (($member['privateMarketingConsentOptionFl'] ?? '') === 'y' || $alreadyNoticed) {
return false;
}
 
// 노출 이력 기록 (계정당 평생 1회 — 노출했다는 사실만 저장, 동의/거부와 무관)
try {
$this->update($member['memNo'], 'memNo', ['privateMarketingConsentNoticePopupDt'], [DateTimeUtils::dateFormat('Y-m-d H:i:s', 'now')]);
} catch (\Exception $e) {
\Logger::channel('userLogin')->warning('마케팅 목적 개인정보 수집 및 이용 동의 안내 노출 이력 기록 실패', ['memNo' => $member['memNo'], 'exception' => $e]);
 
return false;
}
 
return true;
}
 
/**
* 로그인 비밀번호를 재검증 하는 함수
*
$v->add('privateApprovalOptionFl', '', false, '{' . __('개인정보 수집.이용 동의 선택사항') . '}'); // 개인정보동의 이용자 동의사항
$v->add('privateOfferFl', '', false, '{' . __('개인정보동의 제3자 제공') . '}'); // 개인정보동의 제3자 제공
$v->add('privateConsignFl', '', false, '{' . __('개인정보동의 취급업무 위탁') . '}'); // 개인정보동의 취급업무 위탁
$v->add('privateMarketingConsentOptionFl', 'yn', false, '{' . __('마케팅 목적 개인정보 수집 및 이용 동의') . '}'); // 마케팅 목적 개인정보 수집 및 이용 동의
$v->add('maillingFl', 'yn', false, '{' . __('이메일 수신 동의') . '}'); // 광고성 수신 동의 - 이메일
$v->add('smsFl', 'yn', false, '{' . __('모바일 메시지 수신 동의') . '}'); // 광고성 수신 동의 - 모바일
$v->add('foreigner', '', false, '{' . __('내외국인구분') . '}'); // 내외국인구분
$v->add('dupeinfo', '', false, '{' . __('본인확인 중복가입확인정보') . '}'); // 본인확인 중복가입확인정보
$v->add('pakey', '', false, '{' . __('본인확인 번호') . '}'); // 본인확인 번호
$vo->setPrivateApprovalOptionFl(json_encode($joinSession->get('privateApprovalOptionFl'), JSON_UNESCAPED_SLASHES));
$vo->setPrivateOfferFl(json_encode($joinSession->get('privateOfferFl'), JSON_UNESCAPED_SLASHES));
$vo->setPrivateConsignFl(json_encode($joinSession->get('privateConsignFl'), JSON_UNESCAPED_SLASHES));
// 마수동 약관 사용중(modeFl='y')일 때만 동의('y')/미동의('n') 확정. 미사용 시 ''(미응답) = 로그인 안내 팝업 대상.
$privateMarketingConsentOptionFl = $joinSession->get('privateMarketingConsentOptionFl');
$buyerInform = \App::load('\\Component\\Agreement\\BuyerInform');
$privateMarketingMember = $buyerInform->getInformDataArray(\Component\Agreement\BuyerInformCode::PRIVATE_MARKETING_MEMBER, 'modeFl');
if (($privateMarketingMember[0]['modeFl'] ?? 'n') === 'y') {
$privateMarketingConsentOptionFl = ($privateMarketingConsentOptionFl === 'y') ? 'y' : 'n';
// 약관 사용 중 가입 = 이미 선택함 → 로그인 안내 팝업 제외 (노출 이력에 가입 시각 기록)
$vo->setPrivateMarketingConsentNoticePopupDt(date('Y-m-d H:i:s'));
} else {
$privateMarketingConsentOptionFl = '';
}
$vo->setPrivateMarketingConsentOptionFl($privateMarketingConsentOptionFl);
$vo->setMaillingFl($joinSession->get('maillingFl'));
$vo->setSmsFl($joinSession->get('smsFl'));
$vo->setForeigner($joinSession->get('foreigner'));
$vo->setDupeinfo($joinSession->get('dupeinfo'));
$vo->setPakey($joinSession->get('pakey'));
'sexFl',
'marriFl',
'expirationFl',
'privateMarketingConsentOptionFl',
], $memberData
);
 
 
Component/Member/MemberVO.php+34
변경 전MemberVO.php
protected $ex1, $ex2, $ex3, $ex4, $ex5, $ex6;
protected $privateApprovalFl;
protected $privateApprovalOptionFl;
 
 
protected $privateOfferFl;
protected $privateConsignFl;
protected $foreigner;
$this->privateApprovalOptionFl = $privateApprovalOptionFl;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* @param mixed $privateOfferFl
*/
 
변경 후MemberVO.php
protected $ex1, $ex2, $ex3, $ex4, $ex5, $ex6;
protected $privateApprovalFl;
protected $privateApprovalOptionFl;
protected $privateMarketingConsentOptionFl;
protected $privateMarketingConsentNoticePopupDt;
protected $privateOfferFl;
protected $privateConsignFl;
protected $foreigner;
$this->privateApprovalOptionFl = $privateApprovalOptionFl;
}
/**
* @param mixed $privateMarketingConsentOptionFl 마케팅 목적 개인정보 수집 및 이용 동의
*/
public function setPrivateMarketingConsentOptionFl($privateMarketingConsentOptionFl)
{
$this->privateMarketingConsentOptionFl = $privateMarketingConsentOptionFl;
}
/**
* @param mixed $privateMarketingConsentNoticePopupDt 마케팅 목적 개인정보 수집 및 이용 동의 안내 팝업 노출 일시
*/
public function setPrivateMarketingConsentNoticePopupDt($privateMarketingConsentNoticePopupDt)
{
$this->privateMarketingConsentNoticePopupDt = $privateMarketingConsentNoticePopupDt;
}
/**
* @param mixed $maillingFl 이메일 수신 동의
*/
public function setMaillingFl($maillingFl)
{
$this->maillingFl = $maillingFl;
}
/**
* @param mixed $smsFl 모바일 메시지 수신 동의
*/
public function setSmsFl($smsFl)
{
$this->smsFl = $smsFl;
}
/**
* @param mixed $privateOfferFl
*/
 
Component/Member/MyPage.php+13
변경 전MyPage.php
$requestParams['privateConsignFl'] = json_encode($agreementData['privateConsignFl'], JSON_UNESCAPED_SLASHES);
$requestParams['privateOfferFl'] = json_encode($agreementData['privateOfferFl'], JSON_UNESCAPED_SLASHES);
 
 
 
 
 
 
$passValidation = isset($memberSession['memPw']) == false && $memberSession['snsJoinFl'] == 'y';
$requestParams = $this->validateMemberByModification($requestParams, $passValidation);
$addExclude = [
$v->add('privateApprovalOptionFl', '', false, '{' . __('개인정보 수집 및 이용') . '}');
$v->add('privateOfferFl', '', false, '{' . __('개인정보동의 제3자 제공') . '}');
$v->add('privateConsignFl', '', false, '{' . __('개인정보동의 취급업무 위탁') . '}');
 
if (StringUtils::strIsSet($requestParams['memPw'], '') !== '') {
\Component\Member\MemberValidation::validateMemberPassword($requestParams['memPw']);
$v->add('memPw', '', true, '{' . __('비밀번호') . '}');
} else {
$requestParams['privateOfferFl'] = $arrprivateOffer;
}
 
 
 
 
 
 
 
return $requestParams;
}
}
 
변경 후MyPage.php
$requestParams['privateConsignFl'] = json_encode($agreementData['privateConsignFl'], JSON_UNESCAPED_SLASHES);
$requestParams['privateOfferFl'] = json_encode($agreementData['privateOfferFl'], JSON_UNESCAPED_SLASHES);
 
// 마케팅 목적 개인정보 수집 및 이용 동의는 사용 시에만 setAgreementData 세팅 (미사용 시 미포함 → 컬럼값 갱신 안 함, 기존값 유지)
if (array_key_exists('privateMarketingConsentOptionFl', $agreementData)) {
$requestParams['privateMarketingConsentOptionFl'] = $agreementData['privateMarketingConsentOptionFl'];
}
 
$passValidation = isset($memberSession['memPw']) == false && $memberSession['snsJoinFl'] == 'y';
$requestParams = $this->validateMemberByModification($requestParams, $passValidation);
$addExclude = [
$v->add('privateApprovalOptionFl', '', false, '{' . __('개인정보 수집 및 이용') . '}');
$v->add('privateOfferFl', '', false, '{' . __('개인정보동의 제3자 제공') . '}');
$v->add('privateConsignFl', '', false, '{' . __('개인정보동의 취급업무 위탁') . '}');
$v->add('privateMarketingConsentOptionFl', '', false, '{' . __('마케팅 목적 개인정보 수집 및 이용 동의') . '}');
if (StringUtils::strIsSet($requestParams['memPw'], '') !== '') {
\Component\Member\MemberValidation::validateMemberPassword($requestParams['memPw']);
$v->add('memPw', '', true, '{' . __('비밀번호') . '}');
} else {
$requestParams['privateOfferFl'] = $arrprivateOffer;
}
 
// 마케팅 목적 개인정보 수집 및 이용 동의 (사용 시에만 동의 'y' / 미동의 'n' 저장. 미사용 시 빈값 유지 - 로그인 안내 팝업 조건)
$privateMarketingMemberData = $inform->getInformDataArray(BuyerInformCode::PRIVATE_MARKETING_MEMBER);
if (($privateMarketingMemberData[0]['modeFl'] ?? 'n') === 'y') {
$requestParams['privateMarketingConsentOptionFl'] = (($requestParams['privateMarketingConsentOptionFl'] ?? '') === 'y') ? 'y' : 'n';
}
 
return $requestParams;
}
}
 
Component/Member/Util/MemberUtil.php+136-1
변경 전MemberUtil.php
return implode('', $html);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 로그인 되었는 지를 체크 (회원/비회원)
*
$data['agreementInfoFl'] = gd_isset($arrData['agreementInfoFl'], 'n');
$data['privateApprovalFl'] = gd_isset($arrData['privateApprovalFl'], 'n');
$data['under14ConsentFl'] = gd_isset($arrData['under14ConsentFl'], 'n');
 
 
 
//이용약관 체크값 설정
$myPage = \App::load('\\Component\\Member\\MyPage');
$agreementData = $myPage->setAgreementData($arrData);
$data['privateApprovalOptionFl'] = gd_isset($agreementData['privateApprovalOptionFl']);
$data['privateOfferFl'] = gd_isset($agreementData['privateOfferFl']);
$data['privateConsignFl'] = gd_isset($agreementData['privateConsignFl']);
 
 
 
// 인증설정체크해서 데이터 추가 useDataJoinFl
$dreamInfo = gd_policy('member.auth_cellphone');
$params['sexFl'] = $params['sexFl'] ?? '';
$params['maillingFl'] = $params['maillingFl'] ?? '';
$params['smsFl'] = $params['smsFl'] ?? '';
 
$params['calendarFl'] = $params['calendarFl'] ?? '';
$params['expirationFl'] = $params['expirationFl'] ?? '';
 
$checked['sexFl'][$params['sexFl']] =
$checked['maillingFl'][$params['maillingFl']] =
$checked['smsFl'][$params['smsFl']] =
 
$checked['calendarFl'][$params['calendarFl']] =
$checked['expirationFl'][$params['expirationFl']] = 'checked="checked"';
 
 
변경 후MemberUtil.php
return implode('', $html);
}
 
/**
* 약관 동의 표시 항목 생성 (informNm + 동의함/동의안함 라벨)
*
* 개인정보 수집·이용/취급위탁/제3자 제공/마케팅 동의 등 약관 표시 블록을 정형화한다.
*
* @param array $informList 약관 목록 (각 항목에 sno, informNm 포함. modeFl 이 'y' 아니면 '사용안함' 표기)
* @param array $consentBySno 동의 상태 맵 (sno => 'y'/'n')
* @param bool $denyWhenMissing 미응답(y/n 아님)을 '동의안함'으로 표시할지 여부. false면 해당 항목 스킵
* @return array [['informNm' => string, 'label' => string, 'unused'? => bool], ...] (unused=true 면 미사용 약관 → 항목명 없이 '사용안함'만 표기)
*/
public static function makeConsentItems(array $informList, array $consentBySno, bool $denyWhenMissing = false, string $agreementDt = ''): array
{
$items = [];
foreach ($informList as $inform) {
// 개별 약관 미사용(modeFl != 'y')이면 동의 여부와 무관하게 '사용안함' 표기
if (($inform['modeFl'] ?? 'y') !== 'y') {
$items[] = ['informNm' => $inform['informNm'], 'label' => '사용안함', 'unused' => true];
continue;
}
$flag = $consentBySno[$inform['sno']] ?? '';
if ($flag === 'y') {
// 동의: 년월일시분초까지 표기
$label = '동의함' . ($agreementDt !== '' ? '(' . DateTimeUtils::dateFormat('Y-m-d H:i:s', $agreementDt) . ')' : '');
} elseif ($flag === 'n' || $denyWhenMissing) {
// 미동의: 년월일까지만 표기 (일시 없거나 미응답이면 날짜 생략)
$label = '동의안함' . (($agreementDt !== '' && $flag === 'n') ? '(' . DateTimeUtils::dateFormat('Y-m-d', $agreementDt) . ')' : '');
} else {
continue;
}
$items[] = ['informNm' => $inform['informNm'], 'label' => $label];
}
 
return $items;
}
 
/**
* 회원 약관 동의 표시 HTML 생성. 약관 행 설정 배열을 받아 완성된 <tr> 마크업을 반환한다 (htmlExtra 패턴, 뷰는 출력만).
* 약관이 늘어도 호출부에서 배열 항목만 추가하면 되고 메서드 시그니처는 불변.
*
* @param array $agreements 약관 행 목록. 각 항목:
* - title string <th> 제목 (마크업 허용)
* - tooltipSeq string data-tooltip-seq 값(선택). 지정 시 <th> div 에 속성 출력
* - use bool 약관 사용/표시 여부 (false면 '사용안함')
* - informs array 약관 목록 (sno, informNm) — use=true 일 때만 참조
* - flags mixed 동의 상태. sno=>('y'/'n') 배열(개인정보 항목별) 또는 단일 'y'/'n' 문자열(마케팅)
* - denyWhenMissing bool 미응답(y/n 아님)을 '동의안함'으로 표시할지. false면 해당 항목 스킵
* - agreementDt string 동의/미동의 일시(선택). 지정 시 동의함(초까지)/동의안함(날짜까지)에 괄호로 병기. 컬럼 공통 값
* @return string
*/
public static function makePrivateAgreementField(array $agreements): string
{
$html = [];
foreach ($agreements as $agreement) {
$seq = $agreement['tooltipSeq'] ?? '';
$seqAttr = $seq !== '' ? ' data-tooltip-seq="' . $seq . '"' : '';
$html[] = '<tr><th><div' . $seqAttr . '>' . ($agreement['title'] ?? '') . '</div></th><td>';
if (!empty($agreement['use'])) {
$informs = $agreement['informs'] ?? [];
$flags = $agreement['flags'] ?? [];
// 단일 플래그 문자열이면 전 항목에 동일 적용하도록 sno 맵으로 변환
if (!is_array($flags)) {
$singleFlag = (string) $flags;
$flags = [];
foreach ($informs as $inform) {
$flags[$inform['sno']] = $singleFlag;
}
}
$agreementDt = (string) ($agreement['agreementDt'] ?? '');
$unusedShown = false;
foreach (self::makeConsentItems($informs, $flags, !empty($agreement['denyWhenMissing']), $agreementDt) as $item) {
if (!empty($item['unused'])) {
// 미사용 약관(modeFl != 'y')은 항목명/동의여부 없이 '사용안함'만, 그룹당 1회만 표기
if ($unusedShown) {
continue;
}
$unusedShown = true;
$html[] = '<div>사용안함</div>';
} else {
$html[] = '<div>- ' . $item['informNm'] . ' : ' . $item['label'] . '</div>';
}
}
} else {
$html[] = '<div>사용안함</div>';
}
$html[] = '</td></tr>';
}
 
return implode('', $html);
}
 
/**
* 광고성 수신 동의(이메일/모바일 메시지) 표시 HTML 생성. 채널 사용여부 + 수신 flag + 최종 수신동의일(es_memberHistory 파생)로
* 동의함(초까지)/동의안함(날짜까지) 라벨을 조립한다 (htmlExtra 패턴, 뷰는 출력만).
*
* @param array $advertisingReceive gd_policy('member.advertisingReceive') — email.use / mobile.use ('y'/'n')
* @param array $data 회원 데이터 (maillingFl, smsFl, lastReceiveAgreementDt[mail|sms], entryDt)
* @return string 채널 모두 미사용이면 '사용안함'
*/
public static function makeAdvertisingReceiveField(array $advertisingReceive, array $data): string
{
$mailUse = (($advertisingReceive['email']['use'] ?? 'n') === 'y');
$smsUse = (($advertisingReceive['mobile']['use'] ?? 'n') === 'y');
if (!$mailUse && !$smsUse) {
return '<div>사용안함</div>';
}
 
$channels = [];
if ($mailUse) {
$channels[] = ['label' => '이메일', 'flag' => $data['maillingFl'] ?? 'n', 'dt' => $data['lastReceiveAgreementDt']['mail'] ?? ($data['entryDt'] ?? '')];
}
if ($smsUse) {
$channels[] = ['label' => '모바일 메시지', 'flag' => $data['smsFl'] ?? 'n', 'dt' => $data['lastReceiveAgreementDt']['sms'] ?? ($data['entryDt'] ?? '')];
}
 
$html = [];
foreach ($channels as $channel) {
// 동의: 년월일시분초까지 / 미동의: 년월일까지 (일시 없으면 괄호 생략)
if ($channel['flag'] === 'y') {
$label = '동의함' . ($channel['dt'] !== '' ? '(' . DateTimeUtils::dateFormat('Y-m-d H:i:s', $channel['dt']) . ')' : '');
} else {
$label = '동의안함' . ($channel['dt'] !== '' ? '(' . DateTimeUtils::dateFormat('Y-m-d', $channel['dt']) . ')' : '');
}
$html[] = '<div>- ' . $channel['label'] . ' : ' . $label . '</div>';
}
 
return implode('', $html);
}
 
/**
* 로그인 되었는 지를 체크 (회원/비회원)
*
$data['agreementInfoFl'] = gd_isset($arrData['agreementInfoFl'], 'n');
$data['privateApprovalFl'] = gd_isset($arrData['privateApprovalFl'], 'n');
$data['under14ConsentFl'] = gd_isset($arrData['under14ConsentFl'], 'n');
// 광고성 수신 동의 (이메일 수신 동의 / 모바일 메시지 수신 동의)
$data['maillingFl'] = gd_isset($arrData['maillingFl'], 'n');
$data['smsFl'] = gd_isset($arrData['smsFl'], 'n');
 
//이용약관 체크값 설정
$myPage = \App::load('\\Component\\Member\\MyPage');
$agreementData = $myPage->setAgreementData($arrData);
$data['privateApprovalOptionFl'] = gd_isset($agreementData['privateApprovalOptionFl']);
$data['privateOfferFl'] = gd_isset($agreementData['privateOfferFl']);
$data['privateConsignFl'] = gd_isset($agreementData['privateConsignFl']);
// 마케팅 목적 개인정보 수집 및 이용 동의
$data['privateMarketingConsentOptionFl'] = gd_isset($agreementData['privateMarketingConsentOptionFl']);
 
// 인증설정체크해서 데이터 추가 useDataJoinFl
$dreamInfo = gd_policy('member.auth_cellphone');
$params['sexFl'] = $params['sexFl'] ?? '';
$params['maillingFl'] = $params['maillingFl'] ?? '';
$params['smsFl'] = $params['smsFl'] ?? '';
$params['privateMarketingConsentOptionFl'] = $params['privateMarketingConsentOptionFl'] ?? '';
$params['calendarFl'] = $params['calendarFl'] ?? '';
$params['expirationFl'] = $params['expirationFl'] ?? '';
 
$checked['sexFl'][$params['sexFl']] =
$checked['maillingFl'][$params['maillingFl']] =
$checked['smsFl'][$params['smsFl']] =
$checked['privateMarketingConsentOptionFl'][$params['privateMarketingConsentOptionFl']] =
$checked['calendarFl'][$params['calendarFl']] =
$checked['expirationFl'][$params['expirationFl']] = 'checked="checked"';
 
 
Controller/Admin/Member/MemberModifyController.php+27-3
변경 전MemberModifyController.php
}
$memberService->getMemberDataWithChecked($memNo, $memberData, $checked);
$memberData = array_merge($memberData, $memberService->getLastAgreementNotificationByMember($memNo));
$privateApprovalOption = $buyerInformService->getInformDataArray(\Component\Agreement\BuyerInformCode::PRIVATE_APPROVAL_OPTION, 'sno,informNm,content', true, $memberData['mallSno']);
$privateOffer = $buyerInformService->getInformDataArray(\Component\Agreement\BuyerInformCode::PRIVATE_OFFER, 'sno,informNm,content', true, $memberData['mallSno']);
$privateConsign = $buyerInformService->getInformDataArray(\Component\Agreement\BuyerInformCode::PRIVATE_CONSIGN, 'sno,informNm,content', true, $memberData['mallSno']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$memberData = array_merge($memberData, $historyService->getLastReceiveAgreementByMember($memNo));
 
 
$memberHistory = $historyService->getMemberHistory($memNo, $request->get()->get('page', 1), $request->get()->get('pageNum', 10));
$memberData['recommendCnt'] = $memberService->getRecommendCount($memberData['memId']);
if ($memberData['rncheck'] == 'realname') {
$this->setData('privateApprovalOption', $privateApprovalOption);
$this->setData('privateOffer', $privateOffer);
$this->setData('privateConsign', $privateConsign);
 
 
 
 
 
$this->setData('groupCouponConditionManual', gd_policy('member.group')['couponConditionManual']);
$this->setData('hidePasswordBlock', $hidePasswordBlock);
$this->setData('certification', $certification);
 
변경 후MemberModifyController.php
}
$memberService->getMemberDataWithChecked($memNo, $memberData, $checked);
$memberData = array_merge($memberData, $memberService->getLastAgreementNotificationByMember($memNo));
$privateApprovalOption = $buyerInformService->getInformDataArray(\Component\Agreement\BuyerInformCode::PRIVATE_APPROVAL_OPTION, 'sno,informNm,content,modeFl', true, $memberData['mallSno']);
$privateOffer = $buyerInformService->getInformDataArray(\Component\Agreement\BuyerInformCode::PRIVATE_OFFER, 'sno,informNm,content,modeFl', true, $memberData['mallSno']);
$privateConsign = $buyerInformService->getInformDataArray(\Component\Agreement\BuyerInformCode::PRIVATE_CONSIGN, 'sno,informNm,content,modeFl', true, $memberData['mallSno']);
$privateMarketingMember = $buyerInformService->getInformDataArray(\Component\Agreement\BuyerInformCode::PRIVATE_MARKETING_MEMBER, 'sno,informNm,content,modeFl', true, $memberData['mallSno']);
$privateMarketingMemberUse = (($privateMarketingMember[0]['modeFl'] ?? 'n') === 'y');
// 개인정보 동의 항목별 마지막 변경 일시(컬럼 공통). 이력 없으면 가입일(entryDt) 폴백
$privateAgreementDt = $historyService->getLastPrivateAgreementDateByMember((int) $memNo);
$memberEntryDt = $memberData['entryDt'] ?? '';
// 약관 동의 표시 행 조립 (개인정보 항목별/마케팅). 렌더는 MemberUtil::makePrivateAgreementField
$privateAgreements = [
['title' => '개인정보 수집&middot;이용', 'use' => is_array($memberData['privateApprovalOptionFl'] ?? null), 'informs' => $privateApprovalOption, 'flags' => $memberData['privateApprovalOptionFl'] ?? [], 'denyWhenMissing' => false, 'agreementDt' => $privateAgreementDt['privateApprovalOptionFl'] ?? $memberEntryDt],
['title' => '개인정보 취급위탁', 'use' => is_array($memberData['privateConsignFl'] ?? null), 'informs' => $privateConsign, 'flags' => $memberData['privateConsignFl'] ?? [], 'denyWhenMissing' => false, 'agreementDt' => $privateAgreementDt['privateConsignFl'] ?? $memberEntryDt],
['title' => '개인정보 제3자 제공', 'use' => is_array($memberData['privateOfferFl'] ?? null), 'informs' => $privateOffer, 'flags' => $memberData['privateOfferFl'] ?? [], 'denyWhenMissing' => false, 'agreementDt' => $privateAgreementDt['privateOfferFl'] ?? $memberEntryDt],
['title' => '마케팅 목적 개인정보 수집 및 이용 동의', 'use' => $privateMarketingMemberUse, 'informs' => $privateMarketingMember, 'flags' => $memberData['privateMarketingConsentOptionFl'] ?? '', 'denyWhenMissing' => true, 'agreementDt' => $privateAgreementDt['privateMarketingConsentOptionFl'] ?? $memberEntryDt],
];
$advertisingReceiveChannelUse = $buyerInformService->getAdvertisingReceiveChannelUse($memberData['mallSno']);
$advertisingReceive = [
'email' => ['use' => $advertisingReceiveChannelUse['mail']],
'mobile' => ['use' => $advertisingReceiveChannelUse['sms']],
];
$memberData = 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') {
$this->setData('privateApprovalOption', $privateApprovalOption);
$this->setData('privateOffer', $privateOffer);
$this->setData('privateConsign', $privateConsign);
$this->setData('privateMarketingMember', $privateMarketingMember);
$this->setData('privateMarketingMemberUse', $privateMarketingMemberUse);
$this->setData('privateAgreementHtml', \Component\Member\Util\MemberUtil::makePrivateAgreementField($privateAgreements));
$this->setData('advertisingReceive', $advertisingReceive);
$this->setData('advertisingReceiveHtml', \Component\Member\Util\MemberUtil::makeAdvertisingReceiveField($advertisingReceive, $memberData));
$this->setData('groupCouponConditionManual', gd_policy('member.group')['couponConditionManual']);
$this->setData('hidePasswordBlock', $hidePasswordBlock);
$this->setData('certification', $certification);
 
Controller/Admin/Member/MemberPsController.php+26
변경 전MemberPsController.php
use Framework\Debug\Exception\LayerException;
use Origin\Service\Policy\Member\JoinPolicyService;
use Origin\Service\Member\KakaoSync\KakaoSyncSettingService;
 
 
 
/**
* Class 회원 처리
 
switch ($requestAllParams['mode']) {
case 'register':
 
 
 
 
$memberService->register(new MemberVO($requestPostParams));
$this->json(__("회원등록을 성공하였습니다."));
break;
case 'modify':
 
 
 
 
$memberAdminService->modifyMemberData($requestAllParams);
$this->json(__('저장이 완료되었습니다.'));
break;
throw new Exception(__('요청을 처리할 페이지를 찾을 수 없습니다.'), 404);
break;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
} catch (Exception $e) {
if ($request->isAjax() === true) {
switch ($e->getCode()) {
 
변경 후MemberPsController.php
use Framework\Debug\Exception\LayerException;
use Origin\Service\Policy\Member\JoinPolicyService;
use Origin\Service\Member\KakaoSync\KakaoSyncSettingService;
use Respect\Validation\Exceptions\NestedValidationException;
use Respect\Validation\Validator;
 
/**
* Class 회원 처리
 
switch ($requestAllParams['mode']) {
case 'register':
// 마케팅 목적 개인정보 수집 및 이용 동의 형식 검증
Validator::arrayVal()
->key('privateMarketingConsentOptionFl', Validator::in(['y', 'n']), false)
->assert($requestAllParams);
$memberService->register(new MemberVO($requestPostParams));
$this->json(__("회원등록을 성공하였습니다."));
break;
case 'modify':
// 마케팅 목적 개인정보 수집 및 이용 동의 형식 검증
Validator::arrayVal()
->key('privateMarketingConsentOptionFl', Validator::in(['y', 'n']), false)
->assert($requestAllParams);
$memberAdminService->modifyMemberData($requestAllParams);
$this->json(__('저장이 완료되었습니다.'));
break;
throw new Exception(__('요청을 처리할 페이지를 찾을 수 없습니다.'), 404);
break;
}
} catch (NestedValidationException $e) {
\Logger::channel('member')->warning('member.validate.fail', [
'mode' => $requestAllParams['mode'] ?? '',
'errors' => $e->getMessages(),
]);
if ($request->isAjax()) {
$this->json(
[
'success' => false,
'message' => __('잘못된 요청입니다.'),
'data' => []
]
);
} else {
throw new LayerException(__('잘못된 요청입니다.'), $e->getCode(), $e, null, 3000);
}
} catch (Exception $e) {
if ($request->isAjax() === true) {
switch ($e->getCode()) {
 
Controller/Admin/Member/MemberRegisterController.php+32-4
변경 전MemberRegisterController.php
['title' => '마케팅 목적 개인정보 수집 및 이용 동의', 'use' => false],
];
 
// 광고성 수신 동의 채널 사용여부 (신규 회원은 동의 이력 없음 → 채널 사용 시 '동의안함', 미사용 시 '사용안함')
$buyerInformService = \App::getInstance('BuyerInform');
if (!is_object($buyerInformService)) {
$buyerInformService = new \Component\Agreement\BuyerInform();
}
$mallSno = (int) (\Component\Mall\Mall::getSession('sno') ?: DEFAULT_MALL_NUMBER);
$advertisingReceiveChannelUse = $buyerInformService->getAdvertisingReceiveChannelUse($mallSno);
 
$advertisingReceive = [
'email' => ['use' => $advertisingReceiveChannelUse['mail']],
'mobile' => ['use' => $advertisingReceiveChannelUse['sms']],
];
 
// 마케팅 목적 개인정보 수집 및 이용 동의 약관 사용 여부 (약관 사용 시에만 노출)
$companyCertification = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$this->setData('mode', 'register');
$this->setData('joinField', $joinField);
$this->setData('htmlExtra', MemberUtil::makeExtraField());
 
 
 
 
$this->setData('data', $member);
$this->setData('checked', $vo->toChecked());
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
변경 후MemberRegisterController.php
['title' => '마케팅 목적 개인정보 수집 및 이용 동의', 'use' => false],
];
 
 
$buyerInformService = \App::getInstance('BuyerInform');
if (!is_object($buyerInformService)) {
$buyerInformService = new \Component\Agreement\BuyerInform();
}
$mallSno = (int) (\Component\Mall\Mall::getSession('sno') ?: DEFAULT_MALL_NUMBER);
 
// 신규 회원은 동의 이력이 없으므로 광고성 수신 동의도 '사용안함' (몰 설정과 무관)
$advertisingReceive = [
'email' => ['use' => 'n'],
'mobile' => ['use' => 'n'],
];
 
// 마케팅 목적 개인정보 수집 및 이용 동의 약관 사용 여부 (약관 사용 시에만 노출)
$companyCertification = \App::getInstance(\Component\Member\Company\CompanyCertification::class);
$certificationMaxFileSize = $companyCertification->getCompanyCertificationFileSize();
 
// 신규 회원은 동의 이력이 없으므로 전부 '사용안함'
$privateAgreements = [
['title' => '개인정보<br/>수집&middot;이용', 'use' => false],
['title' => '개인정보 취급위탁', 'use' => false],
['title' => '개인정보<br/>제3자 제공', 'use' => false],
['title' => '마케팅 목적 개인정보 수집 및 이용 동의', 'use' => false],
];
 
// 광고성 수신 동의 채널 사용여부 (신규 회원은 동의 이력 없음 → 채널 사용 시 '동의안함', 미사용 시 '사용안함')
$buyerInformService = \App::getInstance('BuyerInform');
if (!is_object($buyerInformService)) {
$buyerInformService = new \Component\Agreement\BuyerInform();
}
$mallSno = (int) (\Component\Mall\Mall::getSession('sno') ?: DEFAULT_MALL_NUMBER);
$advertisingReceiveChannelUse = $buyerInformService->getAdvertisingReceiveChannelUse($mallSno);
$advertisingReceive = [
'email' => ['use' => $advertisingReceiveChannelUse['mail']],
'mobile' => ['use' => $advertisingReceiveChannelUse['sms']],
];
 
// 마케팅 목적 개인정보 수집 및 이용 동의 약관 사용 여부 (약관 사용 시에만 노출)
$privateMarketingMember = $buyerInformService->getInformDataArray(\Component\Agreement\BuyerInformCode::PRIVATE_MARKETING_MEMBER, 'sno,informNm,content,modeFl', true, $mallSno);
$privateMarketingMemberUse = (($privateMarketingMember[0]['modeFl'] ?? 'n') === 'y');
 
$this->setData('mode', 'register');
$this->setData('joinField', $joinField);
$this->setData('htmlExtra', MemberUtil::makeExtraField());
$this->setData('privateAgreementHtml', MemberUtil::makePrivateAgreementField($privateAgreements));
$this->setData('advertisingReceive', $advertisingReceive);
$this->setData('advertisingReceiveHtml', MemberUtil::makeAdvertisingReceiveField($advertisingReceive, $member));
$this->setData('privateMarketingMemberUse', $privateMarketingMemberUse);
$this->setData('data', $member);
$this->setData('checked', $vo->toChecked());
$this->setData('certificationMaxFileSize', $certificationMaxFileSize);
 
Controller/Admin/Policy/BaseAgreementWithPrivateController.php+12
변경 전BaseAgreementWithPrivateController.php
$privateApprovalTableOption = $agreementWithPrivateUtil->getTableByPrivateApprovalOption($mallSno);
$privateConsignTable = $agreementWithPrivateUtil->getTableByPrivateConsign($mallSno);
$privateOfferTable = $agreementWithPrivateUtil->getTableByPrivateOffer($mallSno);
 
 
 
 
 
 
$privateGuestOrder = $buyerInform->getInformData(BuyerInformCode::PRIVATE_GUEST_ORDER, $mallSno);
$privateGuestBoardWrite = $buyerInform->getInformData(BuyerInformCode::PRIVATE_GUEST_BOARD_WRITE, $mallSno);
$privateGuestCommentWrite = $buyerInform->getInformData(BuyerInformCode::PRIVATE_GUEST_COMMENT_WRITE, $mallSno);
$this->setData('privateApprovalTableOption', $privateApprovalTableOption);
$this->setData('privateConsignTable', $privateConsignTable);
$this->setData('privateOfferTable', $privateOfferTable);
 
 
 
 
 
 
$this->setData('privateGuestOrderContent', $privateGuestOrder['content']);
$this->setData('privateGuestBoardWriteContent', $privateGuestBoardWrite['content']);
$this->setData('privateGuestCommentWriteContent', $privateGuestCommentWrite['content']);
 
변경 후BaseAgreementWithPrivateController.php
$privateApprovalTableOption = $agreementWithPrivateUtil->getTableByPrivateApprovalOption($mallSno);
$privateConsignTable = $agreementWithPrivateUtil->getTableByPrivateConsign($mallSno);
$privateOfferTable = $agreementWithPrivateUtil->getTableByPrivateOffer($mallSno);
$privateMarketingMember = $buyerInform->getInformData(BuyerInformCode::PRIVATE_MARKETING_MEMBER, $mallSno);
$advertisingReceive = $buyerInform->getInformData(BuyerInformCode::ADVERTISING_RECEIVE, $mallSno);
//--- 광고성 수신 동의 채널 사용여부 (es_config member.advertisingReceive) 및 회원가입 항목(이메일/휴대폰번호) 사용여부
$advertisingReceiveChannel = gd_policy('member.advertisingReceive', $mallSno);
$joinItemPolicy = \App::load('Component\\Policy\\JoinItemPolicy');
$joinItem = $joinItemPolicy->getPolicy($mallSno);
$privateGuestOrder = $buyerInform->getInformData(BuyerInformCode::PRIVATE_GUEST_ORDER, $mallSno);
$privateGuestBoardWrite = $buyerInform->getInformData(BuyerInformCode::PRIVATE_GUEST_BOARD_WRITE, $mallSno);
$privateGuestCommentWrite = $buyerInform->getInformData(BuyerInformCode::PRIVATE_GUEST_COMMENT_WRITE, $mallSno);
$this->setData('privateApprovalTableOption', $privateApprovalTableOption);
$this->setData('privateConsignTable', $privateConsignTable);
$this->setData('privateOfferTable', $privateOfferTable);
$this->setData('privateMarketingMember', $privateMarketingMember);
$this->setData('advertisingReceive', $advertisingReceive);
$this->setData('advertisingReceiveMailUse', $advertisingReceiveChannel['email']['use'] ?? 'n');
$this->setData('advertisingReceiveSmsUse', $advertisingReceiveChannel['mobile']['use'] ?? 'n');
$this->setData('joinItemEmailUse', $joinItem['email']['use'] ?? 'n');
$this->setData('joinItemCellPhoneUse', $joinItem['cellPhone']['use'] ?? 'n');
$this->setData('privateGuestOrderContent', $privateGuestOrder['content']);
$this->setData('privateGuestBoardWriteContent', $privateGuestBoardWrite['content']);
$this->setData('privateGuestCommentWriteContent', $privateGuestCommentWrite['content']);
 
Controller/Admin/Policy/BaseAgreementWithPrivatePsController.php+35-2
변경 전BaseAgreementWithPrivatePsController.php
use Framework\Debug\Exception\LayerException;
use Origin\Service\Member\KakaoSync\KakaoSyncSettingService;
use Request;
 
 
 
/**
* Class 약관/개인정보설정 처리 페이지
break;
// --- 개인정보수집 동의항목 설정
case 'privateItem':
 
 
 
 
 
 
 
 
\DB::begin_tran();
 
 
 
 
 
 
 
$removeSnoArray = json_decode(Request::post()->get('removeSno', []));
$mallSno = gd_isset(Request::post()->get('mallSno'), 1);
foreach ($removeSnoArray as $key => $val) {
$buyerInform->savePrivateConsign(Request::post()->all());
$buyerInform->savePrivateOffer(Request::post()->all());
$buyerInform->saveInformData(BuyerInformCode::PRIVATE_MARKETING, Request::post()->get('privateMarketingWriteWrite'));
 
 
 
 
 
 
// 카카오 싱크 update 토필 발행
$kakaoSyncSettingService = \App::getInstance(KakaoSyncSettingService::class);
$kakaoSyncSettingService->syncSettingWhenSaveTerms();
\DB::commit();
 
 
 
 
 
 
 
 
$this->json(
[
'message' => __('저장이 완료되었습니다.'),
'code' => 200,
]
);
throw new Exception(__('요청을 처리할 페이지를 찾을 수 없습니다.'), 404);
break;
}
 
 
 
} catch (Exception $e) {
\DB::rollback();
if (Request::isAjax()) {
 
변경 후BaseAgreementWithPrivatePsController.php
use Framework\Debug\Exception\LayerException;
use Origin\Service\Member\KakaoSync\KakaoSyncSettingService;
use Request;
use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\Validator;
 
/**
* Class 약관/개인정보설정 처리 페이지
break;
// --- 개인정보수집 동의항목 설정
case 'privateItem':
// post 유효성 검사
Validator::arrayVal()
->key('privateMarketingMemberFl', Validator::in(['y', 'n']), false)
->key('privateMarketingMemberNoticePopupFl', Validator::in(['y', 'n']), false)
->key('advertisingReceiveMailFl', Validator::in(['y', 'n']), false)
->key('advertisingReceiveSmsFl', Validator::in(['y', 'n']), false)
->assert(Request::post()->all());
 
\DB::begin_tran();
 
// [선택] 광고성 수신 동의 채널을 사용하면서 [선택] 마케팅 목적 개인정보 수집 및 이용 동의를 사용하지 않으면 저장 차단
$advertisingUse = Request::post()->get('advertisingReceiveMailFl', 'n') === 'y' || Request::post()->get('advertisingReceiveSmsFl', 'n') === 'y';
if ($advertisingUse && Request::post()->get('privateMarketingMemberFl', 'n') !== 'y') {
throw new Exception(__("[선택] 마케팅 목적 개인정보 수집 및 이용 동의 약관을 '사용'으로 설정해주세요. [선택] 광고성 수신 동의 약관을 사용하기 위해서는 [선택] 마케팅 목적 개인정보 수집 및 이용 동의 약관을 반드시 사용해야 합니다."), 400);
}
 
$removeSnoArray = json_decode(Request::post()->get('removeSno', []));
$mallSno = gd_isset(Request::post()->get('mallSno'), 1);
foreach ($removeSnoArray as $key => $val) {
$buyerInform->savePrivateConsign(Request::post()->all());
$buyerInform->savePrivateOffer(Request::post()->all());
$buyerInform->saveInformData(BuyerInformCode::PRIVATE_MARKETING, Request::post()->get('privateMarketingWriteWrite'));
$buyerInform->saveInformData(BuyerInformCode::PRIVATE_MARKETING_MEMBER, Request::post()->get('privateMarketingMemberWriteWrite'), $mallSno);
$buyerInform->saveInformData(BuyerInformCode::ADVERTISING_RECEIVE, Request::post()->get('advertisingReceiveWriteWrite'), $mallSno);
 
$advertisingReceiveChannels = $buyerInform->resolveAdvertisingReceiveChannels(Request::post()->all(), (int)$mallSno);
$policy->setValue('member.advertisingReceive', $advertisingReceiveChannels, $mallSno);
 
// 카카오 싱크 update 토필 발행
$kakaoSyncSettingService = \App::getInstance(KakaoSyncSettingService::class);
$kakaoSyncSettingService->syncSettingWhenSaveTerms();
 
\DB::commit();
 
// [선택] 마케팅 목적 개인정보 수집 및 이용 동의를 사용하면서 [선택] 광고성 수신 동의를 사용하지 않으면 안내 문구 노출
$message = __('저장이 완료되었습니다.');
$marketingMemberUse = Request::post()->get('privateMarketingMemberFl', 'n') === 'y';
$advertisingUse = Request::post()->get('advertisingReceiveMailFl', 'n') === 'y' || Request::post()->get('advertisingReceiveSmsFl', 'n') === 'y';
if ($marketingMemberUse && !$advertisingUse) {
$message .= ' ' . __('[선택] 마케팅 목적 개인정보 수집 및 이용 동의 약관만 사용하시면 광고성 메시지를 발송할 수 없습니다. 광고성 메시지를 보내시려면 [선택] 광고성 수신 동의 약관도 함께 사용해주세요.');
}
$this->json(
[
'message' => $message,
'code' => 200,
]
);
throw new Exception(__('요청을 처리할 페이지를 찾을 수 없습니다.'), 404);
break;
}
} catch (ValidationException $e) {
\Logger::channel('agreement')->warning(__METHOD__, ['error' => $e->getMessage()]);
$this->json(['error' => ['code' => 400, 'message' => __('잘못된 요청입니다.')]]);
} catch (Exception $e) {
\DB::rollback();
if (Request::isAjax()) {
 
Controller/Admin/Share/MemberCrmDetailController.php+29-4
변경 전MemberCrmDetailController.php
 
$session->set(Member::SESSION_MODIFY_MEMBER_INFO, $memberData);
//@formatter:off
$checked = SkinUtils::setChecked(['memberFl', 'appFl', 'maillingFl', 'smsFl', 'sexFl', 'marriFl', 'expirationFl',], $memberData);
//@formatter:on
$memberData['privateApprovalOptionFl'] = json_decode(stripslashes($memberData['privateApprovalOptionFl']), true);
$memberData['privateOfferFl'] = json_decode(stripslashes($memberData['privateOfferFl']), true);
 
/** @var \Bundle\Component\Agreement\BuyerInform $buyerInform */
$buyerInform = App::load('\\Component\\Agreement\\BuyerInform');
$privateApprovalOption = $buyerInform->getInformDataArray(BuyerInformCode::PRIVATE_APPROVAL_OPTION, 'sno,informNm,content', true, $memberData['mallSno']);
$privateOffer = $buyerInform->getInformDataArray(BuyerInformCode::PRIVATE_OFFER, 'sno,informNm,content', true, $memberData['mallSno']);
$privateConsign = $buyerInform->getInformDataArray(BuyerInformCode::PRIVATE_CONSIGN, 'sno,informNm,content', true, $memberData['mallSno']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// 하이픈 제거
$memberData['fax'] = str_replace("-", "", $memberData['fax']);
$this->setData('modeTxt', '회원수정');
$this->setData('joinField', MemberUtil::getJoinField($memberData['mallSno']));
$this->setData('htmlExtra', MemberUtil::makeExtraField($memberData));
 
$this->setData('data', $memberData);
$this->setData('checked', $checked);
$this->setData('history', $memberHistory['data']);
$this->setData('privateApprovalOption', $privateApprovalOption);
$this->setData('privateOffer', $privateOffer);
$this->setData('privateConsign', $privateConsign);
 
 
 
 
$this->setData('groupCouponConditionManual', gd_policy('member.group')['couponConditionManual']);
$this->setData('hidePasswordBlock', $hidePasswordBlock);
$this->setData('certification', $certification);
 
변경 후MemberCrmDetailController.php
 
$session->set(Member::SESSION_MODIFY_MEMBER_INFO, $memberData);
//@formatter:off
$checked = SkinUtils::setChecked(['memberFl', 'appFl', 'maillingFl', 'smsFl', 'sexFl', 'marriFl', 'expirationFl', 'privateMarketingConsentOptionFl',], $memberData);
//@formatter:on
$memberData['privateApprovalOptionFl'] = json_decode(stripslashes($memberData['privateApprovalOptionFl']), true);
$memberData['privateOfferFl'] = json_decode(stripslashes($memberData['privateOfferFl']), true);
 
/** @var \Bundle\Component\Agreement\BuyerInform $buyerInform */
$buyerInform = App::load('\\Component\\Agreement\\BuyerInform');
$privateApprovalOption = $buyerInform->getInformDataArray(BuyerInformCode::PRIVATE_APPROVAL_OPTION, 'sno,informNm,content,modeFl', true, $memberData['mallSno']);
$privateOffer = $buyerInform->getInformDataArray(BuyerInformCode::PRIVATE_OFFER, 'sno,informNm,content,modeFl', true, $memberData['mallSno']);
$privateConsign = $buyerInform->getInformDataArray(BuyerInformCode::PRIVATE_CONSIGN, 'sno,informNm,content,modeFl', true, $memberData['mallSno']);
$privateMarketingMember = $buyerInform->getInformDataArray(BuyerInformCode::PRIVATE_MARKETING_MEMBER, 'sno,informNm,content,modeFl', true, $memberData['mallSno']);
$privateMarketingMemberUse = (($privateMarketingMember[0]['modeFl'] ?? 'n') === 'y');
 
// 개인정보 동의 항목별 마지막 변경 일시(컬럼 공통). 이력 없으면 가입일(entryDt) 폴백
$privateAgreementDt = $history->getLastPrivateAgreementDateByMember((int) $memberNo);
$memberEntryDt = $memberData['entryDt'] ?? '';
// 약관 동의 표시 행 조립 (개인정보 항목별/마케팅). 렌더는 MemberUtil::makePrivateAgreementField
$privateAgreements = [
['title' => '개인정보 수집&middot;이용', 'use' => is_array($memberData['privateApprovalOptionFl'] ?? null), 'informs' => $privateApprovalOption, 'flags' => $memberData['privateApprovalOptionFl'] ?? [], 'denyWhenMissing' => false, 'agreementDt' => $privateAgreementDt['privateApprovalOptionFl'] ?? $memberEntryDt],
['title' => '개인정보 취급위탁', 'use' => is_array($memberData['privateConsignFl'] ?? null), 'informs' => $privateConsign, 'flags' => $memberData['privateConsignFl'] ?? [], 'denyWhenMissing' => false, 'agreementDt' => $privateAgreementDt['privateConsignFl'] ?? $memberEntryDt],
['title' => '개인정보 제3자 제공', 'use' => is_array($memberData['privateOfferFl'] ?? null), 'informs' => $privateOffer, 'flags' => $memberData['privateOfferFl'] ?? [], 'denyWhenMissing' => false, 'agreementDt' => $privateAgreementDt['privateOfferFl'] ?? $memberEntryDt],
['title' => '마케팅 목적 개인정보 수집 및 이용 동의', 'use' => $privateMarketingMemberUse, 'informs' => $privateMarketingMember, 'flags' => $memberData['privateMarketingConsentOptionFl'] ?? '', 'denyWhenMissing' => true, 'agreementDt' => $privateAgreementDt['privateMarketingConsentOptionFl'] ?? $memberEntryDt],
];
$advertisingReceiveChannelUse = $buyerInform->getAdvertisingReceiveChannelUse($memberData['mallSno']);
$advertisingReceive = [
'email' => ['use' => $advertisingReceiveChannelUse['mail']],
'mobile' => ['use' => $advertisingReceiveChannelUse['sms']],
];
// 마케팅 목적 개인정보 수집 및 이용 동의/거부일 (없으면 '-')
$memberData['privateMktAgreementDt'] = $memberData['lastReceiveAgreementDt']['privateMkt'] ?? '-';
 
// 하이픈 제거
$memberData['fax'] = str_replace("-", "", $memberData['fax']);
$this->setData('modeTxt', '회원수정');
$this->setData('joinField', MemberUtil::getJoinField($memberData['mallSno']));
$this->setData('htmlExtra', MemberUtil::makeExtraField($memberData));
$this->setData('privateMarketingMemberUse', $privateMarketingMemberUse);
$this->setData('data', $memberData);
$this->setData('checked', $checked);
$this->setData('history', $memberHistory['data']);
$this->setData('privateApprovalOption', $privateApprovalOption);
$this->setData('privateOffer', $privateOffer);
$this->setData('privateConsign', $privateConsign);
$this->setData('privateMarketingMember', $privateMarketingMember);
$this->setData('privateAgreementHtml', MemberUtil::makePrivateAgreementField($privateAgreements));
$this->setData('advertisingReceive', $advertisingReceive);
$this->setData('advertisingReceiveHtml', MemberUtil::makeAdvertisingReceiveField($advertisingReceive, $memberData));
$this->setData('groupCouponConditionManual', gd_policy('member.group')['couponConditionManual']);
$this->setData('hidePasswordBlock', $hidePasswordBlock);
$this->setData('certification', $certification);
 
Controller/Front/Member/JoinAgreementController.php+9
변경 전JoinAgreementController.php
$privateApprovalOption = $inform->getInformDataArray(BuyerInformCode::PRIVATE_APPROVAL_OPTION);
$privateConsign = $inform->getInformDataArray(BuyerInformCode::PRIVATE_CONSIGN);
$privateOffer = $inform->getInformDataArray(BuyerInformCode::PRIVATE_OFFER);
 
 
 
 
$ipinConfig = gd_policy('member.ipin');
$authCellPhoneConfig = gd_get_auth_cellphone_info();
$memberJoinConfig = gd_policy('member.join');
$this->setData('privateApprovalOption', $privateApprovalOption);
$this->setData('privateConsign', $privateConsign);
$this->setData('privateOffer', $privateOffer);
 
 
 
 
 
 
 
// debug($memberJoinConfig);
 
변경 후JoinAgreementController.php
$privateApprovalOption = $inform->getInformDataArray(BuyerInformCode::PRIVATE_APPROVAL_OPTION);
$privateConsign = $inform->getInformDataArray(BuyerInformCode::PRIVATE_CONSIGN);
$privateOffer = $inform->getInformDataArray(BuyerInformCode::PRIVATE_OFFER);
// 마케팅 목적 개인정보 수집 및 이용 동의 / 광고성 수신 동의
$privateMarketingMember = $inform->getInformData(BuyerInformCode::PRIVATE_MARKETING_MEMBER);
$advertisingReceive = $inform->getAdvertisingReceiveContentWithReplaceCode();
$advertisingReceiveChannelUse = $inform->getAdvertisingReceiveChannelUse();
$ipinConfig = gd_policy('member.ipin');
$authCellPhoneConfig = gd_get_auth_cellphone_info();
$memberJoinConfig = gd_policy('member.join');
$this->setData('privateApprovalOption', $privateApprovalOption);
$this->setData('privateConsign', $privateConsign);
$this->setData('privateOffer', $privateOffer);
$this->setData('privateMarketingMember', $privateMarketingMember);
$this->setData('advertisingReceive', $advertisingReceive);
$this->setData('advertisingReceiveMailUse', $advertisingReceiveChannelUse['mail']);
$this->setData('advertisingReceiveSmsUse', $advertisingReceiveChannelUse['sms']);
$this->setData('isUseAdvertisingReceive', $inform->isUseAdvertisingReceive());
 
 
// debug($memberJoinConfig);
 
Controller/Front/Member/LoginPsController.php+7
변경 전LoginPsController.php
\DB::rollback();
$logger->info(__METHOD__ . ', ' . $e->getFile() . '[' . $e->getLine() . '], ' . $e->getMessage());
}
 
 
 
 
 
 
 
}
if($message){
throw new AlertRedirectException($message, 0, null, $returnUrl);
 
변경 후LoginPsController.php
\DB::rollback();
$logger->info(__METHOD__ . ', ' . $e->getFile() . '[' . $e->getLine() . '], ' . $e->getMessage());
}
 
// 마케팅 목적 개인정보 수집 및 이용 동의 안내 (미동의 회원 로그인 시 계정당 1회, 확인 후 마이페이지 이동)
// my_page.php는 진입 시 비밀번호 재확인을 요구하므로 게이트인 my_page_password.php로 직접 보낸다(이중 alert/리다이렉트 방지).
if (empty($message) && $member->markPrivateMarketingConsentNoticeShown()) {
$message = __('마케팅 이메일 및 모바일 메시지 수신을 위해 개인정보 수집 및 이용에 동의해 주세요.');
$returnUrl = '../mypage/my_page_password.php';
}
}
if($message){
throw new AlertRedirectException($message, 0, null, $returnUrl);
 
Controller/Front/Mypage/MyPageController.php+8
변경 전MyPageController.php
$this->setData('privateApprovalOption', $inform->getInformDataArray(BuyerInformCode::PRIVATE_APPROVAL_OPTION));
$this->setData('privateOffer', $inform->getInformDataArray(BuyerInformCode::PRIVATE_OFFER));
$this->setData('privateConsign', $inform->getInformDataArray(BuyerInformCode::PRIVATE_CONSIGN));
 
 
 
 
 
 
 
 
$this->setData('snsConnection', json_encode($snsConnection));
$this->setData('usePaycoLogin', $paycoPolicy->usePaycoLogin());
$this->setData('useNaverLogin', $naverPolicy->useNaverLogin());
 
변경 후MyPageController.php
$this->setData('privateApprovalOption', $inform->getInformDataArray(BuyerInformCode::PRIVATE_APPROVAL_OPTION));
$this->setData('privateOffer', $inform->getInformDataArray(BuyerInformCode::PRIVATE_OFFER));
$this->setData('privateConsign', $inform->getInformDataArray(BuyerInformCode::PRIVATE_CONSIGN));
$this->setData('privateMktApprovalOption', $inform->getInformDataArray(BuyerInformCode::PRIVATE_MARKETING_MEMBER));
$this->setData('advertisingReceive', $inform->getAdvertisingReceiveContentWithReplaceCode((int)$mallSno));
// 광고성 수신 동의 채널(이메일/모바일) 노출 여부
$advertisingReceiveChannelUse = $inform->getAdvertisingReceiveChannelUse((int)$mallSno);
$this->setData('advertisingReceiveMailUse', $advertisingReceiveChannelUse['mail']);
$this->setData('advertisingReceiveSmsUse', $advertisingReceiveChannelUse['sms']);
// 광고성 수신 동의 블록 노출 = 채널 하나라도 사용 (es_buyerInform modeFl 아님)
$this->setData('isUseAdvertisingReceive', $inform->isUseAdvertisingReceive((int)$mallSno));
$this->setData('snsConnection', json_encode($snsConnection));
$this->setData('usePaycoLogin', $paycoPolicy->usePaycoLogin());
$this->setData('useNaverLogin', $naverPolicy->useNaverLogin());
 
Controller/Front/Service/AgreementController.php+6
변경 전AgreementController.php
case BuyerInformCode::PRIVATE_APPROVAL:
$terms = $inform->getInformData(BuyerInformCode::PRIVATE_APPROVAL);
break;
 
 
 
 
 
 
case BuyerInformCode::BASE_PRIVATE:
$terms = $inform->getPrivateWithReplaceCode(BuyerInformCode::BASE_PRIVATE);
break;
 
변경 후AgreementController.php
case BuyerInformCode::PRIVATE_APPROVAL:
$terms = $inform->getInformData(BuyerInformCode::PRIVATE_APPROVAL);
break;
case BuyerInformCode::PRIVATE_MARKETING_MEMBER:
$terms = $inform->getInformData(BuyerInformCode::PRIVATE_MARKETING_MEMBER);
break;
case BuyerInformCode::ADVERTISING_RECEIVE:
$terms = $inform->getAdvertisingReceiveContentWithReplaceCode();
break;
case BuyerInformCode::BASE_PRIVATE:
$terms = $inform->getPrivateWithReplaceCode(BuyerInformCode::BASE_PRIVATE);
break;
 
data/skin/front/moment/img/icon/board/icon_reset.png
변경 전icon_reset.png
Binary files /dev/null and b/user/data/skin/front/moment/img/icon/board/icon_reset.png differ
 
변경 후icon_reset.png
Binary files /dev/null and b/user/data/skin/front/moment/img/icon/board/icon_reset.png differ
 
data/skin/front/moment/member/join_agreement.html+176-1
변경 전join_agreement.html
</div>
<!-- {/} -->
<!-- //join_agreement_box -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<div class="important_check_box">
<strong class="important_check dn">{=__('이용약관과 개인정보 수집 및 이용에 대한 안내 모두 동의해주세요.')}</strong>
</div>
$('.js_terms_view :checkbox', $formTerms).change(function (e) {
$('strong.important_check').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.js_terms_view');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5');
var isTargetChecked = $target.prop('checked') === true;
if (isTargetChecked) {
if (isTermsAgreeSelect) {
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/*
* 14세 동의 항목 체크박스 이벤트
*/
}
});
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
});
</script>
{ # footer }
 
변경 후join_agreement.html
</div>
<!-- {/} -->
<!-- //join_agreement_box -->
 
<!-- {? privateMarketingMember['modeFl']=='y'} -->
<div class="join_agreement_box js_terms_view">
<div class="form_element">
<input type="checkbox" id="termsAgree6" name=""/>
<label class="check_s" for="termsAgree6"><strong class="choice">({=__('선택')})</strong> {=__('마케팅 목적 개인정보 수집 및 이용 동의')} </label>
<span><a href="../service/agreement.php?code={privateMarketingMember['informCd']}" target="_blank">{=__('전체보기')}</a></span>
</div>
<div class="agreement_choice_box">
<table summary="{=__('마케팅 목적 개인정보 수집 및 이용 동의 내용입니다.')}" border="0" cellpadding="0" cellspacing="0">
<colgroup>
<col width="10px">
<col width="300px">
</colgroup>
<thead>
<tr>
<th>{=__('선택')}</th>
<th>{=nl2br(privateMarketingMember['informNm'])}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="form_element">
<input type="checkbox" id="privateMktApprovalOption" name="privateMarketingConsentOptionFl"/>
<label class="check_s" for="privateMktApprovalOption">{=__('선택')}</label>
</div>
</td>
<td>{=nl2br(privateMarketingMember['content'])}</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- {/} -->
<!-- //join_agreement_box -->
 
<!-- {? isUseAdvertisingReceive} -->
<div class="join_agreement_box js_terms_view">
<div class="form_element">
<input type="checkbox" id="termsAgree7" name=""/>
<label class="check_s" for="termsAgree7"><strong class="choice">({=__('선택')})</strong> {=__('광고성 수신 동의')} </label>
<span><a href="../service/agreement.php?code={advertisingReceive['informCd']}" target="_blank">{=__('전체보기')}</a></span>
</div>
<div class="agreement_choice_box">
<table summary="{=__('광고성 수신 동의 내용입니다.')}" border="0" cellpadding="0" cellspacing="0">
<colgroup>
<col width="10px">
<col width="300px">
</colgroup>
<thead>
<tr>
<th>{=__('선택')}</th>
<th>{=nl2br(advertisingReceive['informNm'])}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="form_element">
<input type="checkbox" id="advertisingReceiveAll" name=""/>
<label class="check_s" for="advertisingReceiveAll">{=__('선택')}</label>
</div>
</td>
<td>{=nl2br(advertisingReceive['content'])}</td>
</tr>
</tbody>
</table>
<div class="js_advertising_channel_box" style="display:flex; flex-direction:column; align-items:flex-start; margin:10px;">
<!-- {? advertisingReceiveMailUse=='y'} -->
<div class="form_element">
<input type="checkbox" id="maillingFl" name="maillingFl" class="js_advertising_channel"/>
<label class="check_s" for="maillingFl">{=__('이메일 수신 동의')}</label>
</div>
<!-- {/} -->
<!-- {? advertisingReceiveSmsUse=='y'} -->
<div class="form_element">
<input type="checkbox" id="smsFl" name="smsFl" class="js_advertising_channel"/>
<label class="check_s" for="smsFl">{=__('모바일 메시지 수신 동의')}</label>
</div>
<!-- {/} -->
</div>
</div>
</div>
<!-- {/} -->
<!-- //join_agreement_box -->
 
<div class="important_check_box">
<strong class="important_check dn">{=__('이용약관과 개인정보 수집 및 이용에 대한 안내 모두 동의해주세요.')}</strong>
</div>
$('.js_terms_view :checkbox', $formTerms).change(function (e) {
$('strong.important_check').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.js_terms_view');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5') || (e.target.id === 'termsAgree6') || (e.target.id === 'termsAgree7');
var isTargetChecked = $target.prop('checked') === true;
if (isTargetChecked) {
if (isTermsAgreeSelect) {
}
});
 
/*
* 광고성 수신 동의 ↔ 이메일/모바일 수신 동의 ↔ 마케팅 목적 개인정보 수집 및 이용 동의 연동
* - 광고성 수신 동의 체크 → 이메일/모바일 채널 일괄 + 마케팅 목적 동의 ON
* - 채널(1개 이상) 체크 → 광고성 수신 동의 + 마케팅 목적 동의 ON (채널은 각각 개별 토글)
*/
const checkMarketingApproval = function () {
$('#privateMktApprovalOption', $formTerms).prop('checked', true).val('y').siblings('label').addClass('on');
$('#termsAgree6', $formTerms).prop('checked', true).siblings('label').addClass('on');
};
// 마케팅 목적 개인정보 수집 및 이용 동의 체크 시 광고성 수신 동의·수신 채널 일괄 선택
const checkAdvertising = function () {
if ($('#termsAgree7', $formTerms).length === 0) {
return;
}
$('#termsAgree7', $formTerms).prop('checked', true).siblings('label').addClass('on');
$('#advertisingReceiveAll', $formTerms).prop('checked', true).siblings('label').addClass('on');
$('.js_advertising_channel', $formTerms).prop('checked', true).val('y').siblings('label').addClass('on');
};
$formTerms.on('change', '#termsAgree7', function () {
const isChecked = $(this).prop('checked') === true;
$(this).siblings('label').toggleClass('on', isChecked);
$('#advertisingReceiveAll', $formTerms).prop('checked', isChecked)
.siblings('label').toggleClass('on', isChecked);
$('.js_advertising_channel', $formTerms).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formTerms.on('change', '#advertisingReceiveAll', function () {
const isChecked = $(this).prop('checked') === true;
$('.js_advertising_channel', $formTerms).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
} else {
$('#termsAgree7', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '.js_advertising_channel', function () {
const anyChannelChecked = $('.js_advertising_channel:checked', $formTerms).length > 0;
$('#advertisingReceiveAll', $formTerms).prop('checked', anyChannelChecked)
.siblings('label').toggleClass('on', anyChannelChecked);
if (anyChannelChecked) {
checkMarketingApproval();
}
if ($(this).prop('checked') === false) {
$('#termsAgree7', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '#privateMktApprovalOption', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
} else {
$('#termsAgree6', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '#termsAgree6', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
}
});
 
/*
* 14세 동의 항목 체크박스 이벤트
*/
}
});
}
 
// 그룹 하위 항목이 모두 선택되면 상위 [선택] 헤더(termsAgree3~7)도 선택 (하나라도 해제 시 해제)
$formTerms.on('change', '.js_terms_view .agreement_choice_box :checkbox', function () {
const $termsView = $(this).closest('.js_terms_view');
const $header = $termsView.children('.form_element').children(':checkbox');
const $subs = $termsView.find('.agreement_choice_box :checkbox');
const allChecked = $subs.length > 0 && $subs.not(':checked').length === 0;
$header.prop('checked', allChecked).siblings('label').toggleClass('on', allChecked);
});
 
/*
* 전체 동의 역동기화 — 하위 체크박스가 모두 선택되면 전체 동의도 선택 (하나라도 해제되면 해제)
*/
const syncAllAgree = function () {
const $targets = $(':checkbox', $formTerms).not('#allAgree').not('#termsAgree');
const allChecked = $targets.length > 0 && $targets.not(':checked').length === 0;
$('#allAgree', $formTerms).prop('checked', allChecked)
.siblings('label').toggleClass('on', allChecked);
};
$formTerms.on('change', ':checkbox', function (e) {
if (e.target.id === 'allAgree' || e.target.id === 'termsAgree') {
return;
}
syncAllAgree();
});
});
</script>
{ # footer }
 
data/skin/front/moment/member/_join_view.html-12
변경 전_join_view.html
</select>
</div>
<div class="member_warning js_email"></div>
<!--{? joinField.maillingFl.use === 'y'}-->
<div class="form_element">
<input type="checkbox" id="maillingFl" name="maillingFl" value="y" {? data.maillingFl == 'y'}checked="checked"{/}/>
<label for="maillingFl" class="check_s {? data.maillingFl == 'y'}on{/}">{=__('정보/이벤트 메일 수신에 동의합니다.')}</label>
</div>
<!--{/}-->
</td>
</tr>
<!--{/}-->
<!--{ / }-->
<!--{ / }-->
</div>
<!--{? joinField.smsFl.use === 'y'}-->
<div class="form_element">
<input type="checkbox" id="smsFl" name="smsFl" value="y" {? data.smsFl == 'y'}checked="checked"{/}/>
<label for="smsFl" class="check_s {? data.smsFl == 'y'}on{/}">{=__('정보/이벤트 SMS 수신에 동의합니다.')}</label>
</div>
<!--{/}-->
</td>
</tr>
<!--{/}-->
 
변경 후_join_view.html
</select>
</div>
<div class="member_warning js_email"></div>
 
 
 
 
 
 
</td>
</tr>
<!--{/}-->
<!--{ / }-->
<!--{ / }-->
</div>
 
 
 
 
 
 
</td>
</tr>
<!--{/}-->
 
data/skin/front/moment/member/_join_view_other.html+98-1
변경 전_join_view_other.html
<!--{/}-->
 
<!-- N : 약관동의 시작 -->
<!--{? privateApprovalOption[0]['modeFl'] == 'y' || privateConsign[0]['modeFl']=='y' || privateOffer[0]['modeFl']=='y'}-->
<div class="join_agreement_cont">
<h3>{=__('약관동의현황')}</h3>
<!--{? privateApprovalOption[0]['modeFl'] == 'y'}-->
</div>
<!-- //join_agreement_box -->
<!--{/ // privateOffer modeFl end}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</div>
<!-- //join_agreement_cont -->
<!--{ / }-->
 
변경 후_join_view_other.html
<!--{/}-->
 
<!-- N : 약관동의 시작 -->
<!--{? privateApprovalOption[0]['modeFl'] == 'y' || privateConsign[0]['modeFl']=='y' || privateOffer[0]['modeFl']=='y' || privateMktApprovalOption[0]['modeFl']=='y' || isUseAdvertisingReceive}-->
<div class="join_agreement_cont">
<h3>{=__('약관동의현황')}</h3>
<!--{? privateApprovalOption[0]['modeFl'] == 'y'}-->
</div>
<!-- //join_agreement_box -->
<!--{/ // privateOffer modeFl end}-->
 
<!--{? privateMktApprovalOption[0]['modeFl'] == 'y'}-->
<div class="join_agreement_box">
<div class="form_element">
<input type="checkbox" id="termsAgree6"/>
<label for="termsAgree6" class="check_s"><strong class="choice">({=__('선택')})</strong> {=__('마케팅 목적 개인정보 수집 및 이용 동의')} </label>
<span><a href="../service/agreement.php?code={privateMktApprovalOption[0]['informCd']}" target="_blank">{=__('전체보기')}</a></span>
</div>
<!--{@ privateMktApprovalOption}-->
<div class="agreement_choice_box">
<table border="0" cellpadding="0" cellspacing="0" summary="{=__('마케팅 목적 개인정보 수집 및 이용 동의 내용입니다.')}">
<colgroup>
<col width="10px">
<col width="300px">
</colgroup>
<thead>
<tr>
<th>{=__('선택')}</th>
<th>{=nl2br(.informNm)}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="form_element">
<input type="checkbox" id="privateMarketingConsentOptionFl" name="privateMarketingConsentOptionFl" value="y" <!--{? data['privateMarketingConsentOptionFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="privateMarketingConsentOptionFl" class="check_s <!--{? data['privateMarketingConsentOptionFl'] == 'y'}-->on<!--{/}-->">{=__('선택')}</label>
</div>
</td>
<td>
<div class="agreement_scroll">
{=nl2br(.content)}
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!--{/ // privateMktApprovalOption loop end}-->
</div>
<!-- //join_agreement_box -->
<!--{/ // privateMktApprovalOption modeFl end}-->
 
<!--{? isUseAdvertisingReceive}-->
<div class="join_agreement_box js_terms_view">
<div class="form_element">
<input type="checkbox" id="termsAgree7"/>
<label for="termsAgree7" class="check_s"><strong class="choice">({=__('선택')})</strong> {=__('광고성 수신 동의')} </label>
<span><a href="../service/agreement.php?code={advertisingReceive['informCd']}" target="_blank">{=__('전체보기')}</a></span>
</div>
<div class="agreement_choice_box">
<table border="0" cellpadding="0" cellspacing="0" summary="{=__('광고성 수신 동의 내용입니다.')}">
<colgroup>
<col width="10px">
<col width="300px">
</colgroup>
<thead>
<tr>
<th>{=__('선택')}</th>
<th>{=nl2br(advertisingReceive['informNm'])}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="form_element">
<input type="checkbox" id="advertisingReceiveAll" <!--{? data['maillingFl'] == 'y' || data['smsFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="advertisingReceiveAll" class="check_s <!--{? data['maillingFl'] == 'y' || data['smsFl'] == 'y'}-->on<!--{/}-->">{=__('선택')}</label>
</div>
</td>
<td>
<div class="agreement_scroll">
{=nl2br(advertisingReceive['content'])}
</div>
</td>
</tr>
</tbody>
</table>
<div class="js_advertising_channel_box" style="display:flex; flex-direction:column; align-items:flex-start; margin:10px;">
<!--{? advertisingReceiveMailUse == 'y'}-->
<div class="form_element">
<input type="checkbox" id="advertisingReceiveMail" name="maillingFl" value="y" class="js_advertising_channel" <!--{? data['maillingFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="advertisingReceiveMail" class="check_s <!--{? data['maillingFl'] == 'y'}-->on<!--{/}-->">{=__('이메일 수신 동의')}</label>
</div>
<!--{/}-->
<!--{? advertisingReceiveSmsUse == 'y'}-->
<div class="form_element">
<input type="checkbox" id="advertisingReceiveSms" name="smsFl" value="y" class="js_advertising_channel" <!--{? data['smsFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="advertisingReceiveSms" class="check_s <!--{? data['smsFl'] == 'y'}-->on<!--{/}-->">{=__('모바일 메시지 수신 동의')}</label>
</div>
<!--{/}-->
</div>
</div>
<!-- //agreement_choice_box -->
</div>
<!-- //join_agreement_box -->
<!--{/ // isUseAdvertisingReceive end}-->
</div>
<!-- //join_agreement_cont -->
<!--{ / }-->
 
data/skin/front/moment/mypage/my_page.html+101-1
변경 전my_page.html
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.join_agreement_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5');
var isTargetChecked = $target.prop('checked') === true;
if (isTargetChecked) {
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
gd_select_email_domain('email');
<!--{? (joinField.marriFl.use == 'y' && joinField.marriDate.use == 'y') || joinField.birthDt.use == 'y' }-->
 
변경 후my_page.html
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.join_agreement_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5') || (e.target.id === 'termsAgree6') || (e.target.id === 'termsAgree7');
var isTargetChecked = $target.prop('checked') === true;
if (isTargetChecked) {
}
});
/*
* 광고성 수신 동의 ↔ 이메일/모바일 수신 동의 ↔ 마케팅 목적 개인정보 수집 및 이용 동의 연동
* - 광고성 수신 동의 체크 → 이메일/모바일 채널 일괄 + 마케팅 목적 동의 ON
* - 채널(1개 이상) 체크 → 광고성 수신 동의 + 마케팅 목적 동의 ON (채널은 각각 개별 토글)
*/
const checkMarketingApproval = function () {
$('#privateMarketingConsentOptionFl', $formJoin).prop('checked', true).val('y').siblings('label').addClass('on');
$('#termsAgree6', $formJoin).prop('checked', true).siblings('label').addClass('on');
};
$formJoin.on('change', '#termsAgree7', function () {
const isChecked = $(this).prop('checked') === true;
$(this).siblings('label').toggleClass('on', isChecked);
$('#advertisingReceiveAll', $formJoin).prop('checked', isChecked)
.siblings('label').toggleClass('on', isChecked);
$('.js_advertising_channel', $formJoin).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formJoin.on('change', '#advertisingReceiveAll', function () {
const isChecked = $(this).prop('checked') === true;
$('.js_advertising_channel', $formJoin).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
// 전체선택(advertisingReceiveAll) 직접 조작 시 광고성 수신 동의(termsAgree7) 헤더도 동기화
$('#termsAgree7', $formJoin).prop('checked', isChecked).siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formJoin.on('change', '.js_advertising_channel', function () {
const anyChannelChecked = $('.js_advertising_channel:checked', $formJoin).length > 0;
const allChannelChecked = $('.js_advertising_channel', $formJoin).length > 0
&& $('.js_advertising_channel:not(:checked)', $formJoin).length === 0;
$('#advertisingReceiveAll', $formJoin).prop('checked', anyChannelChecked)
.siblings('label').toggleClass('on', anyChannelChecked);
if (anyChannelChecked) {
checkMarketingApproval();
}
// 수신 채널 전부 선택 시 광고성 수신 동의(termsAgree7) 헤더 ON (일부만이면 켜지 않음)
if (allChannelChecked) {
$('#termsAgree7', $formJoin).prop('checked', true).siblings('label').addClass('on');
}
if ($(this).prop('checked') === false) {
$('#termsAgree7', $formJoin).prop('checked', false).siblings('label').removeClass('on');
}
});
// 마케팅 목적 개인정보 수집 및 이용 동의 체크 시 광고성 수신 동의·수신 채널 일괄 선택
const checkAdvertising = function () {
if ($('#termsAgree7', $formJoin).length === 0) {
return;
}
$('#termsAgree7', $formJoin).prop('checked', true).siblings('label').addClass('on');
$('#advertisingReceiveAll', $formJoin).prop('checked', true).siblings('label').addClass('on');
$('.js_advertising_channel', $formJoin).prop('checked', true).val('y').siblings('label').addClass('on');
};
$formJoin.on('change', '#privateMarketingConsentOptionFl', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
} else {
$('#termsAgree6', $formJoin).prop('checked', false).siblings('label').removeClass('on');
}
});
// 마케팅 목적 개인정보 수집 및 이용 동의 그룹 [선택] 헤더 체크 시 광고성 수신 동의·수신 채널 연동
$formJoin.on('change', '#termsAgree6', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
}
});
// 그룹 하위 항목이 모두 선택되면 상위 [선택] 헤더도 선택 (하나라도 해제 시 해제)
$formJoin.on('change', '.join_agreement_box .agreement_choice_box :checkbox', function () {
const $box = $(this).closest('.join_agreement_box');
const $header = $box.children('.form_element').children(':checkbox');
// 광고성 수신 동의(termsAgree7)는 채널 1개 이상 선택 의미라 전체 선택 동기화에서 제외
if ($header.attr('id') === 'termsAgree7') {
return;
}
const $subs = $box.find('.agreement_choice_box :checkbox');
const allChecked = $subs.length > 0 && $subs.not(':checked').length === 0;
$header.prop('checked', allChecked).siblings('label').toggleClass('on', allChecked);
});
// 초기 로드: 저장된 하위 선택 상태로 상위 [선택] 헤더 동기화
$('.join_agreement_box', $formJoin).each(function () {
const $box = $(this);
const $header = $box.children('.form_element').children(':checkbox');
// 광고성 수신 동의(termsAgree7)는 채널 1개 이상 선택 의미라 전체 선택 동기화에서 제외
if ($header.attr('id') === 'termsAgree7') {
return;
}
const $subs = $box.find('.agreement_choice_box :checkbox');
if ($subs.length > 0 && $subs.not(':checked').length === 0) {
$header.prop('checked', true).siblings('label').addClass('on');
}
});
// 초기 로드: 수신 채널이 전부 선택된 상태면 광고성 수신 동의(termsAgree7) 헤더 ON
if ($('.js_advertising_channel', $formJoin).length > 0
&& $('.js_advertising_channel:not(:checked)', $formJoin).length === 0) {
$('#termsAgree7', $formJoin).prop('checked', true).siblings('label').addClass('on');
}
gd_select_email_domain('email');
<!--{? (joinField.marriFl.use == 'y' && joinField.marriDate.use == 'y') || joinField.birthDt.use == 'y' }-->
 
data/skin/front/mygreek/member/join_agreement.html+176-1
변경 전join_agreement.html
</div>
<!-- {/} -->
<!-- //join_agreement_box -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<div class="important_check_box">
<strong class="important_check dn">{=__('이용약관과 개인정보 수집 및 이용에 대한 안내 모두 동의해주세요.')}</strong>
</div>
$('.js_terms_view :checkbox', $formTerms).change(function (e) {
$('strong.important_check').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.js_terms_view');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5');
var isTargetChecked = $target.prop('checked') === true;
if (isTargetChecked) {
if (isTermsAgreeSelect) {
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/*
* 14세 동의 항목 체크박스 이벤트
*/
}
});
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
});
</script>
{ # footer }
 
변경 후join_agreement.html
</div>
<!-- {/} -->
<!-- //join_agreement_box -->
 
<!-- {? privateMarketingMember['modeFl']=='y'} -->
<div class="join_agreement_box js_terms_view">
<div class="form_element">
<input type="checkbox" id="termsAgree6" name=""/>
<label class="check_s" for="termsAgree6"><strong class="choice">({=__('선택')})</strong> {=__('마케팅 목적 개인정보 수집 및 이용 동의')} </label>
<span><a href="../service/agreement.php?code={privateMarketingMember['informCd']}" target="_blank">{=__('전체보기')}</a></span>
</div>
<div class="agreement_choice_box">
<table summary="{=__('마케팅 목적 개인정보 수집 및 이용 동의 내용입니다.')}" border="0" cellpadding="0" cellspacing="0">
<colgroup>
<col width="10px">
<col width="300px">
</colgroup>
<thead>
<tr>
<th>{=__('선택')}</th>
<th>{=nl2br(privateMarketingMember['informNm'])}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="form_element">
<input type="checkbox" id="privateMktApprovalOption" name="privateMarketingConsentOptionFl"/>
<label class="check_s" for="privateMktApprovalOption">{=__('선택')}</label>
</div>
</td>
<td>{=nl2br(privateMarketingMember['content'])}</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- {/} -->
<!-- //join_agreement_box -->
 
<!-- {? isUseAdvertisingReceive} -->
<div class="join_agreement_box js_terms_view">
<div class="form_element">
<input type="checkbox" id="termsAgree7" name=""/>
<label class="check_s" for="termsAgree7"><strong class="choice">({=__('선택')})</strong> {=__('광고성 수신 동의')} </label>
<span><a href="../service/agreement.php?code={advertisingReceive['informCd']}" target="_blank">{=__('전체보기')}</a></span>
</div>
<div class="agreement_choice_box">
<table summary="{=__('광고성 수신 동의 내용입니다.')}" border="0" cellpadding="0" cellspacing="0">
<colgroup>
<col width="10px">
<col width="300px">
</colgroup>
<thead>
<tr>
<th>{=__('선택')}</th>
<th>{=nl2br(advertisingReceive['informNm'])}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="form_element">
<input type="checkbox" id="advertisingReceiveAll" name=""/>
<label class="check_s" for="advertisingReceiveAll">{=__('선택')}</label>
</div>
</td>
<td>{=nl2br(advertisingReceive['content'])}</td>
</tr>
</tbody>
</table>
<div class="js_advertising_channel_box" style="display:flex; flex-direction:column; align-items:flex-start; margin:10px;">
<!-- {? advertisingReceiveMailUse=='y'} -->
<div class="form_element">
<input type="checkbox" id="maillingFl" name="maillingFl" class="js_advertising_channel"/>
<label class="check_s" for="maillingFl">{=__('이메일 수신 동의')}</label>
</div>
<!-- {/} -->
<!-- {? advertisingReceiveSmsUse=='y'} -->
<div class="form_element">
<input type="checkbox" id="smsFl" name="smsFl" class="js_advertising_channel"/>
<label class="check_s" for="smsFl">{=__('모바일 메시지 수신 동의')}</label>
</div>
<!-- {/} -->
</div>
</div>
</div>
<!-- {/} -->
<!-- //join_agreement_box -->
 
<div class="important_check_box">
<strong class="important_check dn">{=__('이용약관과 개인정보 수집 및 이용에 대한 안내 모두 동의해주세요.')}</strong>
</div>
$('.js_terms_view :checkbox', $formTerms).change(function (e) {
$('strong.important_check').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.js_terms_view');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5') || (e.target.id === 'termsAgree6') || (e.target.id === 'termsAgree7');
var isTargetChecked = $target.prop('checked') === true;
if (isTargetChecked) {
if (isTermsAgreeSelect) {
}
});
 
/*
* 광고성 수신 동의 ↔ 이메일/모바일 수신 동의 ↔ 마케팅 목적 개인정보 수집 및 이용 동의 연동
* - 광고성 수신 동의 체크 → 이메일/모바일 채널 일괄 + 마케팅 목적 동의 ON
* - 채널(1개 이상) 체크 → 광고성 수신 동의 + 마케팅 목적 동의 ON (채널은 각각 개별 토글)
*/
const checkMarketingApproval = function () {
$('#privateMktApprovalOption', $formTerms).prop('checked', true).val('y').siblings('label').addClass('on');
$('#termsAgree6', $formTerms).prop('checked', true).siblings('label').addClass('on');
};
// 마케팅 목적 개인정보 수집 및 이용 동의 체크 시 광고성 수신 동의·수신 채널 일괄 선택
const checkAdvertising = function () {
if ($('#termsAgree7', $formTerms).length === 0) {
return;
}
$('#termsAgree7', $formTerms).prop('checked', true).siblings('label').addClass('on');
$('#advertisingReceiveAll', $formTerms).prop('checked', true).siblings('label').addClass('on');
$('.js_advertising_channel', $formTerms).prop('checked', true).val('y').siblings('label').addClass('on');
};
$formTerms.on('change', '#termsAgree7', function () {
const isChecked = $(this).prop('checked') === true;
$(this).siblings('label').toggleClass('on', isChecked);
$('#advertisingReceiveAll', $formTerms).prop('checked', isChecked)
.siblings('label').toggleClass('on', isChecked);
$('.js_advertising_channel', $formTerms).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formTerms.on('change', '#advertisingReceiveAll', function () {
const isChecked = $(this).prop('checked') === true;
$('.js_advertising_channel', $formTerms).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
} else {
$('#termsAgree7', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '.js_advertising_channel', function () {
const anyChannelChecked = $('.js_advertising_channel:checked', $formTerms).length > 0;
$('#advertisingReceiveAll', $formTerms).prop('checked', anyChannelChecked)
.siblings('label').toggleClass('on', anyChannelChecked);
if (anyChannelChecked) {
checkMarketingApproval();
}
if ($(this).prop('checked') === false) {
$('#termsAgree7', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '#privateMktApprovalOption', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
} else {
$('#termsAgree6', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '#termsAgree6', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
}
});
 
/*
* 14세 동의 항목 체크박스 이벤트
*/
}
});
}
 
// 그룹 하위 항목이 모두 선택되면 상위 [선택] 헤더(termsAgree3~7)도 선택 (하나라도 해제 시 해제)
$formTerms.on('change', '.js_terms_view .agreement_choice_box :checkbox', function () {
const $termsView = $(this).closest('.js_terms_view');
const $header = $termsView.children('.form_element').children(':checkbox');
const $subs = $termsView.find('.agreement_choice_box :checkbox');
const allChecked = $subs.length > 0 && $subs.not(':checked').length === 0;
$header.prop('checked', allChecked).siblings('label').toggleClass('on', allChecked);
});
 
/*
* 전체 동의 역동기화 — 하위 체크박스가 모두 선택되면 전체 동의도 선택 (하나라도 해제되면 해제)
*/
const syncAllAgree = function () {
const $targets = $(':checkbox', $formTerms).not('#allAgree').not('#termsAgree');
const allChecked = $targets.length > 0 && $targets.not(':checked').length === 0;
$('#allAgree', $formTerms).prop('checked', allChecked)
.siblings('label').toggleClass('on', allChecked);
};
$formTerms.on('change', ':checkbox', function (e) {
if (e.target.id === 'allAgree' || e.target.id === 'termsAgree') {
return;
}
syncAllAgree();
});
});
</script>
{ # footer }
 
data/skin/front/mygreek/member/_join_view.html-12
변경 전_join_view.html
</select>
</div>
<div class="member_warning js_email"></div>
<!--{? joinField.maillingFl.use === 'y'}-->
<div class="form_element">
<input type="checkbox" id="maillingFl" name="maillingFl" value="y" {? data.maillingFl == 'y'}checked="checked"{/}/>
<label for="maillingFl" class="check_s {? data.maillingFl == 'y'}on{/}">{=__('정보/이벤트 메일 수신에 동의합니다.')}</label>
</div>
<!--{/}-->
</td>
</tr>
<!--{/}-->
<!--{ / }-->
<!--{ / }-->
</div>
<!--{? joinField.smsFl.use === 'y'}-->
<div class="form_element">
<input type="checkbox" id="smsFl" name="smsFl" value="y" {? data.smsFl == 'y'}checked="checked"{/}/>
<label for="smsFl" class="check_s {? data.smsFl == 'y'}on{/}">{=__('정보/이벤트 SMS 수신에 동의합니다.')}</label>
</div>
<!--{/}-->
</td>
</tr>
<!--{/}-->
 
변경 후_join_view.html
</select>
</div>
<div class="member_warning js_email"></div>
 
 
 
 
 
 
</td>
</tr>
<!--{/}-->
<!--{ / }-->
<!--{ / }-->
</div>
 
 
 
 
 
 
</td>
</tr>
<!--{/}-->
 
data/skin/front/mygreek/member/_join_view_other.html+98-1
변경 전_join_view_other.html
<!--{/}-->
 
<!-- N : 약관동의 시작 -->
<!--{? privateApprovalOption[0]['modeFl'] == 'y' || privateConsign[0]['modeFl']=='y' || privateOffer[0]['modeFl']=='y'}-->
<div class="join_agreement_cont">
<h3>{=__('약관동의현황')}</h3>
<!--{? privateApprovalOption[0]['modeFl'] == 'y'}-->
</div>
<!-- //join_agreement_box -->
<!--{/ // privateOffer modeFl end}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</div>
<!-- //join_agreement_cont -->
<!--{ / }-->
 
변경 후_join_view_other.html
<!--{/}-->
 
<!-- N : 약관동의 시작 -->
<!--{? privateApprovalOption[0]['modeFl'] == 'y' || privateConsign[0]['modeFl']=='y' || privateOffer[0]['modeFl']=='y' || privateMktApprovalOption[0]['modeFl']=='y' || isUseAdvertisingReceive}-->
<div class="join_agreement_cont">
<h3>{=__('약관동의현황')}</h3>
<!--{? privateApprovalOption[0]['modeFl'] == 'y'}-->
</div>
<!-- //join_agreement_box -->
<!--{/ // privateOffer modeFl end}-->
 
<!--{? privateMktApprovalOption[0]['modeFl'] == 'y'}-->
<div class="join_agreement_box">
<div class="form_element">
<input type="checkbox" id="termsAgree6"/>
<label for="termsAgree6" class="check_s"><strong class="choice">({=__('선택')})</strong> {=__('마케팅 목적 개인정보 수집 및 이용 동의')} </label>
<span><a href="../service/agreement.php?code={privateMktApprovalOption[0]['informCd']}" target="_blank">{=__('전체보기')}</a></span>
</div>
<!--{@ privateMktApprovalOption}-->
<div class="agreement_choice_box">
<table border="0" cellpadding="0" cellspacing="0" summary="{=__('마케팅 목적 개인정보 수집 및 이용 동의 내용입니다.')}">
<colgroup>
<col width="10px">
<col width="300px">
</colgroup>
<thead>
<tr>
<th>{=__('선택')}</th>
<th>{=nl2br(.informNm)}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="form_element">
<input type="checkbox" id="privateMarketingConsentOptionFl" name="privateMarketingConsentOptionFl" value="y" <!--{? data['privateMarketingConsentOptionFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="privateMarketingConsentOptionFl" class="check_s <!--{? data['privateMarketingConsentOptionFl'] == 'y'}-->on<!--{/}-->">{=__('선택')}</label>
</div>
</td>
<td>
<div class="agreement_scroll">
{=nl2br(.content)}
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!--{/ // privateMktApprovalOption loop end}-->
</div>
<!-- //join_agreement_box -->
<!--{/ // privateMktApprovalOption modeFl end}-->
 
<!--{? isUseAdvertisingReceive}-->
<div class="join_agreement_box js_terms_view">
<div class="form_element">
<input type="checkbox" id="termsAgree7"/>
<label for="termsAgree7" class="check_s"><strong class="choice">({=__('선택')})</strong> {=__('광고성 수신 동의')} </label>
<span><a href="../service/agreement.php?code={advertisingReceive['informCd']}" target="_blank">{=__('전체보기')}</a></span>
</div>
<div class="agreement_choice_box">
<table border="0" cellpadding="0" cellspacing="0" summary="{=__('광고성 수신 동의 내용입니다.')}">
<colgroup>
<col width="10px">
<col width="300px">
</colgroup>
<thead>
<tr>
<th>{=__('선택')}</th>
<th>{=nl2br(advertisingReceive['informNm'])}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="form_element">
<input type="checkbox" id="advertisingReceiveAll" <!--{? data['maillingFl'] == 'y' || data['smsFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="advertisingReceiveAll" class="check_s <!--{? data['maillingFl'] == 'y' || data['smsFl'] == 'y'}-->on<!--{/}-->">{=__('선택')}</label>
</div>
</td>
<td>
<div class="agreement_scroll">
{=nl2br(advertisingReceive['content'])}
</div>
</td>
</tr>
</tbody>
</table>
<div class="js_advertising_channel_box" style="display:flex; flex-direction:column; align-items:flex-start; margin:10px;">
<!--{? advertisingReceiveMailUse == 'y'}-->
<div class="form_element">
<input type="checkbox" id="advertisingReceiveMail" name="maillingFl" value="y" class="js_advertising_channel" <!--{? data['maillingFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="advertisingReceiveMail" class="check_s <!--{? data['maillingFl'] == 'y'}-->on<!--{/}-->">{=__('이메일 수신 동의')}</label>
</div>
<!--{/}-->
<!--{? advertisingReceiveSmsUse == 'y'}-->
<div class="form_element">
<input type="checkbox" id="advertisingReceiveSms" name="smsFl" value="y" class="js_advertising_channel" <!--{? data['smsFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="advertisingReceiveSms" class="check_s <!--{? data['smsFl'] == 'y'}-->on<!--{/}-->">{=__('모바일 메시지 수신 동의')}</label>
</div>
<!--{/}-->
</div>
</div>
<!-- //agreement_choice_box -->
</div>
<!-- //join_agreement_box -->
<!--{/ // isUseAdvertisingReceive end}-->
</div>
<!-- //join_agreement_cont -->
<!--{ / }-->
 
data/skin/front/mygreek/mypage/my_page.html+101-1
변경 전my_page.html
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.join_agreement_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
gd_select_email_domain('email');
 
<!--{? (joinField.marriFl.use == 'y' && joinField.marriDate.use == 'y') || joinField.birthDt.use == 'y' }-->
 
변경 후my_page.html
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.join_agreement_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5') || (e.target.id === 'termsAgree6') || (e.target.id === 'termsAgree7');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
}
});
 
/*
* 광고성 수신 동의 ↔ 이메일/모바일 수신 동의 ↔ 마케팅 목적 개인정보 수집 및 이용 동의 연동
* - 광고성 수신 동의 체크 → 이메일/모바일 채널 일괄 + 마케팅 목적 동의 ON
* - 채널(1개 이상) 체크 → 광고성 수신 동의 + 마케팅 목적 동의 ON (채널은 각각 개별 토글)
*/
const checkMarketingApproval = function () {
$('#privateMarketingConsentOptionFl', $formJoin).prop('checked', true).val('y').siblings('label').addClass('on');
$('#termsAgree6', $formJoin).prop('checked', true).siblings('label').addClass('on');
};
$formJoin.on('change', '#termsAgree7', function () {
const isChecked = $(this).prop('checked') === true;
$(this).siblings('label').toggleClass('on', isChecked);
$('#advertisingReceiveAll', $formJoin).prop('checked', isChecked)
.siblings('label').toggleClass('on', isChecked);
$('.js_advertising_channel', $formJoin).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formJoin.on('change', '#advertisingReceiveAll', function () {
const isChecked = $(this).prop('checked') === true;
$('.js_advertising_channel', $formJoin).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
// 전체선택(advertisingReceiveAll) 직접 조작 시 광고성 수신 동의(termsAgree7) 헤더도 동기화
$('#termsAgree7', $formJoin).prop('checked', isChecked).siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formJoin.on('change', '.js_advertising_channel', function () {
const anyChannelChecked = $('.js_advertising_channel:checked', $formJoin).length > 0;
const allChannelChecked = $('.js_advertising_channel', $formJoin).length > 0
&& $('.js_advertising_channel:not(:checked)', $formJoin).length === 0;
$('#advertisingReceiveAll', $formJoin).prop('checked', anyChannelChecked)
.siblings('label').toggleClass('on', anyChannelChecked);
if (anyChannelChecked) {
checkMarketingApproval();
}
// 수신 채널 전부 선택 시 광고성 수신 동의(termsAgree7) 헤더 ON (일부만이면 켜지 않음)
if (allChannelChecked) {
$('#termsAgree7', $formJoin).prop('checked', true).siblings('label').addClass('on');
}
if ($(this).prop('checked') === false) {
$('#termsAgree7', $formJoin).prop('checked', false).siblings('label').removeClass('on');
}
});
// 마케팅 목적 개인정보 수집 및 이용 동의 체크 시 광고성 수신 동의·수신 채널 일괄 선택
const checkAdvertising = function () {
if ($('#termsAgree7', $formJoin).length === 0) {
return;
}
$('#termsAgree7', $formJoin).prop('checked', true).siblings('label').addClass('on');
$('#advertisingReceiveAll', $formJoin).prop('checked', true).siblings('label').addClass('on');
$('.js_advertising_channel', $formJoin).prop('checked', true).val('y').siblings('label').addClass('on');
};
$formJoin.on('change', '#privateMarketingConsentOptionFl', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
} else {
$('#termsAgree6', $formJoin).prop('checked', false).siblings('label').removeClass('on');
}
});
// 마케팅 목적 개인정보 수집 및 이용 동의 그룹 [선택] 헤더 체크 시 광고성 수신 동의·수신 채널 연동
$formJoin.on('change', '#termsAgree6', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
}
});
// 그룹 하위 항목이 모두 선택되면 상위 [선택] 헤더도 선택 (하나라도 해제 시 해제)
$formJoin.on('change', '.join_agreement_box .agreement_choice_box :checkbox', function () {
const $box = $(this).closest('.join_agreement_box');
const $header = $box.children('.form_element').children(':checkbox');
// 광고성 수신 동의(termsAgree7)는 채널 1개 이상 선택 의미라 전체 선택 동기화에서 제외
if ($header.attr('id') === 'termsAgree7') {
return;
}
const $subs = $box.find('.agreement_choice_box :checkbox');
const allChecked = $subs.length > 0 && $subs.not(':checked').length === 0;
$header.prop('checked', allChecked).siblings('label').toggleClass('on', allChecked);
});
// 초기 로드: 저장된 하위 선택 상태로 상위 [선택] 헤더 동기화
$('.join_agreement_box', $formJoin).each(function () {
const $box = $(this);
const $header = $box.children('.form_element').children(':checkbox');
// 광고성 수신 동의(termsAgree7)는 채널 1개 이상 선택 의미라 전체 선택 동기화에서 제외
if ($header.attr('id') === 'termsAgree7') {
return;
}
const $subs = $box.find('.agreement_choice_box :checkbox');
if ($subs.length > 0 && $subs.not(':checked').length === 0) {
$header.prop('checked', true).siblings('label').addClass('on');
}
});
// 초기 로드: 수신 채널이 전부 선택된 상태면 광고성 수신 동의(termsAgree7) 헤더 ON
if ($('.js_advertising_channel', $formJoin).length > 0
&& $('.js_advertising_channel:not(:checked)', $formJoin).length === 0) {
$('#termsAgree7', $formJoin).prop('checked', true).siblings('label').addClass('on');
}
 
gd_select_email_domain('email');
 
<!--{? (joinField.marriFl.use == 'y' && joinField.marriDate.use == 'y') || joinField.birthDt.use == 'y' }-->
 
data/skin/front/story_g/member/join_agreement.html+185-1
변경 전join_agreement.html
</div>
</div>
<!-- {/} -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<p class="msg dn">
<span>{=__('이용약관과 개인정보 수집 및 이용에 대한 안내 모두 동의해주세요.')}</span>
</p>
$('.terms-view :checkbox', $formTerms).change(function (e) {
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.terms-view');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/*
* 14세 동의 항목 체크박스 이벤트
*/
}
});
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
});
</script>
{ # footer }
 
변경 후join_agreement.html
</div>
</div>
<!-- {/} -->
<!-- {? privateMarketingMember['modeFl']=='y'} -->
<div class="terms-view">
<p>
<input type="checkbox" class="checkbox" id="termsAgree6" name="">
<label for="termsAgree6">
<span class="option"><strong>({=__('선택')})</strong></span>
{=__('마케팅 목적 개인정보 수집 및 이용 동의')}
</label>
<a href="../service/agreement.php?code={privateMarketingMember['informCd']}" target="_blank">{=__('전체보기')}</a>
</p>
<div class="consignment-box">
<table summary="{=__('마케팅 목적 개인정보 수집 및 이용 동의 내용입니다.')}" class="" cellspacing="0" border="1">
<colgroup>
<col width="79px">
<col>
</colgroup>
<thead>
<tr>
<th scope="col">{=__('선택')}</th>
<th scope="col">{=nl2br(privateMarketingMember['informNm'])}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span class="form-element">
<input type="checkbox" class="checkbox" id="privateMktApprovalOption" name="privateMarketingConsentOptionFl">
<label for="privateMktApprovalOption">{=__('선택')}</label>
</span>
</td>
<td>
<div>
{=nl2br(privateMarketingMember['content'])}
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- {/} -->
<!-- {? isUseAdvertisingReceive} -->
<div class="terms-view">
<p>
<input type="checkbox" class="checkbox" id="termsAgree7" name="">
<label for="termsAgree7">
<span class="option"><strong>({=__('선택')})</strong></span>
{=__('광고성 수신 동의')}
</label>
<a href="../service/agreement.php?code={advertisingReceive['informCd']}" target="_blank">{=__('전체보기')}</a>
</p>
<div class="consignment-box">
<table summary="{=__('광고성 수신 동의 내용입니다.')}" class="" cellspacing="0" border="1">
<colgroup>
<col width="79px">
<col>
</colgroup>
<thead>
<tr>
<th scope="col">{=__('선택')}</th>
<th scope="col">{=nl2br(advertisingReceive['informNm'])}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span class="form-element">
<input type="checkbox" class="checkbox" id="advertisingReceiveAll" name="">
<label for="advertisingReceiveAll">{=__('선택')}</label>
</span>
</td>
<td>
<div>
{=nl2br(advertisingReceive['content'])}
</div>
</td>
</tr>
</tbody>
</table>
<div class="js_advertising_channel_box" style="display:flex; flex-direction:column; align-items:flex-start; gap:8px; margin:10px;">
<!-- {? advertisingReceiveMailUse=='y'} -->
<span class="form-element">
<input type="checkbox" class="checkbox js_advertising_channel" id="maillingFl" name="maillingFl">
<label for="maillingFl">{=__('이메일 수신 동의')}</label>
</span>
<!-- {/} -->
<!-- {? advertisingReceiveSmsUse=='y'} -->
<span class="form-element">
<input type="checkbox" class="checkbox js_advertising_channel" id="smsFl" name="smsFl">
<label for="smsFl">{=__('모바일 메시지 수신 동의')}</label>
</span>
<!-- {/} -->
</div>
</div>
</div>
<!-- {/} -->
<p class="msg dn">
<span>{=__('이용약관과 개인정보 수집 및 이용에 대한 안내 모두 동의해주세요.')}</span>
</p>
$('.terms-view :checkbox', $formTerms).change(function (e) {
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.terms-view');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5') || (e.target.id === 'termsAgree6') || (e.target.id === 'termsAgree7');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
}
});
 
/*
* 광고성 수신 동의 ↔ 이메일/모바일 수신 동의 ↔ 마케팅 목적 개인정보 수집 및 이용 동의 연동
* - 광고성 수신 동의 체크 → 이메일/모바일 채널 일괄 + 마케팅 목적 동의 ON
* - 채널(1개 이상) 체크 → 광고성 수신 동의 + 마케팅 목적 동의 ON (채널은 각각 개별 토글)
*/
const checkMarketingApproval = function () {
$('#privateMktApprovalOption', $formTerms).prop('checked', true).val('y').siblings('label').addClass('on');
$('#termsAgree6', $formTerms).prop('checked', true).siblings('label').addClass('on');
};
// 마케팅 목적 개인정보 수집 및 이용 동의 체크 시 광고성 수신 동의·수신 채널 일괄 선택
const checkAdvertising = function () {
if ($('#termsAgree7', $formTerms).length === 0) {
return;
}
$('#termsAgree7', $formTerms).prop('checked', true).siblings('label').addClass('on');
$('#advertisingReceiveAll', $formTerms).prop('checked', true).siblings('label').addClass('on');
$('.js_advertising_channel', $formTerms).prop('checked', true).val('y').siblings('label').addClass('on');
};
$formTerms.on('change', '#termsAgree7', function () {
const isChecked = $(this).prop('checked') === true;
$(this).siblings('label').toggleClass('on', isChecked);
$('#advertisingReceiveAll', $formTerms).prop('checked', isChecked)
.siblings('label').toggleClass('on', isChecked);
$('.js_advertising_channel', $formTerms).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formTerms.on('change', '#advertisingReceiveAll', function () {
const isChecked = $(this).prop('checked') === true;
$('.js_advertising_channel', $formTerms).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
} else {
$('#termsAgree7', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '.js_advertising_channel', function () {
const anyChannelChecked = $('.js_advertising_channel:checked', $formTerms).length > 0;
$('#advertisingReceiveAll', $formTerms).prop('checked', anyChannelChecked)
.siblings('label').toggleClass('on', anyChannelChecked);
if (anyChannelChecked) {
checkMarketingApproval();
}
if ($(this).prop('checked') === false) {
$('#termsAgree7', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '#privateMktApprovalOption', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
} else {
$('#termsAgree6', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '#termsAgree6', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
}
});
 
/*
* 14세 동의 항목 체크박스 이벤트
*/
}
});
}
 
// 그룹 하위 항목이 모두 선택되면 상위 [선택] 헤더(termsAgree3~7)도 선택 (하나라도 해제 시 해제)
$formTerms.on('change', '.terms-view .consignment-box :checkbox', function () {
const $termsView = $(this).closest('.terms-view');
const $header = $termsView.children('p').children(':checkbox');
const $subs = $termsView.find('.consignment-box :checkbox');
const allChecked = $subs.length > 0 && $subs.not(':checked').length === 0;
$header.prop('checked', allChecked).siblings('label').toggleClass('on', allChecked);
});
 
/*
* 전체 동의 역동기화 — 하위 체크박스가 모두 선택되면 전체 동의도 선택 (하나라도 해제되면 해제)
*/
const syncAllAgree = function () {
const $targets = $(':checkbox', $formTerms).not('#allAgree').not('#termsAgree');
const allChecked = $targets.length > 0 && $targets.not(':checked').length === 0;
$('#allAgree', $formTerms).prop('checked', allChecked)
.siblings('label').toggleClass('on', allChecked);
};
$formTerms.on('change', ':checkbox', function (e) {
if (e.target.id === 'allAgree' || e.target.id === 'termsAgree') {
return;
}
syncAllAgree();
});
});
</script>
{ # footer }
 
data/skin/front/story_g/member/_join_view.html-12
변경 전_join_view.html
</select>
</div>
</div>
<!--{? joinField.maillingFl.use === 'y'}-->
<div class="form-element">
<input type="checkbox" class="checkbox" id="maillingFl" name="maillingFl" value="y" {? data.maillingFl == 'y'}checked="checked"{/}>
<label for="maillingFl" class="{? data.maillingFl == 'y'}on{/}">{=__('정보/이벤트 메일 수신에 동의합니다.')}</label>
</div>
<!--{/}-->
</td>
</tr>
<!--{/}--><!--{? joinField.cellPhone.use == 'y'}-->
</button>
<!--{ / }-->
<!--{ / }-->
<!--{? joinField.smsFl.use === 'y'}-->
<div class="form-element">
<input type="checkbox" class="checkbox" id="smsFl" name="smsFl" value="y" {? data.smsFl == 'y'}checked="checked"{/}>
<label for="smsFl" class="{? data.smsFl == 'y'}on{/}">{=__('정보/이벤트 SMS 수신에 동의합니다.')}</label>
</div>
<!--{/}-->
</td>
</tr>
<!--{/}--><!--{? joinField.phone.use == 'y'}-->
 
변경 후_join_view.html
</select>
</div>
</div>
 
 
 
 
 
 
</td>
</tr>
<!--{/}--><!--{? joinField.cellPhone.use == 'y'}-->
</button>
<!--{ / }-->
<!--{ / }-->
 
 
 
 
 
 
</td>
</tr>
<!--{/}--><!--{? joinField.phone.use == 'y'}-->
 
data/skin/front/story_g/member/_join_view_other.html+102
변경 전_join_view_other.html
</div>
</div>
<!--{/ // privateOffer modeFl end}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<!--{/ // isMyPage end}-->
 
변경 후_join_view_other.html
</div>
</div>
<!--{/ // privateOffer modeFl end}-->
<!--{? privateMktApprovalOption[0]['modeFl'] == 'y'}-->
<div class="terms-view">
<p>
<input type="checkbox" class="checkbox" id="termsAgree6" name="">
<label for="termsAgree6">
<span class="option">
<strong>({=__('선택')})</strong>
</span>
{=__('마케팅 목적 개인정보 수집 및 이용 동의')}
</label>
<a href="../service/agreement.php?code={privateMktApprovalOption[0]['informCd']}" target="_blank">{=__('전체보기')}</a>
</p>
<div class="consignment-box">
<!--{@ privateMktApprovalOption}-->
<table summary="{=__('마케팅 목적 개인정보 수집 및 이용 동의 내용입니다.')}" class="" cellspacing="0" border="1">
<colgroup>
<col width="79px">
<col>
</colgroup>
<thead>
<tr>
<th scope="col">{=__('선택')}</th>
<th scope="col">{=nl2br(.informNm)}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span class="form-element">
<input type="checkbox" class="checkbox" id="privateMarketingConsentOptionFl" name="privateMarketingConsentOptionFl" value="y" <!--{? data['privateMarketingConsentOptionFl'] == 'y'}-->checked="checked"<!--{/}-->>
<label class="<!--{? data['privateMarketingConsentOptionFl'] == 'y'}-->on<!--{/}-->" for="privateMarketingConsentOptionFl">{=__('선택')}</label>
</span>
</td>
<td>
<div>
{=nl2br(.content)}
</div>
</td>
</tr>
</tbody>
</table>
<!--{/ // privateMktApprovalOption loop end}-->
</div>
</div>
<!--{/ // privateMktApprovalOption modeFl end}-->
<!--{? isUseAdvertisingReceive}-->
<div class="terms-view js_terms_view">
<p>
<input type="checkbox" class="checkbox" id="termsAgree7" name="">
<label for="termsAgree7">
<span class="option">
<strong>({=__('선택')})</strong>
</span>
{=__('광고성 수신 동의')}
</label>
<a href="../service/agreement.php?code={advertisingReceive['informCd']}" target="_blank">{=__('전체보기')}</a>
</p>
<div class="consignment-box">
<table summary="{=__('광고성 수신 동의 내용입니다.')}" class="" cellspacing="0" border="1">
<colgroup>
<col width="79px">
<col>
</colgroup>
<thead>
<tr>
<th scope="col">{=__('선택')}</th>
<th scope="col">{=nl2br(advertisingReceive['informNm'])}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span class="form-element">
<input type="checkbox" class="checkbox" id="advertisingReceiveAll" <!--{? data['maillingFl'] == 'y' || data['smsFl'] == 'y'}-->checked="checked"<!--{/}-->>
<label class="<!--{? data['maillingFl'] == 'y' || data['smsFl'] == 'y'}-->on<!--{/}-->" for="advertisingReceiveAll">{=__('선택')}</label>
</span>
</td>
<td>
<div>
{=nl2br(advertisingReceive['content'])}
</div>
</td>
</tr>
</tbody>
</table>
<div class="js_advertising_channel_box" style="display:flex; flex-direction:column; align-items:flex-start; gap:8px; margin:10px;">
<!--{? advertisingReceiveMailUse == 'y'}-->
<span class="form-element">
<input type="checkbox" class="checkbox js_advertising_channel" id="advertisingReceiveMail" name="maillingFl" value="y" <!--{? data['maillingFl'] == 'y'}-->checked="checked"<!--{/}-->>
<label class="<!--{? data['maillingFl'] == 'y'}-->on<!--{/}-->" for="advertisingReceiveMail">{=__('이메일 수신 동의')}</label>
</span>
<!--{/}-->
<!--{? advertisingReceiveSmsUse == 'y'}-->
<span class="form-element">
<input type="checkbox" class="checkbox js_advertising_channel" id="advertisingReceiveSms" name="smsFl" value="y" <!--{? data['smsFl'] == 'y'}-->checked="checked"<!--{/}-->>
<label class="<!--{? data['smsFl'] == 'y'}-->on<!--{/}-->" for="advertisingReceiveSms">{=__('모바일 메시지 수신 동의')}</label>
</span>
<!--{/}-->
</div>
</div>
</div>
<!--{/ // isUseAdvertisingReceive end}-->
<!--{/ // isMyPage end}-->
 
data/skin/front/story_g/mypage/my_page.html+102-1
변경 전my_page.html
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.terms-view');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5');
var isTargetChecked = $target.prop('checked') === true;
if (isTargetChecked) {
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
select_email_domain('email');
<!--{? (joinField.marriFl.use == 'y' && joinField.marriDate.use == 'y') || joinField.birthDt.use == 'y' }-->
 
변경 후my_page.html
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.terms-view');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5') || (e.target.id === 'termsAgree6') || (e.target.id === 'termsAgree7');
var isTargetChecked = $target.prop('checked') === true;
if (isTargetChecked) {
}
});
/*
* 광고성 수신 동의 ↔ 이메일/모바일 수신 동의 ↔ 마케팅 목적 개인정보 수집 및 이용 동의 연동
* - 광고성 수신 동의 체크 → 이메일/모바일 채널 일괄 + 마케팅 목적 동의 ON
* - 채널(1개 이상) 체크 → 광고성 수신 동의 + 마케팅 목적 동의 ON (채널은 각각 개별 토글)
*/
const checkMarketingApproval = function () {
$('#privateMarketingConsentOptionFl', $formJoin).prop('checked', true).val('y').siblings('label').addClass('on');
$('#termsAgree6', $formJoin).prop('checked', true).siblings('label').addClass('on');
};
$formJoin.on('change', '#termsAgree7', function () {
const isChecked = $(this).prop('checked') === true;
$(this).siblings('label').toggleClass('on', isChecked);
$('#advertisingReceiveAll', $formJoin).prop('checked', isChecked)
.siblings('label').toggleClass('on', isChecked);
$('.js_advertising_channel', $formJoin).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formJoin.on('change', '#advertisingReceiveAll', function () {
const isChecked = $(this).prop('checked') === true;
$('.js_advertising_channel', $formJoin).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
// 전체선택(advertisingReceiveAll) 직접 조작 시 광고성 수신 동의(termsAgree7) 헤더도 동기화
$('#termsAgree7', $formJoin).prop('checked', isChecked).siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formJoin.on('change', '.js_advertising_channel', function () {
const anyChannelChecked = $('.js_advertising_channel:checked', $formJoin).length > 0;
const allChannelChecked = $('.js_advertising_channel', $formJoin).length > 0
&& $('.js_advertising_channel:not(:checked)', $formJoin).length === 0;
$('#advertisingReceiveAll', $formJoin).prop('checked', anyChannelChecked)
.siblings('label').toggleClass('on', anyChannelChecked);
if (anyChannelChecked) {
checkMarketingApproval();
}
// 수신 채널 전부 선택 시 광고성 수신 동의(termsAgree7) 헤더 ON (일부만이면 켜지 않음)
if (allChannelChecked) {
$('#termsAgree7', $formJoin).prop('checked', true).siblings('label').addClass('on');
}
if ($(this).prop('checked') === false) {
$('#termsAgree7', $formJoin).prop('checked', false).siblings('label').removeClass('on');
}
});
// 마케팅 목적 개인정보 수집 및 이용 동의 체크 시 광고성 수신 동의·수신 채널 일괄 선택
const checkAdvertising = function () {
if ($('#termsAgree7', $formJoin).length === 0) {
return;
}
$('#termsAgree7', $formJoin).prop('checked', true).siblings('label').addClass('on');
$('#advertisingReceiveAll', $formJoin).prop('checked', true).siblings('label').addClass('on');
$('.js_advertising_channel', $formJoin).prop('checked', true).val('y').siblings('label').addClass('on');
};
$formJoin.on('change', '#privateMarketingConsentOptionFl', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
} else {
$('#termsAgree6', $formJoin).prop('checked', false).siblings('label').removeClass('on');
}
});
// 마케팅 목적 개인정보 수집 및 이용 동의 그룹 [선택] 헤더 체크 시 광고성 수신 동의·수신 채널 연동
$formJoin.on('change', '#termsAgree6', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
}
});
// 그룹 하위 항목이 모두 선택되면 상위 [선택] 헤더도 선택 (하나라도 해제 시 해제)
// - story_g 는 약관 그룹 마크업이 .terms-view / .consignment-box 구조 (moment·mygreek 의 .join_agreement_box 아님)
$formJoin.on('change', '.terms-view .consignment-box :checkbox', function () {
const $box = $(this).closest('.terms-view');
const $subs = $box.find('.consignment-box :checkbox');
const $header = $box.find(':checkbox').not($subs);
// 광고성 수신 동의(termsAgree7)는 채널 1개 이상 선택 의미라 전체 선택 동기화에서 제외
if ($header.attr('id') === 'termsAgree7') {
return;
}
const allChecked = $subs.length > 0 && $subs.not(':checked').length === 0;
$header.prop('checked', allChecked).siblings('label').toggleClass('on', allChecked);
});
// 초기 로드: 저장된 하위 선택 상태로 상위 [선택] 헤더 동기화
$('.terms-view', $formJoin).each(function () {
const $box = $(this);
const $subs = $box.find('.consignment-box :checkbox');
const $header = $box.find(':checkbox').not($subs);
// 광고성 수신 동의(termsAgree7)는 채널 1개 이상 선택 의미라 전체 선택 동기화에서 제외
if ($header.attr('id') === 'termsAgree7') {
return;
}
if ($subs.length > 0 && $subs.not(':checked').length === 0) {
$header.prop('checked', true).siblings('label').addClass('on');
}
});
// 초기 로드: 수신 채널이 전부 선택된 상태면 광고성 수신 동의(termsAgree7) 헤더 ON
if ($('.js_advertising_channel', $formJoin).length > 0
&& $('.js_advertising_channel:not(:checked)', $formJoin).length === 0) {
$('#termsAgree7', $formJoin).prop('checked', true).siblings('label').addClass('on');
}
select_email_domain('email');
<!--{? (joinField.marriFl.use == 'y' && joinField.marriDate.use == 'y') || joinField.birthDt.use == 'y' }-->
 
data/skin/mobile/moment/member/join_agreement.html+176-2
변경 전join_agreement.html
<!-- //privacy_content -->
</div>
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<p class="msg dn">
<span>{=__('이용약관과 개인정보 수집 및 이용에 대한 안내 모두 동의해주세요.')}</span>
</p>
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/*
* 14세 동의 항목 체크박스 이벤트
*/
/*
* 약관 내용보기 이벤트
*/
$('.privacy_box dd button').on({
'click':function(){
var privacy_dp = $(this).parent().parent().parent().find('> .privacy_content').css('display');
if(privacy_dp == 'none'){
}
});
 
 
 
 
 
 
window.addEventListener('message', function (e) {
if (e.origin === "{=authDreamUrl}") {
$('#layerSearch').remove();
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
});
 
/**
 
변경 후join_agreement.html
<!-- //privacy_content -->
</div>
<!--{/}-->
<!--{? privateMarketingMember['modeFl']=='y'}-->
<div class="privacy_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" id="termsAgree6"/>
<label for="termsAgree6">({=__('선택')}) {=__('마케팅 목적 개인정보 수집 및 이용 동의')}</label>
</span>
</dt>
<dd><button type="button">{=__('내용보기')} ▼</button></dd>
</dl>
<div class="privacy_content">
<div class="privacy_big_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" class="sp" id="privateMktApprovalOption" name="privateMarketingConsentOptionFl"/>
<label for="privateMktApprovalOption">{=nl2br(privateMarketingMember['informNm'])}</label>
</span>
</dt>
<dd><button type="button" class="js_agreement_view" data-code="{privateMarketingMember['informCd']}">{=__('전체보기')}</button></dd>
</dl>
<div class="privacy_content">
<div>{=nl2br(privateMarketingMember['content'])}</div>
</div>
<!-- //privacy_content -->
</div>
<!-- //privacy_big_box -->
</div>
<!-- //privacy_content -->
</div>
<!--{/}-->
<!--{? isUseAdvertisingReceive}-->
<div class="privacy_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" id="termsAgree7"/>
<label for="termsAgree7">({=__('선택')}) {=__('광고성 수신 동의')}</label>
</span>
</dt>
<dd><button type="button">{=__('내용보기')} ▼</button></dd>
</dl>
<div class="privacy_content">
<div class="privacy_big_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" class="sp" id="advertisingReceiveAll"/>
<label for="advertisingReceiveAll">{=nl2br(advertisingReceive['informNm'])}</label>
</span>
</dt>
<dd><button type="button" class="js_agreement_view" data-code="{advertisingReceive['informCd']}">{=__('전체보기')}</button></dd>
</dl>
<div class="privacy_content">
<div>{=nl2br(advertisingReceive['content'])}</div>
</div>
<!-- //privacy_content -->
</div>
<!-- //privacy_big_box -->
<div class="js_advertising_channel_box" style="display:flex; flex-direction:column; align-items:flex-start; margin:10px;">
<!--{? advertisingReceiveMailUse=='y'}-->
<span class="inp_chk">
<input type="checkbox" class="sp js_advertising_channel" id="maillingFl" name="maillingFl"/>
<label for="maillingFl">{=__('이메일 수신 동의')}</label>
</span>
<!--{/}-->
<!--{? advertisingReceiveSmsUse=='y'}-->
<span class="inp_chk">
<input type="checkbox" class="sp js_advertising_channel" id="smsFl" name="smsFl"/>
<label for="smsFl">{=__('모바일 메시지 수신 동의')}</label>
</span>
<!--{/}-->
</div>
</div>
<!-- //privacy_content -->
</div>
<!--{/}-->
<p class="msg dn">
<span>{=__('이용약관과 개인정보 수집 및 이용에 대한 안내 모두 동의해주세요.')}</span>
</p>
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5') || (e.target.id === 'termsAgree6') || (e.target.id === 'termsAgree7');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
}
});
 
/*
* 광고성 수신 동의 ↔ 이메일/모바일 수신 동의 ↔ 마케팅 목적 개인정보 수집 및 이용 동의 연동
* - 광고성 수신 동의 체크 → 이메일/모바일 채널 일괄 + 마케팅 목적 동의 ON
* - 채널(1개 이상) 체크 → 광고성 수신 동의 + 마케팅 목적 동의 ON (채널은 각각 개별 토글)
*/
const checkMarketingApproval = function () {
$('#privateMktApprovalOption', $formTerms).prop('checked', true).val('y').siblings('label').addClass('on');
$('#termsAgree6', $formTerms).prop('checked', true).siblings('label').addClass('on');
};
// 마케팅 목적 개인정보 수집 및 이용 동의 체크 시 광고성 수신 동의·수신 채널 일괄 선택
const checkAdvertising = function () {
if ($('#termsAgree7', $formTerms).length === 0) {
return;
}
$('#termsAgree7', $formTerms).prop('checked', true).siblings('label').addClass('on');
$('#advertisingReceiveAll', $formTerms).prop('checked', true).siblings('label').addClass('on');
$('.js_advertising_channel', $formTerms).prop('checked', true).val('y').siblings('label').addClass('on');
};
$formTerms.on('change', '#termsAgree7', function () {
const isChecked = $(this).prop('checked') === true;
$(this).siblings('label').toggleClass('on', isChecked);
$('#advertisingReceiveAll', $formTerms).prop('checked', isChecked)
.siblings('label').toggleClass('on', isChecked);
$('.js_advertising_channel', $formTerms).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formTerms.on('change', '#advertisingReceiveAll', function () {
const isChecked = $(this).prop('checked') === true;
$('.js_advertising_channel', $formTerms).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
} else {
$('#termsAgree7', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '.js_advertising_channel', function () {
const anyChannelChecked = $('.js_advertising_channel:checked', $formTerms).length > 0;
$('#advertisingReceiveAll', $formTerms).prop('checked', anyChannelChecked)
.siblings('label').toggleClass('on', anyChannelChecked);
if (anyChannelChecked) {
checkMarketingApproval();
}
if ($(this).prop('checked') === false) {
$('#termsAgree7', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '#privateMktApprovalOption', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
} else {
$('#termsAgree6', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '#termsAgree6', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
}
});
 
/*
* 14세 동의 항목 체크박스 이벤트
*/
/*
* 약관 내용보기 이벤트
*/
$('.privacy_box dd button:not(.js_agreement_view)').on({
'click':function(){
var privacy_dp = $(this).parent().parent().parent().find('> .privacy_content').css('display');
if(privacy_dp == 'none'){
}
});
 
// 약관 전문 새창 열기 (전체보기)
$('.js_agreement_view').on('click', function () {
window.open('../service/agreement.php?code=' + $(this).data('code'));
});
 
window.addEventListener('message', function (e) {
if (e.origin === "{=authDreamUrl}") {
$('#layerSearch').remove();
}
});
 
// 그룹 하위 항목이 모두 선택되면 상위 [선택] 헤더(termsAgree3~7)도 선택 (하나라도 해제 시 해제)
$formTerms.on('change', '.privacy_box :checkbox', function () {
const $box = $(this).closest('.privacy_box');
const $header = $box.children('dl').find(':checkbox');
const $subs = $box.find(':checkbox').not($header);
if ($subs.length === 0) {
return;
}
const allChecked = $subs.not(':checked').length === 0;
$header.prop('checked', allChecked).siblings('label').toggleClass('on', allChecked);
});
 
/*
* 전체 동의 역동기화 — 하위 체크박스가 모두 선택되면 전체 동의도 선택 (하나라도 해제되면 해제)
*/
const syncAllAgree = function () {
const $targets = $(':checkbox', $formTerms).not('#allAgree').not('#termsAgree');
const allChecked = $targets.length > 0 && $targets.not(':checked').length === 0;
$('#allAgree', $formTerms).prop('checked', allChecked)
.siblings('label').toggleClass('on', allChecked);
};
$formTerms.on('change', ':checkbox', function (e) {
if (e.target.id === 'allAgree' || e.target.id === 'termsAgree') {
return;
}
syncAllAgree();
});
});
 
/**
 
data/skin/mobile/moment/member/_join_view.html-22
변경 전_join_view.html
<div class="input_wrap">
<div class="input_title"></div>
<div class="input_content">
<!--{? joinField.maillingFl.use === 'y'}-->
<div class="description">
<span class="inp_chk">
<input type="checkbox" id="maillingFl" class="ignore" name="maillingFl" value="y" {? data.maillingFl=='y'}checked="checked"{/}/>
<label for="maillingFl">{=__('정보/이벤트 메일 수신에 동의합니다.')}</label>
</span>
</div>
<!--{/}-->
<div class="description">※ {=__('아이디 비밀번호 찾기에 활용 되므로 정확하게 입력해 주세요')}</div>
</div>
</div>
<!--{ / }-->
</div>
</div>
<!--{? joinField.smsFl.use === 'y'}-->
<div class="input_wrap">
<div class="input_title"></div>
<div class="input_content">
<div class="description">
<span class="inp_chk">
<input type="checkbox" class="ignore" id="smsFl" name="smsFl" value="y" {? data.smsFl=='y'}checked="checked"{/}/>
<label for="smsFl">{=__('정보/이벤트 SMS 수신에 동의합니다.')}</label>
</span>
</div>
</div>
</div>
<!--{/}-->
<!--{/}-->
<!--{? joinField.phone.use == 'y'}-->
<div class="input_wrap">
 
변경 후_join_view.html
<div class="input_wrap">
<div class="input_title"></div>
<div class="input_content">
 
 
 
 
 
 
 
 
<div class="description">※ {=__('아이디 비밀번호 찾기에 활용 되므로 정확하게 입력해 주세요')}</div>
</div>
</div>
<!--{ / }-->
</div>
</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<!--{/}-->
<!--{? joinField.phone.use == 'y'}-->
<div class="input_wrap">
 
data/skin/mobile/moment/member/_join_view_other.html+88-3
변경 전_join_view_other.html
<!--{/}-->
</div>
<!--{/}-->
<!--{? privateApprovalOption[0]['modeFl'] == 'y' || privateConsign[0]['modeFl']=='y' || privateOffer[0]['modeFl']=='y'}-->
<p class="tit">{=__('약관동의현황')}</p>
<!--{? privateApprovalOption[0]['modeFl'] == 'y'}-->
<div class="privacy_big_box">
</div>
</div>
<!--{/ // privateOffer modeFl end}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<!--{/}-->
<script type="text/javascript">
$(document).ready(function() {
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
/*
* 약관 내용보기 이벤트
*/
$('.privacy_box dd button').on({
 
 
 
'click':function(){
var privacy_dp = $(this).parent().parent().parent().find('> .privacy_content').css('display');
if(privacy_dp == 'none'){
 
변경 후_join_view_other.html
<!--{/}-->
</div>
<!--{/}-->
<!--{? privateApprovalOption[0]['modeFl'] == 'y' || privateConsign[0]['modeFl']=='y' || privateOffer[0]['modeFl']=='y' || privateMktApprovalOption[0]['modeFl']=='y' || isUseAdvertisingReceive}-->
<p class="tit">{=__('약관동의현황')}</p>
<!--{? privateApprovalOption[0]['modeFl'] == 'y'}-->
<div class="privacy_big_box">
</div>
</div>
<!--{/ // privateOffer modeFl end}-->
<!--{? privateMktApprovalOption[0]['modeFl'] == 'y'}-->
<div class="privacy_big_box">
<div class="privacy_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" id="termsAgree6" name=""/>
<label for="termsAgree6">({=__('선택')}) {=__('마케팅 목적 개인정보 수집 및 이용 동의')}</label>
</span>
</dt>
<dd><button type="button">{=__('내용보기')} ▼</button></dd>
</dl>
<div class="privacy_content">
<!--{@ privateMktApprovalOption}-->
<div class="privacy_big_box">
<div class="privacy_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" id="privateMarketingConsentOptionFl" name="privateMarketingConsentOptionFl" value="y" <!--{? data['privateMarketingConsentOptionFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="privateMarketingConsentOptionFl">{=nl2br(.informNm)}</label>
</span>
</dt>
<dd><button type="button" class="js_agreement_view" data-code="{.informCd}">{=__('전체보기')}</button></dd>
</dl>
<div class="privacy_content">
<div>{=nl2br(.content)}</div>
</div>
</div>
</div>
<!--{/}-->
</div>
</div>
</div>
<!--{/ // privateMktApprovalOption modeFl end}-->
<!--{? isUseAdvertisingReceive}-->
<div class="privacy_big_box">
<div class="privacy_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" id="termsAgree7" name=""/>
<label for="termsAgree7">({=__('선택')}) {=__('광고성 수신 동의')}</label>
</span>
</dt>
<dd><button type="button">{=__('내용보기')} ▼</button></dd>
</dl>
<div class="privacy_content">
<div class="privacy_big_box">
<div class="privacy_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" id="advertisingReceiveAll" name="" <!--{? data['maillingFl'] == 'y' || data['smsFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="advertisingReceiveAll">{=nl2br(advertisingReceive['informNm'])}</label>
</span>
</dt>
<dd><button type="button" class="js_agreement_view" data-code="{advertisingReceive['informCd']}">{=__('전체보기')}</button></dd>
</dl>
<div class="privacy_content">
<div>{=nl2br(advertisingReceive['content'])}</div>
</div>
</div>
</div>
<div class="js_advertising_channel_box" style="display:flex; flex-direction:column; align-items:flex-start; margin:10px;">
<!--{? advertisingReceiveMailUse == 'y'}-->
<span class="inp_chk">
<input type="checkbox" id="advertisingReceiveMail" name="maillingFl" value="y" class="js_advertising_channel" <!--{? data['maillingFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="advertisingReceiveMail">{=__('이메일 수신 동의')}</label>
</span>
<!--{/}-->
<!--{? advertisingReceiveSmsUse == 'y'}-->
<span class="inp_chk">
<input type="checkbox" id="advertisingReceiveSms" name="smsFl" value="y" class="js_advertising_channel" <!--{? data['smsFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="advertisingReceiveSms">{=__('모바일 메시지 수신 동의')}</label>
</span>
<!--{/}-->
</div>
</div>
</div>
</div>
<!--{/ // isUseAdvertisingReceive end}-->
<!--{/}-->
<script type="text/javascript">
$(document).ready(function() {
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5') || (e.target.id === 'termsAgree6') || (e.target.id === 'termsAgree7');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
/*
* 약관 내용보기 이벤트
*/
$('.js_agreement_view').on('click', function () {
window.open('../service/agreement.php?code=' + $(this).data('code'));
});
$('.privacy_box dd button:not(.js_agreement_view)').on({
'click':function(){
var privacy_dp = $(this).parent().parent().parent().find('> .privacy_content').css('display');
if(privacy_dp == 'none'){
 
data/skin/mobile/moment/mypage/my_page.html+95-1
변경 전my_page.html
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5');
var isTargetChecked = $target.prop('checked') === true;
if (isTargetChecked) {
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
gd_select_email_domain('email');
<!--{? (joinField.marriFl.use == 'y' && joinField.marriDate.use == 'y') || joinField.birthDt.use == 'y' }-->
 
변경 후my_page.html
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5') || (e.target.id === 'termsAgree6') || (e.target.id === 'termsAgree7');
var isTargetChecked = $target.prop('checked') === true;
if (isTargetChecked) {
}
});
/*
* 광고성 수신 동의 ↔ 이메일/모바일 수신 동의 ↔ 마케팅 목적 개인정보 수집 및 이용 동의 연동
* - 광고성 수신 동의 체크 → 이메일/모바일 채널 일괄 + 마케팅 목적 동의 ON
* - 채널(1개 이상) 체크 → 광고성 수신 동의 + 마케팅 목적 동의 ON (채널은 각각 개별 토글)
*/
const checkMarketingApproval = function () {
$('#privateMarketingConsentOptionFl', $formJoin).prop('checked', true).val('y').siblings('label').addClass('on');
$('#termsAgree6', $formJoin).prop('checked', true).siblings('label').addClass('on');
};
$formJoin.on('change', '#termsAgree7', function () {
const isChecked = $(this).prop('checked') === true;
$(this).siblings('label').toggleClass('on', isChecked);
$('#advertisingReceiveAll', $formJoin).prop('checked', isChecked)
.siblings('label').toggleClass('on', isChecked);
$('.js_advertising_channel', $formJoin).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formJoin.on('change', '#advertisingReceiveAll', function () {
const isChecked = $(this).prop('checked') === true;
$('.js_advertising_channel', $formJoin).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
// 전체선택(advertisingReceiveAll) 직접 조작 시 광고성 수신 동의(termsAgree7) 헤더도 동기화
$('#termsAgree7', $formJoin).prop('checked', isChecked).siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formJoin.on('change', '.js_advertising_channel', function () {
const anyChannelChecked = $('.js_advertising_channel:checked', $formJoin).length > 0;
const allChannelChecked = $('.js_advertising_channel', $formJoin).length > 0
&& $('.js_advertising_channel:not(:checked)', $formJoin).length === 0;
$('#advertisingReceiveAll', $formJoin).prop('checked', anyChannelChecked)
.siblings('label').toggleClass('on', anyChannelChecked);
if (anyChannelChecked) {
checkMarketingApproval();
}
// 수신 채널 전부 선택 시 광고성 수신 동의(termsAgree7) 헤더 ON (일부만이면 켜지 않음)
if (allChannelChecked) {
$('#termsAgree7', $formJoin).prop('checked', true).siblings('label').addClass('on');
}
if ($(this).prop('checked') === false) {
$('#termsAgree7', $formJoin).prop('checked', false).siblings('label').removeClass('on');
}
});
// 마케팅 목적 개인정보 수집 및 이용 동의 체크 시 광고성 수신 동의·수신 채널 일괄 선택
const checkAdvertising = function () {
if ($('#termsAgree7', $formJoin).length === 0) {
return;
}
$('#termsAgree7', $formJoin).prop('checked', true).siblings('label').addClass('on');
$('#advertisingReceiveAll', $formJoin).prop('checked', true).siblings('label').addClass('on');
$('.js_advertising_channel', $formJoin).prop('checked', true).val('y').siblings('label').addClass('on');
};
$formJoin.on('change', '#privateMarketingConsentOptionFl', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
} else {
$('#termsAgree6', $formJoin).prop('checked', false).siblings('label').removeClass('on');
}
});
// 마케팅 목적 개인정보 수집 및 이용 동의 그룹 [선택] 헤더 체크 시 광고성 수신 동의·수신 채널 연동
$formJoin.on('change', '#termsAgree6', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
}
});
// 그룹 하위 항목이 모두 선택되면 상위 [선택] 헤더도 선택 (하나라도 해제 시 해제) — 중첩 privacy_box 대응: 헤더 기준으로 그룹 판정
$formJoin.on('change', '.privacy_box :checkbox', function () {
$('#termsAgree3, #termsAgree4, #termsAgree5, #termsAgree6', $formJoin).each(function () {
const $header = $(this);
const $subs = $header.closest('.privacy_box').find(':checkbox').not($header);
if ($subs.length === 0) {
return;
}
const allChecked = $subs.not(':checked').length === 0;
$header.prop('checked', allChecked).siblings('label').toggleClass('on', allChecked);
});
});
// 초기 로드: 저장된 하위 선택 상태로 상위 [선택] 헤더 동기화
$('#termsAgree3, #termsAgree4, #termsAgree5, #termsAgree6', $formJoin).each(function () {
const $subs = $(this).closest('.privacy_box').find(':checkbox').not(this);
if ($subs.length > 0 && $subs.not(':checked').length === 0) {
$(this).prop('checked', true).siblings('label').addClass('on');
}
});
// 초기 로드: 수신 채널이 전부 선택된 상태면 광고성 수신 동의(termsAgree7) 헤더 ON
if ($('.js_advertising_channel', $formJoin).length > 0
&& $('.js_advertising_channel:not(:checked)', $formJoin).length === 0) {
$('#termsAgree7', $formJoin).prop('checked', true).siblings('label').addClass('on');
}
gd_select_email_domain('email');
<!--{? (joinField.marriFl.use == 'y' && joinField.marriDate.use == 'y') || joinField.birthDt.use == 'y' }-->
 
data/skin/mobile/mygreek/member/join_agreement.html+176-2
변경 전join_agreement.html
<!-- //privacy_content -->
</div>
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<p class="msg dn">
<span>{=__('이용약관과 개인정보 수집 및 이용에 대한 안내 모두 동의해주세요.')}</span>
</p>
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/*
* 14세 동의 항목 체크박스 이벤트
*/
/*
* 약관 내용보기 이벤트
*/
$('.privacy_box dd button').on({
'click':function(){
var privacy_dp = $(this).parent().parent().parent().find('> .privacy_content').css('display');
if(privacy_dp == 'none'){
}
});
 
 
 
 
 
 
window.addEventListener('message', function (e) {
if (e.origin === "{=authDreamUrl}") {
$('#layerSearch').remove();
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
});
 
/**
 
변경 후join_agreement.html
<!-- //privacy_content -->
</div>
<!--{/}-->
<!--{? privateMarketingMember['modeFl']=='y'}-->
<div class="privacy_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" id="termsAgree6"/>
<label for="termsAgree6">({=__('선택')}) {=__('마케팅 목적 개인정보 수집 및 이용 동의')}</label>
</span>
</dt>
<dd><button type="button">{=__('내용보기')} ▼</button></dd>
</dl>
<div class="privacy_content">
<div class="privacy_big_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" class="sp" id="privateMktApprovalOption" name="privateMarketingConsentOptionFl"/>
<label for="privateMktApprovalOption">{=nl2br(privateMarketingMember['informNm'])}</label>
</span>
</dt>
<dd><button type="button" class="js_agreement_view" data-code="{privateMarketingMember['informCd']}">{=__('전체보기')}</button></dd>
</dl>
<div class="privacy_content">
<div>{=nl2br(privateMarketingMember['content'])}</div>
</div>
<!-- //privacy_content -->
</div>
<!-- //privacy_big_box -->
</div>
<!-- //privacy_content -->
</div>
<!--{/}-->
<!--{? isUseAdvertisingReceive}-->
<div class="privacy_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" id="termsAgree7"/>
<label for="termsAgree7">({=__('선택')}) {=__('광고성 수신 동의')}</label>
</span>
</dt>
<dd><button type="button">{=__('내용보기')} ▼</button></dd>
</dl>
<div class="privacy_content">
<div class="privacy_big_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" class="sp" id="advertisingReceiveAll"/>
<label for="advertisingReceiveAll">{=nl2br(advertisingReceive['informNm'])}</label>
</span>
</dt>
<dd><button type="button" class="js_agreement_view" data-code="{advertisingReceive['informCd']}">{=__('전체보기')}</button></dd>
</dl>
<div class="privacy_content">
<div>{=nl2br(advertisingReceive['content'])}</div>
</div>
<!-- //privacy_content -->
</div>
<!-- //privacy_big_box -->
<div class="js_advertising_channel_box" style="display:flex; flex-direction:column; align-items:flex-start; margin:10px;">
<!--{? advertisingReceiveMailUse=='y'}-->
<span class="inp_chk">
<input type="checkbox" class="sp js_advertising_channel" id="maillingFl" name="maillingFl"/>
<label for="maillingFl">{=__('이메일 수신 동의')}</label>
</span>
<!--{/}-->
<!--{? advertisingReceiveSmsUse=='y'}-->
<span class="inp_chk">
<input type="checkbox" class="sp js_advertising_channel" id="smsFl" name="smsFl"/>
<label for="smsFl">{=__('모바일 메시지 수신 동의')}</label>
</span>
<!--{/}-->
</div>
</div>
<!-- //privacy_content -->
</div>
<!--{/}-->
<p class="msg dn">
<span>{=__('이용약관과 개인정보 수집 및 이용에 대한 안내 모두 동의해주세요.')}</span>
</p>
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5') || (e.target.id === 'termsAgree6') || (e.target.id === 'termsAgree7');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
}
});
 
/*
* 광고성 수신 동의 ↔ 이메일/모바일 수신 동의 ↔ 마케팅 목적 개인정보 수집 및 이용 동의 연동
* - 광고성 수신 동의 체크 → 이메일/모바일 채널 일괄 + 마케팅 목적 동의 ON
* - 채널(1개 이상) 체크 → 광고성 수신 동의 + 마케팅 목적 동의 ON (채널은 각각 개별 토글)
*/
const checkMarketingApproval = function () {
$('#privateMktApprovalOption', $formTerms).prop('checked', true).val('y').siblings('label').addClass('on');
$('#termsAgree6', $formTerms).prop('checked', true).siblings('label').addClass('on');
};
// 마케팅 목적 개인정보 수집 및 이용 동의 체크 시 광고성 수신 동의·수신 채널 일괄 선택
const checkAdvertising = function () {
if ($('#termsAgree7', $formTerms).length === 0) {
return;
}
$('#termsAgree7', $formTerms).prop('checked', true).siblings('label').addClass('on');
$('#advertisingReceiveAll', $formTerms).prop('checked', true).siblings('label').addClass('on');
$('.js_advertising_channel', $formTerms).prop('checked', true).val('y').siblings('label').addClass('on');
};
$formTerms.on('change', '#termsAgree7', function () {
const isChecked = $(this).prop('checked') === true;
$(this).siblings('label').toggleClass('on', isChecked);
$('#advertisingReceiveAll', $formTerms).prop('checked', isChecked)
.siblings('label').toggleClass('on', isChecked);
$('.js_advertising_channel', $formTerms).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formTerms.on('change', '#advertisingReceiveAll', function () {
const isChecked = $(this).prop('checked') === true;
$('.js_advertising_channel', $formTerms).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
} else {
$('#termsAgree7', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '.js_advertising_channel', function () {
const anyChannelChecked = $('.js_advertising_channel:checked', $formTerms).length > 0;
$('#advertisingReceiveAll', $formTerms).prop('checked', anyChannelChecked)
.siblings('label').toggleClass('on', anyChannelChecked);
if (anyChannelChecked) {
checkMarketingApproval();
}
if ($(this).prop('checked') === false) {
$('#termsAgree7', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '#privateMktApprovalOption', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
} else {
$('#termsAgree6', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '#termsAgree6', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
}
});
 
/*
* 14세 동의 항목 체크박스 이벤트
*/
/*
* 약관 내용보기 이벤트
*/
$('.privacy_box dd button:not(.js_agreement_view)').on({
'click':function(){
var privacy_dp = $(this).parent().parent().parent().find('> .privacy_content').css('display');
if(privacy_dp == 'none'){
}
});
 
// 약관 전문 새창 열기 (전체보기)
$('.js_agreement_view').on('click', function () {
window.open('../service/agreement.php?code=' + $(this).data('code'));
});
 
window.addEventListener('message', function (e) {
if (e.origin === "{=authDreamUrl}") {
$('#layerSearch').remove();
}
});
 
// 그룹 하위 항목이 모두 선택되면 상위 [선택] 헤더(termsAgree3~7)도 선택 (하나라도 해제 시 해제)
$formTerms.on('change', '.privacy_box :checkbox', function () {
const $box = $(this).closest('.privacy_box');
const $header = $box.children('dl').find(':checkbox');
const $subs = $box.find(':checkbox').not($header);
if ($subs.length === 0) {
return;
}
const allChecked = $subs.not(':checked').length === 0;
$header.prop('checked', allChecked).siblings('label').toggleClass('on', allChecked);
});
 
/*
* 전체 동의 역동기화 — 하위 체크박스가 모두 선택되면 전체 동의도 선택 (하나라도 해제되면 해제)
*/
const syncAllAgree = function () {
const $targets = $(':checkbox', $formTerms).not('#allAgree').not('#termsAgree');
const allChecked = $targets.length > 0 && $targets.not(':checked').length === 0;
$('#allAgree', $formTerms).prop('checked', allChecked)
.siblings('label').toggleClass('on', allChecked);
};
$formTerms.on('change', ':checkbox', function (e) {
if (e.target.id === 'allAgree' || e.target.id === 'termsAgree') {
return;
}
syncAllAgree();
});
});
 
/**
 
data/skin/mobile/mygreek/member/_join_view.html-22
변경 전_join_view.html
<div class="input_wrap">
<div class="input_title"></div>
<div class="input_content">
<!--{? joinField.maillingFl.use === 'y'}-->
<div class="description">
<span class="inp_chk">
<input type="checkbox" id="maillingFl" class="ignore" name="maillingFl" value="y" {? data.maillingFl=='y'}checked="checked"{/}/>
<label for="maillingFl">{=__('정보/이벤트 메일 수신에 동의합니다.')}</label>
</span>
</div>
<!--{/}-->
<div class="description">※ {=__('아이디 비밀번호 찾기에 활용 되므로 정확하게 입력해 주세요')}</div>
</div>
</div>
<!--{ / }-->
</div>
</div>
<!--{? joinField.smsFl.use === 'y'}-->
<div class="input_wrap">
<div class="input_title"></div>
<div class="input_content">
<div class="description">
<span class="inp_chk">
<input type="checkbox" class="ignore" id="smsFl" name="smsFl" value="y" {? data.smsFl=='y'}checked="checked"{/}/>
<label for="smsFl">{=__('정보/이벤트 SMS 수신에 동의합니다.')}</label>
</span>
</div>
</div>
</div>
<!--{/}-->
<!--{/}-->
<!--{? joinField.phone.use == 'y'}-->
<div class="input_wrap">
 
변경 후_join_view.html
<div class="input_wrap">
<div class="input_title"></div>
<div class="input_content">
 
 
 
 
 
 
 
 
<div class="description">※ {=__('아이디 비밀번호 찾기에 활용 되므로 정확하게 입력해 주세요')}</div>
</div>
</div>
<!--{ / }-->
</div>
</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<!--{/}-->
<!--{? joinField.phone.use == 'y'}-->
<div class="input_wrap">
 
data/skin/mobile/mygreek/member/_join_view_other.html+88-3
변경 전_join_view_other.html
<!--{/}-->
</div>
<!--{/}-->
<!--{? privateApprovalOption[0]['modeFl'] == 'y' || privateConsign[0]['modeFl']=='y' || privateOffer[0]['modeFl']=='y'}-->
<p class="tit">{=__('약관동의현황')}</p>
<!--{? privateApprovalOption[0]['modeFl'] == 'y'}-->
<div class="privacy_big_box">
</div>
</div>
<!--{/ // privateOffer modeFl end}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<!--{/}-->
<script type="text/javascript">
$(document).ready(function() {
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
/*
* 약관 내용보기 이벤트
*/
$('.privacy_box dd button').on({
 
 
 
'click':function(){
var privacy_dp = $(this).parent().parent().parent().find('> .privacy_content').css('display');
if(privacy_dp == 'none'){
 
변경 후_join_view_other.html
<!--{/}-->
</div>
<!--{/}-->
<!--{? privateApprovalOption[0]['modeFl'] == 'y' || privateConsign[0]['modeFl']=='y' || privateOffer[0]['modeFl']=='y' || privateMktApprovalOption[0]['modeFl']=='y' || isUseAdvertisingReceive}-->
<p class="tit">{=__('약관동의현황')}</p>
<!--{? privateApprovalOption[0]['modeFl'] == 'y'}-->
<div class="privacy_big_box">
</div>
</div>
<!--{/ // privateOffer modeFl end}-->
<!--{? privateMktApprovalOption[0]['modeFl'] == 'y'}-->
<div class="privacy_big_box">
<div class="privacy_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" id="termsAgree6" name=""/>
<label for="termsAgree6">({=__('선택')}) {=__('마케팅 목적 개인정보 수집 및 이용 동의')}</label>
</span>
</dt>
<dd><button type="button">{=__('내용보기')} ▼</button></dd>
</dl>
<div class="privacy_content">
<!--{@ privateMktApprovalOption}-->
<div class="privacy_big_box">
<div class="privacy_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" id="privateMarketingConsentOptionFl" name="privateMarketingConsentOptionFl" value="y" <!--{? data['privateMarketingConsentOptionFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="privateMarketingConsentOptionFl">{=nl2br(.informNm)}</label>
</span>
</dt>
<dd><button type="button" class="js_agreement_view" data-code="{.informCd}">{=__('전체보기')}</button></dd>
</dl>
<div class="privacy_content">
<div>{=nl2br(.content)}</div>
</div>
</div>
</div>
<!--{/}-->
</div>
</div>
</div>
<!--{/ // privateMktApprovalOption modeFl end}-->
<!--{? isUseAdvertisingReceive}-->
<div class="privacy_big_box">
<div class="privacy_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" id="termsAgree7" name=""/>
<label for="termsAgree7">({=__('선택')}) {=__('광고성 수신 동의')}</label>
</span>
</dt>
<dd><button type="button">{=__('내용보기')} ▼</button></dd>
</dl>
<div class="privacy_content">
<div class="privacy_big_box">
<div class="privacy_box">
<dl>
<dt>
<span class="inp_chk">
<input type="checkbox" id="advertisingReceiveAll" name="" <!--{? data['maillingFl'] == 'y' || data['smsFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="advertisingReceiveAll">{=nl2br(advertisingReceive['informNm'])}</label>
</span>
</dt>
<dd><button type="button" class="js_agreement_view" data-code="{advertisingReceive['informCd']}">{=__('전체보기')}</button></dd>
</dl>
<div class="privacy_content">
<div>{=nl2br(advertisingReceive['content'])}</div>
</div>
</div>
</div>
<div class="js_advertising_channel_box" style="display:flex; flex-direction:column; align-items:flex-start; margin:10px;">
<!--{? advertisingReceiveMailUse == 'y'}-->
<span class="inp_chk">
<input type="checkbox" id="advertisingReceiveMail" name="maillingFl" value="y" class="js_advertising_channel" <!--{? data['maillingFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="advertisingReceiveMail">{=__('이메일 수신 동의')}</label>
</span>
<!--{/}-->
<!--{? advertisingReceiveSmsUse == 'y'}-->
<span class="inp_chk">
<input type="checkbox" id="advertisingReceiveSms" name="smsFl" value="y" class="js_advertising_channel" <!--{? data['smsFl'] == 'y'}-->checked="checked"<!--{/}-->/>
<label for="advertisingReceiveSms">{=__('모바일 메시지 수신 동의')}</label>
</span>
<!--{/}-->
</div>
</div>
</div>
</div>
<!--{/ // isUseAdvertisingReceive end}-->
<!--{/}-->
<script type="text/javascript">
$(document).ready(function() {
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5') || (e.target.id === 'termsAgree6') || (e.target.id === 'termsAgree7');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
/*
* 약관 내용보기 이벤트
*/
$('.js_agreement_view').on('click', function () {
window.open('../service/agreement.php?code=' + $(this).data('code'));
});
$('.privacy_box dd button:not(.js_agreement_view)').on({
'click':function(){
var privacy_dp = $(this).parent().parent().parent().find('> .privacy_content').css('display');
if(privacy_dp == 'none'){
 
data/skin/mobile/mygreek/mypage/my_page.html+95-1
변경 전my_page.html
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
gd_select_email_domain('email');
 
<!--{? (joinField.marriFl.use == 'y' && joinField.marriDate.use == 'y') || joinField.birthDt.use == 'y' }-->
 
변경 후my_page.html
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy_box');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5') || (e.target.id === 'termsAgree6') || (e.target.id === 'termsAgree7');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
}
});
 
/*
* 광고성 수신 동의 ↔ 이메일/모바일 수신 동의 ↔ 마케팅 목적 개인정보 수집 및 이용 동의 연동
* - 광고성 수신 동의 체크 → 이메일/모바일 채널 일괄 + 마케팅 목적 동의 ON
* - 채널(1개 이상) 체크 → 광고성 수신 동의 + 마케팅 목적 동의 ON (채널은 각각 개별 토글)
*/
const checkMarketingApproval = function () {
$('#privateMarketingConsentOptionFl', $formJoin).prop('checked', true).val('y').siblings('label').addClass('on');
$('#termsAgree6', $formJoin).prop('checked', true).siblings('label').addClass('on');
};
$formJoin.on('change', '#termsAgree7', function () {
const isChecked = $(this).prop('checked') === true;
$(this).siblings('label').toggleClass('on', isChecked);
$('#advertisingReceiveAll', $formJoin).prop('checked', isChecked)
.siblings('label').toggleClass('on', isChecked);
$('.js_advertising_channel', $formJoin).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formJoin.on('change', '#advertisingReceiveAll', function () {
const isChecked = $(this).prop('checked') === true;
$('.js_advertising_channel', $formJoin).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
// 전체선택(advertisingReceiveAll) 직접 조작 시 광고성 수신 동의(termsAgree7) 헤더도 동기화
$('#termsAgree7', $formJoin).prop('checked', isChecked).siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formJoin.on('change', '.js_advertising_channel', function () {
const anyChannelChecked = $('.js_advertising_channel:checked', $formJoin).length > 0;
const allChannelChecked = $('.js_advertising_channel', $formJoin).length > 0
&& $('.js_advertising_channel:not(:checked)', $formJoin).length === 0;
$('#advertisingReceiveAll', $formJoin).prop('checked', anyChannelChecked)
.siblings('label').toggleClass('on', anyChannelChecked);
if (anyChannelChecked) {
checkMarketingApproval();
}
// 수신 채널 전부 선택 시 광고성 수신 동의(termsAgree7) 헤더 ON (일부만이면 켜지 않음)
if (allChannelChecked) {
$('#termsAgree7', $formJoin).prop('checked', true).siblings('label').addClass('on');
}
if ($(this).prop('checked') === false) {
$('#termsAgree7', $formJoin).prop('checked', false).siblings('label').removeClass('on');
}
});
// 마케팅 목적 개인정보 수집 및 이용 동의 체크 시 광고성 수신 동의·수신 채널 일괄 선택
const checkAdvertising = function () {
if ($('#termsAgree7', $formJoin).length === 0) {
return;
}
$('#termsAgree7', $formJoin).prop('checked', true).siblings('label').addClass('on');
$('#advertisingReceiveAll', $formJoin).prop('checked', true).siblings('label').addClass('on');
$('.js_advertising_channel', $formJoin).prop('checked', true).val('y').siblings('label').addClass('on');
};
$formJoin.on('change', '#privateMarketingConsentOptionFl', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
} else {
$('#termsAgree6', $formJoin).prop('checked', false).siblings('label').removeClass('on');
}
});
// 마케팅 목적 개인정보 수집 및 이용 동의 그룹 [선택] 헤더 체크 시 광고성 수신 동의·수신 채널 연동
$formJoin.on('change', '#termsAgree6', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
}
});
// 그룹 하위 항목이 모두 선택되면 상위 [선택] 헤더도 선택 (하나라도 해제 시 해제) — 중첩 privacy_box 대응: 헤더 기준으로 그룹 판정
$formJoin.on('change', '.privacy_box :checkbox', function () {
$('#termsAgree3, #termsAgree4, #termsAgree5, #termsAgree6', $formJoin).each(function () {
const $header = $(this);
const $subs = $header.closest('.privacy_box').find(':checkbox').not($header);
if ($subs.length === 0) {
return;
}
const allChecked = $subs.not(':checked').length === 0;
$header.prop('checked', allChecked).siblings('label').toggleClass('on', allChecked);
});
});
// 초기 로드: 저장된 하위 선택 상태로 상위 [선택] 헤더 동기화
$('#termsAgree3, #termsAgree4, #termsAgree5, #termsAgree6', $formJoin).each(function () {
const $subs = $(this).closest('.privacy_box').find(':checkbox').not(this);
if ($subs.length > 0 && $subs.not(':checked').length === 0) {
$(this).prop('checked', true).siblings('label').addClass('on');
}
});
// 초기 로드: 수신 채널이 전부 선택된 상태면 광고성 수신 동의(termsAgree7) 헤더 ON
if ($('.js_advertising_channel', $formJoin).length > 0
&& $('.js_advertising_channel:not(:checked)', $formJoin).length === 0) {
$('#termsAgree7', $formJoin).prop('checked', true).siblings('label').addClass('on');
}
 
gd_select_email_domain('email');
 
<!--{? (joinField.marriFl.use == 'y' && joinField.marriDate.use == 'y') || joinField.birthDt.use == 'y' }-->
 
data/skin/mobile/story_g/member/join_agreement.html+177-1
변경 전join_agreement.html
</div>
</div>
<!--{/}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<p class="msg dn">
<span>{=__('이용약관과 개인정보 수집 및 이용에 대한 안내 모두 동의해주세요.')}</span>
</p>
$(document).ready(function () {
var body = $('body'), $formTerms = $('#formTerms');
 
 
 
 
 
 
$('#btnNextStep').click(function () {
var pass = true;
/*
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy-item');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
window.addEventListener('message', function (e) {
if (e.origin === "{=authDreamUrl}") {
$('#layerSearch').remove();
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
});
/**
* 아이폰+페이스북앱에서 location.href로 페이지 이동으로 처리시
 
변경 후join_agreement.html
</div>
</div>
<!--{/}-->
<!--{? privateMarketingMember['modeFl']=='y'}-->
<div class="privacy-item toggle-item toggle-open">
<div class="privacy-head">
<span class="inp_chk">
<input type="checkbox" class="sp" id="termsAgree6" name="">
<label for="termsAgree6">({=__('선택')}) {=__('마케팅 목적 개인정보 수집 및 이용 동의')}</label>
</span>
<div class="option">
<button type="button" class="btn-reset toggle-switch">{=__('내용보기')} ▼</button>
</div>
</div>
<div class="privacy-body">
<div class="privacy-item toggle-item toggle-open">
<div class="privacy-head">
<span class="inp_chk">
<input type="checkbox" class="sp" id="privateMktApprovalOption" name="privateMarketingConsentOptionFl">
<label for="privateMktApprovalOption">{=nl2br(privateMarketingMember['informNm'])}</label>
</span>
<div class="option">
<button type="button" class="btn-reset js_agreement_view" data-code="{privateMarketingMember['informCd']}">{=__('전체보기')}</button>
</div>
</div>
<div class="privacy-body">
{=nl2br(privateMarketingMember['content'])}
</div>
</div>
</div>
</div>
<!--{/}-->
<!--{? isUseAdvertisingReceive}-->
<div class="privacy-item toggle-item toggle-open">
<div class="privacy-head">
<span class="inp_chk">
<input type="checkbox" class="sp" id="termsAgree7" name="">
<label for="termsAgree7">({=__('선택')}) {=__('광고성 수신 동의')}</label>
</span>
<div class="option">
<button type="button" class="btn-reset toggle-switch">{=__('내용보기')} ▼</button>
</div>
</div>
<div class="privacy-body">
<div class="privacy-item toggle-item toggle-open">
<div class="privacy-head">
<span class="inp_chk">
<input type="checkbox" class="sp" id="advertisingReceiveAll" name="">
<label for="advertisingReceiveAll">{=nl2br(advertisingReceive['informNm'])}</label>
</span>
<div class="option">
<button type="button" class="btn-reset js_agreement_view" data-code="{advertisingReceive['informCd']}">{=__('전체보기')}</button>
</div>
</div>
<div class="privacy-body">
{=nl2br(advertisingReceive['content'])}
</div>
</div>
<div class="js_advertising_channel_box">
<!--{? advertisingReceiveMailUse=='y'}-->
<div class="privacy-item">
<div class="privacy-head">
<span class="inp_chk">
<input type="checkbox" class="sp js_advertising_channel" id="maillingFl" name="maillingFl">
<label for="maillingFl">{=__('이메일 수신 동의')}</label>
</span>
</div>
</div>
<!--{/}-->
<!--{? advertisingReceiveSmsUse=='y'}-->
<div class="privacy-item">
<div class="privacy-head">
<span class="inp_chk">
<input type="checkbox" class="sp js_advertising_channel" id="smsFl" name="smsFl">
<label for="smsFl">{=__('모바일 메시지 수신 동의')}</label>
</span>
</div>
</div>
<!--{/}-->
</div>
</div>
</div>
<!--{/}-->
<p class="msg dn">
<span>{=__('이용약관과 개인정보 수집 및 이용에 대한 안내 모두 동의해주세요.')}</span>
</p>
$(document).ready(function () {
var body = $('body'), $formTerms = $('#formTerms');
 
// 약관 전문 새창 열기 (전체보기)
body.on('click', '.js_agreement_view', function () {
window.open('../service/agreement.php?code=' + $(this).data('code'));
});
 
$('#btnNextStep').click(function () {
var pass = true;
/*
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy-item');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5') || (e.target.id === 'termsAgree6') || (e.target.id === 'termsAgree7');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
}
});
 
/*
* 광고성 수신 동의 ↔ 이메일/모바일 수신 동의 ↔ 마케팅 목적 개인정보 수집 및 이용 동의 연동
* - 광고성 수신 동의 체크 → 이메일/모바일 채널 일괄 + 마케팅 목적 동의 ON
* - 채널(1개 이상) 체크 → 광고성 수신 동의 + 마케팅 목적 동의 ON (채널은 각각 개별 토글)
*/
const checkMarketingApproval = function () {
$('#privateMktApprovalOption', $formTerms).prop('checked', true).val('y').siblings('label').addClass('on');
$('#termsAgree6', $formTerms).prop('checked', true).siblings('label').addClass('on');
};
// 마케팅 목적 개인정보 수집 및 이용 동의 체크 시 광고성 수신 동의·수신 채널 일괄 선택
const checkAdvertising = function () {
if ($('#termsAgree7', $formTerms).length === 0) {
return;
}
$('#termsAgree7', $formTerms).prop('checked', true).siblings('label').addClass('on');
$('#advertisingReceiveAll', $formTerms).prop('checked', true).siblings('label').addClass('on');
$('.js_advertising_channel', $formTerms).prop('checked', true).val('y').siblings('label').addClass('on');
};
$formTerms.on('change', '#termsAgree7', function () {
const isChecked = $(this).prop('checked') === true;
$(this).siblings('label').toggleClass('on', isChecked);
$('#advertisingReceiveAll', $formTerms).prop('checked', isChecked)
.siblings('label').toggleClass('on', isChecked);
$('.js_advertising_channel', $formTerms).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$formTerms.on('change', '#advertisingReceiveAll', function () {
const isChecked = $(this).prop('checked') === true;
$('.js_advertising_channel', $formTerms).prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
} else {
$('#termsAgree7', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '.js_advertising_channel', function () {
const anyChannelChecked = $('.js_advertising_channel:checked', $formTerms).length > 0;
$('#advertisingReceiveAll', $formTerms).prop('checked', anyChannelChecked)
.siblings('label').toggleClass('on', anyChannelChecked);
if (anyChannelChecked) {
checkMarketingApproval();
}
if ($(this).prop('checked') === false) {
$('#termsAgree7', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '#privateMktApprovalOption', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
} else {
$('#termsAgree6', $formTerms).prop('checked', false).siblings('label').removeClass('on');
}
});
$formTerms.on('change', '#termsAgree6', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
}
});
 
window.addEventListener('message', function (e) {
if (e.origin === "{=authDreamUrl}") {
$('#layerSearch').remove();
}
});
 
// 그룹 하위 항목이 모두 선택되면 상위 [선택] 헤더(termsAgree3~7)도 선택 (하나라도 해제 시 해제)
$formTerms.on('change', '.privacy-item.toggle-item .privacy-body :checkbox', function () {
const $group = $(this).closest('.privacy-body').closest('.privacy-item.toggle-item');
const $header = $group.children('.privacy-head').find(':checkbox');
const $subs = $group.children('.privacy-body').find(':checkbox');
if ($subs.length === 0) {
return;
}
const allChecked = $subs.not(':checked').length === 0;
$header.prop('checked', allChecked).siblings('label').toggleClass('on', allChecked);
});
 
/*
* 전체 동의 역동기화 — 하위 체크박스가 모두 선택되면 전체 동의도 선택 (하나라도 해제되면 해제)
*/
const syncAllAgree = function () {
const $targets = $(':checkbox', $formTerms).not('#allAgree').not('#termsAgree');
const allChecked = $targets.length > 0 && $targets.not(':checked').length === 0;
$('#allAgree', $formTerms).prop('checked', allChecked)
.siblings('label').toggleClass('on', allChecked);
};
$formTerms.on('change', ':checkbox', function (e) {
if (e.target.id === 'allAgree' || e.target.id === 'termsAgree') {
return;
}
syncAllAgree();
});
});
/**
* 아이폰+페이스북앱에서 location.href로 페이지 이동으로 처리시
 
data/skin/mobile/story_g/member/_join_view.html-18
변경 전_join_view.html
<div class="input_wrap">
<div class="input_title"></div>
<div class="input_content">
<!--{? joinField.maillingFl.use === 'y'}-->
<div class="description chk">
<span class="inp_chk">
<input type="checkbox" class="checkbox sp" id="maillingFl" name="maillingFl" value="y" {? data.maillingFl==
'y'}checked="checked"{/}>
<label for="maillingFl">{=__('정보/이벤트 메일 수신에 동의합니다.')}</label>
</span>
</div>
<!--{/}-->
<div class="description_wrap">
<div class="description">※ {=__('아이디 비밀번호 찾기에 활용 되므로 정확하게 입력해 주세요')}</div>
</div>
</div>
<!--{ / }-->
<!--{ / }-->
<!--{? joinField.smsFl.use === 'y'}-->
<div class="description chk">
<span class="inp_chk">
<input type="checkbox" class="checkbox sp" id="smsFl" name="smsFl" value="y" {? data.smsFl==
'y'}checked="checked"{/}>
<label for="smsFl">{=__('정보/이벤트 SMS 수신에 동의합니다.')}</label>
</span>
</div>
<!--{/}-->
</div>
</div>
<!--{/}--><!--{? joinField.phone.use == 'y'}-->
 
변경 후_join_view.html
<div class="input_wrap">
<div class="input_title"></div>
<div class="input_content">
 
 
 
 
 
 
 
 
 
<div class="description_wrap">
<div class="description">※ {=__('아이디 비밀번호 찾기에 활용 되므로 정확하게 입력해 주세요')}</div>
</div>
</div>
<!--{ / }-->
<!--{ / }-->
 
 
 
 
 
 
 
 
 
</div>
</div>
<!--{/}--><!--{? joinField.phone.use == 'y'}-->
 
data/skin/mobile/story_g/member/_join_view_other.html+89-2
변경 전_join_view_other.html
<!--{/}-->
</div>
<!--{/}-->
<!--{? privateApprovalOption[0]['modeFl'] == 'y' || privateConsign[0]['modeFl']=='y' || privateOffer[0]['modeFl']=='y'}-->
<div class="account_title">
<b class="title">{=__('약관동의현황')}</b>
</div>
</div>
</div>
<!--{/ // privateOffer modeFl end}-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<!--{/}-->
<script type="text/javascript">
$(document).ready(function () {
e.preventDefault();
$('p.msg').addClass('hidden');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy-item');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
}
});
 
 
 
 
 
 
<!--{ ? useAppleLogin }-->
$("#apple_btn").on("click", startClicked);
function startClicked(){
 
변경 후_join_view_other.html
<!--{/}-->
</div>
<!--{/}-->
<!--{? privateApprovalOption[0]['modeFl'] == 'y' || privateConsign[0]['modeFl']=='y' || privateOffer[0]['modeFl']=='y' || privateMktApprovalOption[0]['modeFl']=='y' || isUseAdvertisingReceive}-->
<div class="account_title">
<b class="title">{=__('약관동의현황')}</b>
</div>
</div>
</div>
<!--{/ // privateOffer modeFl end}-->
<!--{? privateMktApprovalOption[0]['modeFl'] == 'y'}-->
<div class="privacy-item toggle-item toggle-open">
<div class="privacy-head">
<span class="inp_chk">
<input type="checkbox" class="sp" id="termsAgree6" name="">
<label for="termsAgree6">({=__('선택')}) {=__('마케팅 목적 개인정보 수집 및 이용 동의')}</label>
</span>
<div class="option">
<button type="button" class="btn-reset toggle-switch">{=__('내용보기')} ▼</button>
</div>
</div>
<div class="privacy-body">
<!--{@ privateMktApprovalOption}-->
<div class="privacy-item toggle-item toggle-open">
<div class="privacy-head">
<span class="inp_chk">
<input type="checkbox" class="sp" id="privateMarketingConsentOptionFl" name="privateMarketingConsentOptionFl" value="y" <!--{? data['privateMarketingConsentOptionFl'] == 'y'}-->checked="checked"<!--{/}-->>
<label class="single <!--{? data['privateMarketingConsentOptionFl'] == 'y'}-->on<!--{/}-->" for="privateMarketingConsentOptionFl">{=nl2br(.informNm)}</label>
</span>
<div class="option">
<button type="button" class="btn-reset js_agreement_view" data-code="{.informCd}">{=__('전체보기')}</button>
</div>
</div>
<div class="privacy-body">
{=nl2br(.content)}
</div>
</div>
<!--{/}-->
</div>
</div>
<!--{/ // privateMktApprovalOption modeFl end}-->
<!--{? isUseAdvertisingReceive}-->
<div class="privacy-item toggle-item toggle-open">
<div class="privacy-head">
<span class="inp_chk">
<input type="checkbox" class="sp" id="termsAgree7" name="">
<label for="termsAgree7">({=__('선택')}) {=__('광고성 수신 동의')}</label>
</span>
<div class="option">
<button type="button" class="btn-reset toggle-switch">{=__('내용보기')} ▼</button>
</div>
</div>
<div class="privacy-body">
<div class="privacy-item toggle-item toggle-open">
<div class="privacy-head">
<span class="inp_chk">
<input type="checkbox" class="sp" id="advertisingReceiveAll" <!--{? data['maillingFl'] == 'y' || data['smsFl'] == 'y'}-->checked="checked"<!--{/}-->>
<label class="single <!--{? data['maillingFl'] == 'y' || data['smsFl'] == 'y'}-->on<!--{/}-->" for="advertisingReceiveAll">{=nl2br(advertisingReceive['informNm'])}</label>
</span>
<div class="option">
<button type="button" class="btn-reset js_agreement_view" data-code="{advertisingReceive['informCd']}">{=__('전체보기')}</button>
</div>
</div>
<div class="privacy-body">
{=nl2br(advertisingReceive['content'])}
</div>
</div>
<div class="js_advertising_channel_box" style="display:flex; flex-direction:column; align-items:flex-start; margin:10px;">
<!--{? advertisingReceiveMailUse == 'y'}-->
<div class="privacy-item">
<div class="privacy-head">
<span class="inp_chk">
<input type="checkbox" class="sp js_advertising_channel" id="advertisingReceiveMail" name="maillingFl" value="y" <!--{? data['maillingFl'] == 'y'}-->checked="checked"<!--{/}-->>
<label class="single <!--{? data['maillingFl'] == 'y'}-->on<!--{/}-->" for="advertisingReceiveMail">{=__('이메일 수신 동의')}</label>
</span>
</div>
</div>
<!--{/}-->
<!--{? advertisingReceiveSmsUse == 'y'}-->
<div class="privacy-item">
<div class="privacy-head">
<span class="inp_chk">
<input type="checkbox" class="sp js_advertising_channel" id="advertisingReceiveSms" name="smsFl" value="y" <!--{? data['smsFl'] == 'y'}-->checked="checked"<!--{/}-->>
<label class="single <!--{? data['smsFl'] == 'y'}-->on<!--{/}-->" for="advertisingReceiveSms">{=__('모바일 메시지 수신 동의')}</label>
</span>
</div>
</div>
<!--{/}-->
</div>
</div>
</div>
<!--{/ // isUseAdvertisingReceive end}-->
<!--{/}-->
<script type="text/javascript">
$(document).ready(function () {
e.preventDefault();
$('p.msg').addClass('hidden');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.privacy-item');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5') || (e.target.id === 'termsAgree6') || (e.target.id === 'termsAgree7');
var isTargetChecked = $target.prop('checked') === true;
 
if (isTargetChecked) {
}
});
 
// 마수동/광수동 약관 전문 새창 열기 (전체보기)
$('.js_agreement_view').on('click', function () {
window.open('../service/agreement.php?code=' + $(this).data('code'));
});
 
<!--{ ? useAppleLogin }-->
$("#apple_btn").on("click", startClicked);
function startClicked(){
 
data/skin/mobile/story_g/mypage/my_page.html+97-1
변경 전my_page.html
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.terms-view');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5');
var isTargetChecked = $target.prop('checked') === true;
if (isTargetChecked) {
}
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
select_email_domain('email');
<!--{? (joinField.marriFl.use == 'y' && joinField.marriDate.use == 'y') || joinField.birthDt.use == 'y' }-->
 
변경 후my_page.html
e.preventDefault();
$('p.msg').addClass('dn');
var $target = $(e.target), $label = $target.siblings('label'), $termsView = $target.closest('.terms-view');
var isTermsAgreeSelect = (e.target.id === 'termsAgree3') || (e.target.id === 'termsAgree4') || (e.target.id === 'termsAgree5') || (e.target.id === 'termsAgree6') || (e.target.id === 'termsAgree7');
var isTargetChecked = $target.prop('checked') === true;
if (isTargetChecked) {
}
});
/*
* 광고성 수신 동의 ↔ 이메일/모바일 수신 동의 ↔ 마케팅 목적 개인정보 수집 및 이용 동의 연동 (마이페이지 전용)
* - 광고성 수신 동의 체크 → 이메일/모바일 채널 일괄 + 마케팅 목적 동의 ON
* - 채널(1개 이상) 체크 → 광고성 수신 동의 + 마케팅 목적 동의 ON (채널은 각각 개별 토글)
* - 이 스크립트는 마이페이지(my_page.html)에서만 로드되므로 $(document) 위임으로 바인딩해도 회원가입 화면엔 적용되지 않음
* (광고성 체크박스가 #formJoin 밖에 렌더되는 경우가 있어 $formJoin 스코프는 사용하지 않음)
*/
const checkMarketingApproval = function () {
$('#privateMarketingConsentOptionFl').prop('checked', true).val('y').siblings('label').addClass('on');
$('#termsAgree6').prop('checked', true).siblings('label').addClass('on');
};
$(document).on('change', '#termsAgree7', function () {
const isChecked = $(this).prop('checked') === true;
$(this).siblings('label').toggleClass('on', isChecked);
$('#advertisingReceiveAll').prop('checked', isChecked)
.siblings('label').toggleClass('on', isChecked);
$('.js_advertising_channel').prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$(document).on('change', '#advertisingReceiveAll', function () {
const isChecked = $(this).prop('checked') === true;
$('.js_advertising_channel').prop('checked', isChecked).val(isChecked ? 'y' : 'n')
.siblings('label').toggleClass('on', isChecked);
// 전체선택(advertisingReceiveAll) 직접 조작 시 광고성 수신 동의(termsAgree7) 헤더도 동기화
$('#termsAgree7').prop('checked', isChecked).siblings('label').toggleClass('on', isChecked);
if (isChecked) {
checkMarketingApproval();
}
});
$(document).on('change', '.js_advertising_channel', function () {
const anyChannelChecked = $('.js_advertising_channel:checked').length > 0;
const allChannelChecked = $('.js_advertising_channel').length > 0
&& $('.js_advertising_channel:not(:checked)').length === 0;
$('#advertisingReceiveAll').prop('checked', anyChannelChecked)
.siblings('label').toggleClass('on', anyChannelChecked);
if (anyChannelChecked) {
checkMarketingApproval();
}
// 수신 채널 전부 선택 시 광고성 수신 동의(termsAgree7) 헤더 ON (일부만이면 켜지 않음)
if (allChannelChecked) {
$('#termsAgree7').prop('checked', true).siblings('label').addClass('on');
}
if ($(this).prop('checked') === false) {
$('#termsAgree7').prop('checked', false).siblings('label').removeClass('on');
}
});
// 마케팅 목적 개인정보 수집 및 이용 동의 체크 시 광고성 수신 동의·수신 채널 일괄 선택
const checkAdvertising = function () {
if ($('#termsAgree7').length === 0) {
return;
}
$('#termsAgree7').prop('checked', true).siblings('label').addClass('on');
$('#advertisingReceiveAll').prop('checked', true).siblings('label').addClass('on');
$('.js_advertising_channel').prop('checked', true).val('y').siblings('label').addClass('on');
};
$(document).on('change', '#privateMarketingConsentOptionFl', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
} else {
$('#termsAgree6').prop('checked', false).siblings('label').removeClass('on');
}
});
// 마케팅 목적 개인정보 수집 및 이용 동의 그룹 [선택] 헤더 체크 시 광고성 수신 동의·수신 채널 연동
$(document).on('change', '#termsAgree6', function () {
if ($(this).prop('checked') === true) {
checkAdvertising();
}
});
// 그룹 하위 항목이 모두 선택되면 상위 [선택] 헤더도 선택 (하나라도 해제 시 해제)
$(document).on('change', '.privacy-head :checkbox', function () {
$('#termsAgree3, #termsAgree4, #termsAgree5, #termsAgree6').each(function () {
const $header = $(this);
const $subs = $header.closest('.privacy-item').find(':checkbox').not($header);
if ($subs.length === 0) {
return;
}
const allChecked = $subs.not(':checked').length === 0;
$header.prop('checked', allChecked).siblings('label').toggleClass('on', allChecked);
});
});
// 초기 로드: 저장된 하위 선택 상태로 상위 [선택] 헤더 동기화
$('#termsAgree3, #termsAgree4, #termsAgree5, #termsAgree6').each(function () {
const $subs = $(this).closest('.privacy-item').find(':checkbox').not(this);
if ($subs.length > 0 && $subs.not(':checked').length === 0) {
$(this).prop('checked', true).siblings('label').addClass('on');
}
});
// 초기 로드: 수신 채널이 전부 선택된 상태면 광고성 수신 동의(termsAgree7) 헤더 ON
if ($('.js_advertising_channel').length > 0
&& $('.js_advertising_channel:not(:checked)').length === 0) {
$('#termsAgree7').prop('checked', true).siblings('label').addClass('on');
}
select_email_domain('email');
<!--{? (joinField.marriFl.use == 'y' && joinField.marriDate.use == 'y') || joinField.birthDt.use == 'y' }-->
 
지역별 추가배송비 구간별 반복 부과 옵션 추가
Admin/policy/delivery_regist.php+84-2
변경 전delivery_regist.php
</div>
</td>
</tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
</tbody>
<tbody>
<tr>
</script>
<script type="text/html" id="templateMethodEtc">
<tr>
<th>배송비 설정(<%=strTitle%>별)</th>
<td colspan="3">
<% if (deliveryConfigType == 'all') { %>
<table id="basicDeliveryConfigFeeForm" class="table table-cols mgb0">
</script>
<script type="text/html" id="templateMethodEtcRangeRepeat">
<tr>
<th>배송비 설정(<%=strTitle%>별)</th>
<td colspan="3">
<% if (deliveryConfigType == 'all') { %>
<table id="basicDeliveryConfigFeeForm" class="table table-cols mgb0">
</td>
</tr>
</script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<script type="text/javascript">
<!--
var data = <?=json_encode($data)?>;
* @param string fixMethod 배송비 책정 방법
*/
var defaultMethod, defaultDeliveryConfigType, defaultRangeRepeat;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
function form_delivery_charge(fixMethod) {
deliveryConfigType();
 
// 배송비설정 초기화
form_delivery_charge(fixFl);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// 금액 입력부 초기화
$('input[name*=\'[unitStart]\']').number_only();
$('input[name*=\'[unitEnd]\']').number_only();
$('#basic_fixFl').change(function () {
fixFl = this.value;
form_delivery_charge(this.value);
 
});
 
// 공급사 구분 선택 이벤트
else {
$('#areaGroupSelect').hide();
}
 
});
 
// 출고지/반품/교환지 주소 토글
 
변경 후delivery_regist.php
</div>
</td>
</tr>
<tr id="areaChargeRepeatArea"<?= (in_array($data['basic']['fixFl'], ['count', 'weight']) && $data['basic']['areaFl'] == 'y') ? '' : ' style="display:none;"' ?>>
<th>지역별 추가배송비<br>부과방법
<button type="button" class="btn btn-xs js-area-charge-repeat-help"><span class="icon-tooltip"></span></button>
</th>
<td colspan="3">
<label class="radio-inline">
<input type="radio" name="basic[areaChargeRepeatFl]" value="n" <?= $checked['areaChargeRepeatFl']['n'] ?? '' ?> /> 배송비 구간에 상관없이 1회 부과
</label>
<label class="radio-inline">
<input type="radio" name="basic[areaChargeRepeatFl]" value="y" <?= $checked['areaChargeRepeatFl']['y'] ?? '' ?> /> 배송비 구간마다 반복 부과
</label>
</td>
</tr>
</tbody>
<tbody>
<tr>
</script>
<script type="text/html" id="templateMethodEtc">
<tr>
<th>배송비 <%= (fixMethod == 'count' || fixMethod == 'weight') ? '구간 ' : '' %>설정(<%=strTitle%>별)</th>
<td colspan="3">
<% if (deliveryConfigType == 'all') { %>
<table id="basicDeliveryConfigFeeForm" class="table table-cols mgb0">
</script>
<script type="text/html" id="templateMethodEtcRangeRepeat">
<tr>
<th>배송비 <%= (fixMethod == 'count' || fixMethod == 'weight') ? '구간 ' : '' %>설정(<%=strTitle%>별)</th>
<td colspan="3">
<% if (deliveryConfigType == 'all') { %>
<table id="basicDeliveryConfigFeeForm" class="table table-cols mgb0">
</td>
</tr>
</script>
<!-- 지역별 추가배송비 부과방법 도움말 (팝오버 콘텐츠) -->
<div id="areaChargeRepeatHelp" class="display-none">
<p><strong>배송비 구간에 상관없이 1회 부과</strong><br/>
- 주문한 상품의 수량, 무게에 상관없이 지역별 추가 배송비가 1회만 부과됩니다.</p>
<p><strong>배송비 구간마다 반복 부과</strong><br/>
- 배송비 구간 설정에서 입력한 수량, 무게 범위 구간마다 지역별 추가 배송비가 추가 부과됩니다.</p>
<table class="table table-cols">
<colgroup><col style="width:60%"/><col style="width:40%"/></colgroup>
<thead><tr><th>구매수량 범위</th><th>배송비</th></tr></thead>
<tbody>
<tr><td>0개 이상 ~ 2개 미만일 때</td><td>1,000원</td></tr>
<tr><td>3개 이상</td><td>3,000원</td></tr>
</tbody>
</table>
<p>: 지역별 배송비가 500원일 때, 4개 구매 시 지역별 배송비가 2회 부과되어<br/>
총 배송비는 3,000원 + (500원 x 2) = 4,000원</p>
<p>- 범위 반복이 설정된 경우 입력한 수량, 무게 단위로 지역별 배송비가 추가 부과됩니다.</p>
<table class="table table-cols">
<colgroup><col style="width:60%"/><col style="width:40%"/></colgroup>
<thead><tr><th>구매수량 범위</th><th>배송비</th></tr></thead>
<tbody>
<tr><td>0개 이상 ~ 2개 미만일 때</td><td>1,000원</td></tr>
<tr><td>2개 이상 ~ 2개 마다 반복 부과</td><td>2,000원</td></tr>
</tbody>
</table>
<p>: 지역별 배송비가 500원일 때, 6개 구매 시 지역별 배송비가 4회 부과되어<br/>
총 배송비는 1,000원 + (2,000원 x 3) + (500원 x 4) = 9,000원</p>
</div>
<style>
button.js-area-charge-repeat-help { background-color: transparent; margin: 0; }
.area-charge-repeat-popover { max-width: 480px; }
.area-charge-repeat-popover .popover-content { padding: 15px; }
.area-charge-repeat-popover table { margin-bottom: 8px; }
.area-charge-repeat-popover table td { text-align: left; }
.area-charge-repeat-popover .popover-content { text-align: left; }
</style>
<script type="text/javascript">
<!--
var data = <?=json_encode($data)?>;
* @param string fixMethod 배송비 책정 방법
*/
var defaultMethod, defaultDeliveryConfigType, defaultRangeRepeat;
 
/**
* 지역별 추가배송비 부과방법(1회/구간반복) 노출 토글
* 노출조건: 배송비 유형이 수량별/무게별 이고, 지역별 추가배송비가 "있음"일 때만
*/
function toggleAreaChargeRepeat() {
var fixFlVal = $('#basic_fixFl').val();
var areaFlVal = $('input[name="basic[areaFl]"]:checked').val();
if ((fixFlVal == 'count' || fixFlVal == 'weight') && areaFlVal == 'y') {
$('#areaChargeRepeatArea').show();
} else {
$('#areaChargeRepeatArea').hide();
}
}
 
function form_delivery_charge(fixMethod) {
deliveryConfigType();
 
// 배송비설정 초기화
form_delivery_charge(fixFl);
 
// 지역별 추가배송비 부과방법 노출 초기화
toggleAreaChargeRepeat();
 
// 지역별 추가배송비 부과방법 도움말 팝오버
$('.js-area-charge-repeat-help').popover({
trigger: 'hover',
container: '#content',
html: true,
sanitize: false,
placement: 'right',
content: function () {
return $('#areaChargeRepeatHelp').html();
},
template: '<div class="popover area-charge-repeat-popover" role="tooltip"><div class="arrow"></div><div class="popover-content"></div></div>'
});
 
// 금액 입력부 초기화
$('input[name*=\'[unitStart]\']').number_only();
$('input[name*=\'[unitEnd]\']').number_only();
$('#basic_fixFl').change(function () {
fixFl = this.value;
form_delivery_charge(this.value);
toggleAreaChargeRepeat();
});
 
// 공급사 구분 선택 이벤트
else {
$('#areaGroupSelect').hide();
}
toggleAreaChargeRepeat();
});
 
// 출고지/반품/교환지 주소 토글
 
Admin/provider/policy/delivery_regist.php+84-2
변경 전delivery_regist.php
</div>
</td>
</tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
</tbody>
<tbody>
<tr>
</script>
<script type="text/html" id="templateMethodEtc">
<tr>
<th>배송비 설정(<%=strTitle%>별)</th>
<td colspan="3">
<% if (deliveryConfigType == 'all') { %>
<table id="basicDeliveryConfigFeeForm" class="table table-cols mgb0">
</script>
<script type="text/html" id="templateMethodEtcRangeRepeat">
<tr>
<th>배송비 설정(<%=strTitle%>별)</th>
<td colspan="3">
<% if (deliveryConfigType == 'all') { %>
<table id="basicDeliveryConfigFeeForm" class="table table-cols mgb0">
</tr>
</script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<script type="text/javascript">
<!--
var data = <?=json_encode($data)?>;
* @param string fixMethod 배송비 책정 방법
*/
var defaultMethod, defaultDeliveryConfigType, defaultRangeRepeat;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
function form_delivery_charge(fixMethod) {
deliveryConfigType();
 
// 배송비설정 초기화
form_delivery_charge(fixFl);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// 금액 입력 초기화
$('input[name*=\'[unitStart]\']').number_only();
$('input[name*=\'[unitEnd]\']').number_only();
console.log($('#basic_fixFl option:selected').val());
fixFl = this.value;
form_delivery_charge(this.value);
 
});
 
// 삭제 버튼 클릭시 이벤트
else {
$('#areaGroupSelect').hide();
}
 
});
 
// 출고지/반품/교환지 주소 토글
 
변경 후delivery_regist.php
</div>
</td>
</tr>
<tr id="areaChargeRepeatArea"<?= (in_array($data['basic']['fixFl'], ['count', 'weight']) && $data['basic']['areaFl'] == 'y') ? '' : ' style="display:none;"' ?>>
<th>지역별 추가배송비<br>부과방법
<button type="button" class="btn btn-xs js-area-charge-repeat-help"><span class="icon-tooltip"></span></button>
</th>
<td colspan="3">
<label class="radio-inline">
<input type="radio" name="basic[areaChargeRepeatFl]" value="n" <?= $checked['areaChargeRepeatFl']['n'] ?? '' ?> /> 배송비 구간에 상관없이 1회 부과
</label>
<label class="radio-inline">
<input type="radio" name="basic[areaChargeRepeatFl]" value="y" <?= $checked['areaChargeRepeatFl']['y'] ?? '' ?> /> 배송비 구간마다 반복 부과
</label>
</td>
</tr>
</tbody>
<tbody>
<tr>
</script>
<script type="text/html" id="templateMethodEtc">
<tr>
<th>배송비 <%= (fixMethod == 'count' || fixMethod == 'weight') ? '구간 ' : '' %>설정(<%=strTitle%>별)</th>
<td colspan="3">
<% if (deliveryConfigType == 'all') { %>
<table id="basicDeliveryConfigFeeForm" class="table table-cols mgb0">
</script>
<script type="text/html" id="templateMethodEtcRangeRepeat">
<tr>
<th>배송비 <%= (fixMethod == 'count' || fixMethod == 'weight') ? '구간 ' : '' %>설정(<%=strTitle%>별)</th>
<td colspan="3">
<% if (deliveryConfigType == 'all') { %>
<table id="basicDeliveryConfigFeeForm" class="table table-cols mgb0">
</tr>
</script>
 
<!-- 지역별 추가배송비 부과방법 도움말 (팝오버 콘텐츠) -->
<div id="areaChargeRepeatHelp" class="display-none">
<p><strong>배송비 구간에 상관없이 1회 부과</strong><br/>
- 주문한 상품의 수량, 무게에 상관없이 지역별 추가 배송비가 1회만 부과됩니다.</p>
<p><strong>배송비 구간마다 반복 부과</strong><br/>
- 배송비 구간 설정에서 입력한 수량, 무게 범위 구간마다 지역별 추가 배송비가 추가 부과됩니다.</p>
<table class="table table-cols">
<colgroup><col style="width:60%"/><col style="width:40%"/></colgroup>
<thead><tr><th>구매수량 범위</th><th>배송비</th></tr></thead>
<tbody>
<tr><td>0개 이상 ~ 2개 미만일 때</td><td>1,000원</td></tr>
<tr><td>3개 이상</td><td>3,000원</td></tr>
</tbody>
</table>
<p>: 지역별 배송비가 500원일 때, 4개 구매 시 지역별 배송비가 2회 부과되어<br/>
총 배송비는 3,000원 + (500원 x 2) = 4,000원</p>
<p>- 범위 반복이 설정된 경우 입력한 수량, 무게 단위로 지역별 배송비가 추가 부과됩니다.</p>
<table class="table table-cols">
<colgroup><col style="width:60%"/><col style="width:40%"/></colgroup>
<thead><tr><th>구매수량 범위</th><th>배송비</th></tr></thead>
<tbody>
<tr><td>0개 이상 ~ 2개 미만일 때</td><td>1,000원</td></tr>
<tr><td>2개 이상 ~ 2개 마다 반복 부과</td><td>2,000원</td></tr>
</tbody>
</table>
<p>: 지역별 배송비가 500원일 때, 6개 구매 시 지역별 배송비가 4회 부과되어<br/>
총 배송비는 1,000원 + (2,000원 x 3) + (500원 x 4) = 9,000원</p>
</div>
<style>
button.js-area-charge-repeat-help { background-color: transparent; margin: 0; }
.area-charge-repeat-popover { max-width: 480px; }
.area-charge-repeat-popover .popover-content { padding: 15px; }
.area-charge-repeat-popover table { margin-bottom: 8px; }
.area-charge-repeat-popover table td { text-align: left; }
.area-charge-repeat-popover .popover-content { text-align: left; }
</style>
<script type="text/javascript">
<!--
var data = <?=json_encode($data)?>;
* @param string fixMethod 배송비 책정 방법
*/
var defaultMethod, defaultDeliveryConfigType, defaultRangeRepeat;
 
/**
* 지역별 추가배송비 부과방법(1회/구간반복) 노출 토글
* 노출조건: 배송비 유형이 수량별/무게별 이고, 지역별 추가배송비가 "있음"일 때만
*/
function toggleAreaChargeRepeat() {
var fixFlVal = $('#basic_fixFl').val();
var areaFlVal = $('input[name="basic[areaFl]"]:checked').val();
if ((fixFlVal == 'count' || fixFlVal == 'weight') && areaFlVal == 'y') {
$('#areaChargeRepeatArea').show();
} else {
$('#areaChargeRepeatArea').hide();
}
}
 
function form_delivery_charge(fixMethod) {
deliveryConfigType();
 
// 배송비설정 초기화
form_delivery_charge(fixFl);
 
// 지역별 추가배송비 부과방법 노출 초기화
toggleAreaChargeRepeat();
 
// 지역별 추가배송비 부과방법 도움말 팝오버
$('.js-area-charge-repeat-help').popover({
trigger: 'hover',
container: '#content',
html: true,
sanitize: false,
placement: 'right',
content: function () {
return $('#areaChargeRepeatHelp').html();
},
template: '<div class="popover area-charge-repeat-popover" role="tooltip"><div class="arrow"></div><div class="popover-content"></div></div>'
});
 
// 금액 입력 초기화
$('input[name*=\'[unitStart]\']').number_only();
$('input[name*=\'[unitEnd]\']').number_only();
console.log($('#basic_fixFl option:selected').val());
fixFl = this.value;
form_delivery_charge(this.value);
toggleAreaChargeRepeat();
});
 
// 삭제 버튼 클릭시 이벤트
else {
$('#areaGroupSelect').hide();
}
toggleAreaChargeRepeat();
});
 
// 출고지/반품/교환지 주소 토글
 
Component/Cart/Cart.php+31-1
변경 전Cart.php
if ($sameGoodsDeliveryFl !== 'y') {
// 배송비 계산
if ($tmp['deliveryByCalculate'] === 'y') {
 
if ($getDeliveryInfo[$deliverySno]['rangeRepeat'] === 'y') {
//범위 반복 설정이 되어있는 경우
$deliveryStandardFinal = 0;
}
 
$goodsDeliveryPrice += ($deliveryStandardFinal * $conditionRepeat['price']);
 
}
}
}
}
if ($tmp['deliveryByStandard'] >= $cVal['unitStart'] && $tmp['deliveryByStandard'] < $cVal['unitEnd']) {
$goodsDeliveryPrice = $cVal['price'];
 
continue;
}
}
}
 
 
 
 
 
 
}
 
// 방문수령 배송비 무료 처리
if (isset($setDeliveryCond[$deliverySno][$gVal['goodsNo']]['goodsDeliveryCollectFl']) === false || empty($setDeliveryCond[$deliverySno][$gVal['goodsNo']]['goodsDeliveryCollectFl']) === true) {
$setDeliveryCond[$deliverySno][$gVal['goodsNo']]['goodsDeliveryCollectFl'] = $goodsDeliveryCollectFl;
}
 
 
 
 
 
 
}
}
// 배송비조건별 계산
// SCM 번호 설정
$scmNo = $deliveryCond['scmNo'];
 
 
 
// 배송비 계산
if ($deliveryCond['deliveryByCalculate'] === 'y') {
foreach ($setDeliveryCharge as $cKey => $cVal) {
$deliveryStandardFinal += 1;
}
$rangeRepeatPrice += ($deliveryStandardFinal * $cVal['price']);
 
}
}
}
//범위반복 미사용일 시
if ($deliveryCond['deliveryByStandard'] >= $cVal['unitStart'] && $deliveryCond['deliveryByStandard'] < $cVal['unitEnd']) {
$conditionSatisfy = true;
 
}
}
 
$checkZeroPrice = true;
StringUtils::strIsSet($deliveryCond['goodsDeliveryAreaPrice'], 0);
if ($deliveryCond['goodsDeliveryAreaPrice'] > 0) {
$deliveryCond['goodsDeliveryCollectPrice'] += $deliveryCond['goodsDeliveryAreaPrice'];
 
 
 
 
 
}
}
 
}
}
 
 
 
 
 
 
 
// 상품별 지역배송비 총 배송 금액
gd_isset($this->totalGoodsDeliveryAreaPrice[$key], 0);
if ($multiShippingFl == 'y') gd_isset($this->totalGoodsMultiDeliveryAreaPrice[$orderInfoCd][$key], 0);
 
변경 후Cart.php
if ($sameGoodsDeliveryFl !== 'y') {
// 배송비 계산
if ($tmp['deliveryByCalculate'] === 'y') {
$areaChargeRepeatCount = 1; // 지역별 추가배송비 반복 구간 순번 (기본 1회)
if ($getDeliveryInfo[$deliverySno]['rangeRepeat'] === 'y') {
//범위 반복 설정이 되어있는 경우
$deliveryStandardFinal = 0;
}
 
$goodsDeliveryPrice += ($deliveryStandardFinal * $conditionRepeat['price']);
$areaChargeRepeatCount = $deliveryStandardFinal + 1; // 범위반복: 첫 구간(1) + 반복 횟수
}
}
}
}
if ($tmp['deliveryByStandard'] >= $cVal['unitStart'] && $tmp['deliveryByStandard'] < $cVal['unitEnd']) {
$goodsDeliveryPrice = $cVal['price'];
$areaChargeRepeatCount = $cKey + 1; // 매칭 구간 순번
continue;
}
}
}
 
// 지역별 추가배송비 구간 반복 부과
// 부과방법이 '구간마다 반복(Y)'이면 매칭 구간 순번(N)만큼 지역배송비를 곱한다
if ($getDeliveryInfo[$deliverySno]['areaChargeRepeatFl'] === 'y' && $goodsDeliveryAreaPrice > 0) {
$goodsDeliveryAreaPrice = $goodsDeliveryAreaPrice * $areaChargeRepeatCount;
}
}
 
// 방문수령 배송비 무료 처리
if (isset($setDeliveryCond[$deliverySno][$gVal['goodsNo']]['goodsDeliveryCollectFl']) === false || empty($setDeliveryCond[$deliverySno][$gVal['goodsNo']]['goodsDeliveryCollectFl']) === true) {
$setDeliveryCond[$deliverySno][$gVal['goodsNo']]['goodsDeliveryCollectFl'] = $goodsDeliveryCollectFl;
}
 
// 지역별 추가배송비 '구간마다 반복(y)'인 경우, 매칭 구간 순번(N) 곱셈을 위해 getDeliveryCond 로 전달
if ($getDeliveryInfo[$deliverySno]['areaChargeRepeatFl'] === 'y' && $goodsDeliveryAreaPrice > 0) {
$setDeliveryCond[$deliverySno][$gVal['goodsNo']]['goodsDeliveryAreaPrice'] = $goodsDeliveryAreaPrice;
$goodsDeliveryAreaPrice = 0;
}
}
}
// 배송비조건별 계산
// SCM 번호 설정
$scmNo = $deliveryCond['scmNo'];
 
$areaChargeRepeatCount = 1; // 지역별 추가배송비 반복 구간 순번 (기본 1회)
 
// 배송비 계산
if ($deliveryCond['deliveryByCalculate'] === 'y') {
foreach ($setDeliveryCharge as $cKey => $cVal) {
$deliveryStandardFinal += 1;
}
$rangeRepeatPrice += ($deliveryStandardFinal * $cVal['price']);
$areaChargeRepeatCount = $deliveryStandardFinal + 1; // 범위반복: 첫 구간(1) + 반복 횟수
}
}
}
//범위반복 미사용일 시
if ($deliveryCond['deliveryByStandard'] >= $cVal['unitStart'] && $deliveryCond['deliveryByStandard'] < $cVal['unitEnd']) {
$conditionSatisfy = true;
$areaChargeRepeatCount = $cKey + 1; // 매칭 구간 순번
}
}
 
$checkZeroPrice = true;
StringUtils::strIsSet($deliveryCond['goodsDeliveryAreaPrice'], 0);
if ($deliveryCond['goodsDeliveryAreaPrice'] > 0) {
// 지역별 추가배송비 구간 반복 부과 (착불도 매칭 구간 순번 N만큼 합산)
$repeatedAreaPrice = $deliveryCond['goodsDeliveryAreaPrice'];
if ($deliveryInfo['areaChargeRepeatFl'] === 'y') {
$repeatedAreaPrice = $repeatedAreaPrice * $areaChargeRepeatCount;
}
$deliveryCond['goodsDeliveryCollectPrice'] += $repeatedAreaPrice;
}
}
 
}
}
 
// 지역별 추가배송비 구간 반복 부과
// 부과방법이 '구간마다 반복(y)'이면 매칭 구간 순번(N)만큼 지역배송비를 곱한다
if ($deliveryInfo['areaChargeRepeatFl'] === 'y' && $deliveryCond['deliveryByCalculate'] === 'y' && !empty($deliveryCond['goodsDeliveryAreaPrice'])) {
$deliveryCond['goodsDeliveryAreaPrice'] = $deliveryCond['goodsDeliveryAreaPrice'] * $areaChargeRepeatCount;
}
 
// 상품별 지역배송비 총 배송 금액
gd_isset($this->totalGoodsDeliveryAreaPrice[$key], 0);
if ($multiShippingFl == 'y') gd_isset($this->totalGoodsMultiDeliveryAreaPrice[$orderInfoCd][$key], 0);
 
Component/Database/DBTableField.php+1
변경 전DBTableField.php
['val' => 'dmVisitAddressUseFl', 'typ' => 's', 'def' => 'n'], // 방문수령지 상품상세노출여부
['val' => 'rangeRepeat', 'typ' => 's', 'def' => 'n'], // 범위반복구간여부
['val' => 'addGoodsCountInclude', 'typ' => 's', 'def' => 'n'], // 수량별배송비 추가옵션수량 포함여부
 
];
// @formatter:on
 
 
변경 후DBTableField.php
['val' => 'dmVisitAddressUseFl', 'typ' => 's', 'def' => 'n'], // 방문수령지 상품상세노출여부
['val' => 'rangeRepeat', 'typ' => 's', 'def' => 'n'], // 범위반복구간여부
['val' => 'addGoodsCountInclude', 'typ' => 's', 'def' => 'n'], // 수량별배송비 추가옵션수량 포함여부
['val' => 'areaChargeRepeatFl', 'typ' => 's', 'def' => 'n'], // 지역별 추가배송비 부과방법 (y:구간마다 반복 / n:1회)
];
// @formatter:on
 
 
Component/Delivery/DeliveryCart.php+1
변경 전DeliveryCart.php
'rangeLimitWeight',
'rangeRepeat',
'addGoodsCountInclude',
 
'deliveryMethodFl',
'deliveryVisitPayFl',
'deliveryConfigType',
 
변경 후DeliveryCart.php
'rangeLimitWeight',
'rangeRepeat',
'addGoodsCountInclude',
'areaChargeRepeatFl',
'deliveryMethodFl',
'deliveryVisitPayFl',
'deliveryConfigType',
 
Component/Delivery/Delivery.php+1
변경 전Delivery.php
$data['basic']['dmVisitTypeDisplayFl'] = gd_isset($arrData['basic']['dmVisitTypeDisplayFl'], 'n');
$data['basic']['rangeRepeat'] = gd_isset($arrData['basic']['rangeRepeat'], 'n');
$data['basic']['addGoodsCountInclude'] = gd_isset($arrData['basic']['addGoodsCountInclude'], 'n');
 
$data['basic']['deliveryVisitPayFl'] = gd_isset($arrData['basic']['deliveryVisitPayFl'], 'y');
$data['basic']['dmVisitAddressUseFl'] = gd_isset($arrData['basic']['dmVisitAddressUseFl'], 'n');
$data['basic']['sameGoodsDeliveryFl'] = gd_isset($arrData['basic']['sameGoodsDeliveryFl'], 'n');
 
변경 후Delivery.php
$data['basic']['dmVisitTypeDisplayFl'] = gd_isset($arrData['basic']['dmVisitTypeDisplayFl'], 'n');
$data['basic']['rangeRepeat'] = gd_isset($arrData['basic']['rangeRepeat'], 'n');
$data['basic']['addGoodsCountInclude'] = gd_isset($arrData['basic']['addGoodsCountInclude'], 'n');
$data['basic']['areaChargeRepeatFl'] = $arrData['basic']['areaChargeRepeatFl'] ?? 'n';
$data['basic']['deliveryVisitPayFl'] = gd_isset($arrData['basic']['deliveryVisitPayFl'], 'y');
$data['basic']['dmVisitAddressUseFl'] = gd_isset($arrData['basic']['dmVisitAddressUseFl'], 'n');
$data['basic']['sameGoodsDeliveryFl'] = gd_isset($arrData['basic']['sameGoodsDeliveryFl'], 'n');
 
Controller/Admin/Policy/DeliveryRegistController.php+2
변경 전DeliveryRegistController.php
gd_isset($data['basic']['dmVisitTypeFl'], 'same');
gd_isset($data['basic']['dmVisitTypeDisplayFl'], 'n');
gd_isset($data['basic']['rangeRepeat'], 'n');
 
gd_isset($data['manage']['scmNo'], (Manager::isProvider() && !Request::get()->has('sno') ? Session::get('manager.scmNo') : $data['manage']['scmNo']));
gd_isset($data['basic']['deliveryConfigType'], 'all');
 
$checked['dmVisitAddressUseFl'][$data['basic']['dmVisitAddressUseFl']] =
$checked['rangeRepeat'][$data['basic']['rangeRepeat']] =
$checked['addGoodsCountInclude'][$data['basic']['addGoodsCountInclude']] =
 
$checked['deliveryConfigType'][$data['basic']['deliveryConfigType']] = 'checked="checked"';
 
//배송 방식
 
변경 후DeliveryRegistController.php
gd_isset($data['basic']['dmVisitTypeFl'], 'same');
gd_isset($data['basic']['dmVisitTypeDisplayFl'], 'n');
gd_isset($data['basic']['rangeRepeat'], 'n');
$data['basic']['areaChargeRepeatFl'] = $data['basic']['areaChargeRepeatFl'] ?? 'n';
gd_isset($data['manage']['scmNo'], (Manager::isProvider() && !Request::get()->has('sno') ? Session::get('manager.scmNo') : $data['manage']['scmNo']));
gd_isset($data['basic']['deliveryConfigType'], 'all');
 
$checked['dmVisitAddressUseFl'][$data['basic']['dmVisitAddressUseFl']] =
$checked['rangeRepeat'][$data['basic']['rangeRepeat']] =
$checked['addGoodsCountInclude'][$data['basic']['addGoodsCountInclude']] =
$checked['areaChargeRepeatFl'][$data['basic']['areaChargeRepeatFl']] =
$checked['deliveryConfigType'][$data['basic']['deliveryConfigType']] = 'checked="checked"';
 
//배송 방식
 
data/skin/front/moment/css/common/layer/layer.css+1-1
변경 전layer.css
#wrap .ly_wrap.delivery_layer{width:305px; top:0px; left:-219px;}
/* 지역별추가배송비 레이어 */
#wrap .ly_wrap.delivery_zone_layer{width:305px; top:0px; left:-94px;}
.delivery_zone_layer .delivery_list{overflow-y:scroll; max-height:200px;}
/* 배송비 레잉어 공통 영역 */
.ly_wrap .delivery_list ul{border-bottom:1px solid #e8e8e8;}
.ly_wrap .delivery_list ul li{padding:10px 5px 10px 5px; font-weight:bold; border-top:1px solid #e8e8e8;}
 
변경 후layer.css
#wrap .ly_wrap.delivery_layer{width:305px; top:0px; left:-219px;}
/* 지역별추가배송비 레이어 */
#wrap .ly_wrap.delivery_zone_layer{width:305px; top:0px; left:-94px;}
.delivery_zone_layer .delivery_list{overflow-y:auto; max-height:200px;}
/* 배송비 레잉어 공통 영역 */
.ly_wrap .delivery_list ul{border-bottom:1px solid #e8e8e8;}
.ly_wrap .delivery_list ul li{padding:10px 5px 10px 5px; font-weight:bold; border-top:1px solid #e8e8e8;}
 
data/skin/front/moment/goods/goods_view.html+7
변경 전goods_view.html
<!--{ / }-->
</ul>
</div>
 
 
 
 
 
 
 
</div>
<!-- //ly_cont -->
<a href="#close" class="ly_close"><img src="../img/common/layer/btn_layer_close.png" alt="{=__('닫기')}"></a>
 
변경 후goods_view.html
<!--{ / }-->
</ul>
</div>
<!--{ ? goodsView['delivery']['basic']['areaChargeRepeatFl'] == 'y' }-->
<!--{ ? goodsView['delivery']['basic']['fixFl'] == 'count' }-->
<p class="chk_none">{=__('주문 수량이 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ : goodsView['delivery']['basic']['fixFl'] == 'weight' }-->
<p class="chk_none">{=__('주문 무게가 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ / }-->
<!--{ / }-->
</div>
<!-- //ly_cont -->
<a href="#close" class="ly_close"><img src="../img/common/layer/btn_layer_close.png" alt="{=__('닫기')}"></a>
 
data/skin/front/moment/goods/layer_option.html+7
변경 전layer_option.html
<!--{ / }-->
</ul>
</div>
 
 
 
 
 
 
 
</div>
<!-- //ly_cont -->
<a href="#close" class="ly_close"><img src="../img/common/layer/btn_layer_close.png" alt="{=__('닫기')}"></a>
 
변경 후layer_option.html
<!--{ / }-->
</ul>
</div>
<!--{ ? goodsView['delivery']['basic']['areaChargeRepeatFl'] == 'y' }-->
<!--{ ? goodsView['delivery']['basic']['fixFl'] == 'count' }-->
<p class="chk_none">{=__('주문 수량이 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ : goodsView['delivery']['basic']['fixFl'] == 'weight' }-->
<p class="chk_none">{=__('주문 무게가 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ / }-->
<!--{ / }-->
</div>
<!-- //ly_cont -->
<a href="#close" class="ly_close"><img src="../img/common/layer/btn_layer_close.png" alt="{=__('닫기')}"></a>
 
data/skin/front/mygreek/css/common/layer/layer.css+6-1
변경 전layer.css
}
.delivery_zone_layer .delivery_list {
overflow-y: scroll;
max-height: 200px;
}
 
 
 
 
 
/* 배송비 레잉어 공통 영역 */
.ly_wrap .delivery_list ul {
border-bottom: 1px solid #e8e8e8;
 
변경 후layer.css
}
.delivery_zone_layer .delivery_list {
overflow-y: auto;
max-height: 200px;
}
.delivery_zone_layer .chk_none {
padding: 5px 0 5px 19px;
background-image: url('../../../img/icon/etc/icon_warning_green.svg');
}
/* 배송비 레잉어 공통 영역 */
.ly_wrap .delivery_list ul {
border-bottom: 1px solid #e8e8e8;
 
data/skin/front/mygreek/goods/goods_view.html+7
변경 전goods_view.html
<!--{ / }-->
</ul>
</div>
 
 
 
 
 
 
 
</div>
<!-- //ly_cont -->
<a href="#close" class="ly_close"><img src="../img/common/layer/btn_layer_close.png" alt="{=__('닫기')}"></a>
 
변경 후goods_view.html
<!--{ / }-->
</ul>
</div>
<!--{ ? goodsView['delivery']['basic']['areaChargeRepeatFl'] == 'y' }-->
<!--{ ? goodsView['delivery']['basic']['fixFl'] == 'count' }-->
<p class="chk_none">{=__('주문 수량이 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ : goodsView['delivery']['basic']['fixFl'] == 'weight' }-->
<p class="chk_none">{=__('주문 무게가 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ / }-->
<!--{ / }-->
</div>
<!-- //ly_cont -->
<a href="#close" class="ly_close"><img src="../img/common/layer/btn_layer_close.png" alt="{=__('닫기')}"></a>
 
data/skin/front/mygreek/goods/layer_option.html+7
변경 전layer_option.html
<!--{ / }-->
</ul>
</div>
 
 
 
 
 
 
 
</div>
<!-- //ly_cont -->
<a href="#close" class="ly_close"><img src="../img/common/layer/btn_layer_close.png" alt="{=__('닫기')}"></a>
 
변경 후layer_option.html
<!--{ / }-->
</ul>
</div>
<!--{ ? goodsView['delivery']['basic']['areaChargeRepeatFl'] == 'y' }-->
<!--{ ? goodsView['delivery']['basic']['fixFl'] == 'count' }-->
<p class="chk_none">{=__('주문 수량이 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ : goodsView['delivery']['basic']['fixFl'] == 'weight' }-->
<p class="chk_none">{=__('주문 무게가 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ / }-->
<!--{ / }-->
</div>
<!-- //ly_cont -->
<a href="#close" class="ly_close"><img src="../img/common/layer/btn_layer_close.png" alt="{=__('닫기')}"></a>
 
data/skin/front/mygreek/img/icon/etc/icon_warning_green.svg+5
변경 전icon_warning_green.svg
 
 
 
 
 
 
변경 후icon_warning_green.svg
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" y="0.5" width="13" height="13" rx="6.5" stroke="#0cc472"/>
<path d="M4.4541 7.51363V6.36328H9.54501V7.51363H4.4541Z" fill="white"/>
<path d="M7.91618 3L7.76051 8.53342H6.22775L6.07208 3H7.91618ZM6.00023 10.0832C5.98826 9.58117 6.44329 9.1719 7.0061 9.17735C7.53898 9.1719 8 9.58117 8 10.0832C8 10.5907 7.53898 11 7.0061 11C6.44329 11 5.98826 10.5907 6.00023 10.0832Z" fill="#0cc472"/>
</svg>
 
data/skin/front/story_g/css/gd_share.css+22
변경 전gd_share.css
border: 1px solid #555;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.goods-view .goods .info .item ul li.delivery .delivery-layer .wrap > strong,
.option-layer .view .content-section .list .delivery-layer .wrap > strong {
display: block;
 
변경 후gd_share.css
border: 1px solid #555;
}
 
.goods-view .goods .info .item ul li.delivery .delivery-layer.delivery-area,
.option-layer .view .content-section .list .delivery-layer.delivery-area {
height: auto;
}
 
.goods-view .goods .info .item ul li.delivery .delivery-layer.delivery-area .wrap,
.option-layer .view .content-section .list .delivery-layer.delivery-area .wrap {
height: auto;
padding-bottom: 9px;
}
 
.goods-view .goods .info .item ul li.delivery .delivery-layer.delivery-area .wrap div,
.option-layer .view .content-section .list .delivery-layer.delivery-area .wrap div {
height: auto;
max-height: 219px;
}
 
.goods-view .goods .info .item ul li.delivery .delivery-layer.delivery-area .wrap .caution-msg1,
.option-layer .view .content-section .list .delivery-layer.delivery-area .wrap .caution-msg1 {
margin: 12px 9px 3px 19px;
}
 
.goods-view .goods .info .item ul li.delivery .delivery-layer .wrap > strong,
.option-layer .view .content-section .list .delivery-layer .wrap > strong {
display: block;
 
data/skin/front/story_g/goods/goods_view.html+7
변경 전goods_view.html
<!--{ / }-->
</table>
</div>
 
 
 
 
 
 
 
<button type="button" class="close target-delivery-area" title="{=__('닫기')}">{=__('닫기')}</button>
</div>
</div>
 
변경 후goods_view.html
<!--{ / }-->
</table>
</div>
<!--{ ? goodsView['delivery']['basic']['areaChargeRepeatFl'] == 'y' }-->
<!--{ ? goodsView['delivery']['basic']['fixFl'] == 'count' }-->
<p class="caution-msg1">{=__('주문 수량이 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ : goodsView['delivery']['basic']['fixFl'] == 'weight' }-->
<p class="caution-msg1">{=__('주문 무게가 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ / }-->
<!--{ / }-->
<button type="button" class="close target-delivery-area" title="{=__('닫기')}">{=__('닫기')}</button>
</div>
</div>
 
data/skin/front/story_g/goods/layer_option.html+7
변경 전layer_option.html
<!--{ / }-->
</table>
</div>
 
 
 
 
 
 
 
<button type="button" class="target-delivery-area" title="{=__('닫기')}">{=__('닫기')}</button>
</div>
</div>
 
변경 후layer_option.html
<!--{ / }-->
</table>
</div>
<!--{ ? goodsView['delivery']['basic']['areaChargeRepeatFl'] == 'y' }-->
<!--{ ? goodsView['delivery']['basic']['fixFl'] == 'count' }-->
<p class="caution-msg1">{=__('주문 수량이 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ : goodsView['delivery']['basic']['fixFl'] == 'weight' }-->
<p class="caution-msg1">{=__('주문 무게가 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ / }-->
<!--{ / }-->
<button type="button" class="target-delivery-area" title="{=__('닫기')}">{=__('닫기')}</button>
</div>
</div>
 
data/skin/mobile/moment/goods/goods_view.html+7
변경 전goods_view.html
<!--{ / }-->
</tbody>
</table>
 
 
 
 
 
 
 
</div>
</div>
</div>
 
변경 후goods_view.html
<!--{ / }-->
</tbody>
</table>
<!--{ ? goodsView['delivery']['basic']['areaChargeRepeatFl'] == 'y' }-->
<!--{ ? goodsView['delivery']['basic']['fixFl'] == 'count' }-->
<p style="margin:8px 0 0;padding:5px 10px;color:#ab3e55;font-size:12px;line-height:1.4;">※ {=__('주문 수량이 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ : goodsView['delivery']['basic']['fixFl'] == 'weight' }-->
<p style="margin:8px 0 0;padding:5px 10px;color:#ab3e55;font-size:12px;line-height:1.4;">※ {=__('주문 무게가 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ / }-->
<!--{ / }-->
</div>
</div>
</div>
 
data/skin/mobile/mygreek/goods/goods_view.html+7
변경 전goods_view.html
<!--{ / }-->
</tbody>
</table>
 
 
 
 
 
 
 
</div>
</div>
</div>
 
변경 후goods_view.html
<!--{ / }-->
</tbody>
</table>
<!--{ ? goodsView['delivery']['basic']['areaChargeRepeatFl'] == 'y' }-->
<!--{ ? goodsView['delivery']['basic']['fixFl'] == 'count' }-->
<p style="margin:8px 0 0;padding:5px 10px;color:#ab3e55;font-size:12px;line-height:1.4;">※ {=__('주문 수량이 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ : goodsView['delivery']['basic']['fixFl'] == 'weight' }-->
<p style="margin:8px 0 0;padding:5px 10px;color:#ab3e55;font-size:12px;line-height:1.4;">※ {=__('주문 무게가 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ / }-->
<!--{ / }-->
</div>
</div>
</div>
 
data/skin/mobile/story_g/goods/goods_view.html+7
변경 전goods_view.html
<!--{ / }-->
</tbody>
</table>
 
 
 
 
 
 
 
</div>
</div>
</div>
 
변경 후goods_view.html
<!--{ / }-->
</tbody>
</table>
<!--{ ? goodsView['delivery']['basic']['areaChargeRepeatFl'] == 'y' }-->
<!--{ ? goodsView['delivery']['basic']['fixFl'] == 'count' }-->
<p style="margin:8px 0 0;padding:5px 10px;color:#ab3e55;font-size:12px;line-height:1.4;">※ {=__('주문 수량이 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ : goodsView['delivery']['basic']['fixFl'] == 'weight' }-->
<p style="margin:8px 0 0;padding:5px 10px;color:#ab3e55;font-size:12px;line-height:1.4;">※ {=__('주문 무게가 속한 배송비 구간 수만큼, 지역별추가배송비가 반복 부과됩니다.')}</p>
<!--{ / }-->
<!--{ / }-->
</div>
</div>
</div>
 
- [게시판] 비회원 글쓰기 보안 강화
Component/Board/Board.php+17
변경 전Board.php
const TEXT_INSUFFICIENT_INPUTDATA = '입력 정보가 부족합니다';
const TEXT_NOTMATCH_PASSWORD = '비밀번호가 일치하지 않습니다';
const TEXT_NOTHAVE_AUTHORITY = '%s권한이 없습니다.';
 
const TEXT_UPLOAD_IMPOSSIBLE = '업로드가 불가능합니다';
const EXCEPTION_CODE_AUTH = 700;
const UPLOAD_DEFAULT_MAX_SIZE = 5; //업로드 최대용량 디플트 값(mb)
if($result['cnt']>0) {
throw new \Exception(__("중복된 게시물을 연속으로 등록할 수 없습니다. \n중복 게시물이 아닌 경우, 잠시 후 다시 등록하시기 바랍니다."));
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
return true;
}
 
변경 후Board.php
const TEXT_INSUFFICIENT_INPUTDATA = '입력 정보가 부족합니다';
const TEXT_NOTMATCH_PASSWORD = '비밀번호가 일치하지 않습니다';
const TEXT_NOTHAVE_AUTHORITY = '%s권한이 없습니다.';
const TEXT_GUEST_WRITE_RATE_LIMIT = '잠시 후 다시 등록해 주세요. (1분 이내 연속 등록 제한)';
const TEXT_UPLOAD_IMPOSSIBLE = '업로드가 불가능합니다';
const EXCEPTION_CODE_AUTH = 700;
const UPLOAD_DEFAULT_MAX_SIZE = 5; //업로드 최대용량 디플트 값(mb)
if($result['cnt']>0) {
throw new \Exception(__("중복된 게시물을 연속으로 등록할 수 없습니다. \n중복 게시물이 아닌 경우, 잠시 후 다시 등록하시기 바랍니다."));
}
 
}
 
// 비회원(memNo=0) 게시글/답변 연속 등록 제한: 동일 IP 60초 이내 재등록 차단 (제목 무관)
if (in_array($this->req['mode'], ['write', 'reply'], true) && (int) $this->member['memNo'] === 0) {
$remoteAddr = Request::getRemoteAddress();
$guestBind = [];
$this->db->bind_param_push($guestBind, 's', $remoteAddr);
$guestResult = $this->db->query_fetch("SELECT count(*) as cnt FROM " . DB_BD_ . $this->cfg['bdId'] . " WHERE memNo = 0 AND writerIp = ? AND regDt >= (now() - INTERVAL 60 SECOND) ", $guestBind, false);
if ($guestResult['cnt'] > 0) {
try {
\Logger::channel('board')->warning('[Board] 비회원 연속 등록 제한', ['bdId' => $this->cfg['bdId'], 'writerIp' => $remoteAddr]);
} catch (\Throwable $e) {
}
throw new \Exception(__(self::TEXT_GUEST_WRITE_RATE_LIMIT));
}
}
return true;
}
 
Controller/Mobile/Board/BoardPsController.php+6
변경 전BoardPsController.php
use Component\Member\MemberReport;
use Component\Validator\Validator;
use Framework\Debug\Exception\AlertBackException;
 
use Framework\ObjectStorage\Service\ImageUploadService;
use function GuzzleHttp\Psr7\parse_query;
use View\Template;
exit;
 
} catch (\Exception $e) {
 
 
 
 
 
throw new AlertBackException($e->getMessage());
}
break;
 
변경 후BoardPsController.php
use Component\Member\MemberReport;
use Component\Validator\Validator;
use Framework\Debug\Exception\AlertBackException;
use Framework\Debug\Exception\AlertRedirectException;
use Framework\ObjectStorage\Service\ImageUploadService;
use function GuzzleHttp\Psr7\parse_query;
use View\Template;
exit;
 
} catch (\Exception $e) {
// 비밀글은 글 상세가 POST로 열리므로 답글 실패 후 뒤로가기 시 양식 재전송 확인 페이지가 노출됨
$isListReturn = gd_isset($req['gboard']) != 'y' && gd_isset($req['gboard']) != 'r';
if ($req['mode'] == 'reply' && $isListReturn && isset($boardAct) && $boardAct->cfg['bdSecretFl'] != '2') {
throw new AlertRedirectException($e->getMessage(), 0, null, '../board/list.php?' . $req['returnUrl']);
}
throw new AlertBackException($e->getMessage());
}
break;
 
LMS 메시지 발송 시 제목 입력 기능
Admin/member/sms_auto.php+39-3
변경 전sms_auto.php
</label>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][memberMode]" value="<?php echo $typeData['memberMode']; ?>"/>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][memberSno]" value="<?php echo $typeData['memberSno']; ?>"/>
<textarea name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][memberContents]" rows="4" class="form-control"><?php echo $typeData['memberContents']; ?></textarea>
 
 
 
<?php } else { ?>
<div class="text-center text-blue">운영자 전용</div>
<?php } ?>
</label>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][adminMode]" value="<?php echo $typeData['adminMode']; ?>"/>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][adminSno]" value="<?php echo $typeData['adminSno']; ?>"/>
 
 
 
<textarea name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][adminContents]" rows="4"
class="form-control <?php if ($sKey == 'admin') { ?> width100p <?php } ?>"><?php echo $typeData['adminContents']; ?></textarea>
<?php } else { ?>
<div class="text-center text-orange-red">회원 전용</div>
<?php } ?>
</label>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][providerMode]" value="<?php echo $typeData['providerMode']; ?>"/>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][providerSno]" value="<?php echo $typeData['providerSno']; ?>"/>
<textarea name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][providerContents]" rows="4" class="form-control"><?php echo $typeData['providerContents']; ?></textarea>
 
 
 
<?php } else { ?>
<?php if ($sKey == 'admin') { ?>
<div class="text-center text-orange-red">본사 전용</div>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][providerSno]" value="<?php echo $typeData['providerSno']; ?>"/>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][providerMode]" value="<?php echo $typeData['providerMode']; ?>"/>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][providerContents]" value="<?php echo $typeData['providerContents']; ?>"/>
 
<?php } ?>
</tr>
<?php
<script type="text/javascript">
<!--
$(document).ready(function () {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$('.btn-change-password').click(function () {
$.get('../share/layer_sms_password.php?mode=change', function () {
BootstrapDialog.closeAll();
 
변경 후sms_auto.php
</label>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][memberMode]" value="<?php echo $typeData['memberMode']; ?>"/>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][memberSno]" value="<?php echo $typeData['memberSno']; ?>"/>
<div class="js-sms-auto-subject-wrap mgb5">
<input type="text" name="<?= $sKey ?>[<?= $typeData['code'] ?>][memberMessageTitle]" class="form-control js-sms-auto-subject" placeholder="제목 입력" value="<?= gd_isset($typeData['memberMessageTitle']) ?>"/>
</div>
<textarea name="<?= $sKey ?>[<?= $typeData['code'] ?>][memberContents]" rows="4" class="form-control js-sms-auto-contents"><?= $typeData['memberContents'] ?></textarea>
<?php } else { ?>
<div class="text-center text-blue">운영자 전용</div>
<?php } ?>
</label>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][adminMode]" value="<?php echo $typeData['adminMode']; ?>"/>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][adminSno]" value="<?php echo $typeData['adminSno']; ?>"/>
<div class="js-sms-auto-subject-wrap mgb5">
<input type="text" name="<?= $sKey ?>[<?= $typeData['code'] ?>][adminMessageTitle]" class="form-control js-sms-auto-subject" placeholder="제목 입력" value="<?= gd_isset($typeData['adminMessageTitle']) ?>"/>
</div>
<textarea name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][adminContents]" rows="4"
class="form-control js-sms-auto-contents <?php if ($sKey == 'admin') { ?> width100p <?php } ?>"><?= $typeData['adminContents'] ?></textarea>
<?php } else { ?>
<div class="text-center text-orange-red">회원 전용</div>
<?php } ?>
</label>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][providerMode]" value="<?php echo $typeData['providerMode']; ?>"/>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][providerSno]" value="<?php echo $typeData['providerSno']; ?>"/>
<div class="js-sms-auto-subject-wrap mgb5">
<input type="text" name="<?= $sKey ?>[<?= $typeData['code'] ?>][providerMessageTitle]" class="form-control js-sms-auto-subject" placeholder="제목 입력" value="<?= gd_isset($typeData['providerMessageTitle']) ?>"/>
</div>
<textarea name="<?= $sKey ?>[<?= $typeData['code'] ?>][providerContents]" rows="4" class="form-control js-sms-auto-contents"><?= $typeData['providerContents'] ?></textarea>
<?php } else { ?>
<?php if ($sKey == 'admin') { ?>
<div class="text-center text-orange-red">본사 전용</div>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][providerSno]" value="<?php echo $typeData['providerSno']; ?>"/>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][providerMode]" value="<?php echo $typeData['providerMode']; ?>"/>
<input type="hidden" name="<?php echo $sKey; ?>[<?php echo $typeData['code']; ?>][providerContents]" value="<?php echo $typeData['providerContents']; ?>"/>
<input type="hidden" name="<?= $sKey ?>[<?= $typeData['code'] ?>][providerMessageTitle]" value="<?= gd_isset($typeData['providerMessageTitle']) ?>"/>
<?php } ?>
</tr>
<?php
<script type="text/javascript">
<!--
$(document).ready(function () {
// 제목 바이트 계산 (한글 등 멀티바이트 2byte, ASCII 1byte, 개행 제외)
function smsAutoStringToByte(str) {
var length = 0;
for (var i = 0; i < str.length; i++) {
if (escape(str.charAt(i)).length >= 4) length += 2;
else if (escape(str.charAt(i)) != "%0D") length++;
}
return length;
}
// 이모티콘 제거 (서로게이트 페어 + 변형선택자, 기획: 제목·본문 입력 불가)
function smsAutoStripEmoji(str) {
if (!str) return str;
return str.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '').replace(/[\uFE00-\uFE0F\u200D\u20E3]/g, '');
}
// 자동발송 제목 영역은 항상 활성 노출(C3). 본문은 이모티콘만 자동 제거.
$('.js-sms-auto-contents').on('keyup change', function () {
var $ta = $(this);
var stripped = smsAutoStripEmoji($ta.val());
if (stripped !== $ta.val()) { $ta.val(stripped); }
});
$('.js-sms-auto-subject').on('keyup keydown', function () {
var input = $(this);
var text = smsAutoStripEmoji(input.val());
while (smsAutoStringToByte(text) > <?= $lmsSubjectLimit; ?>) { text = text.substring(0, text.length - 1); }
input.val(text);
});
$('.btn-change-password').click(function () {
$.get('../share/layer_sms_password.php?mode=change', function () {
BootstrapDialog.closeAll();
 
Admin/member/sms_log.php+4
변경 전sms_log.php
$listHtml[] = '<td class="text-center number">' . ($data['receiverCnt'] * $lmsPoint) . '</td>';
}
$listHtml[] = '<td style="word-break:break-all;word-wrap:break-word;overflow:hidden;" class="multirows">';
 
 
 
 
$listHtml[] = '<div class="div-contents">' . $data['contents'] . '</div>';
if ($data['sendStatus'] === 'r' && $data['smsType'] === 'user') {
$listHtml[] = '<div><button type="button" class="btn btn-xs btn-gray btn-modify">수정하기</button></div>';
 
변경 후sms_log.php
$listHtml[] = '<td class="text-center number">' . ($data['receiverCnt'] * $lmsPoint) . '</td>';
}
$listHtml[] = '<td style="word-break:break-all;word-wrap:break-word;overflow:hidden;" class="multirows">';
if ($data['sendFl'] === 'lms') {
$subjectText = ($data['subject'] !== null && $data['subject'] !== '') ? $data['subject'] : '[' . __('제목없음') . ']';
$listHtml[] = '<div class="div-subject text-darkblue"><strong>' . gd_htmlspecialchars($subjectText) . '</strong></div>';
}
$listHtml[] = '<div class="div-contents">' . $data['contents'] . '</div>';
if ($data['sendStatus'] === 'r' && $data['smsType'] === 'user') {
$listHtml[] = '<div><button type="button" class="btn btn-xs btn-gray btn-modify">수정하기</button></div>';
 
Admin/member/sms_send.php+75-2
변경 전sms_send.php
return length;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* SMS 내용 길이 체크
*/
function setContentsLength(contentsNm, countId) {
var textarea = $('textarea[name=' + contentsNm + ']');
var contentsText = textarea.val();
 
 
 
 
var textLength = stringToByte(contentsText);
if (textLength > <?php echo $smsStringLimit;?>) {
if (textLength > <?php echo $lmsStringLimit;?>) {
$('.sms-type').hide();
$('.lms-type').show();
$('input[name=sendFl]').val('lms');
 
 
} else {
$('#' + countId).css("color", "");
$('.sms-type').show();
$('.lms-type').hide();
$('input[name=sendFl]').val('sms');
 
}
$('#' + countId).val(textLength);
}
setContentsLength('smsContents', 'smsStringCount');
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
function setReceiverCount() {
var checkedType = $('[name=receiverType]:checked').val();
var receiverCount = 0, agreeCount = 0, rejectCount = 0;
dialog: false,
debug: true,
submitHandler: function (form) {
console.log('submitHan', form);
 
 
 
 
 
var divisionInt = 1;
if ($('input[name=sendFl]').val() === 'lms') {
divisionInt = <?php echo $lmsPoint;?>;
<div class="notice-danger pull-left mgl15 display-none">회원 외 치환코드는 정상 적용되지 않으니 저장된 메시지 수정 시에만 이용바랍니다.</div>
</div>
</div>
 
 
 
 
 
 
 
 
<div class="row pdt5">
<div class="col-xs-3 pdr0">
<label class="width100p">
<div class="col-xs-12">
<div class="notice-info">URL 삽입 시 [단축 URL] 앱을 이용하시면 짧고 간단하게 URL을 사용하실 수 있습니다. <a href="https://apps.godo.co.kr/apps/1519" class="btn-link" target="_blank">바로가기</a></div>
<div class="notice-info">치환코드 사용 시 LMS로 발송될 수 있으며 일부 문자가 포인트 부족으로 발송되지 않을 수 있습니다.<br/>- 포인트 충전 후 <a href="../member/sms_log.php" class="btn-link" target="_blank">SMS 발송 내역 보기</a>에서 재발송하실 수 있습니다.</div>
 
<div class="notice-danger sms-large-caution">발송내용에 이모지 또는 사용 불가능한 특수문자, 맞춤법이 바르지 않은 문자가 포함되어있으면 일부 내용은 삭제되고 발송되오니 주의하시기 바랍니다.<br/>대량 SMS(LMS) 발송 시 이모지를 사용하지 않는 것과 맞춤법에 어긋나는 문자가 입력 되지는 않았는지 확인하시는 것을 권장 드리며,<br/> 발송 내용에 사용가능한 특수문자는 매뉴얼을 참고하시기 바랍니다.</div>
</div>
</div>
<%= checkbox %> <%= subject %>
<button type="button" class="btn btn-sm btn-white pull-right js-btn-save" data-text="저장">수정</button>
<button type="button" class="btn btn-sm btn-white pull-right js-btn-insert mgr5">삽입</button>
 
<label class="width100p pdt5">
<textarea rows="13" class="form-control width100p" name="contents"><%= contents %></textarea>
</label>
 
변경 후sms_send.php
return length;
}
 
/**
* 이모티콘 제거 (제목/본문 이모티콘 입력 불가 - 자동 삭제)
*/
function stripEmoji(str) {
if (!str) {
return str;
}
return str
.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '')
.replace(/[\uFE00-\uFE0F\u200D\u20E3]/g, '');
}
 
/**
* SMS 내용 길이 체크
*/
function setContentsLength(contentsNm, countId) {
var textarea = $('textarea[name=' + contentsNm + ']');
var strippedBody = stripEmoji(textarea.val());
if (strippedBody !== textarea.val()) {
textarea.val(strippedBody);
}
var contentsText = strippedBody;
var textLength = stringToByte(contentsText);
if (textLength > <?php echo $smsStringLimit;?>) {
if (textLength > <?php echo $lmsStringLimit;?>) {
$('.sms-type').hide();
$('.lms-type').show();
$('input[name=sendFl]').val('lms');
$('#smsSubject').prop('disabled', false); // LMS: 제목 영역 활성
setSubjectLength();
} else {
$('#' + countId).css("color", "");
$('.sms-type').show();
$('.lms-type').hide();
$('input[name=sendFl]').val('sms');
$('#smsSubject').prop('disabled', true); // SMS: 제목 영역 비활성(값 유지, 미발송)
}
$('#' + countId).val(textLength);
}
setContentsLength('smsContents', 'smsStringCount');
}
 
/**
* LMS 제목 Byte 체크 (공백 포함 최대 <?= $lmsSubjectLimit; ?>Byte, 초과분 자동 삭제)
*/
function setSubjectLength() {
var input = $('#smsSubject');
if (input.length === 0) {
return;
}
var limit = <?= $lmsSubjectLimit; ?>;
var text = stripEmoji(input.val());
var adChecked = $('input[name=sms080Reject]').is(':checked');
var byte = stringToByte(text);
if (adChecked && byte > limit) {
// C4-2: (광고) 자동 삽입으로 40Byte 초과 -> 절삭하지 않고 에러 표기
input.val(text);
setSubjectOver(true);
} else {
// C1-1: 직접 입력 40Byte 초과분 자동삭제
while (stringToByte(text) > limit) {
text = text.substring(0, text.length - 1);
}
input.val(text);
byte = stringToByte(text);
setSubjectOver(false);
}
$('#smsSubjectCount').val(byte);
}
 
function setSubjectOver(isOver) {
var input = $('#smsSubject');
if (isOver) {
input.addClass('js-subject-over').css('border-color', '#e74c3c');
$('#smsSubjectCount').css('color', '#e74c3c');
} else {
input.removeClass('js-subject-over').css('border-color', '');
$('#smsSubjectCount').css('color', '');
}
}
 
function setReceiverCount() {
var checkedType = $('[name=receiverType]:checked').val();
var receiverCount = 0, agreeCount = 0, rejectCount = 0;
dialog: false,
debug: true,
submitHandler: function (form) {
// C4-2: 제목 40Byte 초과(광고 삽입 등) 시 발송 차단
if ($('input[name=sendFl]').val() === 'lms' && $('#smsSubject').length && stringToByte(stripEmoji($('#smsSubject').val())) > <?= $lmsSubjectLimit; ?>) {
BootstrapDialog.show({title: '경고', message: '제목은 최대 <?= $lmsSubjectLimit; ?>bytes까지 입력 가능합니다.', closable: true});
$('#smsSubject').focus();
return false;
}
var divisionInt = 1;
if ($('input[name=sendFl]').val() === 'lms') {
divisionInt = <?php echo $lmsPoint;?>;
<div class="notice-danger pull-left mgl15 display-none">회원 외 치환코드는 정상 적용되지 않으니 저장된 메시지 수정 시에만 이용바랍니다.</div>
</div>
</div>
<div class="row pdt5 js-subject-row">
<div class="col-xs-3 pdr0">
<input type="text" name="smsSubject" id="smsSubject" class="form-control width100p" placeholder="제목을 입력해주세요." value="<?= gd_isset($smsSubject); ?>" onkeyup="setSubjectLength();" onkeydown="setSubjectLength();" disabled="disabled"/>
<div class="mgt5">
<input type="text" id="smsSubjectCount" value="0" readonly="readonly" class="form-control width-3xs"> / <?= $lmsSubjectLimit; ?> Bytes
</div>
</div>
</div>
<div class="row pdt5">
<div class="col-xs-3 pdr0">
<label class="width100p">
<div class="col-xs-12">
<div class="notice-info">URL 삽입 시 [단축 URL] 앱을 이용하시면 짧고 간단하게 URL을 사용하실 수 있습니다. <a href="https://apps.godo.co.kr/apps/1519" class="btn-link" target="_blank">바로가기</a></div>
<div class="notice-info">치환코드 사용 시 LMS로 발송될 수 있으며 일부 문자가 포인트 부족으로 발송되지 않을 수 있습니다.<br/>- 포인트 충전 후 <a href="../member/sms_log.php" class="btn-link" target="_blank">SMS 발송 내역 보기</a>에서 재발송하실 수 있습니다.</div>
<div class="notice-info">본문 내용이 LMS인 경우에만 제목 입력이 가능하며, 제목 영역에는 직접 (광고) 문구를 입력하지 않도록 하고 광고 삽입이 필요한 경우 광고성 문구 추가 기능을 사용해야 합니다.</div>
<div class="notice-danger sms-large-caution">발송내용에 이모지 또는 사용 불가능한 특수문자, 맞춤법이 바르지 않은 문자가 포함되어있으면 일부 내용은 삭제되고 발송되오니 주의하시기 바랍니다.<br/>대량 SMS(LMS) 발송 시 이모지를 사용하지 않는 것과 맞춤법에 어긋나는 문자가 입력 되지는 않았는지 확인하시는 것을 권장 드리며,<br/> 발송 내용에 사용가능한 특수문자는 매뉴얼을 참고하시기 바랍니다.</div>
</div>
</div>
<%= checkbox %> <%= subject %>
<button type="button" class="btn btn-sm btn-white pull-right js-btn-save" data-text="저장">수정</button>
<button type="button" class="btn btn-sm btn-white pull-right js-btn-insert mgr5">삽입</button>
<input type="text" name="messageTitle" class="form-control width100p mgt5 js-sms-contents-subject" placeholder="제목을 입력해주세요." value="<%= messageTitle %>" disabled="disabled"/>
<label class="width100p pdt5">
<textarea rows="13" class="form-control width100p" name="contents"><%= contents %></textarea>
</label>
 
Admin/promotion/cart_remind_regist.php+69-14
변경 전cart_remind_regist.php
}
if (e.target.checked) {
$body.val('(광고)\n' + $body.val() + '\n무료거부 ' + $('input[name="sms080Reject"]').data('reject-number'));
 
 
 
}
changeCartRemindContentsLength();
 
// 본문 반영으로 SMS/LMS 판정이 끝난 뒤에 제목 처리 — 제목 영역이 비활성(SMS)이면 (광고) 미표기
if (e.target.checked && $subject.length && !$subject.prop('disabled')) {
$subject.val('(광고)' + $subject.val());
}
changeCartRemindSubjectLength();
});
 
}
if (e.target.checked) {
$body.val('(광고)\n' + $body.val() + '\n무료거부 ' + $('input[name="sms080Reject"]').data('reject-number'));
if ($subject.length) {
$subject.val('(광고)' + $subject.val());
}
}
changeCartRemindContentsLength();
 
 
 
 
 
changeCartRemindSubjectLength();
});
 
<span class="cart-remind-sms notice-info">SMS : 발송 건당 1포인트 차감</span>
</div>
</div>
 
 
 
 
<div class="form-inline mgt10">
<textarea name="cartRemindSendMessage" rows="8" class="smsContents form-control width-xl js-sms080-update"><?= $cartRemindData['cartRemindSendMessage']; ?></textarea>
<div class="mgt5">
<a href="https://www.nhn-commerce.com/customer/board-view.gd?type=notice&idx=1237" target="_blank" class="btn-link">자세히보기></a>
</p>
<p class="notice-info">장바구니 링크 치환코드는 LMS인 경우에만 정상적으로 발송됩니다</p>
 
</div>
</td>
</tr>
 
// 글자수 체크
$('textarea[name=cartRemindSendMessage]').keyup(changeCartRemindContentsLength);
 
displayCartRemindCouponLink();
changeCartRemindType();
changeCartRemindSendType();
changeCartRemindManualDirectPeriod();
changeCartRemindContentsLength();
 
 
// 광고성 문구 추가
$('input[name="sms080Reject"]').click(function (e) {
$('.js-sms080-update').val($('.js-sms080-update').val().replace(/(\n무료거부\s[0-9\-]*)/g, ''));
if(e.target.checked){
$('.js-sms080-update').val($('.js-sms080-update').val() + '\n무료거부 ' + $('input[name="sms080Reject"]').data('reject-number'));
};
 
 
 
 
 
 
 
 
 
 
});
 
});
* SMS 내용 길이 체크
*/
function changeCartRemindContentsLength() {
var contentsText = $('textarea[name=cartRemindSendMessage]').val();
 
 
 
 
 
var textLength = stringToByte(contentsText);
 
if ($('input:hidden[name="cartRemindSendType"]').val() == 'sms' && textLength > <?= $smsStringLimit; ?>) {
}
$('#cartRemindSendMessageCount').val(textLength);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// 발송유형 따른 폼 변경
function changeCartRemindType() {
if ($('input:radio[name="cartRemindType"]:checked').val() == 'manual') {
$('.cart-remind-sms').hide();
$('.cart-remind-sms select').attr('disabled', 'disabled');
$('.cart-remind-sms input').attr('disabled', 'disabled');
 
 
// sms발송
} else if ($('input:hidden[name="cartRemindSendType"]').val() == 'sms') {
$('.cart-remind-lms').hide();
$('.cart-remind-sms').show();
$('.cart-remind-sms select').removeAttr('disabled');
$('.cart-remind-sms input').removeAttr('disabled');
 
 
}
}
// 발급방식에 따른 폼 변경
}
return length;
}
 
 
 
 
 
 
 
 
 
 
 
 
</script>
 
변경 후cart_remind_regist.php
}
if (e.target.checked) {
$body.val('(광고)\n' + $body.val() + '\n무료거부 ' + $('input[name="sms080Reject"]').data('reject-number'));
if ($subject.length) {
$subject.val('(광고)' + $subject.val());
}
}
changeCartRemindContentsLength();
 
 
 
 
 
changeCartRemindSubjectLength();
});
 
}
if (e.target.checked) {
$body.val('(광고)\n' + $body.val() + '\n무료거부 ' + $('input[name="sms080Reject"]').data('reject-number'));
 
 
 
}
changeCartRemindContentsLength();
 
// 본문 반영으로 SMS/LMS 판정이 끝난 뒤에 제목 처리 — 제목 영역이 비활성(SMS)이면 (광고) 미표기
if (e.target.checked && $subject.length && !$subject.prop('disabled')) {
$subject.val('(광고)' + $subject.val());
}
changeCartRemindSubjectLength();
});
 
<span class="cart-remind-sms notice-info">SMS : 발송 건당 1포인트 차감</span>
</div>
</div>
<div class="form-inline mgt10 js-cart-subject-row">
<input type="text" name="cartRemindSendSubject" id="cartRemindSendSubject" class="form-control width-xl" placeholder="제목을 입력해주세요." value="<?= gd_isset($cartRemindData['cartRemindSendSubject']); ?>" disabled="disabled"/>
<input type="text" id="cartRemindSubjectCount" value="0" readonly="readonly" class="form-control width-3xs"> / <?= $lmsSubjectLimit; ?> Bytes
</div>
<div class="form-inline mgt10">
<textarea name="cartRemindSendMessage" rows="8" class="smsContents form-control width-xl js-sms080-update"><?= $cartRemindData['cartRemindSendMessage']; ?></textarea>
<div class="mgt5">
<a href="https://www.nhn-commerce.com/customer/board-view.gd?type=notice&idx=1237" target="_blank" class="btn-link">자세히보기></a>
</p>
<p class="notice-info">장바구니 링크 치환코드는 LMS인 경우에만 정상적으로 발송됩니다</p>
<p class="notice-info">본문 내용이 LMS인 경우에만 제목 입력이 가능하며, 제목 영역에는 직접 (광고) 문구를 입력하지 않도록 하고 광고 삽입이 필요한 경우 광고성 문구 추가 기능을 사용해야 합니다.</p>
</div>
</td>
</tr>
 
// 글자수 체크
$('textarea[name=cartRemindSendMessage]').keyup(changeCartRemindContentsLength);
$('#cartRemindSendSubject').on('keyup keydown', changeCartRemindSubjectLength);
displayCartRemindCouponLink();
changeCartRemindType();
changeCartRemindSendType();
changeCartRemindManualDirectPeriod();
changeCartRemindContentsLength();
changeCartRemindSubjectLength();
 
// 광고성 문구 추가 (본문: (광고) 접두 + 무료거부 접미 / LMS 제목: (광고) 접두)
$('input[name="sms080Reject"]').click(function (e) {
var $body = $('.js-sms080-update');
$body.val($body.val().replace(/(\(광고\)\n)|(\n무료거부\s[0-9\-]*)/g, ''));
var $subject = $('#cartRemindSendSubject');
if ($subject.length) {
$subject.val($subject.val().replace(/^\(광고\)/, ''));
}
if (e.target.checked) {
$body.val('(광고)\n' + $body.val() + '\n무료거부 ' + $('input[name="sms080Reject"]').data('reject-number'));
if ($subject.length) {
$subject.val('(광고)' + $subject.val());
}
}
changeCartRemindContentsLength();
changeCartRemindSubjectLength();
});
 
});
* SMS 내용 길이 체크
*/
function changeCartRemindContentsLength() {
var $cartTa = $('textarea[name=cartRemindSendMessage]');
var strippedBody = stripEmoji($cartTa.val());
if (strippedBody !== $cartTa.val()) {
$cartTa.val(strippedBody);
}
var contentsText = strippedBody;
var textLength = stringToByte(contentsText);
 
if ($('input:hidden[name="cartRemindSendType"]').val() == 'sms' && textLength > <?= $smsStringLimit; ?>) {
}
$('#cartRemindSendMessageCount').val(textLength);
}
 
/**
* LMS 제목 Byte 체크 (공백 포함 최대 <?= $lmsSubjectLimit; ?>Byte, 초과분 자동 삭제)
*/
function changeCartRemindSubjectLength() {
var input = $('#cartRemindSendSubject');
if (input.length === 0) {
return;
}
var limit = <?= $lmsSubjectLimit; ?>;
var text = stripEmoji(input.val());
while (stringToByte(text) > limit) {
text = text.substring(0, text.length - 1);
}
input.val(text);
$('#cartRemindSubjectCount').val(stringToByte(text));
}
// 발송유형 따른 폼 변경
function changeCartRemindType() {
if ($('input:radio[name="cartRemindType"]:checked').val() == 'manual') {
$('.cart-remind-sms').hide();
$('.cart-remind-sms select').attr('disabled', 'disabled');
$('.cart-remind-sms input').attr('disabled', 'disabled');
 
$('#cartRemindSendSubject').prop('disabled', false); // LMS: 제목 영역 활성
// sms발송
} else if ($('input:hidden[name="cartRemindSendType"]').val() == 'sms') {
$('.cart-remind-lms').hide();
$('.cart-remind-sms').show();
$('.cart-remind-sms select').removeAttr('disabled');
$('.cart-remind-sms input').removeAttr('disabled');
 
$('#cartRemindSendSubject').prop('disabled', true); // SMS: 제목 영역 비활성(값 유지, 미저장/미발송)
}
}
// 발급방식에 따른 폼 변경
}
return length;
}
 
/**
* 이모티콘 제거 (제목/본문 이모티콘 입력 불가 - 자동 삭제)
*/
function stripEmoji(str) {
if (!str) {
return str;
}
return str
.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '')
.replace(/[\uFE00-\uFE0F\u200D\u20E3]/g, '');
}
</script>
 
Admin/promotion/comeback_coupon_regist.php+68-11
변경 전comeback_coupon_regist.php
}
if (e.target.checked) {
$send_contents.val('(광고)\n' + $send_contents.val() + '\n무료거부 ' + $(selector).data('reject-number'));
 
 
 
 
}
refresh_send_contents();
 
// 본문 반영으로 SMS/LMS 판정이 끝난 뒤에 제목 처리 — 제목 영역이 비활성(SMS)이면 (광고) 미표기
if (e.target.checked && $smsSubject.length && !$smsSubject.prop('disabled')) {
$smsSubject.val('(광고)' + $smsSubject.val());
setSubjectLength();
}
});
}
</script>
}
if (e.target.checked) {
$send_contents.val('(광고)\n' + $send_contents.val() + '\n무료거부 ' + $(selector).data('reject-number'));
if ($smsSubject.length) {
$smsSubject.val('(광고)' + $smsSubject.val());
setSubjectLength();
}
}
refresh_send_contents();
 
 
 
 
 
 
});
}
</script>
<button type="button" class="btn btn-white btn-sm pull-right js-toggle-replace-code" data-target=".replace_code_area" data-text="치환코드 닫기">치환코드 보기</button>
</div>
</div>
 
 
 
 
 
 
 
 
<div class="row pdt5">
<div class="col-xs-3 pdr0">
<label class="width100p">
링크는 단축 URL로 자동 변환하였습니다.<br/>
[단축 URL] 앱을 이용하여 단축 URL을 생성하면, 조회수 및 통계 자료를 확인하실 수 있습니다. <a href="https://apps.godo.co.kr/apps/1519" class="btn-link" target="_blank">바로가기</a>
</div>
 
</div>
</div>
</td>
return length;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* SMS 내용 길이 체크
*/
function setContentsLength(contentsNm, countId) {
var textarea = $('textarea[name=' + contentsNm + ']');
var contentsText = textarea.val();
 
 
 
 
var textLength = stringToByte(contentsText);
if (textLength > <?php echo $smsStringLimit;?>) {
if (textLength > <?php echo $lmsStringLimit;?>) {
$('.sms-type').hide();
$('.lms-type').show();
$('input[name=sendFl]').val('lms');
 
 
 
 
} else {
$('#' + countId).css("color", "");
$('.sms-type').show();
$('.lms-type').hide();
$('input[name=sendFl]').val('sms');
 
}
$('#' + countId).val(textLength);
}
 
// 글자수 체크
$('textarea[name=smsContents]').keyup(setSendLength).change(setSendLength);
 
 
$("#frmCoupon").validate({
submitHandler: function (form) {
changeTargetType();
checkSms();
setSendLength();
 
set_click_replace_code_insert('.replace-code-area .js-btn-insert');
set_change_focus_contents('textarea[name="smsContents"]');
set_click_sms080_contents(':checkbox[name="sms080Reject"]');
function set_click_sms080_contents (selector) {
$(selector).click(function (e) {
$send_contents.val($send_contents.val().replace(/(\(광고\)\n)|(\n무료거부\s[0-9\-]*)/g, ''));
 
 
 
 
if (e.target.checked) {
$send_contents.val('(광고)\n' + $send_contents.val() + '\n무료거부 ' + $(selector).data('reject-number'));
 
 
 
 
}
refresh_send_contents();
});
 
변경 후comeback_coupon_regist.php
}
if (e.target.checked) {
$send_contents.val('(광고)\n' + $send_contents.val() + '\n무료거부 ' + $(selector).data('reject-number'));
if ($smsSubject.length) {
$smsSubject.val('(광고)' + $smsSubject.val());
setSubjectLength();
}
}
refresh_send_contents();
 
 
 
 
 
 
});
}
</script>
}
if (e.target.checked) {
$send_contents.val('(광고)\n' + $send_contents.val() + '\n무료거부 ' + $(selector).data('reject-number'));
 
 
 
 
}
refresh_send_contents();
 
// 본문 반영으로 SMS/LMS 판정이 끝난 뒤에 제목 처리 — 제목 영역이 비활성(SMS)이면 (광고) 미표기
if (e.target.checked && $smsSubject.length && !$smsSubject.prop('disabled')) {
$smsSubject.val('(광고)' + $smsSubject.val());
setSubjectLength();
}
});
}
</script>
<button type="button" class="btn btn-white btn-sm pull-right js-toggle-replace-code" data-target=".replace_code_area" data-text="치환코드 닫기">치환코드 보기</button>
</div>
</div>
<div class="row pdt5 js-subject-row">
<div class="col-xs-3 pdr0">
<input type="text" name="smsSubject" id="smsSubject" class="form-control width100p" placeholder="제목을 입력해주세요." value="<?= gd_isset($couponData['smsSubject']) ?>" disabled="disabled"/>
<div class="mgt5">
<input type="text" id="smsSubjectCount" value="0" readonly="readonly" class="form-control width-3xs"> / <?= $lmsSubjectLimit; ?> Bytes
</div>
</div>
</div>
<div class="row pdt5">
<div class="col-xs-3 pdr0">
<label class="width100p">
링크는 단축 URL로 자동 변환하였습니다.<br/>
[단축 URL] 앱을 이용하여 단축 URL을 생성하면, 조회수 및 통계 자료를 확인하실 수 있습니다. <a href="https://apps.godo.co.kr/apps/1519" class="btn-link" target="_blank">바로가기</a>
</div>
<div class="notice-info">본문 내용이 LMS인 경우에만 제목 입력이 가능하며, 제목 영역에는 직접 (광고) 문구를 입력하지 않도록 하고 광고 삽입이 필요한 경우 광고성 문구 추가 기능을 사용해야 합니다.</div>
</div>
</div>
</td>
return length;
}
 
/**
* 이모티콘 제거 (제목/본문 이모티콘 입력 불가 - 자동 삭제)
*/
function stripEmoji(str) {
if (!str) {
return str;
}
return str
.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '')
.replace(/[\uFE00-\uFE0F\u200D\u20E3]/g, '');
}
 
/**
* LMS 제목 Byte 체크 (공백 포함 최대 <?= $lmsSubjectLimit; ?>Byte, 초과분 자동 삭제)
*/
function setSubjectLength() {
var input = $('#smsSubject');
if (input.length === 0) {
return;
}
var limit = <?= $lmsSubjectLimit; ?>;
var text = stripEmoji(input.val());
while (stringToByte(text) > limit) {
text = text.substring(0, text.length - 1);
}
input.val(text);
$('#smsSubjectCount').val(stringToByte(text));
}
 
/**
* SMS 내용 길이 체크
*/
function setContentsLength(contentsNm, countId) {
var textarea = $('textarea[name=' + contentsNm + ']');
var stripped = stripEmoji(textarea.val());
if (stripped !== textarea.val()) {
textarea.val(stripped);
}
var contentsText = stripped;
var textLength = stringToByte(contentsText);
if (textLength > <?php echo $smsStringLimit;?>) {
if (textLength > <?php echo $lmsStringLimit;?>) {
$('.sms-type').hide();
$('.lms-type').show();
$('input[name=sendFl]').val('lms');
<?php if ($checkMode == 'canModify') { ?>
$('#smsSubject').prop('disabled', false); // LMS: 제목 영역 활성
<?php } ?>
setSubjectLength();
} else {
$('#' + countId).css("color", "");
$('.sms-type').show();
$('.lms-type').hide();
$('input[name=sendFl]').val('sms');
$('#smsSubject').prop('disabled', true); // SMS: 제목 영역 비활성(값 유지)
}
$('#' + countId).val(textLength);
}
 
// 글자수 체크
$('textarea[name=smsContents]').keyup(setSendLength).change(setSendLength);
$('#smsSubject').on('keyup keydown', setSubjectLength);
 
$("#frmCoupon").validate({
submitHandler: function (form) {
changeTargetType();
checkSms();
setSendLength();
setSubjectLength();
set_click_replace_code_insert('.replace-code-area .js-btn-insert');
set_change_focus_contents('textarea[name="smsContents"]');
set_click_sms080_contents(':checkbox[name="sms080Reject"]');
function set_click_sms080_contents (selector) {
$(selector).click(function (e) {
$send_contents.val($send_contents.val().replace(/(\(광고\)\n)|(\n무료거부\s[0-9\-]*)/g, ''));
var $smsSubject = $('#smsSubject');
if ($smsSubject.length) {
$smsSubject.val($smsSubject.val().replace(/^\(광고\)/, ''));
}
if (e.target.checked) {
$send_contents.val('(광고)\n' + $send_contents.val() + '\n무료거부 ' + $(selector).data('reject-number'));
if ($smsSubject.length) {
$smsSubject.val('(광고)' + $smsSubject.val());
setSubjectLength();
}
}
refresh_send_contents();
});
 
Admin/promotion/layer_cart_remind_message.php+46-1
변경 전layer_cart_remind_message.php
<span class="cart-remind-sms notice-info">SMS : 발송 건당 1포인트 차감</span>
</div>
</div>
 
 
 
 
<div class="form-inline mgt10">
<textarea name="cartRemindSendMessage" rows="8" class="smsContents form-control width-xl"><?= $cartRemindData['cartRemindSendMessage']; ?></textarea>
<div class="mgt5">
<a href="https://www.nhn-commerce.com/customer/board-view.gd?type=notice&idx=1237" target="_blank" class="btn-link">자세히보기></a>
</p>
<p class="notice-info">장바구니 링크 치환코드는 LMS인 경우에만 정상적으로 발송됩니다</p>
 
</div>
</td>
</tr>
 
// 글자수 체크
$('textarea[name=cartRemindSendMessage]').keyup(changeCartRemindContentsLength);
 
changeCartRemindSendType();
changeCartRemindContentsLength();
 
});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* SMS 내용 길이 체크
*/
function changeCartRemindContentsLength() {
var contentsText = $('textarea[name=cartRemindSendMessage]').val();
 
 
 
 
 
var textLength = stringToByte(contentsText);
 
if ($('input:hidden[name="cartRemindSendType"]').val() == 'sms' && textLength > <?= $smsStringLimit; ?>) {
$('.cart-remind-sms').hide();
$('.cart-remind-sms select').attr('disabled', 'disabled');
$('.cart-remind-sms input').attr('disabled', 'disabled');
 
 
// sms발송
} else if ($('input:hidden[name="cartRemindSendType"]').val() == 'sms') {
$('.cart-remind-lms').hide();
$('.cart-remind-sms').show();
$('.cart-remind-sms select').removeAttr('disabled');
$('.cart-remind-sms input').removeAttr('disabled');
 
 
}
}
/**
}
return length;
}
 
 
 
 
 
 
 
 
 
 
 
 
</script>
 
 
변경 후layer_cart_remind_message.php
<span class="cart-remind-sms notice-info">SMS : 발송 건당 1포인트 차감</span>
</div>
</div>
<div class="form-inline mgt10 js-cart-subject-row">
<input type="text" name="cartRemindSendSubject" id="cartRemindSendSubject" class="form-control width-xl" placeholder="제목을 입력해주세요." value="<?= gd_isset($cartRemindData['cartRemindSendSubject']); ?>" disabled="disabled"/>
<input type="text" id="cartRemindSubjectCount" value="0" readonly="readonly" class="form-control width-3xs"> / <?= $lmsSubjectLimit; ?> Bytes
</div>
<div class="form-inline mgt10">
<textarea name="cartRemindSendMessage" rows="8" class="smsContents form-control width-xl"><?= $cartRemindData['cartRemindSendMessage']; ?></textarea>
<div class="mgt5">
<a href="https://www.nhn-commerce.com/customer/board-view.gd?type=notice&idx=1237" target="_blank" class="btn-link">자세히보기></a>
</p>
<p class="notice-info">장바구니 링크 치환코드는 LMS인 경우에만 정상적으로 발송됩니다</p>
<p class="notice-info">본문 내용이 LMS인 경우에만 제목 입력이 가능하며, 제목 영역에는 직접 (광고) 문구를 입력하지 않도록 하고 광고 삽입이 필요한 경우 광고성 문구 추가 기능을 사용해야 합니다.</p>
</div>
</td>
</tr>
 
// 글자수 체크
$('textarea[name=cartRemindSendMessage]').keyup(changeCartRemindContentsLength);
$('#cartRemindSendSubject').on('keyup keydown', changeCartRemindSubjectLength);
changeCartRemindSendType();
changeCartRemindContentsLength();
changeCartRemindSubjectLength();
});
 
/**
* LMS 제목 Byte 체크 (공백 포함 최대 <?= $lmsSubjectLimit; ?>Byte, 초과분 자동 삭제)
*/
function changeCartRemindSubjectLength() {
var input = $('#cartRemindSendSubject');
if (input.length === 0) {
return;
}
var limit = <?= $lmsSubjectLimit; ?>;
var text = stripEmoji(input.val());
while (stringToByte(text) > limit) {
text = text.substring(0, text.length - 1);
}
input.val(text);
$('#cartRemindSubjectCount').val(stringToByte(text));
}
/**
* SMS 내용 길이 체크
*/
function changeCartRemindContentsLength() {
var $cartTa = $('textarea[name=cartRemindSendMessage]');
var strippedBody = stripEmoji($cartTa.val());
if (strippedBody !== $cartTa.val()) {
$cartTa.val(strippedBody);
}
var contentsText = strippedBody;
var textLength = stringToByte(contentsText);
 
if ($('input:hidden[name="cartRemindSendType"]').val() == 'sms' && textLength > <?= $smsStringLimit; ?>) {
$('.cart-remind-sms').hide();
$('.cart-remind-sms select').attr('disabled', 'disabled');
$('.cart-remind-sms input').attr('disabled', 'disabled');
 
$('#cartRemindSendSubject').prop('disabled', false); // LMS: 제목 영역 활성
// sms발송
} else if ($('input:hidden[name="cartRemindSendType"]').val() == 'sms') {
$('.cart-remind-lms').hide();
$('.cart-remind-sms').show();
$('.cart-remind-sms select').removeAttr('disabled');
$('.cart-remind-sms input').removeAttr('disabled');
 
$('#cartRemindSendSubject').prop('disabled', true); // SMS: 제목 영역 비활성(값 유지, 미저장/미발송)
}
}
/**
}
return length;
}
 
/**
* 이모티콘 제거 (제목/본문 이모티콘 입력 불가 - 자동 삭제)
*/
function stripEmoji(str) {
if (!str) {
return str;
}
return str
.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '')
.replace(/[\uFE00-\uFE0F\u200D\u20E3]/g, '');
}
</script>
 
 
Admin/share/layer_comeback_coupon_sms.php+6
변경 전layer_comeback_coupon_sms.php
<col style="width:80%" />
</colgroup>
<tbody>
 
 
 
 
 
 
<tr>
<th>발송 내용</th>
<td>
 
변경 후layer_comeback_coupon_sms.php
<col style="width:80%" />
</colgroup>
<tbody>
<tr>
<th>제목</th>
<td>
<input type="text" class="form-control width100p" readonly="readonly" value="<?= gd_isset($data['smsSubject']) !== '' ? gd_isset($data['smsSubject']) : '[제목없음]' ?>"/>
</td>
</tr>
<tr>
<th>발송 내용</th>
<td>
 
Admin/share/layer_standby_sms.php+48-6
변경 전layer_standby_sms.php
*/
?>
<form action="" method="post">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<div class="row">
<div class="col-xs-12">
<div class="pull-left">
<span class="sms-type text-darkblue">SMS : 발송 건당 1포인트 차감</span>
<span class="lms-type text-orange-red display-none">LMS : 발송 건당 <?php echo $lmsPoint; ?>포인트 차감</span>
</div>
<div class="pull-right">
<input type="text" id="smsStringCount" value="0" readonly="readonly" class="form-control width-3xs"> /
<span class="sms-type"><?php echo $smsStringLimit; ?></span><span class="lms-type display-none"><?php echo number_format($lmsStringLimit); ?></span> Bytes
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<textarea name="contents" id="contents" rows="8" class="form-control"><?= $data['contents']; ?></textarea>
</div>
</div>
<div class="row">
<div class="center modal-footer">
<button type="submit" id="modify" class="btn btn-red">수정</button>
$(document).ready(function () {
var $textarea = $('textarea[name=contents]');
$textarea.on('keyup change', setSendLength).trigger('change');
 
 
});
function setSendLength() {
setContentsLength('contents', 'smsStringCount');
$('.sms-type').hide();
$('.lms-type').show();
$('input[name=sendFl]').val('lms');
 
 
} else {
$('#' + countId).css("color", "");
$('.sms-type').show();
$('.lms-type').hide();
$('input[name=sendFl]').val('sms');
 
}
$('#' + countId).val(textLength);
}
}
return length;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
</script>
 
변경 후layer_standby_sms.php
*/
?>
<form action="" method="post">
<div class="row">
<div class="col-xs-12">
<div class="pull-right form-inline">
<input type="text" id="subjectStringCount" value="0" readonly="readonly" class="form-control width-3xs"> / <?= $lmsSubjectLimit; ?> Bytes
</div>
<div style="overflow:hidden; padding-right:10px;">
<input type="text" name="subject" id="subject" class="form-control" placeholder="제목을 입력해주세요." value="<?= gd_isset($data['subject']); ?>" disabled="disabled"/>
</div>
</div>
</div>
<div class="row mgt10">
<div class="col-xs-12">
<textarea name="contents" id="contents" rows="8" class="form-control"><?= $data['contents']; ?></textarea>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="pull-left">
<span class="sms-type text-darkblue">SMS : 발송 건당 1포인트 차감</span>
<span class="lms-type text-orange-red display-none">LMS : 발송 건당 <?php echo $lmsPoint; ?>포인트 차감</span>
</div>
 
<div class="pull-right">
<input type="text" id="smsStringCount" value="0" readonly="readonly" class="form-control width-3xs"> /
<span class="sms-type"><?php echo $smsStringLimit; ?></span><span class="lms-type display-none"><?php echo number_format($lmsStringLimit); ?></span> Bytes
</div>
</div>
</div>
 
 
 
 
 
<div class="row">
<div class="center modal-footer">
<button type="submit" id="modify" class="btn btn-red">수정</button>
$(document).ready(function () {
var $textarea = $('textarea[name=contents]');
$textarea.on('keyup change', setSendLength).trigger('change');
$('#subject').on('keyup keydown', setSubjectLength);
setSubjectLength();
});
function setSendLength() {
setContentsLength('contents', 'smsStringCount');
$('.sms-type').hide();
$('.lms-type').show();
$('input[name=sendFl]').val('lms');
$('#subject').prop('disabled', false); // LMS: 제목 영역 활성
setSubjectLength();
} else {
$('#' + countId).css("color", "");
$('.sms-type').show();
$('.lms-type').hide();
$('input[name=sendFl]').val('sms');
$('#subject').prop('disabled', true); // SMS: 제목 영역 비활성(값 유지, 미발송)
}
$('#' + countId).val(textLength);
}
}
return length;
}
/**
* 이모티콘 제거 (제목/본문 이모티콘 입력 불가 - 자동 삭제)
*/
function stripEmoji(str) {
if (!str) {
return str;
}
return str
.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '')
.replace(/[\uFE00-\uFE0F\u200D\u20E3]/g, '');
}
/**
* LMS 제목 Byte 체크 (공백 포함 최대 <?= $lmsSubjectLimit; ?>Byte, 초과분 자동 삭제)
*/
function setSubjectLength() {
var input = $('#subject');
if (input.length === 0) {
return;
}
var limit = <?= $lmsSubjectLimit; ?>;
var text = stripEmoji(input.val());
while (stringToByte(text) > limit) {
text = text.substring(0, text.length - 1);
}
input.val(text);
$('#subjectStringCount').val(stringToByte(text));
}
</script>
 
Admin/share/member_crm_sms.php+8
변경 전member_crm_sms.php
$listHtml[] = '<td class="text-center">' . $sSendFl . '</td>';
$listHtml[] = '<td style="word-break:break-all;word-wrap:break-word;overflow:hidden;" class="multirows">';
if ($data['sendFl'] != 'kakao') {
 
 
 
 
 
 
 
 
$listHtml[] = '<div>' . $data['contents'] . '</div>';
} else {
$listHtml[] = '<div>' . nl2br($data['templateContent']) . '</div>';
 
변경 후member_crm_sms.php
$listHtml[] = '<td class="text-center">' . $sSendFl . '</td>';
$listHtml[] = '<td style="word-break:break-all;word-wrap:break-word;overflow:hidden;" class="multirows">';
if ($data['sendFl'] != 'kakao') {
// LMS 제목 — 있으면 그대로, 없으면 '[제목없음]' 표시(표시 시점 변환). 제목은 LMS 한정.
if ($data['sendFl'] == 'lms') {
$smsSubject = trim($data['subject'] ?? '');
if ($smsSubject === '') {
$smsSubject = '[제목없음]';
}
$listHtml[] = '<div><strong>' . gd_htmlspecialchars($smsSubject) . '</strong></div>';
}
$listHtml[] = '<div>' . $data['contents'] . '</div>';
} else {
$listHtml[] = '<div>' . nl2br($data['templateContent']) . '</div>';
 
Component/CartRemind/CartRemind.php+15
변경 전CartRemind.php
$getCartRemindSend['autoSendTime'] = $cartRemindData['cartRemindAutoSendTime'];
$getCartRemindSend['smsType'] = $cartRemindData['cartRemindSendType'];
$getCartRemindSend['message'] = $cartRemindData['cartRemindSendMessage'];
 
$getCartRemindSend['cartUrl'] = $cartRemindData['cartRemindSendUrl'];
if ($cartRemindData['cartRemindCoupon'] > 0) {
$getCartRemindSend['coupon'] = $cartRemindData['cartRemindCoupon'];
$validator->add('cartRemindCoupon', null, null); // 발송쿠폰
$validator->add('cartRemindSendType', null, true); // 발송타입 (sms,lms)
$validator->add('cartRemindSendMessage', null, true); // 발송메세지
 
 
if ($validator->act($arrData, true) === false) {
throw new \Exception(implode("<br/>", $validator->errors));
// 선택에 따른 값의 초기화를 위한 빈값 제거 - 주석처리 함 - 상태에 따른 빈값 저장(초기화)이 필요한 경우가 존재함.
// $arrData = ArrayUtils::removeEmpty($arrData);
 
 
 
 
 
 
switch (substr($arrData['mode'], 0, 6)) {
case 'insert' : {
// 저장
$validator->add('cartRemindNo', 'number', true); // 장바구니 알림 고유번호
$validator->add('cartRemindSendType', null, true); // 발송타입 (sms,lms)
$validator->add('cartRemindSendMessage', null, true); // 발송메세지
 
 
if ($validator->act($arrData, true) === false) {
throw new \Exception(implode("<br/>", $validator->errors));
// 선택에 따른 값의 초기화를 위한 빈값 제거 - 주석처리 함 - 상태에 따른 빈값 저장(초기화)이 필요한 경우가 존재함.
// $arrData = ArrayUtils::removeEmpty($arrData);
 
 
 
 
 
 
// 수정
$arrBind = $this->db->get_binding(DBTableField::tableCartRemind(), $arrData, 'update', array_keys($arrData), ['cartRemindNo']);
$this->db->bind_param_push($arrBind['bind'], 'i', $arrData['cartRemindNo']);
}
// sms, lms
$smsSendData['sendFl'] = $cartRemindSendData['smsType'];
 
 
 
// ??
$smsSendData['agreeCnt'] = '';
 
변경 후CartRemind.php
$getCartRemindSend['autoSendTime'] = $cartRemindData['cartRemindAutoSendTime'];
$getCartRemindSend['smsType'] = $cartRemindData['cartRemindSendType'];
$getCartRemindSend['message'] = $cartRemindData['cartRemindSendMessage'];
$getCartRemindSend['subject'] = isset($cartRemindData['cartRemindSendSubject']) ? $cartRemindData['cartRemindSendSubject'] : '';
$getCartRemindSend['cartUrl'] = $cartRemindData['cartRemindSendUrl'];
if ($cartRemindData['cartRemindCoupon'] > 0) {
$getCartRemindSend['coupon'] = $cartRemindData['cartRemindCoupon'];
$validator->add('cartRemindCoupon', null, null); // 발송쿠폰
$validator->add('cartRemindSendType', null, true); // 발송타입 (sms,lms)
$validator->add('cartRemindSendMessage', null, true); // 발송메세지
$validator->add('cartRemindSendSubject', null, null); // LMS 제목 (선택, lms 시)
 
if ($validator->act($arrData, true) === false) {
throw new \Exception(implode("<br/>", $validator->errors));
// 선택에 따른 값의 초기화를 위한 빈값 제거 - 주석처리 함 - 상태에 따른 빈값 저장(초기화)이 필요한 경우가 존재함.
// $arrData = ArrayUtils::removeEmpty($arrData);
 
// LMS 제목은 LMS 상태에서만 저장(C5). 본문이 SMS면 제목 영역은 저장하지 않음(빈값).
if (gd_isset($arrData['cartRemindSendType']) === 'sms') {
$arrData['cartRemindSendSubject'] = '';
}
 
switch (substr($arrData['mode'], 0, 6)) {
case 'insert' : {
// 저장
$validator->add('cartRemindNo', 'number', true); // 장바구니 알림 고유번호
$validator->add('cartRemindSendType', null, true); // 발송타입 (sms,lms)
$validator->add('cartRemindSendMessage', null, true); // 발송메세지
$validator->add('cartRemindSendSubject', null, null); // LMS 제목 (선택, lms 시)
 
if ($validator->act($arrData, true) === false) {
throw new \Exception(implode("<br/>", $validator->errors));
// 선택에 따른 값의 초기화를 위한 빈값 제거 - 주석처리 함 - 상태에 따른 빈값 저장(초기화)이 필요한 경우가 존재함.
// $arrData = ArrayUtils::removeEmpty($arrData);
 
// LMS 제목은 LMS 상태에서만 저장(C5). 본문이 SMS면 제목 영역은 저장하지 않음(빈값).
if (gd_isset($arrData['cartRemindSendType']) === 'sms') {
$arrData['cartRemindSendSubject'] = '';
}
 
// 수정
$arrBind = $this->db->get_binding(DBTableField::tableCartRemind(), $arrData, 'update', array_keys($arrData), ['cartRemindNo']);
$this->db->bind_param_push($arrBind['bind'], 'i', $arrData['cartRemindNo']);
}
// sms, lms
$smsSendData['sendFl'] = $cartRemindSendData['smsType'];
// LMS 제목 (LMS 발송 시에만 SmsAdmin 에서 사용)
$smsSendData['smsSubject'] = isset($cartRemindSendData['subject']) ? $cartRemindSendData['subject'] : '';
 
// ??
$smsSendData['agreeCnt'] = '';
 
Component/Coupon/CouponAdmin.php+3
변경 전CouponAdmin.php
지금 바로 확인하세요!";
}
$validator->add('smsContents', 'required', true); // SMS 발송 내용
 
 
// 전송일 null처리
$arrData['sendDt'] = null;
$smsSendData['smsPoint'] = Sms::getPoint();
// 전송 내용
$smsSendData['smsContents'] = str_replace('rc_memNm', 'memNm', $getData['smsContents']);
 
 
// 치환 코드 그룹
$smsSendData['replaceCodeGroup'] = 'promotion';
// 전송요청 수
 
변경 후CouponAdmin.php
지금 바로 확인하세요!";
}
$validator->add('smsContents', 'required', true); // SMS 발송 내용
$validator->add('smsSubject', null, null); // LMS 제목 (검증 없음, garbageDelete 방지용 등록)
 
// 전송일 null처리
$arrData['sendDt'] = null;
$smsSendData['smsPoint'] = Sms::getPoint();
// 전송 내용
$smsSendData['smsContents'] = str_replace('rc_memNm', 'memNm', $getData['smsContents']);
// LMS 제목 (LMS 발송 시에만 SmsAdmin 에서 사용)
$smsSendData['smsSubject'] = isset($getData['smsSubject']) ? $getData['smsSubject'] : '';
// 치환 코드 그룹
$smsSendData['replaceCodeGroup'] = 'promotion';
// 전송요청 수
 
Component/Database/DBTableField.php+3
변경 전DBTableField.php
['val' => 'cartRemindAutoSendTime', 'typ' => 'i', 'def' => '10'], // 장바구니 알림 자동발송 시 발송 시간
['val' => 'cartRemindSendType', 'typ' => 's', 'def' => 'lms'], // 장바구니 알림 전송 형식 - sms, lms
['val' => 'cartRemindSendMessage', 'typ' => 's', 'def' => '(광고)[{rc_mallNm}] {rc_memNm}님의 장바구니에 상품이 담겨 있습니다. 아래 장바구니 바로가기를 통해 바로 확인하실 수 있습니다. ▶ 장바구니 바로가기: {rc_cartRemindLink}'], // 장바구니 알림 전송 내용
 
['val' => 'cartRemindSendUrl', 'typ' => 's', 'def' => ''], // 장바구니 알림 바로가기 링크
['val' => 'cartRemindInsertAdminId', 'typ' => 's', 'def' => null], // 장바구니 알림 등록자 아이디
['val' => 'managerNo', 'typ' => 'i', 'def' => 0], // 장바구니 알림 등록자 키
['val' => 'smsAutoType', 'typ' => 's', 'def' => null], // SMS 자동발송 수신 종류 (member, admin, provider)
['val' => 'subject', 'typ' => 's', 'def' => null], // SMS 템플릿 제목
['val' => 'contents', 'typ' => 's', 'def' => null], // SMS 템플릿 내용
 
['val' => 'description', 'typ' => 's', 'def' => null], // 설명
['val' => 'isUserBasic', 'typ' => 's', 'def' => 'n'], // 전송타입(user)기본제공여부
['val' => 'modDt', 'typ' => 's', 'def' => null], // 수정일
['val' => 'smsFl', 'typ' => 's', 'def' => 'n'], // sms동시 발송여부 - y:발송 / n:미발송
['val' => 'smsSpamFl', 'typ' => 's', 'def' => 'n'], // 광고성 문구 추가 - y:추가 / n:미추가
['val' => 'smsContents', 'typ' => 's', 'def' => ''], // SMS 발송 내용
 
['val' => 'managerNo', 'typ' => 'i', 'def' => ''], // 등록 관리자 고유번호
['val' => 'deleteFl', 'typ' => 's', 'def' => 'n'], // 삭제 flag - y:삭제 / n:미삭제
['val' => 'sendDt', 'typ' => 's', 'def' => null], // 전송일
 
변경 후DBTableField.php
['val' => 'cartRemindAutoSendTime', 'typ' => 'i', 'def' => '10'], // 장바구니 알림 자동발송 시 발송 시간
['val' => 'cartRemindSendType', 'typ' => 's', 'def' => 'lms'], // 장바구니 알림 전송 형식 - sms, lms
['val' => 'cartRemindSendMessage', 'typ' => 's', 'def' => '(광고)[{rc_mallNm}] {rc_memNm}님의 장바구니에 상품이 담겨 있습니다. 아래 장바구니 바로가기를 통해 바로 확인하실 수 있습니다. ▶ 장바구니 바로가기: {rc_cartRemindLink}'], // 장바구니 알림 전송 내용
['val' => 'cartRemindSendSubject', 'typ' => 's', 'def' => ''], // 장바구니 알림 LMS 제목
['val' => 'cartRemindSendUrl', 'typ' => 's', 'def' => ''], // 장바구니 알림 바로가기 링크
['val' => 'cartRemindInsertAdminId', 'typ' => 's', 'def' => null], // 장바구니 알림 등록자 아이디
['val' => 'managerNo', 'typ' => 'i', 'def' => 0], // 장바구니 알림 등록자 키
['val' => 'smsAutoType', 'typ' => 's', 'def' => null], // SMS 자동발송 수신 종류 (member, admin, provider)
['val' => 'subject', 'typ' => 's', 'def' => null], // SMS 템플릿 제목
['val' => 'contents', 'typ' => 's', 'def' => null], // SMS 템플릿 내용
['val' => 'messageTitle', 'typ' => 's', 'def' => null], // LMS 메시지 제목
['val' => 'description', 'typ' => 's', 'def' => null], // 설명
['val' => 'isUserBasic', 'typ' => 's', 'def' => 'n'], // 전송타입(user)기본제공여부
['val' => 'modDt', 'typ' => 's', 'def' => null], // 수정일
['val' => 'smsFl', 'typ' => 's', 'def' => 'n'], // sms동시 발송여부 - y:발송 / n:미발송
['val' => 'smsSpamFl', 'typ' => 's', 'def' => 'n'], // 광고성 문구 추가 - y:추가 / n:미추가
['val' => 'smsContents', 'typ' => 's', 'def' => ''], // SMS 발송 내용
['val' => 'smsSubject', 'typ' => 's', 'def' => ''], // LMS 제목
['val' => 'managerNo', 'typ' => 'i', 'def' => ''], // 등록 관리자 고유번호
['val' => 'deleteFl', 'typ' => 's', 'def' => 'n'], // 삭제 flag - y:삭제 / n:미삭제
['val' => 'sendDt', 'typ' => 's', 'def' => null], // 전송일
 
Component/Sms/SmsAdmin.php+10
변경 전SmsAdmin.php
$dbData[$autoData[$autoType . 'Mode']][$smsType][$autoCode][$autoType]['sno'] = $autoData[$autoType . 'Sno'];
$dbData[$autoData[$autoType . 'Mode']][$smsType][$autoCode][$autoType]['subject'] = $autoData['subject'];
$dbData[$autoData[$autoType . 'Mode']][$smsType][$autoCode][$autoType]['contents'] = $autoData[$autoType . 'Contents'];
 
// $dbData[$autoData[$autoType . 'Mode']][$smsType][$autoCode][$autoType]['smsType'] = $smsType;
unset($request[$smsType][$autoCode][$autoType . 'Mode']);
unset($request[$smsType][$autoCode][$autoType . 'Sno']);
unset($request[$smsType][$autoCode]['subject']);
unset($request[$smsType][$autoCode][$autoType . 'Contents']);
 
}
}
}
$getData = gd_htmlspecialchars_stripslashes($this->db->query_fetch($strSQL, null, false));
foreach ($getData as $data) {
$setData[$data['smsType']][$data['smsAutoCode']][$data['smsAutoType']]['contents'] = $data['contents'];
 
$setData[$data['smsType']][$data['smsAutoCode']][$data['smsAutoType']]['sno'] = $data['sno'];
}
unset($getData);
foreach ($arrType as $sendType) {
if (isset($setData[$keyType][$val['code']][$sendType]['contents']) === true) {
$smsAutoType[$keyType][$key][$sendType . 'Contents'] = $setData[$keyType][$val['code']][$sendType]['contents'];
 
$smsAutoType[$keyType][$key][$sendType . 'Mode'] = 'update';
$smsAutoType[$keyType][$key][$sendType . 'Sno'] = $setData[$keyType][$val['code']][$sendType]['sno'];
} else {
$smsAutoType[$keyType][$key][$sendType . 'Contents'] = $val[$sendType . 'Contents'];
 
$smsAutoType[$keyType][$key][$sendType . 'Mode'] = 'insert';
$smsAutoType[$keyType][$key][$sendType . 'Sno'] = '';
}
}
if ($receiverData['sendFl'] === 'lms') {
$message = new \Component\Sms\LmsMessage($receiverData['smsContents'], $receiverData['replaceCodeGroup']);
 
 
 
 
 
} else {
$message = new \Component\Sms\SmsMessage($receiverData['smsContents'], $receiverData['replaceCodeGroup']);
}
 
변경 후SmsAdmin.php
$dbData[$autoData[$autoType . 'Mode']][$smsType][$autoCode][$autoType]['sno'] = $autoData[$autoType . 'Sno'];
$dbData[$autoData[$autoType . 'Mode']][$smsType][$autoCode][$autoType]['subject'] = $autoData['subject'];
$dbData[$autoData[$autoType . 'Mode']][$smsType][$autoCode][$autoType]['contents'] = $autoData[$autoType . 'Contents'];
$dbData[$autoData[$autoType . 'Mode']][$smsType][$autoCode][$autoType]['messageTitle'] = gd_isset($autoData[$autoType . 'MessageTitle'], '');
// $dbData[$autoData[$autoType . 'Mode']][$smsType][$autoCode][$autoType]['smsType'] = $smsType;
unset($request[$smsType][$autoCode][$autoType . 'Mode']);
unset($request[$smsType][$autoCode][$autoType . 'Sno']);
unset($request[$smsType][$autoCode]['subject']);
unset($request[$smsType][$autoCode][$autoType . 'Contents']);
unset($request[$smsType][$autoCode][$autoType . 'MessageTitle']);
}
}
}
$getData = gd_htmlspecialchars_stripslashes($this->db->query_fetch($strSQL, null, false));
foreach ($getData as $data) {
$setData[$data['smsType']][$data['smsAutoCode']][$data['smsAutoType']]['contents'] = $data['contents'];
$setData[$data['smsType']][$data['smsAutoCode']][$data['smsAutoType']]['messageTitle'] = $data['messageTitle'];
$setData[$data['smsType']][$data['smsAutoCode']][$data['smsAutoType']]['sno'] = $data['sno'];
}
unset($getData);
foreach ($arrType as $sendType) {
if (isset($setData[$keyType][$val['code']][$sendType]['contents']) === true) {
$smsAutoType[$keyType][$key][$sendType . 'Contents'] = $setData[$keyType][$val['code']][$sendType]['contents'];
$smsAutoType[$keyType][$key][$sendType . 'MessageTitle'] = gd_isset($setData[$keyType][$val['code']][$sendType]['messageTitle'], '');
$smsAutoType[$keyType][$key][$sendType . 'Mode'] = 'update';
$smsAutoType[$keyType][$key][$sendType . 'Sno'] = $setData[$keyType][$val['code']][$sendType]['sno'];
} else {
$smsAutoType[$keyType][$key][$sendType . 'Contents'] = $val[$sendType . 'Contents'];
$smsAutoType[$keyType][$key][$sendType . 'MessageTitle'] = '';
$smsAutoType[$keyType][$key][$sendType . 'Mode'] = 'insert';
$smsAutoType[$keyType][$key][$sendType . 'Sno'] = '';
}
}
if ($receiverData['sendFl'] === 'lms') {
$message = new \Component\Sms\LmsMessage($receiverData['smsContents'], $receiverData['replaceCodeGroup']);
// LMS 제목 (미입력 시 빈 값)
// 튜닝 상점 대비: 구버전 SmsSender(setSubject 미보유)에서 발송 중단 방지
if (method_exists($transport, 'setSubject')) {
$transport->setSubject(isset($receiverData['smsSubject']) ? $receiverData['smsSubject'] : '');
}
} else {
$message = new \Component\Sms\SmsMessage($receiverData['smsContents'], $receiverData['replaceCodeGroup']);
}
 
Component/Sms/SmsAuto.php+6-1
변경 전SmsAuto.php
}
$transport->setSmsPoint(Sms::getPoint());
$transport->setMessage($message);
 
 
 
 
 
$transport->setSmsType($item['smsType']);
$transport->setReceiver($receiverData);
$transport->setSendDate($this->smsAutoSendDate);
{
$logger = \App::getInstance('logger');
$binds = [];
$this->db->strField = 'smsType, smsAutoType, contents, subject';
$this->db->strJoin = DB_SMS_CONTENTS;
$this->db->strWhere = 'smsType= ? AND smsAutoCode = ? AND smsAutoType IN (\'' . implode('\', \'', $wheres) . '\') AND contents != \'\' AND contents IS NOT NULL';
$this->db->bind_param_push($binds, 's', $this->smsType);
 
변경 후SmsAuto.php
}
$transport->setSmsPoint(Sms::getPoint());
$transport->setMessage($message);
// LMS 제목 (설정된 자동발송 문구 제목 - LMS 발송 시에만 SmsSender 에서 사용, 미입력 시 [제목없음])
// 튜닝 상점 대비: 구버전 SmsSender(setSubject 미보유)에서 발송 중단 방지
if (method_exists($transport, 'setSubject')) {
$transport->setSubject($item['messageTitle'] ?? '');
}
$transport->setSmsType($item['smsType']);
$transport->setReceiver($receiverData);
$transport->setSendDate($this->smsAutoSendDate);
{
$logger = \App::getInstance('logger');
$binds = [];
$this->db->strField = 'smsType, smsAutoType, contents, subject, messageTitle';
$this->db->strJoin = DB_SMS_CONTENTS;
$this->db->strWhere = 'smsType= ? AND smsAutoCode = ? AND smsAutoType IN (\'' . implode('\', \'', $wheres) . '\') AND contents != \'\' AND contents IS NOT NULL';
$this->db->bind_param_push($binds, 's', $this->smsType);
 
Component/Sms/SmsSender.php+31-1
변경 전SmsSender.php
protected $password;
/** @var bool SMS 발송 시 Exception 을 전달할 경우 사용 */
protected $isThrowPasswordException = false;
 
 
/** @var string SMS 대량발송 파일 경로 */
private $_smsLargeFilePath;
/** @var object SMS 대량발송 TXT 파일 생성 로거 */
];
//@formatter:on
if ($this->_isLms()) {
$this->sendSms['subject'] = '';
}
}
];
if ($this->_isLms()) {
$this->smsLog['sendFl'] = 'lms';
 
}
}
$this->isThrowPasswordException = $isThrowPasswordException;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* validPassword
* sms 패스워드 확인 - 초기 패스워드가 아닐 경우 검증
 
변경 후SmsSender.php
protected $password;
/** @var bool SMS 발송 시 Exception 을 전달할 경우 사용 */
protected $isThrowPasswordException = false;
/** @var string|null LMS 제목 */
protected $subject;
/** @var string SMS 대량발송 파일 경로 */
private $_smsLargeFilePath;
/** @var object SMS 대량발송 TXT 파일 생성 로거 */
];
//@formatter:on
if ($this->_isLms()) {
$this->sendSms['subject'] = $this->resolveSubject();
}
}
];
if ($this->_isLms()) {
$this->smsLog['sendFl'] = 'lms';
$this->smsLog['subject'] = trim(preg_replace('/#?\{[^}]*\}/u', '', (string) $this->subject)); // 저장은 치환자 제거한 원문(빈값 유지), [제목없음] 변환은 발송/표시 시점만
}
}
$this->isThrowPasswordException = $isThrowPasswordException;
}
/**
* LMS 제목 설정 (LMS 발송 시에만 사용)
*
* @param string|null $subject
*/
public function setSubject($subject)
{
$this->subject = $subject;
}
/**
* 실발송용 LMS 제목 계산
* - 제목 치환자({..}/#{..})는 미지원이므로 공란 처리
* - LMS 인데 제목이 없으면(또는 치환자만 있어 공란) '[제목없음]' 으로 발송
*
* @return string
*/
protected function resolveSubject(): string
{
$subject = trim(preg_replace('/#?\{[^}]*\}/u', '', (string) $this->subject));
if ($subject === '') {
return '[제목없음]';
}
return $subject;
}
/**
* validPassword
* sms 패스워드 확인 - 초기 패스워드가 아닐 경우 검증
 
Controller/Admin/Member/SmsAutoController.php+1
변경 전SmsAutoController.php
// SMS 포인트 Sync
Sms::saveSmsPoint();
$memberJoin = ComponentUtils::getPolicy('member.join');
 
$this->setData('smsAutoList', Sms::SMS_AUTO_RECEIVE_LIST);
$this->setData('smsAutoOrderPeriod', Sms::SMS_AUTO_ORDER_PERIOD);
$this->setData('smsAutoOrderAfterPeriod', Sms::SMS_ORDER_AFTER_PERIOD);
 
변경 후SmsAutoController.php
// SMS 포인트 Sync
Sms::saveSmsPoint();
$memberJoin = ComponentUtils::getPolicy('member.join');
$this->setData('lmsSubjectLimit', defined(Sms::class . '::LMS_SUBJECT_LIMIT') ? Sms::LMS_SUBJECT_LIMIT : 40);
$this->setData('smsAutoList', Sms::SMS_AUTO_RECEIVE_LIST);
$this->setData('smsAutoOrderPeriod', Sms::SMS_AUTO_ORDER_PERIOD);
$this->setData('smsAutoOrderAfterPeriod', Sms::SMS_ORDER_AFTER_PERIOD);
 
Controller/Admin/Member/SmsLogPsController.php+25-14
변경 전SmsLogPsController.php
try {
$requestParams = $request->post()->all();
$godoSms = new GodoSmsServerApi();
$smsLog = $componentSmsLog->getSmsLog('*', $requestParams['smsLogSno']);
 
 
 
 
 
 
 
 
 
 
 
 
if ($smsLog['replaceCodeType'] == 'none') {
// SMS 결과 수신 처리
if ($godoSms->smsReserveChange($requestParams['sno'], 'modify', $requestParams['contents']) !== true) {
throw new LayerException(__('수정이 실패되었습니다.'));
} else {
$componentSmsLog->editContents($requestParams);
$this->json(__('수정되었습니다.'));
}
} else {
// SMS 결과 수신 처리
if ($godoSms->smsSendListReserveChange($requestParams['sno'], 'modify', $requestParams['contents']) !== true) {
throw new LayerException(__('수정이 실패되었습니다.'));
} else {
$componentSmsLog->editContents($requestParams);
$this->json(__('수정되었습니다.'));
}
 
 
 
 
 
}
 
} catch (LayerException $e) {
$this->json($e->getMessage());
}
 
변경 후SmsLogPsController.php
try {
$requestParams = $request->post()->all();
$godoSms = new GodoSmsServerApi();
// 발송내역 고유번호 (수정 레이어는 sno 로 전달)
$smsLogSno = gd_isset($requestParams['smsLogSno'], gd_isset($requestParams['sno']));
$smsLog = $componentSmsLog->getSmsLog('*', $smsLogSno);
if (empty($smsLog)) {
throw new LayerException(__('발송내역을 찾을 수 없습니다.'));
}
// 예약변경 API 는 DB 의 contents/subject 를 읽어 외부(고도 SMS 서버)로 전송하므로
// 외부 예약 메시지에 수정 내용이 반영되도록 DB 를 먼저 갱신한다.
$requestParams['sno'] = $smsLogSno;
$componentSmsLog->editContents($requestParams);
if ($smsLog['replaceCodeType'] == 'none') {
$result = $godoSms->smsReserveChange($smsLogSno, 'modify');
 
 
 
 
 
 
} else {
// 치환코드 발송건은 수신자별로 재구성되므로 해당 발송내역의 발송리스트 sno 목록을 전달한다.
$smsSendList = $componentSmsLog->getSmsSendList(['smsLogSno' => $smsLogSno]);
$sendListSno = [];
foreach ((array) gd_isset($smsSendList['data'], []) as $sendListRow) {
$sendListSno[] = $sendListRow['sno'];
 
}
$result = $godoSms->smsSendListReserveChange($smsLogSno, 'modify', $sendListSno);
}
if ($result !== true) {
throw new LayerException(__('수정이 실패되었습니다.'));
}
$this->json(__('수정되었습니다.'));
} catch (LayerException $e) {
$this->json($e->getMessage());
}
 
Controller/Admin/Member/SmsSendController.php+4
변경 전SmsSendController.php
'board' => '게시판',
];
$smsContents = '';
 
$receiveTotal = $rejectCount = 0;
$receiverData = $reSenderData = [];
$popupMode = false;
$componentSmsLog = \App::load('Component\\Sms\\SmsLog');
$smsLog = $componentSmsLog->getSmsLog('*', $request->post()->get('smsLogSno')); // 재전송 문자내역 조회
$smsContents = StringUtils::htmlSpecialCharsStripSlashes($smsLog['contents']); // 재전송 메시지 설정
 
$smsSendList = $componentSmsLog->getSmsSendList($request->post()->all())['data']; // 재전송 문자내역 발송내역 조회
$hasGuest = $componentSmsLog->hasGuestBySendList($smsSendList); // 발송내역 중 비회원 발송내역 확인
$isReSendAll = $request->post()->get('mode', '') == 'resend_all_member';
$this->setData('sms080Policy', ComponentUtils::getPolicy('sms.sms080'));
$this->setData('smsStringLimit', Sms::SMS_STRING_LIMIT);
$this->setData('lmsStringLimit', Sms::LMS_STRING_LIMIT);
 
$this->setData('smsForbidTime', Sms::SMS_FORBID_TIME);
$this->setData('lmsPoint', Sms::LMS_POINT);
$this->setData('smsCallNum', $smsCallNum);
$this->setData('receiverMode', $receiverMode);
$this->setData('popupMode', $popupMode);
$this->setData('smsContents', $smsContents);
 
$this->setData('reSenderData', $reSenderData);
$this->setData('receiveTotal', $receiveTotal);
$this->setData('rejectCount', $rejectCount);
 
변경 후SmsSendController.php
'board' => '게시판',
];
$smsContents = '';
$smsSubject = '';
$receiveTotal = $rejectCount = 0;
$receiverData = $reSenderData = [];
$popupMode = false;
$componentSmsLog = \App::load('Component\\Sms\\SmsLog');
$smsLog = $componentSmsLog->getSmsLog('*', $request->post()->get('smsLogSno')); // 재전송 문자내역 조회
$smsContents = StringUtils::htmlSpecialCharsStripSlashes($smsLog['contents']); // 재전송 메시지 설정
$smsSubject = StringUtils::htmlSpecialCharsStripSlashes(isset($smsLog['subject']) ? $smsLog['subject'] : ''); // 재전송 LMS 제목 복원
$smsSendList = $componentSmsLog->getSmsSendList($request->post()->all())['data']; // 재전송 문자내역 발송내역 조회
$hasGuest = $componentSmsLog->hasGuestBySendList($smsSendList); // 발송내역 중 비회원 발송내역 확인
$isReSendAll = $request->post()->get('mode', '') == 'resend_all_member';
$this->setData('sms080Policy', ComponentUtils::getPolicy('sms.sms080'));
$this->setData('smsStringLimit', Sms::SMS_STRING_LIMIT);
$this->setData('lmsStringLimit', Sms::LMS_STRING_LIMIT);
$this->setData('lmsSubjectLimit', defined(Sms::class . '::LMS_SUBJECT_LIMIT') ? Sms::LMS_SUBJECT_LIMIT : 40);
$this->setData('smsForbidTime', Sms::SMS_FORBID_TIME);
$this->setData('lmsPoint', Sms::LMS_POINT);
$this->setData('smsCallNum', $smsCallNum);
$this->setData('receiverMode', $receiverMode);
$this->setData('popupMode', $popupMode);
$this->setData('smsContents', $smsContents);
$this->setData('smsSubject', $smsSubject);
$this->setData('reSenderData', $reSenderData);
$this->setData('receiveTotal', $receiveTotal);
$this->setData('rejectCount', $rejectCount);
 
Controller/Admin/Promotion/CartRemindRegistController.php+1
변경 전CartRemindRegistController.php
$this->setData('selected', $selected);
$this->setData('smsStringLimit', Sms::SMS_STRING_LIMIT);
$this->setData('lmsStringLimit', Sms::LMS_STRING_LIMIT);
 
$this->setData('lmsPoint', Sms::LMS_POINT);
$this->setData('sms080Policy', ComponentUtils::getPolicy('sms.sms080'));
$this->setData('commerceSmsRefusalIntroUrl', ConfigUrlUtils::getNhnCommerceEchostUrl('sms-refusal-intro'));
 
변경 후CartRemindRegistController.php
$this->setData('selected', $selected);
$this->setData('smsStringLimit', Sms::SMS_STRING_LIMIT);
$this->setData('lmsStringLimit', Sms::LMS_STRING_LIMIT);
$this->setData('lmsSubjectLimit', defined(Sms::class . '::LMS_SUBJECT_LIMIT') ? Sms::LMS_SUBJECT_LIMIT : 40);
$this->setData('lmsPoint', Sms::LMS_POINT);
$this->setData('sms080Policy', ComponentUtils::getPolicy('sms.sms080'));
$this->setData('commerceSmsRefusalIntroUrl', ConfigUrlUtils::getNhnCommerceEchostUrl('sms-refusal-intro'));
 
Controller/Admin/Promotion/ComebackCouponRegistController.php+1
변경 전ComebackCouponRegistController.php
]);
$this->setData('smsStringLimit', Sms::SMS_STRING_LIMIT);
$this->setData('lmsStringLimit', Sms::LMS_STRING_LIMIT);
 
$this->setData('smsForbidTime', Sms::SMS_FORBID_TIME);
$this->setData('lmsPoint', Sms::LMS_POINT);
$this->setData('checkMode', gd_isset($checkMode));
 
변경 후ComebackCouponRegistController.php
]);
$this->setData('smsStringLimit', Sms::SMS_STRING_LIMIT);
$this->setData('lmsStringLimit', Sms::LMS_STRING_LIMIT);
$this->setData('lmsSubjectLimit', defined(Sms::class . '::LMS_SUBJECT_LIMIT') ? Sms::LMS_SUBJECT_LIMIT : 40);
$this->setData('smsForbidTime', Sms::SMS_FORBID_TIME);
$this->setData('lmsPoint', Sms::LMS_POINT);
$this->setData('checkMode', gd_isset($checkMode));
 
Controller/Admin/Promotion/LayerCartRemindMessageController.php+2-1
변경 전LayerCartRemindMessageController.php
{
$cartRemindNo = Request::get()->get('cartRemindNo');
$cartRemind = new CartRemind();
$cartRemindData = $cartRemind->getCartRemindInfo($cartRemindNo,'cartRemindNo, cartRemindSendType, cartRemindSendMessage');
 
$this->setData('cartRemindData', $cartRemindData);
$this->setData('smsStringLimit', Sms::SMS_STRING_LIMIT);
$this->setData('lmsStringLimit', Sms::LMS_STRING_LIMIT);
 
$this->setData('lmsPoint', Sms::LMS_POINT);
$this->getView()->setDefine('layout', 'layout_layer.php');
}
 
변경 후LayerCartRemindMessageController.php
{
$cartRemindNo = Request::get()->get('cartRemindNo');
$cartRemind = new CartRemind();
$cartRemindData = $cartRemind->getCartRemindInfo($cartRemindNo,'cartRemindNo, cartRemindSendType, cartRemindSendMessage, cartRemindSendSubject');
 
$this->setData('cartRemindData', $cartRemindData);
$this->setData('smsStringLimit', Sms::SMS_STRING_LIMIT);
$this->setData('lmsStringLimit', Sms::LMS_STRING_LIMIT);
$this->setData('lmsSubjectLimit', defined(Sms::class . '::LMS_SUBJECT_LIMIT') ? Sms::LMS_SUBJECT_LIMIT : 40);
$this->setData('lmsPoint', Sms::LMS_POINT);
$this->getView()->setDefine('layout', 'layout_layer.php');
}
 
Controller/Admin/Share/LayerStandbySmsController.php+2-1
변경 전LayerStandbySmsController.php
{
/** @var \Bundle\Component\Sms\SmsLog $smsLog */
$smsLog = App::load('\\Component\\Sms\\SmsLog');
$data = $smsLog->getSmsLog('sno, sendFl, contents, contentsMask', Request::get()->get('sno'));
$this->getView()->setDefine('layout', 'layout_layer.php');
$this->setData('data', gd_htmlspecialchars_stripslashes($data));
$this->setData('smsStringLimit', Sms::SMS_STRING_LIMIT);
$this->setData('lmsStringLimit', Sms::LMS_STRING_LIMIT);
 
$this->setData('smsForbidTime', Sms::SMS_FORBID_TIME);
$this->setData('lmsPoint', Sms::LMS_POINT);
}
 
변경 후LayerStandbySmsController.php
{
/** @var \Bundle\Component\Sms\SmsLog $smsLog */
$smsLog = App::load('\\Component\\Sms\\SmsLog');
$data = $smsLog->getSmsLog('sno, sendFl, subject, contents, contentsMask', Request::get()->get('sno'));
$this->getView()->setDefine('layout', 'layout_layer.php');
$this->setData('data', gd_htmlspecialchars_stripslashes($data));
$this->setData('smsStringLimit', Sms::SMS_STRING_LIMIT);
$this->setData('lmsStringLimit', Sms::LMS_STRING_LIMIT);
$this->setData('lmsSubjectLimit', defined(Sms::class . '::LMS_SUBJECT_LIMIT') ? Sms::LMS_SUBJECT_LIMIT : 40);
$this->setData('smsForbidTime', Sms::SMS_FORBID_TIME);
$this->setData('lmsPoint', Sms::LMS_POINT);
}
 
무통장 입금은행 보안 강화.
Component/Order/OrderAdminNew.php+40-31
변경 전OrderAdminNew.php
use Framework\Debug\Exception\LayerNotReloadException;
use Framework\Debug\Exception\AlertRedirectException;
use Framework\Debug\Exception\WarningException;
 
use Framework\StaticProxy\Proxy\UserFilePath;
use Framework\Utility\ArrayUtils;
use Framework\Utility\DateTimeUtils;
 
$this->checked['useFl'][$this->search['useFl']] = 'checked="checked"';
 
// 키워드 검색
if ($this->search['keyword']) {
if ($this->search['key'] == '') {
$tmpWhere = [
'bankName',
'accountNumber',
'depositor',
];
$arrWhereAll = [];
foreach ($tmpWhere as $keyNm) {
$arrWhereAll[] = '(' . $keyNm . ' LIKE concat(\'%\',?,\'%\'))';
$this->db->bind_param_push($this->arrBind, 's', $this->search['keyword']);
}
$this->arrWhere[] = '(' . implode(' OR ', $arrWhereAll) . ')';
} else {
$this->arrWhere[] = '' . $this->search['key'] . ' LIKE concat(\'%\',?,\'%\')';
$this->db->bind_param_push($this->arrBind, 's', $this->search['keyword']);
}
}
 
// 사용 여부 검색
if ($this->search['useFl']) {
$this->arrWhere[] = 'useFl = ?';
$page->setPage();
$page->setUrl(\Request::getQueryString());
 
// 현 페이지 결과
$this->db->strField = '*';
$this->db->strWhere = implode(' AND ', gd_isset($this->arrWhere));
$this->db->strOrder = "defaultFl desc," . $this->search['sort'];
$this->db->strLimit = $page->recode['start'] . ',' . $request['pageNum'];
 
$query = $this->db->query_complete();
$strSQL = 'SELECT ' . array_shift($query) . ' FROM ' . DB_MANAGE_BANK . implode(' ', $query);
$data = $this->db->query_fetch($strSQL, $this->arrBind);
 
 
 
 
// 레코드 수
unset($query['group'], $query['order'], $query['limit']);
$strCntSQL = 'SELECT COUNT(*) AS total FROM ' . DB_MANAGE_BANK . implode(' ', $query);
$page->recode['total'] = $this->db->query_fetch($strCntSQL, $this->arrBind, false)['total'];
//list($page->recode['total']) = $this->db->fetch('SELECT FOUND_ROWS()', 'row');
$page->setPage();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// 각 데이터 배열화
$getData['data'] = gd_htmlspecialchars_stripslashes(gd_isset($data));
throw new Exception(__('예금주은(는) 필수 항목 입니다.'));
}
 
 
 
 
if (empty($arrData['defaultFl']) === true) {
$arrData['defaultFl'] = "n";
}
 
변경 후OrderAdminNew.php
use Framework\Debug\Exception\LayerNotReloadException;
use Framework\Debug\Exception\AlertRedirectException;
use Framework\Debug\Exception\WarningException;
use Framework\Security\ManageBankCryptor;
use Framework\StaticProxy\Proxy\UserFilePath;
use Framework\Utility\ArrayUtils;
use Framework\Utility\DateTimeUtils;
 
$this->checked['useFl'][$this->search['useFl']] = 'checked="checked"';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// 사용 여부 검색
if ($this->search['useFl']) {
$this->arrWhere[] = 'useFl = ?';
$page->setPage();
$page->setUrl(\Request::getQueryString());
 
 
$this->db->strField = '*';
$this->db->strWhere = implode(' AND ', gd_isset($this->arrWhere));
$this->db->strOrder = "defaultFl desc," . $this->search['sort'];
 
 
$keyword = (string) $this->search['keyword'];
if ($keyword !== '') {
// 계좌번호는 암호화 저장되어 SQL 조건 검색이 불가하므로, 전체 목록을 조회·복호화 후 검색 항목(은행명·계좌번호·예금주) 기준으로 필터한다.
$query = $this->db->query_complete();
$strSQL = 'SELECT ' . array_shift($query) . ' FROM ' . DB_MANAGE_BANK . implode(' ', $query);
$data = gd_isset($this->db->query_fetch($strSQL, $this->arrBind), []);
 
foreach ($data as $index => $bankInfo) {
$data[$index]['accountNumber'] = ManageBankCryptor::decrypt($bankInfo['accountNumber']);
}
 
// 검색 항목 기준으로 키워드 부분검색 필터
$data = $this->filterBankListByKeyword($data, $keyword, (string) $this->search['key'], false);
 
$page->recode['total'] = count($data);
$page->setPage();
$data = array_slice($data, $page->recode['start'], (int) $request['pageNum']);
} else {
$this->db->strLimit = $page->recode['start'] . ',' . $request['pageNum'];
 
$query = $this->db->query_complete();
$strSQL = 'SELECT ' . array_shift($query) . ' FROM ' . DB_MANAGE_BANK . implode(' ', $query);
$data = $this->db->query_fetch($strSQL, $this->arrBind);
 
// 계좌번호 복호화
if (!empty($data)) {
foreach ($data as $index => $bankInfo) {
$data[$index]['accountNumber'] = ManageBankCryptor::decrypt($bankInfo['accountNumber']);
}
}
 
// 레코드 수
unset($query['group'], $query['order'], $query['limit']);
$strCntSQL = 'SELECT COUNT(*) AS total FROM ' . DB_MANAGE_BANK . implode(' ', $query);
$page->recode['total'] = $this->db->query_fetch($strCntSQL, $this->arrBind, false)['total'];
$page->setPage();
}
 
// 각 데이터 배열화
$getData['data'] = gd_htmlspecialchars_stripslashes(gd_isset($data));
throw new Exception(__('예금주은(는) 필수 항목 입니다.'));
}
 
// 계좌번호 암호화 저장
$arrData['accountNumber'] = ManageBankCryptor::encrypt($arrData['accountNumber']);
 
if (empty($arrData['defaultFl']) === true) {
$arrData['defaultFl'] = "n";
}
 
Component/Order/OrderAdmin.php+65-39
변경 전OrderAdmin.php
use Framework\Debug\Exception\LayerNotReloadException;
use Framework\Debug\Exception\AlertRedirectException;
use Framework\Debug\Exception\WarningException;
 
use Framework\StaticProxy\Proxy\UserFilePath;
use Framework\Utility\ArrayUtils;
use Framework\Utility\DateTimeUtils;
 
$this->checked['useFl'][$this->search['useFl']] = 'checked="checked"';
 
// 키워드 검색
if ($this->search['keyword']) {
if ($this->search['key'] == '') {
$tmpWhere = [
'bankName',
'accountNumber',
'depositor',
];
$arrWhereAll = [];
foreach ($tmpWhere as $keyNm) {
if ($this->search['searchKind'] == 'equalSearch') {
$arrWhereAll[] = '(' . $keyNm . ' = ? )';
} else {
$arrWhereAll[] = '(' . $keyNm . ' LIKE concat(\'%\',?,\'%\'))';
}
$this->db->bind_param_push($this->arrBind, 's', $this->search['keyword']);
}
$this->arrWhere[] = '(' . implode(' OR ', $arrWhereAll) . ')';
} else {
if ($this->search['searchKind'] == 'equalSearch') {
$this->arrWhere[] = '' . $this->search['key'] . ' = ? ';
} else {
$this->arrWhere[] = '' . $this->search['key'] . ' LIKE concat(\'%\',?,\'%\')';
}
$this->db->bind_param_push($this->arrBind, 's', $this->search['keyword']);
}
}
 
// 사용 여부 검색
if ($this->search['useFl']) {
$this->arrWhere[] = 'useFl = ?';
$page->setPage();
$page->setUrl(\Request::getQueryString());
 
// 현 페이지 결과
$this->db->strField = '*';
$this->db->strWhere = implode(' AND ', gd_isset($this->arrWhere));
$this->db->strOrder = "defaultFl desc," . $this->search['sort'];
$this->db->strLimit = $page->recode['start'] . ',' . $request['pageNum'];
 
$query = $this->db->query_complete();
$strSQL = 'SELECT ' . array_shift($query) . ' FROM ' . DB_MANAGE_BANK . implode(' ', $query);
$data = $this->db->query_fetch($strSQL, $this->arrBind);
 
 
 
 
// 레코드 수
unset($query['group'], $query['order'], $query['limit']);
$strCntSQL = 'SELECT COUNT(*) AS total FROM ' . DB_MANAGE_BANK . implode(' ', $query);
$page->recode['total'] = $this->db->query_fetch($strCntSQL, $this->arrBind, false)['total'];
//list($page->recode['total']) = $this->db->fetch('SELECT FOUND_ROWS()', 'row');
$page->setPage();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// 각 데이터 배열화
$getData['data'] = gd_htmlspecialchars_stripslashes(gd_isset($data));
return $getData;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 주문정책내 무통장 입금은행 등록 / 수정
*
throw new Exception(__('예금주은(는) 필수 항목 입니다.'));
}
 
 
 
 
if (empty($arrData['defaultFl']) === true) {
$arrData['defaultFl'] = "n";
}
 
변경 후OrderAdmin.php
use Framework\Debug\Exception\LayerNotReloadException;
use Framework\Debug\Exception\AlertRedirectException;
use Framework\Debug\Exception\WarningException;
use Framework\Security\ManageBankCryptor;
use Framework\StaticProxy\Proxy\UserFilePath;
use Framework\Utility\ArrayUtils;
use Framework\Utility\DateTimeUtils;
 
$this->checked['useFl'][$this->search['useFl']] = 'checked="checked"';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
// 사용 여부 검색
if ($this->search['useFl']) {
$this->arrWhere[] = 'useFl = ?';
$page->setPage();
$page->setUrl(\Request::getQueryString());
 
 
$this->db->strField = '*';
$this->db->strWhere = implode(' AND ', gd_isset($this->arrWhere));
$this->db->strOrder = "defaultFl desc," . $this->search['sort'];
 
 
$keyword = (string) $this->search['keyword'];
if ($keyword !== '') {
// 계좌번호는 암호화 저장되어 SQL 조건 검색이 불가하므로, 전체 목록을 조회·복호화 후 검색 항목(은행명·계좌번호·예금주) 기준으로 필터한다.
$query = $this->db->query_complete();
$strSQL = 'SELECT ' . array_shift($query) . ' FROM ' . DB_MANAGE_BANK . implode(' ', $query);
$data = gd_isset($this->db->query_fetch($strSQL, $this->arrBind), []);
 
foreach ($data as $index => $bankInfo) {
$data[$index]['accountNumber'] = ManageBankCryptor::decrypt($bankInfo['accountNumber']);
}
 
// 검색 항목 기준으로 키워드 필터
$data = $this->filterBankListByKeyword($data, $keyword, (string) $this->search['key'], $this->search['searchKind'] == 'equalSearch');
 
$page->recode['total'] = count($data);
$page->setPage();
$data = array_slice($data, $page->recode['start'], (int) $request['pageNum']);
} else {
$this->db->strLimit = $page->recode['start'] . ',' . $request['pageNum'];
 
$query = $this->db->query_complete();
$strSQL = 'SELECT ' . array_shift($query) . ' FROM ' . DB_MANAGE_BANK . implode(' ', $query);
$data = $this->db->query_fetch($strSQL, $this->arrBind);
 
// 계좌번호 복호화
if (!empty($data)) {
foreach ($data as $index => $bankInfo) {
$data[$index]['accountNumber'] = ManageBankCryptor::decrypt($bankInfo['accountNumber']);
}
}
 
// 레코드 수
unset($query['group'], $query['order'], $query['limit']);
$strCntSQL = 'SELECT COUNT(*) AS total FROM ' . DB_MANAGE_BANK . implode(' ', $query);
$page->recode['total'] = $this->db->query_fetch($strCntSQL, $this->arrBind, false)['total'];
$page->setPage();
}
 
// 각 데이터 배열화
$getData['data'] = gd_htmlspecialchars_stripslashes(gd_isset($data));
return $getData;
}
 
/**
* 무통장 입금은행 목록을 검색어(은행명·계좌번호·예금주) 기준으로 필터링
*
* @param array $data 복호화 완료된 은행 목록
* @param string $keyword 검색어
* @param string $key 검색 항목 (빈 값이면 통합검색: 은행명·계좌번호·예금주)
* @param bool $isEqual 완전일치 여부 (false 면 부분검색)
*
* @return array 필터링된 목록 (인덱스 재정렬)
*/
protected function filterBankListByKeyword(array $data, string $keyword, string $key, bool $isEqual): array
{
$fields = $key === '' ? ['bankName', 'accountNumber', 'depositor'] : [$key];
 
return array_values(array_filter($data, function ($row) use ($fields, $keyword, $isEqual) {
foreach ($fields as $field) {
$target = (string) $row[$field];
if ($isEqual ? $target === $keyword : mb_strpos($target, $keyword) !== false) {
return true;
}
}
return false;
}));
}
 
/**
* 주문정책내 무통장 입금은행 등록 / 수정
*
throw new Exception(__('예금주은(는) 필수 항목 입니다.'));
}
 
// 계좌번호 암호화 저장
$arrData['accountNumber'] = ManageBankCryptor::encrypt($arrData['accountNumber']);
 
if (empty($arrData['defaultFl']) === true) {
$arrData['defaultFl'] = "n";
}
 
Component/Order/OrderNew.php+19
변경 전OrderNew.php
use Framework\Helper\MallHelper;
use Framework\SimpleCache\SimpleCache;
use Framework\SimpleCache\SimpleCacheException;
 
use Framework\Utility\ArrayUtils;
use Framework\Utility\ComponentUtils;
use Framework\Utility\KafkaUtils;
if (empty($data) === true) {
return false;
} else {
 
 
 
 
 
return gd_htmlspecialchars_stripslashes($data);
}
}
$strSQL = 'SELECT sno, ' . implode(', ', DBTableField::setTableField('tableManageBank')) . ' FROM ' . DB_MANAGE_BANK . ' WHERE ' . implode(' AND ', $arrWhere);
$data = $this->db->query_fetch($strSQL, $arrBind, $boolFetch);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
return gd_htmlspecialchars_stripslashes($data);
}
 
 
변경 후OrderNew.php
use Framework\Helper\MallHelper;
use Framework\SimpleCache\SimpleCache;
use Framework\SimpleCache\SimpleCacheException;
use Framework\Security\ManageBankCryptor;
use Framework\Utility\ArrayUtils;
use Framework\Utility\ComponentUtils;
use Framework\Utility\KafkaUtils;
if (empty($data) === true) {
return false;
} else {
// 계좌번호 복호화
foreach ($data as $index => $bankInfo) {
$data[$index]['accountNumber'] = ManageBankCryptor::decrypt($bankInfo['accountNumber']);
}
 
return gd_htmlspecialchars_stripslashes($data);
}
}
$strSQL = 'SELECT sno, ' . implode(', ', DBTableField::setTableField('tableManageBank')) . ' FROM ' . DB_MANAGE_BANK . ' WHERE ' . implode(' AND ', $arrWhere);
$data = $this->db->query_fetch($strSQL, $arrBind, $boolFetch);
 
// 계좌번호 복호화
if ($boolFetch) {
if (!empty($data)) {
foreach ($data as $index => $bankInfo) {
$data[$index]['accountNumber'] = ManageBankCryptor::decrypt($bankInfo['accountNumber']);
}
}
} else {
if (!empty($data['accountNumber'])) {
$data['accountNumber'] = ManageBankCryptor::decrypt($data['accountNumber']);
}
}
 
return gd_htmlspecialchars_stripslashes($data);
}
 
 
Component/Order/Order.php+19
변경 전Order.php
use Framework\Debug\Exception\AlertOnlyException;
use Framework\Debug\Exception\AlertRedirectException;
use Framework\Helper\MallHelper;
 
use Framework\Utility\ArrayUtils;
use Framework\Utility\ComponentUtils;
use Framework\Utility\NumberUtils;
if (empty($data) === true) {
return false;
} else {
 
 
 
 
 
return gd_htmlspecialchars_stripslashes($data);
}
}
$strSQL = 'SELECT sno, ' . implode(', ', DBTableField::setTableField('tableManageBank')) . ' FROM ' . DB_MANAGE_BANK . ' WHERE ' . implode(' AND ', $arrWhere);
$data = $this->db->secondary()->query_fetch($strSQL, $arrBind, $boolFetch);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
return gd_htmlspecialchars_stripslashes($data);
}
 
 
변경 후Order.php
use Framework\Debug\Exception\AlertOnlyException;
use Framework\Debug\Exception\AlertRedirectException;
use Framework\Helper\MallHelper;
use Framework\Security\ManageBankCryptor;
use Framework\Utility\ArrayUtils;
use Framework\Utility\ComponentUtils;
use Framework\Utility\NumberUtils;
if (empty($data) === true) {
return false;
} else {
// 계좌번호 복호화
foreach ($data as $index => $bankInfo) {
$data[$index]['accountNumber'] = ManageBankCryptor::decrypt($bankInfo['accountNumber']);
}
 
return gd_htmlspecialchars_stripslashes($data);
}
}
$strSQL = 'SELECT sno, ' . implode(', ', DBTableField::setTableField('tableManageBank')) . ' FROM ' . DB_MANAGE_BANK . ' WHERE ' . implode(' AND ', $arrWhere);
$data = $this->db->secondary()->query_fetch($strSQL, $arrBind, $boolFetch);
 
// 계좌번호 복호화
if ($boolFetch) {
if (!empty($data)) {
foreach ($data as $index => $bankInfo) {
$data[$index]['accountNumber'] = ManageBankCryptor::decrypt($bankInfo['accountNumber']);
}
}
} else {
if (!empty($data['accountNumber'])) {
$data['accountNumber'] = ManageBankCryptor::decrypt($data['accountNumber']);
}
}
 
return gd_htmlspecialchars_stripslashes($data);
}
 
 
무료보안 관리자 화면 안정성 개선
Component/SiteLink/SecureSocketLayer.php+6-4
변경 전SecureSocketLayer.php
$checkData = $this->getSsl($searchArr);
if (count($checkData) > 0) {
$returnData['status'] = 'usePay';
} else if ($this->getFreeSslUse()) {
$returnData['status'] = 'used';
} else {
$returnData['status'] = 'process';
$isValidPeriod = ($sDateCheck >= 0 && $eDateCheck >= 0); // 설치완료
if ($isExpired) {
$returnData['status'] = 'request';
} else if ($isRenewRange) {
if (in_array($sslData['sslConfigStatus'], ['wait', 'process']) === true) {
$returnData['status'] = $sslData['sslConfigStatus'];
} else if ($sslData['sslConfigType'] == 'godo') {
$returnData['status'] = 'renewrequest';
 
 
}
} else if ($isValidPeriod) {
$returnData['status'] = 'used';
} else {
$returnData['status'] = $sslData['sslConfigStatus'];
 
변경 후SecureSocketLayer.php
$checkData = $this->getSsl($searchArr);
if (count($checkData) > 0) {
$returnData['status'] = 'usePay';
} elseif ($this->getFreeSslUse()) {
$returnData['status'] = 'used';
} else {
$returnData['status'] = 'process';
$isValidPeriod = ($sDateCheck >= 0 && $eDateCheck >= 0); // 설치완료
if ($isExpired) {
$returnData['status'] = 'request';
} elseif ($isRenewRange) {
if (in_array($sslData['sslConfigStatus'], ['wait', 'process']) === true) {
$returnData['status'] = $sslData['sslConfigStatus'];
} elseif ($sslData['sslConfigType'] == 'godo') {
$returnData['status'] = 'renewrequest';
} elseif ($sslData['sslConfigType'] === 'free_multi') {
$returnData['status'] = 'used';
}
} elseif ($isValidPeriod) {
$returnData['status'] = 'used';
} else {
$returnData['status'] = $sslData['sslConfigStatus'];
 
해외 상점 도메인 정보 표시 개선.
Admin/policy/base_seo.php+1-1
변경 전base_seo.php
<tr>
<th>모바일 쇼핑몰</th>
<td class="form-inline">
<?php echo URI_MOBILE;?><input type="text" name="errPage[mobile]" value="<?php echo $data['errPage']['mobile']; ?>" class="form-control width-lg"/>
</td>
</tr>
</table>
 
변경 후base_seo.php
<tr>
<th>모바일 쇼핑몰</th>
<td class="form-inline">
<?=$data['mallMobileDomain'] ?? URI_MOBILE?><input type="text" name="errPage[mobile]" value="<?php echo $data['errPage']['mobile']; ?>" class="form-control width-lg"/>
</td>
</tr>
</table>
 
Component/Mall/Mall.php-1
변경 전Mall.php
const GLOBAL_MALL_BASE_INFO = [
'mallNmEng',
'mallFavicon',
'mallDomain',
'mallCategory',
'businessNo',
'service',
 
변경 후Mall.php
const GLOBAL_MALL_BASE_INFO = [
'mallNmEng',
'mallFavicon',
 
'mallCategory',
'businessNo',
'service',
 
Controller/Admin/Policy/BaseInfoController.php+9
변경 전BaseInfoController.php
if (in_array($key, Mall::GLOBAL_MALL_BASE_INFO) === true) $data[$key] = $value;
}
 
 
 
 
 
 
 
 
 
 
$this->setData('disabled', self::ELEMENT_DISABLED);
$this->setData('readonly', self::ELEMENT_READONLY);
}
 
변경 후BaseInfoController.php
if (in_array($key, Mall::GLOBAL_MALL_BASE_INFO) === true) $data[$key] = $value;
}
 
//설정한 shopDomain 있으면 덮어쓰기
if (!empty($globalsInfo[$mallSno]['connectDomain'])) {
$globalShopDomains = json_decode($globalsInfo[$mallSno]['connectDomain'], true);
$domainIndex = $globalsInfo[$mallSno]['useShopDomain'] ?? null;
if (isset($globalShopDomains['connect'][$domainIndex])) {
$data['mallDomain'] = $globalShopDomains['connect'][$domainIndex];
}
}
 
$this->setData('disabled', self::ELEMENT_DISABLED);
$this->setData('readonly', self::ELEMENT_READONLY);
}
 
Controller/Admin/Policy/BaseSeoController.php+10
변경 전BaseSeoController.php
$socialData = $socialShare->getConfig();
gd_isset($socialData['snsRepresentTitle'],'{=gMall.mallNm}');
 
 
 
 
 
 
 
 
 
 
//RSS 설정 ,페이지 경로 설정 , 대표URL 설정 , 연관채널 설정
$seoData = gd_policy('basic.seo', $mallSno);
 
변경 후BaseSeoController.php
$socialData = $socialShare->getConfig();
gd_isset($socialData['snsRepresentTitle'],'{=gMall.mallNm}');
//설정한 shopDomain 있으면 덮어쓰기
$globalsInfo = \Globals::get('gGlobal.mallList');
if (!empty($globalsInfo[$mallSno]['connectDomain'])) {
$globalShopDomains = json_decode($globalsInfo[$mallSno]['connectDomain'], true);
$domainIndex = $globalsInfo[$mallSno]['useShopDomain'] ?? null;
if (isset($globalShopDomains['connect'][$domainIndex])) {
$data['mallDomain'] = $globalShopDomains['connect'][$domainIndex];
$data['mallMobileDomain'] = \Request::getDomainUrl(DOMAIN_USEABLE_LIST['mobile'] . '.' . $globalShopDomains['connect'][$domainIndex]) . DS;
}
}
//RSS 설정 ,페이지 경로 설정 , 대표URL 설정 , 연관채널 설정
$seoData = gd_policy('basic.seo', $mallSno);
 
본인인증(아이핀) 페이지 보안 강화
Controller/Front/Member/Ipin/IpinApplyController.php+3-1
변경 전IpinApplyController.php
// 사용자 정보를 복호화 합니다.
// 실행방법은 싱글쿼터(`) 외에도, 'exec(), system(), shell_exec()' 등등 귀사 정책에 맞게 처리하시기 바랍니다.
$sDecData = exec("$sModulePath $sType $sSiteCode $sSitePw $sEncData");
 
 
Logger::info(__METHOD__ . '$sDecData=>' . $sDecData . ', ' . "$sModulePath $sType $sSiteCode $sSitePw $sEncData");
if ($sDecData == -9) {
 
변경 후IpinApplyController.php
// 사용자 정보를 복호화 합니다.
// 실행방법은 싱글쿼터(`) 외에도, 'exec(), system(), shell_exec()' 등등 귀사 정책에 맞게 처리하시기 바랍니다.
$sDecData = exec(
implode(' ', array_map('escapeshellarg', [$sModulePath, $sType, $sSiteCode, $sSitePw, $sEncData]))
);
Logger::info(__METHOD__ . '$sDecData=>' . $sDecData . ', ' . "$sModulePath $sType $sSiteCode $sSitePw $sEncData");
if ($sDecData == -9) {
 
Controller/Front/Member/Ipin/IpinResultController.php+3-1
변경 전IpinResultController.php
if ($sEncData != "") {
// 사용자 정보를 복호화 합니다.
// 실행방법은 싱글쿼터(`) 외에도, 'exec(), system(), shell_exec()' 등등 귀사 정책에 맞게 처리하시기 바랍니다.
$sDecData = exec("$sModulePath $sType $sSiteCode $sSitePw $sEncData");
 
 
Logger::info('sDecData=>' . $sDecData . ', ' . "$sModulePath $sType $sSiteCode $sSitePw $sEncData");
 
if ($sDecData == -9) {
 
변경 후IpinResultController.php
if ($sEncData != "") {
// 사용자 정보를 복호화 합니다.
// 실행방법은 싱글쿼터(`) 외에도, 'exec(), system(), shell_exec()' 등등 귀사 정책에 맞게 처리하시기 바랍니다.
$sDecData = exec(
implode(' ', array_map('escapeshellarg', [$sModulePath, $sType, $sSiteCode, $sSitePw, $sEncData]))
);
Logger::info('sDecData=>' . $sDecData . ', ' . "$sModulePath $sType $sSiteCode $sSitePw $sEncData");
 
if ($sDecData == -9) {
 
Controller/Mobile/Member/Ipin/IpinApplyController.php+3-1
변경 전IpinApplyController.php
// 사용자 정보를 복호화 합니다.
// 실행방법은 싱글쿼터(`) 외에도, 'exec(), system(), shell_exec()' 등등 귀사 정책에 맞게 처리하시기 바랍니다.
$sDecData = exec("$sModulePath $sType $sSiteCode $sSitePw $sEncData");
 
 
Logger::info(__METHOD__ . '$sDecData=>' . $sDecData . ', ' . "$sModulePath $sType $sSiteCode $sSitePw $sEncData");
if ($sDecData == -9) {
 
변경 후IpinApplyController.php
// 사용자 정보를 복호화 합니다.
// 실행방법은 싱글쿼터(`) 외에도, 'exec(), system(), shell_exec()' 등등 귀사 정책에 맞게 처리하시기 바랍니다.
$sDecData = exec(
implode(' ', array_map('escapeshellarg', [$sModulePath, $sType, $sSiteCode, $sSitePw, $sEncData]))
);
Logger::info(__METHOD__ . '$sDecData=>' . $sDecData . ', ' . "$sModulePath $sType $sSiteCode $sSitePw $sEncData");
if ($sDecData == -9) {
 
본인인증(아이핀) 페이지 보안 강화
Controller/Front/Member/Ipin/IpinMainController.php+8-2
변경 전IpinMainController.php
// 앞서 설명드린 바와같이, CP 요청번호는 배포된 모듈을 통해 아래와 같이 생성할 수 있습니다.
// 실행방법은 싱글쿼터(`) 외에도, 'exec(), system(), shell_exec()' 등등 귀사 정책에 맞게 처리하시기 바랍니다.
$sCPRequest = exec("$sModulePath $sType $sSiteCode", $output, $error);
 
 
 
 
if ($error !== 0) {
Logger::error(__METHOD__ . ' $sCPRequest=>' . $sCPRequest . ', ' . "$sModulePath $sType $sSiteCode", $output);
}
// 리턴 결과값에 따라, 프로세스 진행여부를 파악합니다.
// 실행방법은 싱글쿼터(`) 외에도, 'exec(), system(), shell_exec()' 등등 귀사 정책에 맞게 처리하시기 바랍니다.
$sEncData = exec("$sModulePath $sType $sSiteCode $sSitePw $sCPRequest $sReturnURL");
 
 
Logger::info(__METHOD__ . ' $sEncData=>' . $sEncData . ', ' . "$sModulePath $sType $sSiteCode $sSitePw $sCPRequest $sReturnURL");
// 리턴 결과값에 따른 처리사항
 
변경 후IpinMainController.php
// 앞서 설명드린 바와같이, CP 요청번호는 배포된 모듈을 통해 아래와 같이 생성할 수 있습니다.
// 실행방법은 싱글쿼터(`) 외에도, 'exec(), system(), shell_exec()' 등등 귀사 정책에 맞게 처리하시기 바랍니다.
$sCPRequest = exec(
implode(' ', array_map('escapeshellarg', [$sModulePath, $sType, $sSiteCode])),
$output,
$error
);
if ($error !== 0) {
Logger::error(__METHOD__ . ' $sCPRequest=>' . $sCPRequest . ', ' . "$sModulePath $sType $sSiteCode", $output);
}
// 리턴 결과값에 따라, 프로세스 진행여부를 파악합니다.
// 실행방법은 싱글쿼터(`) 외에도, 'exec(), system(), shell_exec()' 등등 귀사 정책에 맞게 처리하시기 바랍니다.
$sEncData = exec(
implode(' ', array_map('escapeshellarg', [$sModulePath, $sType, $sSiteCode, $sSitePw, $sCPRequest, $sReturnURL]))
);
Logger::info(__METHOD__ . ' $sEncData=>' . $sEncData . ', ' . "$sModulePath $sType $sSiteCode $sSitePw $sCPRequest $sReturnURL");
// 리턴 결과값에 따른 처리사항
 
상품 수정 시 이미지 보존 처리 개선
Admin/goods/goods_register_option_stock.php+1
변경 전goods_register_option_stock.php
 
$imageInput = '<input type="hidden" name="imageDB[sno][]" value="' . $iVal['sno'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageSize][]" value="' . $iVal['imageSize'] . '" /> ';
 
$imageInput .= '<input type="hidden" name="imageDB[imageNo][]" value="' . $iVal['imageNo'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageKind][]" value="' . $iVal['imageKind'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageName][]" value="' . $iVal['imageName'] . '" /> ';
 
변경 후goods_register_option_stock.php
 
$imageInput = '<input type="hidden" name="imageDB[sno][]" value="' . $iVal['sno'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageSize][]" value="' . $iVal['imageSize'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageHeightSize][]" value="' . $iVal['imageHeightSize'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageNo][]" value="' . $iVal['imageNo'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageKind][]" value="' . $iVal['imageKind'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageName][]" value="' . $iVal['imageName'] . '" /> ';
 
Admin/goods/goods_register.php+1
변경 전goods_register.php
 
$imageInput = '<input type="hidden" name="imageDB[sno][]" value="' . $iVal['sno'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageSize][]" value="' . $iVal['imageSize'] . '" /> ';
 
$imageInput .= '<input type="hidden" name="imageDB[imageNo][]" value="' . $iVal['imageNo'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageKind][]" value="' . $iVal['imageKind'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageName][]" value="' . $iVal['imageName'] . '" /> ';
 
변경 후goods_register.php
 
$imageInput = '<input type="hidden" name="imageDB[sno][]" value="' . $iVal['sno'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageSize][]" value="' . $iVal['imageSize'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageHeightSize][]" value="' . $iVal['imageHeightSize'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageNo][]" value="' . $iVal['imageNo'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageKind][]" value="' . $iVal['imageKind'] . '" /> ';
$imageInput .= '<input type="hidden" name="imageDB[imageName][]" value="' . $iVal['imageName'] . '" /> ';
 
상품 검색 보안 강화.
Component/Goods/Goods.php+14
변경 전Goods.php
$this->search['reSearchKey'] = gd_isset(array_values($getValue['reSearchKey']));
$this->search['reSearch'] = gd_isset($getValue['reSearch']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$this->search['cateGoods'] = ArrayUtils::last(gd_isset($getValue['cateGoods']));
$this->search['brand'] = gd_isset($getValue['brand']);
$this->search['quickBrandGoods'] = gd_isset($getValue['quickBrandGoods']);
 
변경 후Goods.php
$this->search['reSearchKey'] = gd_isset(array_values($getValue['reSearchKey']));
$this->search['reSearch'] = gd_isset($getValue['reSearch']);
 
// 검색 필드키 화이트리스트 검증 (SQL 식별자 인젝션 방어 - 허용된 검색키만 컬럼명으로 결합)
$allowedSearchKey = array_merge(array_keys($this->search['combineSearch']), ['brandNm']);
if ($this->search['key'] && !in_array($this->search['key'], $allowedSearchKey, true)) {
$this->search['key'] = 'all';
}
if (is_array($this->search['reSearchKey'])) {
foreach ($this->search['reSearchKey'] as $reSearchKeyIdx => $reSearchKeyVal) {
if (!in_array($reSearchKeyVal, $allowedSearchKey, true)) {
unset($this->search['reSearchKey'][$reSearchKeyIdx]);
unset($this->search['reSearchKeyword'][$reSearchKeyIdx]);
}
}
}
 
$this->search['cateGoods'] = ArrayUtils::last(gd_isset($getValue['cateGoods']));
$this->search['brand'] = gd_isset($getValue['brand']);
$this->search['quickBrandGoods'] = gd_isset($getValue['quickBrandGoods']);
 
사업자 회원 비활성화 시 회원정보 수정 프로세스 개선
Component/Member/MyPage.php+1-1
변경 전MyPage.php
}
 
// 사업자번호 중복여부 체크
if ($requestParams['memberFl'] == 'business' && ($require['busiNo'] || !empty($requestParams['busiNo']))) {
$newBusiNo = gd_remove_special_char($requestParams['busiNo']);
$memberData = \Component\Member\MyPage::myInformation();
$oldBusiNo = $memberData['busiNo'];
 
변경 후MyPage.php
}
 
// 사업자번호 중복여부 체크
if (!empty($joinItemPolicy['businessinfo']) && $requestParams['memberFl'] == 'business' && ($require['busiNo'] || !empty($requestParams['busiNo']))) {
$newBusiNo = gd_remove_special_char($requestParams['busiNo']);
$memberData = \Component\Member\MyPage::myInformation();
$oldBusiNo = $memberData['busiNo'];
 
Controller/Front/Mypage/MyPagePsController.php+2-1
변경 전MyPagePsController.php
$requestParams = array_merge($request->post()->xss()->all(), $request->files()->toArray());
 
// CSRF 토큰 체크
if (!Token::check('myPageToken', $requestParams)) {
 
throw new Exception(__('잘못된 경로로 접근하셨습니다.'));
}
 
 
변경 후MyPagePsController.php
$requestParams = array_merge($request->post()->xss()->all(), $request->files()->toArray());
 
// CSRF 토큰 체크
// 숨김 iframe 으로 제출되어 검증 실패 시 폼이 다시 그려지지 않으므로, 토큰을 소거하지 않고 재제출을 허용한다.
if (!Token::check('myPageToken', $requestParams, false, null, true)) {
throw new Exception(__('잘못된 경로로 접근하셨습니다.'));
}
 
 
data/skin/front/moment/js/gd_member2.js+2
변경 전gd_member2.js
var $button = $(parent.document.getElementsByClassName('js_btn_join')[0]);
$button.html('<em>' + $button.val() + '</em>');
$button.data('action', '');
 
 
});
$this.data('action', 'click');
$this.html('<em>' + __('진행 중') + '</em>');
 
변경 후gd_member2.js
var $button = $(parent.document.getElementsByClassName('js_btn_join')[0]);
$button.html('<em>' + $button.val() + '</em>');
$button.data('action', '');
// validation_submit 에서 잠근 버튼을 함께 풀어야 검증 실패 후 재제출이 가능하다
$button.prop('disabled', false);
});
$this.data('action', 'click');
$this.html('<em>' + __('진행 중') + '</em>');
 
data/skin/front/mygreek/js/gd_member2.js+2
변경 전gd_member2.js
var $button = $(parent.document.getElementsByClassName('js_btn_join')[0]);
$button.html('<em>' + $button.val() + '</em>');
$button.data('action', '');
 
 
});
$this.data('action', 'click');
$this.html('<em>' + __('진행 중') + '</em>');
 
변경 후gd_member2.js
var $button = $(parent.document.getElementsByClassName('js_btn_join')[0]);
$button.html('<em>' + $button.val() + '</em>');
$button.data('action', '');
// validation_submit 에서 잠근 버튼을 함께 풀어야 검증 실패 후 재제출이 가능하다
$button.prop('disabled', false);
});
$this.data('action', 'click');
$this.html('<em>' + __('진행 중') + '</em>');
 
data/skin/front/story_g/js/gd_member2.js+2
변경 전gd_member2.js
var $button = $(parent.document.getElementsByClassName('btn-join')[0]);
$button.html('<em>' + $button.val() + '</em>');
$button.data('action', '');
 
 
});
$this.data('action', 'click');
$this.html('<em>' + __('진행 중') + '</em>');
 
변경 후gd_member2.js
var $button = $(parent.document.getElementsByClassName('btn-join')[0]);
$button.html('<em>' + $button.val() + '</em>');
$button.data('action', '');
// validation_submit 에서 잠근 버튼을 함께 풀어야 검증 실패 후 재제출이 가능하다
$button.prop('disabled', false);
});
$this.data('action', 'click');
$this.html('<em>' + __('진행 중') + '</em>');
 
data/skin/mobile/moment/js/gd_member2.js+2
변경 전gd_member2.js
var $button = $(parent.document.getElementsByClassName('join_ok_btn')[0]);
$button.html('<em>' + $button.val() + '</em>');
$button.data('action', '');
 
 
});
$this.data('action', 'click');
$this.html('<em>' + __('진행 중') + '</em>');
 
변경 후gd_member2.js
var $button = $(parent.document.getElementsByClassName('join_ok_btn')[0]);
$button.html('<em>' + $button.val() + '</em>');
$button.data('action', '');
// validation_submit 에서 잠근 버튼을 함께 풀어야 검증 실패 후 재제출이 가능하다
$button.prop('disabled', false);
});
$this.data('action', 'click');
$this.html('<em>' + __('진행 중') + '</em>');
 
data/skin/mobile/mygreek/js/gd_member2.js+2
변경 전gd_member2.js
var $button = $(parent.document.getElementsByClassName('join_ok_btn')[0]);
$button.html('<em>' + $button.val() + '</em>');
$button.data('action', '');
 
 
});
$this.data('action', 'click');
$this.html('<em>' + __('진행 중') + '</em>');
 
변경 후gd_member2.js
var $button = $(parent.document.getElementsByClassName('join_ok_btn')[0]);
$button.html('<em>' + $button.val() + '</em>');
$button.data('action', '');
// validation_submit 에서 잠근 버튼을 함께 풀어야 검증 실패 후 재제출이 가능하다
$button.prop('disabled', false);
});
$this.data('action', 'click');
$this.html('<em>' + __('진행 중') + '</em>');
 
data/skin/mobile/story_g/js/gd_member2.js+2
변경 전gd_member2.js
var $button = $(parent.document.getElementsByClassName('btn-join')[0]);
$button.html('<em>' + $button.val() + '</em>');
$button.data('action', '');
 
 
});
$this.data('action', 'click');
$this.html('<em>' + __('진행 중') + '</em>');
 
변경 후gd_member2.js
var $button = $(parent.document.getElementsByClassName('btn-join')[0]);
$button.html('<em>' + $button.val() + '</em>');
$button.data('action', '');
// validation_submit 에서 잠근 버튼을 함께 풀어야 검증 실패 후 재제출이 가능하다
$button.prop('disabled', false);
});
$this.data('action', 'click');
$this.html('<em>' + __('진행 중') + '</em>');
 
구매평 연동 플러스리뷰 설정 안정성 개선
Component/Policy/Policy.php-4
변경 전Policy.php
 
// 사용기간 체크
foreach ($plusShopData as $key => $val) {
if (date('Ymd') > $val['appExpireData']) {
$plusShopData[$key]['appUseFl'] = 'n';
}
 
if (!$val['appInstallFl']) {
$plusShopData[$key]['appInstallFl'] = 'y';
}
 
변경 후Policy.php
 
// 사용기간 체크
foreach ($plusShopData as $key => $val) {
 
 
 
 
if (!$val['appInstallFl']) {
$plusShopData[$key]['appInstallFl'] = 'y';
}
 
카카오 간편 로그인 설정 안정성 개선
Admin/member/kakao_login_config.php+2-1
변경 전kakao_login_config.php
* @var array $checked 카카오 로그인 설정 여부 'checked="checked"'
* @var array $data KakaoLoginPolicy 설정 정보
* @var bool $installedKakaoSync 카카오 싱크 앱 설치 여부
 
* @var bool $useKakaoSync 카카오 싱크 사용 여부
* @var bool $useKakaoLogin 카카오 로그인 사용 여부
* @var bool $isAvailableOnlyKakaoSync 카카오 싱크 배포일 이후 상점 true, 이전 상점 false
?>
<link type="text/css" href="<?= PATH_ADMIN_GD_SHARE ?>script/slider/slick/slick.css" rel="stylesheet"/>
<script type="text/javascript" src="<?= PATH_ADMIN_GD_SHARE ?>script/slider/slick/slick.js"></script>
<?php if ($installedKakaoSync && $isAvailableOnlyKakaoSync === false) : ?>
<div class="page-header js-affix">
<h3><?php echo end($naviMenu->location); ?></h3>
</div>
 
변경 후kakao_login_config.php
* @var array $checked 카카오 로그인 설정 여부 'checked="checked"'
* @var array $data KakaoLoginPolicy 설정 정보
* @var bool $installedKakaoSync 카카오 싱크 앱 설치 여부
* @var bool $installedKakaoLogin 카카오 로그인 설치 여부
* @var bool $useKakaoSync 카카오 싱크 사용 여부
* @var bool $useKakaoLogin 카카오 로그인 사용 여부
* @var bool $isAvailableOnlyKakaoSync 카카오 싱크 배포일 이후 상점 true, 이전 상점 false
?>
<link type="text/css" href="<?= PATH_ADMIN_GD_SHARE ?>script/slider/slick/slick.css" rel="stylesheet"/>
<script type="text/javascript" src="<?= PATH_ADMIN_GD_SHARE ?>script/slider/slick/slick.js"></script>
<?php if ($installedKakaoSync || !$installedKakaoLogin) : ?>
<div class="page-header js-affix">
<h3><?php echo end($naviMenu->location); ?></h3>
</div>
 
Controller/Admin/Member/KakaoLoginConfigController.php+4
변경 전KakaoLoginConfigController.php
$kakaoLoginPolicy = \App::getInstance(KakaoLoginPolicy::class);
$policy = $kakaoLoginPolicy->getPolicy();
 
 
 
 
gd_isset($policy['useFl'], 'n');
gd_isset($policy['simpleLoginFl'], 'y');
gd_isset($policy['baseInfo'], 'y');
$this->setData('checked', $checked);
$this->setData('data', $policy);
$this->setData('installedKakaoSync', $kakaoLoginPolicy->installedKakaoSync());
 
$this->setData('useKakaoSync', $kakaoLoginPolicy->useKakaoSync());
$this->setData('useKakaoLogin', $kakaoLoginPolicy->useKakaoLogin());
$this->setData('isAvailableOnlyKakaoSync', $isAvailableOnlyKakaoSync);
 
변경 후KakaoLoginConfigController.php
$kakaoLoginPolicy = \App::getInstance(KakaoLoginPolicy::class);
$policy = $kakaoLoginPolicy->getPolicy();
 
//카카오싱크 미설치 상태에서 Policy가 비어있지 않으면, 카카오 로그인 세팅된 것으로 간주
$isInstalledKakaoLogin = !$kakaoLoginPolicy->installedKakaoSync() && !empty($policy);
 
gd_isset($policy['useFl'], 'n');
gd_isset($policy['simpleLoginFl'], 'y');
gd_isset($policy['baseInfo'], 'y');
$this->setData('checked', $checked);
$this->setData('data', $policy);
$this->setData('installedKakaoSync', $kakaoLoginPolicy->installedKakaoSync());
$this->setData('installedKakaoLogin', $isInstalledKakaoLogin);
$this->setData('useKakaoSync', $kakaoLoginPolicy->useKakaoSync());
$this->setData('useKakaoLogin', $kakaoLoginPolicy->useKakaoLogin());
$this->setData('isAvailableOnlyKakaoSync', $isAvailableOnlyKakaoSync);
 
메타 전환 이벤트 중복집계 개선
Controller/Front/Order/OrderEndController.php+4-2
변경 전OrderEndController.php
use Bundle\Service\Order\OrderEndService;
use Component\CartRemind\CartRemind;
use Framework\Debug\Exception\AlertRedirectException;
 
use Component\Mall\Mall;
use Message;
use Globals;
}
}
 
//facebook Dynamic Ads 외부 스크립트 적용
$facebookAd = \App::Load('\\Component\\Marketing\\FacebookAd');
$currency = gd_isset(Mall::getSession('currencyConfig')['code'], 'KRW');
$fbConfig = $facebookAd->getConfig();
$fbConfigExtension = $facebookAd->getExtensionConfig();
if(($fbConfig['fbUseFl'] == 'y' && $fbConfig['orderEndScriptFl'] == 'y') || $fbConfigExtension['fbUseFl'] == 'y') {
$goodsInfo = $order->getOrderGoodsData($orderInfo['orderNo']);
// 상품번호 추출
$goodsNo = [];
$goodsNo[] = $val2['goodsNo'];
}
}
 
$fbScript = $facebookAd->getFbOrderEndScript($goodsNo, $orderInfo['settlePrice'], $currency);
$this->setData('fbOrderEndScript', $fbScript['script']);
 
 
변경 후OrderEndController.php
use Bundle\Service\Order\OrderEndService;
use Component\CartRemind\CartRemind;
use Framework\Debug\Exception\AlertRedirectException;
use Origin\Enum\Order\OrderStatusGroup;
use Component\Mall\Mall;
use Message;
use Globals;
}
}
 
//facebook Dynamic Ads 외부 스크립트 적용(결제가 정상적으로 이루어지지 않은경우 제외 출력)
$facebookAd = \App::Load('\\Component\\Marketing\\FacebookAd');
$currency = gd_isset(Mall::getSession('currencyConfig')['code'], 'KRW');
$fbConfig = $facebookAd->getConfig();
$fbConfigExtension = $facebookAd->getExtensionConfig();
if($orderInfo['orderStatus'] != OrderStatusGroup::FAIL && (($fbConfig['fbUseFl'] == 'y' && $fbConfig['orderEndScriptFl'] == 'y') || $fbConfigExtension['fbUseFl'] == 'y')) {
$goodsInfo = $order->getOrderGoodsData($orderInfo['orderNo']);
// 상품번호 추출
$goodsNo = [];
$goodsNo[] = $val2['goodsNo'];
}
}
$facebookAd->orderNo = $orderInfo['orderNo'];
$fbScript = $facebookAd->getFbOrderEndScript($goodsNo, $orderInfo['settlePrice'], $currency);
$this->setData('fbOrderEndScript', $fbScript['script']);
 
 
Controller/Mobile/Order/OrderEndController.php+4-2
변경 전OrderEndController.php
use Component\Mall\Mall;
use DateTime;
use Framework\Debug\Exception\AlertRedirectException;
 
use Message;
use Globals;
use Session;
}
}
 
//facebook Dynamic Ads 외부 스크립트 적용
$facebookAd = \App::Load('\\Component\\Marketing\\FacebookAd');
$currency = gd_isset(Mall::getSession('currencyConfig')['code'], 'KRW');
$fbConfig = $facebookAd->getConfig();
$fbConfigExtension = $facebookAd->getExtensionConfig();
$goodsInfo = $order->getOrderGoodsData($orderInfo['orderNo']);
if(($fbConfig['fbUseFl'] == 'y' && $fbConfig['orderEndScriptFl'] == 'y') || $fbConfigExtension['fbUseFl'] == 'y') {
// 상품번호 추출
$goodsNo = [];
foreach ($goodsInfo as $key => $val){
$goodsNo[] = $val2['goodsNo'];
}
}
 
$fbScript = $facebookAd->getFbOrderEndScript($goodsNo, $orderInfo['settlePrice'], $currency);
$this->setData('fbOrderEndScript', $fbScript['script']);
 
 
변경 후OrderEndController.php
use Component\Mall\Mall;
use DateTime;
use Framework\Debug\Exception\AlertRedirectException;
use Origin\Enum\Order\OrderStatusGroup;
use Message;
use Globals;
use Session;
}
}
 
//facebook Dynamic Ads 외부 스크립트 적용(결제가 정상적으로 이루어지지 않은경우 제외 출력)
$facebookAd = \App::Load('\\Component\\Marketing\\FacebookAd');
$currency = gd_isset(Mall::getSession('currencyConfig')['code'], 'KRW');
$fbConfig = $facebookAd->getConfig();
$fbConfigExtension = $facebookAd->getExtensionConfig();
$goodsInfo = $order->getOrderGoodsData($orderInfo['orderNo']);
if($orderInfo['orderStatus'] != OrderStatusGroup::FAIL && (($fbConfig['fbUseFl'] == 'y' && $fbConfig['orderEndScriptFl'] == 'y') || $fbConfigExtension['fbUseFl'] == 'y')) {
// 상품번호 추출
$goodsNo = [];
foreach ($goodsInfo as $key => $val){
$goodsNo[] = $val2['goodsNo'];
}
}
$facebookAd->orderNo = $orderInfo['orderNo'];
$fbScript = $facebookAd->getFbOrderEndScript($goodsNo, $orderInfo['settlePrice'], $currency);
$this->setData('fbOrderEndScript', $fbScript['script']);
 
 
관리자-유저 세션 격리 강화
Component/Member/MemberSnsDAO.php+1
변경 전MemberSnsDAO.php
$this->db->strField .= ', m.email, m.adultConfirmDt, m.adultFl, m.loginCnt, m.changePasswordDt, m.guidePasswordDt';
$this->db->strField .= ', m.modDt AS mModDt, m.regDt AS mRegDt, ms.snsJoinFl, ms.snsTypeFl, ms.connectFl, ms.accessToken';
$this->db->strField .= ', mg.groupNm, mg.groupSort, mh.sno AS hackOutSno';
 
$this->db->strJoin = ' LEFT JOIN ' . DB_MEMBER . ' AS m ON ms.memNo = m.memNo';
$this->db->strJoin .= ' LEFT JOIN ' . DB_MEMBER_GROUP . ' AS mg ON mg.sno = m.groupSno';
$this->db->strJoin .= ' LEFT JOIN ' . DB_MEMBER_HACKOUT . ' AS mh ON mh.memNo = m.memNo';
 
변경 후MemberSnsDAO.php
$this->db->strField .= ', m.email, m.adultConfirmDt, m.adultFl, m.loginCnt, m.changePasswordDt, m.guidePasswordDt';
$this->db->strField .= ', m.modDt AS mModDt, m.regDt AS mRegDt, ms.snsJoinFl, ms.snsTypeFl, ms.connectFl, ms.accessToken';
$this->db->strField .= ', mg.groupNm, mg.groupSort, mh.sno AS hackOutSno';
$this->db->strField .= ', m.mallSno'; // 세션 저장 시 기준몰 판정에 사용 (누락되면 세션 핸들러가 회원을 재조회하며 세션ID를 재발급한다)
$this->db->strJoin = ' LEFT JOIN ' . DB_MEMBER . ' AS m ON ms.memNo = m.memNo';
$this->db->strJoin .= ' LEFT JOIN ' . DB_MEMBER_GROUP . ' AS mg ON mg.sno = m.groupSno';
$this->db->strJoin .= ' LEFT JOIN ' . DB_MEMBER_HACKOUT . ' AS mh ON mh.memNo = m.memNo';
 
회원 등급 평가 스케줄러 개선
Component/Coupon/CouponAdmin.php+2-2
변경 전CouponAdmin.php
$smsAuto->setSmsAutoCodeType(Code::COUPON_MANUAL);
$smsAuto->setSmsType(SmsAutoCode::PROMOTION);
$smsAuto->setReceiver($member);
$smsAuto->setReplaceArguments(['name' => $member['memNm'], 'CouponName' => $couponInfo['couponNm'], 'rc_memid' => $member['memId']]);
$smsAuto->autoSend();
} else {
$logger->info(sprintf('Disallow sms receiving. memNo[%s], smsFl [%s]', $member['memNo'], $member['smsFl']));
$smsAuto->setSmsAutoCodeType(Code::COUPON_MANUAL);
$smsAuto->setSmsType(SmsAutoCode::PROMOTION);
$smsAuto->setReceiver($val);
$smsAuto->setReplaceArguments(['name' => $val['memNm'], 'CouponName' => $couponInfo['couponNm'], 'rc_memid' => $val['memId']]);
$smsAuto->autoSend();
} else {
$logger->info(sprintf('Disallow sms receiving. memNo[%s], smsFl [%s]', $val['memNo'], $val['smsFl']));
 
변경 후CouponAdmin.php
$smsAuto->setSmsAutoCodeType(Code::COUPON_MANUAL);
$smsAuto->setSmsType(SmsAutoCode::PROMOTION);
$smsAuto->setReceiver($member);
$smsAuto->setReplaceArguments(['name' => $member['memNm'], 'CouponName' => $couponInfo['couponNm'], 'rc_memid' => $member['memId'], 'rc_mallNm' => Globals::get('gMall.mallNm')]);
$smsAuto->autoSend();
} else {
$logger->info(sprintf('Disallow sms receiving. memNo[%s], smsFl [%s]', $member['memNo'], $member['smsFl']));
$smsAuto->setSmsAutoCodeType(Code::COUPON_MANUAL);
$smsAuto->setSmsType(SmsAutoCode::PROMOTION);
$smsAuto->setReceiver($val);
$smsAuto->setReplaceArguments(['name' => $val['memNm'], 'CouponName' => $couponInfo['couponNm'], 'rc_memid' => $val['memId'], 'rc_mallNm' => Globals::get('gMall.mallNm')]);
$smsAuto->autoSend();
} else {
$logger->info(sprintf('Disallow sms receiving. memNo[%s], smsFl [%s]', $val['memNo'], $val['smsFl']));
 
Component/Member/Group/Appraisal.php+262-28
변경 전Appraisal.php
/** @var array 현재 평가대상 회원 */
protected $currentMembers;
/** @var array 등급평가 제외 설정된 등급 sno 배열 */
protected $apprExclusionOfRating;
/** @var array 그룹 sno별 등급 */
protected $groupSort;
 
 
/** @var array 그룹 관리 설정 */
public $policy;
/** @var array 기본 설정 */
protected $couponAdmin;
/** @var array [couponNo => [memNo, ...]] — updateGroup에서 누적 후 flush 로 쿠폰별 일괄 발급 */
protected $couponSmsBuffer = [];
 
 
/**
* Appraisal constructor.
*
public function __construct(AppraisalSearch $search = null)
{
parent::__construct();
 
 
 
$this->setSearch($search);
$this->groupConfig();
$this->validateAppraisalGroupConfig();
$this->policy = ComponentUtils::getPolicy('member.group');
$this->basicInfo = gd_policy('basic.info');
$this->memberFields = DBTableField::getFieldTypes('tableMember');
$this->logger = App::getInstance('logger');
$this->couponAdmin = new CouponAdmin();
ini_set('memory_limit', '-1');
}
$validation->validateOverlapStandard();
$this->groupSort[$group['sno']] = $group['groupSort']; // 그룹 key: sno, value: sort 배열 생성
}
 
 
 
 
 
 
// 회원등급 평가시 제외인 등급 그룹 배열 생성
$exclusionGroups = $dao->selectGroupExclusion();
foreach ($exclusionGroups as $key){
$this->groupConfig = $groups;
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* setGroupNames
* @return void
{
$session = \App::getInstance('session');
$db = \App::getInstance('DB');
 
 
try {
$groupSno = $this->group->get('sno');
$settleGb = $this->group->get('settleGb');
$this->checkGroupByFigure($item);
}
$beforeGroupSort = $this->groupSort[$item['groupSno']];
$afterGroupSort = $this->groupSort[$groupSno];
//하향펑가를 설정하지 않았거나, 하향평가를 사용하거나, 하향평가를 사용하지 않고 변경 등급이 기존 등급보다 높거나 같을 때 만 업데이트
if (empty($this->policy['downwardAdjustment']) || $this->policy['downwardAdjustment'] == 'y' || ($this->policy['downwardAdjustment'] == 'n' && $beforeGroupSort < $afterGroupSort)) {
if ($this->isCurrentGroupMember || $this->isDefaultGroupMember) {
$this->logger->info('Group change target. sno[' . $this->group->get('sno', 0) . '], name[' . $this->group->get('', '-') . ']', $item);
 
$this->updateGroup($memNo);
$this->writeHistory($memNo);
$this->addMailReceiver($storage, $this->group);
$this->addSmsReceiver($storage, $this->group);
unset($members[$index]);
}
}
$db->commit();
$this->currentMembers = $members;
}
 
 
 
 
 
} catch (Exception $e) {
$this->logger->error(__METHOD__ . ', ' . $e->getFile() . '[' . $e->getLine() . '], ' . $e->getMessage(), $e->getTrace());
$db->rollback();
$this->couponSmsBuffer = [];
 
 
 
 
}
}
foreach ($this->couponSmsBuffer as $couponNo => $memNos) {
\Request::post()->set('couponNo', $couponNo);
$this->couponAdmin->saveMemberCouponSms($memNos, null, $passwordCheckFlBool);
 
 
 
}
$this->couponSmsBuffer = [];
}
$memNos,
$couponSaveAdminId,
$passwordCheckFl,
$targetDate
 
);
}
/**
* 평가 대상 중 "현재 기본등급(1)인 회원"만 autoGroupAppraisalDt를 targetDate로 기록한다.
* - 전체 기본등급이 아니라, 이번 실행의 대상(memNo 배열)만 처리
* - 이미 targetDate로 기록된 회원은 제외
*
* @param array $memNos
* @param string $targetDate Y-m-d
return;
}
 
 
 
 
$db = \App::getInstance('DB');
$touchDateTime = $targetDate . ' 00:00:00';
$from = $targetDate . ' 00:00:00';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
$arrBind = [];
$db->bind_param_push($arrBind, 's', $touchDateTime);
$placeholders = implode(',', array_fill(0, count($memNos), '?'));
foreach ($memNos as $memNo) {
$db->bind_param_push($arrBind, 'i', $memNo);
}
// 기본등급 + 활성회원만
$db->bind_param_push($arrBind, 'i', 1);
$db->bind_param_push($arrBind, 's', 'y');
$db->bind_param_push($arrBind, 's', 'n');
// 이미 targetDate 이후로 평가 완료된 회원은 제외
$db->bind_param_push($arrBind, 's', $from);
$strField = 'autoGroupAppraisalDt = ?';
$strWhere = 'memNo IN (' . $placeholders . ')'
. ' AND groupSno = ?'
. ' AND appFl = ?'
. ' AND sleepFl = ?'
. ' AND (autoGroupAppraisalDt IS NULL OR autoGroupAppraisalDt < ?)';
$db->set_update_db(DB_MEMBER, $strField, $strWhere, $arrBind);
$this->logger->info('Update autoGroupAppraisalDt for default group members', [
'table' => DB_MEMBER,
'memNoCount' => count($memNos),
'from' => $from,
]);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 수정이력 추가
$observer = new SmsAutoObserver();
$observer->setSmsType(SmsAutoCode::MEMBER);
$observer->setSmsAutoCodeType(Code::GROUP_CHANGE);
$observer->setReceiver($storage->get('cellPhone'));
 
 
 
 
 
$observer->setReplaceArguments(
[
'rc_groupNm' => $group->get('groupNm'),
'name' => $storage->get('memNm'),
'memNm' => $storage->get('memNm'),
 
'groupNm' => $group->get('groupNm'),
'rc_mallNm' => \Globals::get('gMall.mallNm'),
'shopUrl' => $this->basicInfo['mallDomain'],
* 전체 등급 설정을 스캔하여 실제 필요한 데이터 유형을 결정
* @return array ['order' => bool, 'review' => bool, 'login' => bool]
*/
private function resolveRequiredData(): array
{
$isPoint = $this->_isAppraisalSystemPoint();
 
변경 후Appraisal.php
/** @var array 현재 평가대상 회원 */
protected $currentMembers;
/** @var array 등급평가 제외 설정된 등급 sno 배열 */
protected $apprExclusionOfRating = [];
/** @var array 평가 대상 그룹 sno별 등급 */
protected $groupSort;
/** @var array 평가 대상 여부와 무관한 전체 그룹 sno별 등급 */
protected $allGroupSort = [];
/** @var array 그룹 관리 설정 */
public $policy;
/** @var array 기본 설정 */
protected $couponAdmin;
/** @var array [couponNo => [memNo, ...]] — updateGroup에서 누적 후 flush 로 쿠폰별 일괄 발급 */
protected $couponSmsBuffer = [];
/** @var array rollback 된 배치의 memNo — 유지회원 stamp 제외 대상 */
protected $rolledBackMemNos = [];
/**
* Appraisal constructor.
*
public function __construct(AppraisalSearch $search = null)
{
parent::__construct();
$this->memberFields = DBTableField::getFieldTypes('tableMember');
$this->logger = App::getInstance('logger');
$this->setSearch($search);
$this->groupConfig();
$this->validateAppraisalGroupConfig();
$this->policy = ComponentUtils::getPolicy('member.group');
$this->basicInfo = gd_policy('basic.info');
 
 
$this->couponAdmin = new CouponAdmin();
ini_set('memory_limit', '-1');
}
$validation->validateOverlapStandard();
$this->groupSort[$group['sno']] = $group['groupSort']; // 그룹 key: sno, value: sort 배열 생성
}
$this->allGroupSort = (array)$this->groupSort;
if ($isAppraisalFigure) {
foreach ($dao->selectAppraisalGroups() as $group) {
$this->allGroupSort[$group['sno']] = $group['groupSort'];
}
}
// 회원등급 평가시 제외인 등급 그룹 배열 생성
$exclusionGroups = $dao->selectGroupExclusion();
foreach ($exclusionGroups as $key){
$this->groupConfig = $groups;
}
/**
* 직전 평가일(autoAppraisalDateTime)은 배치 완료 후에 갱신되므로, 평가주기만큼 전진시켜 이번 회차를 찾는다.
*
* @param string $targetDate Y-m-d
*
* @return string Y-m-d
*/
protected function resolveAppraisalCycleStartDate($targetDate)
{
$calcCycleDay = (int)$this->getPolicyValue('calcCycleDay');
$base = date_create((string)$targetDate);
if ($calcCycleDay < 1 || $base === false) {
return $targetDate;
}
$base = date_create($base->format('Y-m-d'));
$cycleStart = $this->resolveCycleStartByPreviousAppraisal($base, $calcCycleDay);
if ($cycleStart === null) {
$cycleStart = $this->cycleDateInMonth($base, $calcCycleDay);
if ($cycleStart > $base) {
$cycleStart = $this->cycleDateInMonth($this->shiftMonth($base, -1), $calcCycleDay);
}
}
return $cycleStart->format('Y-m-d');
}
/**
* @param \DateTime $base
* @param int $calcCycleDay
*
* @return \DateTime|null
*/
protected function resolveCycleStartByPreviousAppraisal(\DateTime $base, $calcCycleDay)
{
$calcCycleMonth = (int)$this->getPolicyValue('calcCycleMonth');
$previous = (string)$this->getPolicyValue('autoAppraisalDateTime');
if ($calcCycleMonth < 1 || $previous === '') {
return null;
}
$cycleStart = date_create($previous);
if ($cycleStart === false) {
return null;
}
$cycleStart = date_create($cycleStart->format('Y-m-d'));
if ($cycleStart > $base) {
return null;
}
while (true) {
$next = $this->cycleDateInMonth($this->shiftMonth($cycleStart, $calcCycleMonth), $calcCycleDay);
if ($next > $base) {
return $cycleStart;
}
$cycleStart = $next;
}
}
/**
* @param \DateTime $base
* @param int $months
*
* @return \DateTime
*/
protected function shiftMonth(\DateTime $base, $months)
{
return date_create($base->format('Y-m-01'))->modify(sprintf('%+d month', $months));
}
/**
* @param \DateTime $base
* @param int $calcCycleDay
*
* @return \DateTime
*/
protected function cycleDateInMonth(\DateTime $base, $calcCycleDay)
{
$day = min($calcCycleDay, (int)$base->format('t'));
return date_create($base->format('Y-m-') . sprintf('%02d', $day));
}
/**
* @param string $key
*
* @return mixed
*/
protected function getPolicyValue($key)
{
return isset($this->policy[$key]) ? $this->policy[$key] : '';
}
/**
* @param int $groupSno
*
* @return int
*/
protected function resolveGroupSort($groupSno)
{
if (array_key_exists($groupSno, $this->allGroupSort)) {
return (int)$this->allGroupSort[$groupSno];
}
if (array_key_exists($groupSno, (array)$this->groupSort)) {
return (int)$this->groupSort[$groupSno];
}
$this->logger->warning('Not found groupSort. groupSno[' . $groupSno . ']');
return 0;
}
/**
* setGroupNames
* @return void
{
$session = \App::getInstance('session');
$db = \App::getInstance('DB');
$updateTargetMemNos = [];
$pendingReceivers = [];
try {
$groupSno = $this->group->get('sno');
$settleGb = $this->group->get('settleGb');
$this->checkGroupByFigure($item);
}
$beforeGroupSort = $this->resolveGroupSort($item['groupSno']);
$afterGroupSort = $this->resolveGroupSort($groupSno);
//하향펑가를 설정하지 않았거나, 하향평가를 사용하거나, 하향평가를 사용하지 않고 변경 등급이 기존 등급보다 높거나 같을 때 만 업데이트
if (empty($this->policy['downwardAdjustment']) || $this->policy['downwardAdjustment'] == 'y' || ($this->policy['downwardAdjustment'] == 'n' && $beforeGroupSort < $afterGroupSort)) {
if ($this->isCurrentGroupMember || $this->isDefaultGroupMember) {
$this->logger->info('Group change target. sno[' . $this->group->get('sno', 0) . '], name[' . $this->group->get('', '-') . ']', $item);
$updateTargetMemNos[] = $memNo;
$this->updateGroup($memNo);
$this->writeHistory($memNo);
$pendingReceivers[] = $storage;
 
unset($members[$index]);
}
}
$db->commit();
$this->currentMembers = $members;
}
foreach ($pendingReceivers as $receiver) {
$this->addMailReceiver($receiver, $this->group);
$this->addSmsReceiver($receiver, $this->group);
}
} catch (Exception $e) {
$this->logger->error(__METHOD__ . ', ' . $e->getMessage(), ['exception' => $e]);
$db->rollback();
$this->couponSmsBuffer = [];
$this->rolledBackMemNos = array_merge($this->rolledBackMemNos, $updateTargetMemNos);
if (method_exists($this->search, 'removeEvaluatedMemberSnapshots')) {
$this->search->removeEvaluatedMemberSnapshots($updateTargetMemNos);
}
}
}
foreach ($this->couponSmsBuffer as $couponNo => $memNos) {
\Request::post()->set('couponNo', $couponNo);
$result = $this->couponAdmin->saveMemberCouponSms($memNos, null, $passwordCheckFlBool);
if ($result === false) {
$this->logger->warning(sprintf('Coupon issue skipped (checkCouponType failed). couponNo[%d] memNo_cnt[%d]', $couponNo, count($memNos)));
}
}
$this->couponSmsBuffer = [];
}
$memNos,
$couponSaveAdminId,
$passwordCheckFl,
$targetDate,
$this->resolveAppraisalCycleStartDate($targetDate)
);
}
/**
* 변경자는 updateGroup 에서 이미 stamp 되므로, 유지자만 보완해 동일자 재평가 대상에서 제외되도록 한다.
 
 
*
* @param array $memNos
* @param string $targetDate Y-m-d
return;
}
if (!method_exists($this->search, 'getEvaluatedMemberSnapshots')) {
throw new Exception('AppraisalSearch 구버전 감지: getEvaluatedMemberSnapshots 누락. 평가 스냅샷 없이 유지회원 stamp 시 미평가 회원까지 평가완료 처리되어 다음 회차에서 누락될 수 있어 사전 차단합니다.');
}
$db = \App::getInstance('DB');
$touchDateTime = $this->appraisalDateTime ?: ($targetDate . ' 00:00:00');
$from = $targetDate . ' 00:00:00';
$snapshots = $this->search->getEvaluatedMemberSnapshots();
$exclusion = $this->apprExclusionOfRating ?? [];
$appraisalGroupSnos = $this->resolveAppraisalGroupSnos();
if (empty($appraisalGroupSnos)) {
$this->logger->warning('Skip retained member stamp. Not found appraisal target group.', [
'groupSort' => $this->groupSort,
'exclusion' => $exclusion,
]);
return;
}
if (empty($snapshots)) {
// 평가 검색이 실행되지 않은 실행(평가기준 그룹 없음 등) — 종전 라이브 조회 방식으로 stamp
$memNos = array_values(array_diff($memNos, $this->rolledBackMemNos));
if (empty($memNos)) {
return;
}
$arrBind = [];
$db->bind_param_push($arrBind, 's', $touchDateTime);
$placeholders = implode(',', array_fill(0, count($memNos), '?'));
foreach ($memNos as $memNo) {
$db->bind_param_push($arrBind, 'i', $memNo);
}
$db->bind_param_push($arrBind, 's', 'y');
$db->bind_param_push($arrBind, 's', 'n');
$groupPlaceholders = implode(',', array_fill(0, count($appraisalGroupSnos), '?'));
foreach ($appraisalGroupSnos as $sno) {
$db->bind_param_push($arrBind, 'i', $sno);
}
$db->bind_param_push($arrBind, 's', $from);
$strWhere = 'memNo IN (' . $placeholders . ')'
. ' AND appFl = ?'
. ' AND sleepFl = ?'
. ' AND groupSno IN (' . $groupPlaceholders . ')'
. ' AND (autoGroupAppraisalDt IS NULL OR autoGroupAppraisalDt < ?)';
$db->set_update_db(DB_MEMBER, 'autoGroupAppraisalDt = ?', $strWhere, $arrBind);
$this->logger->info('Update autoGroupAppraisalDt for retained members (no snapshot fallback)', [
'table' => DB_MEMBER,
'memNoCount' => count($memNos),
'from' => $from,
]);
return;
}
$retainedMemNos = $this->resolveRetainedStampTargets($snapshots, $exclusion, $appraisalGroupSnos);
if (empty($retainedMemNos)) {
return;
}
$arrBind = [];
$db->bind_param_push($arrBind, 's', $touchDateTime);
$placeholders = implode(',', array_fill(0, count($retainedMemNos), '?'));
foreach ($retainedMemNos as $memNo) {
$db->bind_param_push($arrBind, 'i', $memNo);
}
 
 
$db->bind_param_push($arrBind, 's', 'y');
$db->bind_param_push($arrBind, 's', 'n');
 
 
$db->bind_param_push($arrBind, 's', $from);
 
$strWhere = 'memNo IN (' . $placeholders . ')'
 
. ' AND appFl = ?'
. ' AND sleepFl = ?'
. ' AND (autoGroupAppraisalDt IS NULL OR autoGroupAppraisalDt < ?)';
$db->set_update_db(DB_MEMBER, 'autoGroupAppraisalDt = ?', $strWhere, $arrBind);
$this->logger->info('Update autoGroupAppraisalDt for retained members', [
'table' => DB_MEMBER,
'memNoCount' => count($retainedMemNos),
'from' => $from,
]);
}
/**
* @param array $snapshots memNo => search 결과 row
* @param array $exclusion 제외그룹 sno => sno
* @param array $appraisalGroupSnos 평가 대상 등급 sno 배열
*
* @return array
*/
public function resolveRetainedStampTargets(array $snapshots, array $exclusion, array $appraisalGroupSnos)
{
$retainedMemNos = [];
$appraisalGroupSnos = array_map('intval', $appraisalGroupSnos);
foreach ($snapshots as $memNo => $row) {
$groupSno = is_array($row) ? ($row['groupSno'] ?? null) : null;
if ($groupSno !== null && array_key_exists($groupSno, $exclusion)) {
continue;
}
if ($groupSno !== null && in_array((int)$groupSno, $appraisalGroupSnos, true) === false) {
continue;
}
$retainedMemNos[] = (int)$memNo;
}
return $retainedMemNos;
}
/**
* @return array
*/
public function resolveAppraisalGroupSnos()
{
$groupSnos = array_keys((array)$this->groupSort);
$exclusionSnos = array_values((array)$this->apprExclusionOfRating);
return array_values(array_diff($groupSnos, $exclusionSnos));
}
/**
* 수정이력 추가
$observer = new SmsAutoObserver();
$observer->setSmsType(SmsAutoCode::MEMBER);
$observer->setSmsAutoCodeType(Code::GROUP_CHANGE);
$observer->setReceiver([
'memNo' => $storage->get('memNo'),
'memNm' => $storage->get('memNm'),
'smsFl' => $storage->get('smsFl', 'y'),
'cellPhone' => $storage->get('cellPhone'),
]);
$observer->setReplaceArguments(
[
'rc_groupNm' => $group->get('groupNm'),
'name' => $storage->get('memNm'),
'memNm' => $storage->get('memNm'),
'memNo' => $storage->get('memNo'),
'groupNm' => $group->get('groupNm'),
'rc_mallNm' => \Globals::get('gMall.mallNm'),
'shopUrl' => $this->basicInfo['mallDomain'],
* 전체 등급 설정을 스캔하여 실제 필요한 데이터 유형을 결정
* @return array ['order' => bool, 'review' => bool, 'login' => bool]
*/
protected function resolveRequiredData(): array
{
$isPoint = $this->_isAppraisalSystemPoint();
 
Component/Member/Group/AppraisalSearch.php+27-4
변경 전AppraisalSearch.php
protected $targetDateTime;
/** @var array airflow 가 지정한 memNo 배열 */
protected $targetMembers = [];
 
 
/** @var array 필요한 서브쿼리 플래그 ['order' => bool, 'review' => bool, 'login' => bool] */
protected $requiredData = ['order' => true, 'review' => true, 'login' => true];
$this->buildQuery(empty($this->targetMembers) ? '' : $this->whereExcludeCompleteMember());
$logger->info(sprintf('Build query complete. %s', $this->query));
$results = $this->db->query_fetch($this->query);
$logger->debug('Appraisal search result keys', array_keys($results[0]));
$return = [];
foreach ($results as $index => $result) {
if (key_exists($result['memNo'], $return)) {
$return[$result['memNo']] = $result;
}
 
 
 
 
 
 
 
 
return $return;
}
*/
public function searchDefaultGroup($appraisalDateTime)
{
$this->db->strField = 'm.memNo, m.memNm, m.email, m.cellPhone, m.groupSno, m.adminMemo, m.groupModDt';
// 다른등급 대상 회원 조회(_pushWhere())와 조건 동일하게 설정
$this->db->strWhere = 'm.sleepFl=\'n\' AND m.appFl=\'y\'';
if (!empty($this->targetMembers)) {
$return[$result['memNo']] = $result;
}
}
 
return $return;
}
*/
private function _pushColumn()
{
$this->column[] = 'm.memNo, m.memNm, m.email, m.cellPhone, m.groupSno, m.adminMemo, m.groupModDt';
if ($this->requiredData['login']) {
$this->column[] = 'IFNULL(l.cnt, 0) AS loginCount';
$this->targetMembers = $target;
}
 
 
 
 
 
 
 
 
 
 
 
 
/*
* 타겟일자기준 회원등급평가 완료대상 제외 where 조건
*
*/
public function whereExcludeCompleteMember()
{
$from = "{$this->targetDateTime} 00:00:00";
return "(m.autoGroupAppraisalDt IS NULL OR m.autoGroupAppraisalDt < '{$from}')";
}
}
 
변경 후AppraisalSearch.php
protected $targetDateTime;
/** @var array airflow 가 지정한 memNo 배열 */
protected $targetMembers = [];
/** @var array 실제 평가된 회원 스냅샷 (memNo => search 결과 row). 유지회원 stamp 대상 판정 기준 */
protected $evaluatedMembers = [];
/** @var array 필요한 서브쿼리 플래그 ['order' => bool, 'review' => bool, 'login' => bool] */
protected $requiredData = ['order' => true, 'review' => true, 'login' => true];
$this->buildQuery(empty($this->targetMembers) ? '' : $this->whereExcludeCompleteMember());
$logger->info(sprintf('Build query complete. %s', $this->query));
$results = $this->db->query_fetch($this->query);
$logger->debug('Appraisal search result keys', empty($results) ? [] : array_keys($results[0]));
$return = [];
foreach ($results as $index => $result) {
if (key_exists($result['memNo'], $return)) {
$return[$result['memNo']] = $result;
}
$logger->info(sprintf('Appraisal search matched %d of %d requested members. groupSno[%s]', count($return), count($this->targetMembers), $group->get('sno', '-')));
if (!empty($this->targetMembers)) {
foreach ($return as $memNo => $row) {
$this->evaluatedMembers[$memNo] = $row;
}
}
return $return;
}
*/
public function searchDefaultGroup($appraisalDateTime)
{
$this->db->strField = 'm.memNo, m.memNm, m.email, m.cellPhone, m.smsFl, m.maillingFl, m.groupSno, m.adminMemo, m.groupModDt';
// 다른등급 대상 회원 조회(_pushWhere())와 조건 동일하게 설정
$this->db->strWhere = 'm.sleepFl=\'n\' AND m.appFl=\'y\'';
if (!empty($this->targetMembers)) {
$return[$result['memNo']] = $result;
}
}
return $return;
}
*/
private function _pushColumn()
{
$this->column[] = 'm.memNo, m.memNm, m.email, m.cellPhone, m.smsFl, m.maillingFl, m.groupSno, m.adminMemo, m.groupModDt';
if ($this->requiredData['login']) {
$this->column[] = 'IFNULL(l.cnt, 0) AS loginCount';
$this->targetMembers = $target;
}
public function getEvaluatedMemberSnapshots()
{
return $this->evaluatedMembers;
}
public function removeEvaluatedMemberSnapshots(array $memNos)
{
foreach ($memNos as $memNo) {
unset($this->evaluatedMembers[$memNo]);
}
}
/*
* 타겟일자기준 회원등급평가 완료대상 제외 where 조건
*
*/
public function whereExcludeCompleteMember()
{
$from = $this->db->escape("{$this->targetDateTime} 00:00:00");
return "(m.autoGroupAppraisalDt IS NULL OR m.autoGroupAppraisalDt < '{$from}')";
}
}
 
Component/Member/History.php+4-11
변경 전History.php
/**
* 수정 전/후 데이터 불러오기
*
* @param array $before 수정 전 데이터를 호출부에서 주입 (empty 면 세션에서 조회)
* @param array $after 수정 후 데이터를 호출부에서 주입 (empty 면 DB 에서 조회)
* @return $this
*/
public function initBeforeAndAfter(array $before = [], array $after = [])
{
if (empty($before)) {
$session = \App::getInstance('session');
$before = $session->get(Member::SESSION_MODIFY_MEMBER_INFO, null);
}
if (empty($after)) {
// 호출부가 수정 후 데이터를 주입하지 않은 경우에만 DB 조회 (자동 등급평가 등 대량 호출 시 주입으로 SELECT N→0 감소)
$after = $this->db->getData(DB_MEMBER, $this->memNo, 'memNo');
}
 
// 자동 등급평가 등 세션 미세팅 경로에서 null 이 들어올 수 있음.
// combineMemberData → ArrayUtils::unsetDiff(array $keys) 가 strict 타입이라 TypeError 발생 → 빈 배열로 보정.
 
변경 후History.php
/**
* 수정 전/후 데이터 불러오기
*
 
 
* @return $this
*/
public function initBeforeAndAfter()
{
$session = \App::getInstance('session');
$before = $session->get(Member::SESSION_MODIFY_MEMBER_INFO, null);
$after = $this->db->getData(DB_MEMBER, $this->memNo, 'memNo');
 
 
 
 
 
 
// 자동 등급평가 등 세션 미세팅 경로에서 null 이 들어올 수 있음.
// combineMemberData → ArrayUtils::unsetDiff(array $keys) 가 strict 타입이라 TypeError 발생 → 빈 배열로 보정.