초기소스

This commit is contained in:
jazz
2025-10-29 17:08:05 +09:00
parent e531aa9540
commit 439a379a02
7551 changed files with 1234427 additions and 3 deletions

View File

@@ -0,0 +1,37 @@
package com.wb.domainserver.domain.naverpay;
public class ItemStack {
private String _itemId;
private String _itemName;
private int _itemUPrice;
private String _itemImage;
private String _itemUrl;
/**
* @param itemId Mall Item Code
* @param itemName 상품
* @param itemPrice 상품 개별 가격
*/
public ItemStack(String itemId, String itemName, int itemUPrice, String itemImage,String itemUrl) {
_itemId = itemId;
_itemName = itemName;
_itemUPrice = itemUPrice;
_itemImage = itemImage;
_itemUrl = itemUrl;
}
public String getItemId() {
return _itemId;
}
public String getItemName() {
return _itemName;
}
public int getItemUnitPrice() {
return _itemUPrice;
}
public String getItemImage() {
return _itemImage;
}
public String getItemUrl() {
return _itemUrl;
}
}

View File

@@ -0,0 +1,217 @@
package com.wb.domainserver.domain.naverpay;
import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class JavaZzimSample{
private static final String ENCODING = "UTF-8";
private static final String NCKEY_ITEMID = "ITEM_ID"; //상품 ID
private static final String NCKEY_ITEMNAME = "ITEM_NAME"; //상품 이름
private static final String NCKEY_UPRICE = "ITEM_UPRICE"; //개별 상품 단가. 0 보다 커야 한다
private static final String NCKEY_ITEMIMAGE = "ITEM_IMAGE"; //상품 사진 URL
private static final String NCKEY_ITEMURL = "ITEM_URL"; //상품 정보 URL
private static final String NCKEY_SHOPID = "SHOP_ID"; //상점 ID. 네이버페이에 가입 승인될 때 정해진다
private static final String NCKEY_CERTIKEY = "CERTI_KEY"; //인증키. 네이버페이에 가입 승인될 때 정해진다
private static final String NCKEY_RESERVE1 = "RESERVE1";
private static final String NCKEY_RESERVE2 = "RESERVE2";
private static final String NCKEY_RESERVE3 = "RESERVE3";
private static final String NCKEY_RESERVE4 = "RESERVE4";
private static final String NCKEY_RESERVE5 = "RESERVE5";
public URL _url;
private SSLSocketFactory _sslSockFactory;
public JavaZzimSample() {
_url = null;
}
public JavaZzimSample(URL url) {
_url = url;
_initHttps();
}
public JavaZzimSample(String url) throws MalformedURLException {
this(new URL(url));
}
public void setUrl(String url) throws MalformedURLException {
_url = new URL(url);
}
// public static class ItemStack {
// private String _itemId;
// private String _itemName;
// private int _itemUPrice;
// private String _itemImage;
// private String _itemUrl;
//
// /**
// * @param itemId Mall Item Code
// * @param itemName 상품
// * @param itemPrice 상품 개별 가격
// */
// public ItemStack(String itemId, String itemName, int itemUPrice, String itemImage,String itemUrl) {
// _itemId = itemId;
// _itemName = itemName;
// _itemUPrice = itemUPrice;
// _itemImage = itemImage;
// _itemUrl = itemUrl;
// }
// public String getItemId() {
// return _itemId;
// }
// public String getItemName() {
// return _itemName;
// }
// public int getItemUnitPrice() {
// return _itemUPrice;
// }
// public String getItemImage() {
// return _itemImage;
// }
// public String getItemUrl() {
// return _itemUrl;
// }
// }
private void _urlEncode(StringBuffer sb, String key, String value) {
try {
sb.append(URLEncoder.encode(key, ENCODING)); //php예제에서는 키는 encoding 안함
sb.append('=');
sb.append(URLEncoder.encode(value, ENCODING));
}
catch(UnsupportedEncodingException e) {
//일어나지 않음
throw new Error(e);
}
}
private String _makeQueryString(String shopId, String certificationKey, com.wb.domainserver.domain.naverpay.ItemStack[] items) {
StringBuffer sb = new StringBuffer();
_urlEncode(sb, NCKEY_SHOPID, shopId);
sb.append('&');
_urlEncode(sb, NCKEY_CERTIKEY, certificationKey);
sb.append('&');
for (com.wb.domainserver.domain.naverpay.ItemStack is : items) {
_urlEncode(sb, NCKEY_ITEMID, is.getItemId());
sb.append('&');
_urlEncode(sb, NCKEY_ITEMNAME, is.getItemName());
sb.append('&');
_urlEncode(sb, NCKEY_UPRICE, String.valueOf(is.getItemUnitPrice()));
sb.append('&');
_urlEncode(sb, NCKEY_ITEMIMAGE, String.valueOf(is.getItemImage()));
sb.append('&');
_urlEncode(sb, NCKEY_ITEMURL, String.valueOf(is.getItemUrl()));
sb.append('&');
}
_urlEncode(sb, NCKEY_RESERVE1, "");
sb.append('&');
_urlEncode(sb, NCKEY_RESERVE2, "");
sb.append('&');
_urlEncode(sb, NCKEY_RESERVE3, "");
sb.append('&');
_urlEncode(sb, NCKEY_RESERVE4, "");
sb.append('&');
_urlEncode(sb, NCKEY_RESERVE5, "");
System.out.println("[_makeQueryString]"+sb.toString());
return sb.toString();
}
/* test 환경에서는 인증서 오류가 날 수도 있다. 이 코드를 이용해 인증서 오류를 회피한다. */
private void _initHttps(){
TrustManager[] trustAllCerts = new TrustManager[]
{ new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
};
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new SecureRandom());
_sslSockFactory = sslContext.getSocketFactory();
}
catch(Exception e) {
RuntimeException re = new RuntimeException(e);
re.setStackTrace(e.getStackTrace());
throw re;
}
}
/**
* @param items 주문 상품 목록.
* @return 주문키
* @throws IOException
*/
public String[] sendZzimToNC(String shopId, String certificationKey, com.wb.domainserver.domain.naverpay.ItemStack[] items) throws IOException {
HttpURLConnection conn = (HttpURLConnection)_url.openConnection();
/* test 환경에서는 인증서 오류가 날 수도 있다. 이 코드를 이용해 인증서 오류를 회피한다. */
if (conn instanceof HttpsURLConnection) {
((HttpsURLConnection)conn).setSSLSocketFactory(_sslSockFactory);
((HttpsURLConnection)conn).setHostnameVerifier(
new HostnameVerifier(){
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
);
}
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
Writer writer = new OutputStreamWriter(conn.getOutputStream(), ENCODING);
writer.write(_makeQueryString(shopId, certificationKey, items));
writer.flush();
writer.close();
int respCode = conn.getResponseCode();
if (respCode != 200) {
throw new RuntimeException(String.format("NC Response fail : %d %s", respCode, conn.getResponseMessage()));
}
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String retStr = reader.readLine();
return retStr.split(",");
}
public static void main(String[] args) throws IOException {
//주문상품 내역으로 items 데이터를 생성한다. ==> DB에서 읽어옴
List<com.wb.domainserver.domain.naverpay.ItemStack> items = new ArrayList<com.wb.domainserver.domain.naverpay.ItemStack>();
items.add(new com.wb.domainserver.domain.naverpay.ItemStack("a1", "아이템1", 1000, "http://mymall.com/images/a1.jpg", "http://mymall.com/iteminfo?item_id=a1"));
items.add(new com.wb.domainserver.domain.naverpay.ItemStack("a2", "아이템2", 1000, "http://mymall.com/images/a2.jpg", "http://mymall.com/iteminfo?item_id=a2"));
JavaZzimSample sample = new JavaZzimSample("https://test-pay.naver.com/customer/api/wishlist.nhn");
// JavaZzimSample sample = new JavaZzimSample("https://pay.naver.com/customer/api/wishlist.nhn");
//알파랩
String shopId = "np_bgbcp347244";
String certificationKey = "7DE67E95-DB00-4890-A4E0-56242D6CD00D"; //[1200047309, 1200047310] //[1229584613, 1229584614]
//알파랩
// String shopId = "np_nbxsi348787";
// String certificationKey = "641914BE-67E4-4195-950C-431F3EB292EE"; //[1200047309, 1200047310] //[1229584613, 1229584614]
//그래스팜
// String shopId = "np_mruyo723355";
// String certificationKey = "892CEEEE-0CED-499D-A78A-DCA6A1B407E4"; //[1200047344, 1200047345]//[1229584649, 1229584650]
String[] prodSeqs = sample.sendZzimToNC(shopId, certificationKey, items.toArray(new com.wb.domainserver.domain.naverpay.ItemStack[0]));
//여기서 얻은prodSeqs로 zzim popup을 띄운다.
System.out.println(Arrays.toString(prodSeqs));
}
}

View File

@@ -0,0 +1,960 @@
package com.wb.domainserver.domain.naverpay;
import com.wb.domainserver. exception.code.ErrCode;
import com.wb.domainserver.exception.WnbtException;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
@Slf4j
public class NaverPay{
private static final String ENCODING = "UTF-8";
private static final String serviceName = "MallService5";
private static final String detailLevel = "Full";
private static final String version = "5.0";
private static final String NAVER_GOODS_FIELD = "goods_seq"; // Npay, EPurl(스마트스토어) 상품 연동 항목 (goods_seq:상품번호, goods_code:바코드)
private String accessLicense;
private String secretkey;
private String shopId;
private String certiKey;
private String targetUrl; //상품정보 전달 할 네이버 url
private String targetLink; //응답값이 왔을때 네이버주문서 url
private String cusTargetUrl; //CustomerInquiryService(문의내역조회), CustomerInquiryService(문의답변및수정)
public URL _url;
private SSLSocketFactory _sslSockFactory;
public NaverPay() {
_url = null;
}
public NaverPay(URL url) {
_url = url;
_initHttps();
}
public NaverPay(String url) throws MalformedURLException {
this(new URL(url));
}
public void setUrl(String url) throws MalformedURLException {
_url = new URL(url);
}
/** 네이버 URL 주소 설정, 프로퍼티 값들 받아와서 설정함
* @param mode 상품페이지, 주문관리 페이지 구분.
* @throws
*/
public void get_license_info(String mode, String useMode, String webMode){
if(mode.equals("")||mode==null) mode ="buy"; //상품구매 //order 은 장바구니5.0 백단
//access_license, secretkey 를 퍼스트몰 중계서버에 두고 받아옴 >> 우리는 프로퍼티에서 받아옴 (accessLicense,secretkey,shopId,certiKey,useMode,webMode)
accessLicense = "";
secretkey = "";
shopId = "";
certiKey = "";
// String useMode = "test"; //use
// String webMode = "PC"; //PC / mobile
if(useMode.equals("test")){ //개발
if(mode.equals("buy")){
targetUrl = "https://test-api.pay.naver.com/o/customer/api/order/v20/register";
if(webMode.equals("mobile")){
targetLink = "https://test-m.pay.naver.com/o/customer/buy";
}else{
targetLink = "https://test-order.pay.naver.com/customer/buy";
}
}else{
targetUrl = "http://sandbox.api.naver.com/Checkout/MallService5";
//CustomerInquiryService(문의내역조회), CustomerInquiryService(문의답변및수정)
cusTargetUrl = "http://sandbox.api.naver.com/Checkout/CustomerInquiryService";
}
}else if(useMode.equals("use")){ //운영
if(mode.equals("buy")){
targetUrl = "https://api.pay.naver.com/o/customer/api/order/v20/register";
if(webMode.equals("mobile")){
targetLink = "https://m.pay.naver.com/o/customer/buy";
}else{
targetLink = "https://order.pay.naver.com/customer/buy";
}
}else{
targetUrl = "http://ec.api.naver.com/Checkout/MallService5";
cusTargetUrl = "http://ec.api.naver.com/Checkout/CustomerInquiryService";
}
}
}
//------------- XML 구성하기 2.1 ---------------------------------------
//상품주문 : XML 헤더정의
public String set_header(){
StringBuffer headerXml = new StringBuffer();
headerXml.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
.append("<order>\n")
.append(auth_xml_data());
return headerXml.toString();
}
//상품주문 : XML footer
public String set_footer(){
StringBuffer footerMml = new StringBuffer();
footerMml.append("</order>\n");
return footerMml.toString();
}
//상품주문 : make xml data 인증
public String auth_xml_data(){
String returnUrl = ""; //javax.servlet.http.HttpServletRequest request.getHeader("referer"); 이전 주소를 받아와야 한다.
StringBuffer authXml = new StringBuffer();
authXml.append("<merchantId>").append(shopId).append("</merchantId>");
authXml.append("<certiKey>").append(certiKey).append("</certiKey>");
authXml.append("<backUrl>").append(returnUrl).append("</backUrl>");
authXml.append("<mcstCultureBenefitYn>N</bacmcstCultureBenefitYnkUrl>"); //문화체육관광부의 도서공연비 소득공제 정책을 적용할 수 있는 주문에 해당한다면 true 를 입력한다(선택)
return authXml.toString();
}
// 상품주문 : 상품 상세 페이지의 연동 정보
public String set_interface(){
StringBuffer interXml = new StringBuffer();
//salesCode : 경로별 매출 코드. 매출코드가 필요한 경우 입력
//cpaInflowCode : 지식쇼핑 CPA코드. 지식쇼핑 가맹점 중 파라미터 방식 이용한 CPA과금을 원하는 경우 입력
//naverInflowCode : 네이버 서비스 유입경로 코드
//saClickId : SA CLICK ID. 네이버 검색광고 이용 가맹점 중 광고주
interXml.append("<interface>");
interXml.append(" <salesCode>XXX</salesCode>");
interXml.append(" <cpaInflowCode>XXX</cpaInflowCode>");
interXml.append(" <naverInflowCode>XXX</naverInflowCode>");
interXml.append(" <saClickId>XXX</saClickId>");
interXml.append("</interface>");
return interXml.toString();
}
/*
상품주문 : make xml data
//id : 상품번호. 최대 30자
//merchantProductId : 판매자 상품번호(입점몰)
//ecMallProductId : 지식쇼핑 EP mall_pid
//basePrice : 본상품 1개의 판매가격, 1 이상만 입력
//taxType : 과세 TAX, 면세 TAX_FREE, 영세 : ZERO_TAX
//infoUrl : 상품상세 URL
///imageUrl : 상품원본 이미지 URL
//option 옵션 */
public String product_xml_data(ArrayList $arr, HashMap<String,Object> product, int totalSale){
// $mode = $arr['mode'];
// $shipping_method = $arr['shipping_method'];
// $shipping_packageId = $arr['shipping_packageId'];
// $shipping_group_policy = $arr['shipping_group_policy'];
// $shipping_paytype = $arr['shipping_paytype']; //배송비결제방법(선불/착불)
// $session_tmp = $arr['session_id']."_".$arr['mktime']; //mktime() <> System.currentTimeMillis(); 앞에서 받아올때 mktime이 고정일지 여기서 생성가능한지 확인필요
// $tot_ea = 0;
// $xml = array();
StringBuffer xmlPrdt = new StringBuffer();
if(product != null){
String taxtype = "TAX";
if(product.get("tax").equals("tax")){
taxtype = "TAX"; //과제
}else if(product.get("tax").equals("exempt")){
taxtype = "TAX_FREE"; //면세
}else{
taxtype = "ZERO_TAX"; //영세
}
//request 또는 프로퍼티에서 host 값 읽어와야 함
//$domain = $_SERVER['HTTP_HOST'];
String domain = "";
String infoUrl = "https://www.nutricore.co.kr/goods/view?no="+product.get("goods_seq"); // /goods앞에 get_connet_protocol().$domain 만들어서 제공해야 함
//[옵션상품 xml]
String optXml = "";
int opt_tot_ea = 0;
@SuppressWarnings("unchecked")
ArrayList<HashMap<String,String>> prdOptionInfoList = (ArrayList<HashMap<String,String>>)product.get("options");
if(prdOptionInfoList != null ) optXml= option_xml_data(prdOptionInfoList); //xml, opt_tot_ea 2개 return 받아야 하는데 조금 더 분석 후 변형
//[추가상품 xml]
String suboptXml = "";
if(product.get("suboptions") != null ) suboptXml= "";
//평균가증정중 단독평균가증정품일때 [평균가증정]상품중 하나에 추가구성상품으로 전달 gcs ysm @2019-08-12
//네이버페이 > N+1 증정품 : 추가구성상품으로 전달 0 추가(재고 X) gcs ysm @2019-01-11
// if($this->shippingmodel->multi_order_cfg['oneplusone_use'] == 'Y' && $product['oneplusone'] && $product['oneplusone_ea'] && !$product['oneplusone_cross']) {
// list($subopt_xml,$sub_tot_ea) = $this->oneplusone_xml_data($product);
// }
//네이버페이 > N+M 평균가증정품
// else if($this->shippingmodel->multi_order_cfg['oneplusonecross_use'] == 'Y' && $product['oneplusone'] && $product['cross_options']) {
// list($subopt_xml,$sub_tot_ea) = $this->oneplusone_cross_xml_data($product, $product['cross_options']);
// }
//상품주문 : 추가옵션
// else{
@SuppressWarnings("unchecked")
ArrayList<HashMap<String,String>> subOptionInfoList = (ArrayList<HashMap<String,String>>)product.get("suboptions");
suboptXml = suboption_xml_data(subOptionInfoList);
// }
int sub_tot_ea = 0;
int tot_ea = opt_tot_ea + sub_tot_ea;
String merchantProductId = "session_id"+System.currentTimeMillis(); //$session_tmp; $arr['session_id']."_".$arr['mktime']
/*
//옵션별 할인가
$opt_sale = $opt_code = array();
$opt_single_code = '';
foreach($opt_managecode as $managecode => $codedata){
//단일옵션일때 merchantcode에 옵션코드 포함 시키기
if($product['opttype'] == 'single'){
$merchant_product_id = $session_tmp."@".$managecode;
}else{
// interface 에 옵션별 할인가 포함(npay 주문 직전 금액 검증)
$opt_sale[] = $managecode."@".$codedata;
$opt_code[] = $managecode;
}
}
*/
//[배송방법 xml]
//선택한 배송방법(배송정책)
// list($shipping_xml,$return_ship_type) = $this->shipping_xml_data($shipping_packageId,$product['shipping_set'],$shipping_paytype,$tot_ea);
String shippingXml = "";
/*
$inp_cnt = 0;
if($product['options']){
foreach($product['options'] as $opt_k=>$opt){
foreach($opt['inputs'] as $inp_k=>$inp){
$inp_cnt++;
}
}
}
// 싱글옵션 : 옵션이 아무것도 없을때
if($product['options'][0]['type'] == "single" && $inp_cnt == 0){
$product['default_price'] = $product['default_price'] - abs($product['options'][0]['opt_add_price']);
}
*/
/*
//상품정보확인 URL 생성
$goods_info_product = array();
//2019.03.11 lsm 상품연동 처리
$goods_info_product['id'] = $product[NAVER_GOODS_FIELD];
$goods_info_product['merchantProductId'] = base64_encode($merchant_product_id);
$goods_info_product['optionManageCodes'] = implode(",",$opt_code);
$goods_info_product['return_ship_type'] = $return_ship_type;
*/
//상품명
String goodsName = (String)product.get("goods_name");
if(goodsName!=null && goodsName.length() > 100) goodsName = goodsName.substring(0, 100);
//이미지경로
String imageUrl = (String)product.get("images"); //product['images']['image'] == 받아오는 값을 조정하여 처리함
Pattern pattern = Pattern.compile("^(http|https)://");
Matcher matcher = pattern.matcher(imageUrl);
if(imageUrl != null && !matcher.find()){
imageUrl = "http://" + domain + imageUrl;
}
//최종적으로 해야 할 것은 xml 을 만드는 것이다.
xmlPrdt = new StringBuffer();
xmlPrdt.append("<product>")
.append("<id>").append(product.get("goods_seq")).append("</id>") //2019.03.11 lsm 상품연동 처리
.append("<merchantProductId>").append(Base64.getEncoder().encodeToString(merchantProductId.getBytes())).append("</merchantProductId>")
.append("<ecMallProductId>").append(product.get("goods_seq")).append("</ecMallProductId>") //2019.03.11 lsm 상품연동 처리
.append("<name>").append(goodsName).append("</name>")
.append("<basePrice>").append(product.get("default_price")).append("</basePrice>")
.append("<taxType>").append(taxtype).append("</taxType>")
.append("<infoUrl>").append(infoUrl).append("</infoUrl>")
.append("<imageUrl>").append(imageUrl).append("</imageUrl>")
.append(optXml) //옵션
.append(suboptXml) //추가상품
.append(shippingXml) //배송정보
.append("</product>");
}
return xmlPrdt.toString();
}
/*
* 뉴트리코어는 옵션을 5개로 고정되어 있음. 5개의 값이 있는지 여부에 따라 싱글(본품)주문인지 확인함. =>to_be는 4개
* */
// 상품주문 : 옵션
public String option_xml_data(ArrayList<HashMap<String,String>> opt){
StringBuffer optData = new StringBuffer();
ArrayList<String> returnManageCode = new ArrayList();
int optTotEa = 0;
String manageCod;
String optTitle;
String optVal;
String optId;
// 옵션
for (int i=0;i<opt.size();i++){
HashMap<String, String> optTmp = opt.get(i);
String optSeq = optTmp.get("option_seq");
int inputCnt = 0;
if(!optTmp.get("inputs").isEmpty()){ //optTmp.get("inputs")
//입력형이고 값이 있으면 카운트 ====> 카운트에 대한 이해 필요
// for($opt_tmp['inputs'] as $inp){
// if(trim($inp['input_value'])) $input_cnt++;
// }
inputCnt++;
}
optTotEa += Integer.parseInt(optTmp.get("ea"));
/*
<single> <!-- 옵션 상품 정보와 공존할 수 없다. -->
<quantity>5</quantity>
</single>
<option> <!-- 옵션 수량만큼 구성됨 -->
……
</option>
*/
// 옵션 정보가 없는 본상품 주문일 경우는 <single> 요소가 반드시 들어가야 한다.
if(!optTmp.get("option1").isEmpty() && !optTmp.get("option2").isEmpty() && !optTmp.get("option3").isEmpty()
&& !optTmp.get("option4").isEmpty() && inputCnt == 0){
optData.append(" <single>\n")
.append(" <quantity>").append(optTmp.get("ea")).append("</quantity>\n")
.append(" </single>\n");
manageCod = "opt1"+optSeq; //single code
//1개당 할인 받은 금액 --- 따로 넘겨주는 값인데 확인필요
//$return_manageCode[$manageCode] = $opt_tmp['one_total_sale_price'];
}else{
manageCod = "opt1"+optSeq;
if(!optTmp.get("option2").isEmpty()) manageCod += "_opt2"+optSeq;
if(!optTmp.get("option3").isEmpty()) manageCod += "_opt3"+optSeq;
if(!optTmp.get("option4").isEmpty()) manageCod += "_opt4"+optSeq;
//1개당 할인 받은 금액 --- 따로 넘겨주는 값인데 확인필요
//$return_manageCode[$manageCode] = $opt_tmp['one_total_sale_price'];
optData.append(" <option>\n")
.append(" <quantity>").append(optTmp.get("ea")).append("</quantity>\n")
.append(" <price>").append(optTmp.get("opt_add_price")).append("</price>\n") //옵션추가금액이 있을 경우
.append(" <manageCode>").append(manageCod).append("</manageCode>\n");
//선택옵션
for(int j=1; j<=4; j++){
optTitle = optTmp.get("title"+j);
optVal = optTmp.get("option"+j);
if(!optTmp.get("option"+j).isEmpty()) optId = "opt"+j+optSeq; else optId = "";
if(!optVal.isEmpty()) optData.append(option_xml_selectItem("SELECT",optId,optTitle,optVal));
}
//입력옵션
if(!optTmp.get("inputs").isEmpty()){
for(int j=0;j<optTmp.get("inputs").length();j++) {
optTitle = optTmp.get("input_title");
optVal = optTmp.get("input_value");
optId = "inp"+j+optSeq;
if(!optVal.isEmpty()) optData.append(option_xml_selectItem("INPUT",optId,optTitle,optVal));
}
}
optData.append(" </option>");
}
}
return optData.toString();
}
// 상품주문 : 옵션 XML 정리 : 선택한 옵션 정보. 옵션 종류만큼 반복한다 (색상 빨강, 사이즈S => 2번 작성됨)
public String option_xml_selectItem(String type, String id, String title, String value){
StringBuffer optData = new StringBuffer();
optData.append("<selectedItem>\n")
.append(" <type>").append(type).append("</type>\n")
.append(" <name><![CDATA[").append(title).append("]]></name>\n")
.append(" <value>\n")
.append(" <id>").append(id).append("</id>\n")
.append(" <text><![CDATA[").append(value).append("]]></text>\n")
.append(" </value>\n")
.append("</selectedItem>\n");
return optData.toString();
}
//주문수집 라이센스를 가져오나 이건 백단작업
// 상품주문 : 추가옵션
public String suboption_xml_data(ArrayList<HashMap<String,String>> subopt){
StringBuffer optData = new StringBuffer();
int subTotEa = 0;
String subId;
//추가옵션
if(subopt != null) {
for (int i=0;i<subopt.size();i++){
HashMap<String, String> optTmp = subopt.get(i);
if( NAVER_GOODS_FIELD.equals("goods_seq") ) {
subId = optTmp.get("option_code")+"_"+optTmp.get("suboption_seq");
}else{
subId = optTmp.get("option_seq")+"_"+optTmp.get("suboption_seq");
}
int subPrice = Integer.parseInt(optTmp.get("price"))-Integer.parseInt(optTmp.get("member_sale"));
optData.append(sub_option_xml_selectItem(subId, optTmp.get("suboption"), subPrice+"", optTmp.get("ea")));
//$sub_tot_ea += $val['ea'];
}
}
return optData.toString();
}
//네이버페이 > N+1 증정품 : 추가구성상품으로 전달 gcs ysm @2019-01-20
public String oneplusone_xml_data(ArrayList<HashMap<String,String>> subopt){
StringBuffer optData = new StringBuffer();
String subId;
String oneplusoneTermsText;
//추가옵션
for (int i=0;i<subopt.size();i++){
HashMap<String, String> optTmp = subopt.get(i);
//N+1 수량 체크 // N+1 -> N+M gcs ysm @2019-06-27
int opoEa = Integer.parseInt(optTmp.get("oneplusone_ea"));
int opoCnt = Integer.parseInt(optTmp.get("oneplusone_cnt"));
int opoCalc = 0;
if(opoEa == 1 && opoCnt == 1) {
opoCalc = Integer.parseInt(optTmp.get("ea"))*opoEa;
}else{
opoCalc = calculateOp(Integer.parseInt(optTmp.get("ea")), opoEa, opoCnt); // N+1 -> N+M (2019-04-04, guinee)
}
if(opoCalc!=0) {
oneplusoneTermsText = "["+opoEa+"+"+opoCnt+" 판매]"; //M+M판매
//N+1 증정품 개발 gcs ysm @2018-11-20
oneplusoneTermsText += "[본품증정]";
oneplusoneTermsText += optTmp.get("goods_name_real");
// $sub_tot_ea = $oneplusone;
//2019.03.11 lsm 상품연동 처리
subId = optTmp.get(NAVER_GOODS_FIELD)+"_";//+$product['options'][0]['option_seq']; 이부분 분석필요
optData.append(sub_option_xml_selectItem(subId, oneplusoneTermsText, 0+"", opoCalc+""));
}
}
return optData.toString();
}
/**
* 수량 계산
*/
public int calculateOp(int ea, int opoEa, int opoCnt){
return (ea/opoEa) * opoCnt; // N+1 -> N+M (2019-04-04, guinee)
}
//네이버페이 > N+M 평균가증정품 : 추가구성상품으로 전달 gcs ysm @2019-08-12
public String oneplusone_cross_xml_data(ArrayList<HashMap<String,String>> subopt, ArrayList<HashMap<String,String>> crossprdt){
StringBuffer optData = new StringBuffer();
// if(!$this->goodsmodel)$this->load->model('goodsmodel');
// if(!$this->shippingmodel)$this->load->model('shippingmodel');
// //debug($crossproducts);
// foreach($crossproducts as $crossproduct) {
// // 상품정보
// $cross_goods = $this->goodsmodel->get_goods($crossproduct['goods_seq']);
//
// if($this->shippingmodel->multi_order_cfg['oneplusonecross_use'] == 'Y') {
// $product['oneplusone_ea'] = $this->shippingmodel->multi_order_cfg['oneplusonecross_ea'];
// $product['oneplusone_cnt'] = $this->shippingmodel->multi_order_cfg['oneplusonecross_cnt'];
// }
// $oneplusone_terms_text = "[{$product['oneplusone_ea']}+".$product['oneplusone_cnt']." 판매]";
//
// //N+1 증정품 개발 gcs ysm @2018-11-20
// $oneplusone_terms_text .= "[평균가증정]";
// $cross_goods['goods_name'] = $oneplusone_terms_text.$cross_goods['goods_name'];
//
//
// unset($optJoin);
// if( $crossproduct['title1']!='' ) $optJoin[] = $crossproduct['title1'];
// if( $crossproduct['option1']!='' ) $optJoin[] = $crossproduct['option1'];
// if( $optJoin )$cross_goods['goods_name'] .= " ".implode(':',$optJoin);
//
//// $sub_tot_ea += $crossproduct['ea'];
//
// //[평균가증정]상품 연결상품 구조찾기 > 부모상품번호 _ 부모장바구니옵션공유번호_평균가증정 상품고유번호 _ 옵션고유번호_장바구니고유번호_장바구니옵션고유번호
// $id = $product[NAVER_GOODS_FIELD]."_".$product['options'][0]['option_seq']."_".$cross_goods['goods_seq']."_".$crossproduct['cross_option_seq']."_".$crossproduct['cart_seq']."_".$crossproduct['cart_option_seq'];
//
// $opt_data[] = ' <supplement>';
// $opt_data[] = ' <id>' .$id. '</id>';
// $opt_data[] = ' <name><![CDATA[' .$cross_goods['goods_name']. ']]></name>';
// $opt_data[] = ' <price>0</price>';
// $opt_data[] = ' <quantity>'.$crossproduct['ea'].'</quantity>';
// $opt_data[] = ' </supplement>';
// }
// $return_data = implode("\n",$opt_data);
// unset($opt_data);
//
return optData.toString();
}
//상품주문 : 배송정책 @2016-10-18
public String shipping_xml_data(){
// //std 기본, add 추가, hop 희망
// //배송정책 기본 사용여부
// if($shipping_set['std']){ $shipping_set_type = "std"; }
// //배송정책 희망배송 사용여부
// if($shipping_set['hop']){ $shipping_set_type = "hop"; }
//
// if($shipping_set['baserule']['shipping_set_code'] == "direct_store"){
// $shipping_set_type = "direct_store";
// }
//
// # 희망배송이 세팅된 배송방법 선택시 주문 불가.
// if($shipping_set_type == "hop"){
// $this->naverpaylib->order_except_msg("<span class=fx12>희망배송 사용오류!</span>");
// }
//
// if($shipping_set_type != "direct_store" && $shipping_set_type != "std"){
// $this->naverpaylib->order_except_msg("<span class=fx12>기본배송정책 사용안함 오류!</span>");
// }
//
// //groupId : 배송비 묶음 그룹 ID
// //$groupId = $shipping_set['shipping_group_seq'];
// //$setId = $shipping_set['shipping_set_seq'];
// //$shipping_packageId = str_pad($groupId,4,"0",STR_PAD_LEFT).str_pad($setId,4,"0",STR_PAD_LEFT);
//
// $debug_log[] = "배송그룹번호 : ".$groupId;
// $debug_log[] = "배송방법번호 : ".$setId;
// $debug_log[] = "배송비 결제방법 : ".$shipping_paytype;
// $debug_log[] = "기본배송정책사용 : ".$shipping_set_type;
//
//
// // method : 배송방법
// // - 택배소포등기 DELIVERY (무료, 유료, 조건부무료, 수량별 부과)
// // - 퀵서비스 QUICK_SVC => npay 강제 적용 : 배송비 묶음 불가, 유료, 착불, 배송비 빈값
// // - 직접배달 DIRECT_DELIVERY => 사용안함
// // - 방문수령 VISIT_RECEIPT => npay 강제 적용 : 배송비 묶음 불가, 무료
// // - 배송없음 NOTHING => 사용안함
// // paytype : 배송비 지급방법(선불 PREPAYED /착불 CASH_ON_DELIVERY)
// // feeType : 배송비 유형(무료 FREE, 유료:CHARGE, 조건부무료:CONDITIONAL_FREE, 수량별부과 : CHARGE_BY_QUANTITY)
// $ship_return = $this->shipping_method_type($shipping_set,$shipping_paytype);
// $shipping_check_msg = $ship_return['shipping_check_msg']; //배송정책 체크 결과 메세지
// String method = $ship_return['method']; //배송방법
// $feePayType = $ship_return['fee_paytype']; //배송비 지급방법
// String feeType = $ship_return['fee_type']; //배송비 유형
// $basePrice = (!$ship_return['basic_price'])? "0":$ship_return['basic_price']; //조건부무료 기준배송비
// $feePrice = (!$ship_return['fee_price'])? "0":$ship_return['fee_price']; //기본배송비
// $add_shipping = $ship_return['add_shipping']; //추가배송비
//
// if($shipping_check_msg){
// $this->naverpaylib->order_except_msg("<span class=fx12>배송방법/배송비지급방법/배송비유형 오류!</span>");
// }
//
// # 수량별반복부과시 추가 세팅
// if($feeType == "CHARGE_BY_QUANTITY"){
// $charge_by_quantity_type = "REPEAT";
// $repeat_ea = $shipping_set['std'][1]['section_ed']; //반복수량
// }
//
// # 배송조건 부합시 실제 부과될 배송비
// if($feeType == "CHARGE_BY_QUANTITY"){
// $feePrice_tmp = $feePrice * ceil(($tot_ea+0.01) / $repeat_ea);
// }else{
// $feePrice_tmp = $feePrice;
// }
// //결제시 상품정보 검증용(배송그룹, 배송비 결제방법, 배송금액)
// $return_shipping_type = $shipping_basic['shipping_group']."@".$feePayType."@".$feePrice_tmp;
// XML REQUEST -----------------------------------------------------------------
String feeType = "";
String addShipping = "";
String charge_by_quantity_type = "";
int repeat_ea = 0;
StringBuffer shipData = new StringBuffer();
shipData.append(" <shippingPolicy>")
.append(" <groupId>").append("shipping_packageId").append("</groupId>")
.append(" <method>").append("method").append("</method>'")
.append(" <feeType>").append("feeType").append("</feeType>")
.append(" <feePayType>").append("feePayType").append("</feePayType>")
.append(" <feePrice>").append("feePrice").append("</feePrice>"); //기본배송비
//조건부무료
if(feeType.equals("CONDITIONAL_FREE")) {
shipData.append(" <conditionalFree>")
.append(" <basePrice>").append("basePrice").append("</basePrice>")
.append(" </conditionalFree>");
//수량별 부과
} else if (feeType.equals("CHARGE_BY_QUANTITY")) {
shipData.append(" <chargeByQuantity>");
//일정 수량별 반복 부과:REPEAT
shipData.append(" <type>").append(charge_by_quantity_type).append("</type>");
if (charge_by_quantity_type == "REPEAT") {
// 포장 단위별 추가 배송비 설정 항목이 없을때만 사용.
shipData.append(" <repeatQuantity>").append(repeat_ea).append("</repeatQuantity>");
} else if (charge_by_quantity_type == "RANGE") {
// 수량 구간별 => 사용 안함.
}
shipData.append(" </chargeByQuantity>");
}
//surchargeByArea : 지역별 배송비. 지역별 추가 배송비를 사용하고, 가맹점 별도 API를 사용하지 않는 경우에만 입력.
if (!addShipping.equals("")) {
shipData.append(" <surchargeByArea>")
.append(" <apiSupport>true</apiSupport>") //지역별 배송비 조회 API 사용
.append(" </surchargeByArea>");
}
shipData.append(" </shippingPolicy>");
//------------------------------------------------------------------------------
return shipData.toString();
}
// 상품주문 : 추가상품 xml
public String sub_option_xml_selectItem(String id, String name, String price, String quantity){
StringBuffer optData = new StringBuffer();
optData.append("<supplement>\n")
.append(" <id>").append(id).append("</id>\n")
.append(" <name><![CDATA[").append(name).append("]]></name>\n")
.append(" <price>").append(price).append("</price>\n")
.append(" <quantity>").append(quantity).append("</quantity>\n")
.append("</supplement>\n");
return optData.toString();
}
//------------- XML 구성하기 ---------------------------------------
// 코드 매핑
public String get_npay_code_mapping(String code){//($mode,$code){
String rtnCode = "";
// switch($mode){
// case "shipping_method":
//delivery','direct','quick','postpaid'
switch(code){
case "DELIVERY": rtnCode = "delivery"; break; //택배,등기,소포
case "GDFW_ISSUE_SVC": rtnCode = ""; break; //굿스플로 송장 출력";
case "VISIT_RECEIPT": rtnCode = "direct"; break; //방문수령";
case "DIRECT_DELIVERY": rtnCode = ""; break; //직접전달";
case "QUICK_SVC": rtnCode = "quick"; break; //퀵서비스";
case "NOTHING": rtnCode = ""; break; //배송없음";
case "RETURN_DESIGNATED": rtnCode = ""; break; //지정반품택배";
case "RETURN_DELIVERY": rtnCode = ""; break; //일반반품택배";
case "RETURN_INDIVIDUAL": rtnCode = ""; break; //직접반송";
}
// break;
// }
return rtnCode;
}
// 상품정보 네이버로 전송
public String npayOrderApi(String code) throws MalformedURLException{//($mode,$code){
String sendMakeXml = "";
//1. XML 정보 구성
//1-1. 인증정보 포함 header 구성
sendMakeXml = set_header();
//1-2. 인터페이스정보 구성
sendMakeXml = set_interface();
//1-3. 상품정보 구성 - 상품정보, 배송정보, 옵션정보, 추가상품정보
ArrayList $arr = new ArrayList();
HashMap<String,Object> product = new HashMap<String,Object>();
int totalSale=0;
sendMakeXml = product_xml_data($arr,product,totalSale);
//1-4. footer 구성
sendMakeXml = set_footer();
//2. 네이버로 전송 후 결과 받음
get_license_info("buy", "test", "PC");
NaverPay sample = new NaverPay(targetUrl);
//response = resultCode=Success&인증키={네이버페이 인증키}&가맹점번호={가맹점번호}
//$requestParam = 인증키={네이버페이 인증키}/가맹점번호={가맹점번호}
String result="";
try {
result = sample.sendToNC(sendMakeXml );
} catch (IOException e) {
throw new WnbtException(ErrCode.BAD_REQUEST, e.getMessage());
}
//3. 네이버 주문서로 Redirect 시킬 url 리턴
return targetLink+"?"+result;
}
/* test 환경에서는 인증서 오류가 날 수도 있다. 이 코드를 이용해 인증서 오류를 회피한다. */
private void _initHttps() {
TrustManager[] trustAllCerts = new TrustManager[]
{new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
};
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new SecureRandom());
_sslSockFactory = sslContext.getSocketFactory();
} catch (WnbtException wre) {
throw new WnbtException(ErrCode.BAD_REQUEST);
} catch(Exception e) {
RuntimeException re = new RuntimeException(e);
throw re;
}
}
public String sendToNC(String sendXml) throws IOException {
HttpURLConnection conn = null;
String retStr = "";
try {
conn = (HttpURLConnection)_url.openConnection();
/* test 환경에서는 인증서 오류가 날 수도 있다. 이 코드를 이용해 인증서 오류를 회피한다. */
if (conn instanceof HttpsURLConnection) {
((HttpsURLConnection)conn).setSSLSocketFactory(_sslSockFactory);
((HttpsURLConnection)conn).setHostnameVerifier(
new HostnameVerifier(){
@Override
public boolean verify(String hostname, SSLSession session) {
HostnameVerifier defaultVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
return defaultVerifier.verify(hostname, session);
}
}
);
}
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
try (Writer writer = new OutputStreamWriter(conn.getOutputStream(), ENCODING)) {
writer.write(sendXml);
}
int respCode = conn.getResponseCode();
if (respCode != 200) {
throw new RuntimeException(String.format("NC Response fail : %d %s", respCode, conn.getResponseMessage()));
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
retStr = reader.readLine();
} catch (WnbtException wre) {
throw new WnbtException(ErrCode.BAD_REQUEST, wre.getMessage());
}
} catch (WnbtException wre) {
throw new WnbtException(ErrCode.BAD_REQUEST, wre.getMessage());
} finally {
if(conn != null) {
conn.disconnect();
}
}
return retStr;
}
/**
* @param items 주문 상품 목록.
* @return 주문키
* @throws IOException
*/
public String[] sendZzimToNC(String shopId, String certificationKey, ItemStack[] items) throws IOException {
HttpURLConnection conn = null;
String[] result = null;
try {
conn = (HttpURLConnection)_url.openConnection();
/* test 환경에서는 인증서 오류가 날 수도 있다. 이 코드를 이용해 인증서 오류를 회피한다. */
if (conn instanceof HttpsURLConnection) {
((HttpsURLConnection)conn).setSSLSocketFactory(_sslSockFactory);
((HttpsURLConnection)conn).setHostnameVerifier(
new HostnameVerifier(){
@Override
public boolean verify(String hostname, SSLSession session) {
HostnameVerifier defaultVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
return defaultVerifier.verify(hostname, session);
}
}
);
}
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
try (Writer writer = new OutputStreamWriter(conn.getOutputStream(), ENCODING)) {
writer.write("data to send");
writer.write("");
writer.flush();
}
int respCode = conn.getResponseCode();
if (respCode != 200) {
throw new RuntimeException(String.format("NC Response fail : %d %s", respCode, conn.getResponseMessage()));
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
String retStr = reader.readLine();
if(retStr != null) {
result = retStr.split(",");
}
} catch (WnbtException e) {
throw new WnbtException(ErrCode.BAD_REQUEST, e.getMessage());
}
} catch (WnbtException e) {
throw new WnbtException(ErrCode.BAD_REQUEST, e.getMessage());
} finally {
if(conn != null) {
conn.disconnect();
}
}
return result;
}
private void urlEncode(StringBuffer sb, String key, String value) {
try {
sb.append(URLEncoder.encode(key, ENCODING)); //php예제에서는 키는 encoding 안함
sb.append('=');
sb.append(URLEncoder.encode(value, ENCODING));
}
catch(UnsupportedEncodingException e) {
//일어나지 않음
throw new Error(e);
}
}
public static void main(String[] args) throws IOException {
//주문상품 내역으로 items 데이터를 생성한다. ==> DB에서 읽어옴
List<ItemStack> items = new ArrayList<ItemStack>();
items.add(new ItemStack("a1", "아이템1", 1000, "http://mymall.com/images/a1.jpg", "http://mymall.com/iteminfo?item_id=a1"));
items.add(new ItemStack("a2", "아이템2", 1000, "http://mymall.com/images/a2.jpg", "http://mymall.com/iteminfo?item_id=a2"));
// JavaZzimSample sample = new JavaZzimSample("https://test-pay.naver.com/customer/api/wishlist.nhn");
NaverPay sample = new NaverPay("https://pay.naver.com/customer/api/wishlist.nhn");
//알파랩
String shopId = "np_nbxsi348787";
String certificationKey = "641914BE-67E4-4195-950C-431F3EB292EE"; //[1200047309, 1200047310] //[1229584613, 1229584614]
//그래스팜
// String shopId = "np_mruyo723355";
// String certificationKey = "892CEEEE-0CED-499D-A78A-DCA6A1B407E4"; //[1200047344, 1200047345]//[1229584649, 1229584650]
String[] prodSeqs = sample.sendZzimToNC(shopId, certificationKey, items.toArray(new ItemStack[0]));
//여기서 얻은prodSeqs로 zzim popup을 띄운다.
System.out.println(Arrays.toString(prodSeqs));
}
}