쇼핑몰에서 재고 관리는 무엇보다 중요하다. 그래서 WMS 시스템 같은 것을 직접 만들거나 외부 솔루션을 이용하거나 해서 재고 관리를 하는 경우가 많다. 여기서는 그렇게까지는 못해도 WMS 비슷하게 흉내를 내서 해보려고 한다. WMS 테이블을 만들어서 작업을 해보자. 우선 테이블을 만들어보자.
CREATE TABLE `wms` ( `wid` int(11) NOT NULL AUTO_INCREMENT, `pid` int(11) DEFAULT NULL, `wcode` varchar(100) DEFAULT NULL, `cnt` int(11) DEFAULT NULL, `status` tinyint(4) DEFAULT 1, PRIMARY KEY (`wid`) ) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4;
늘 얘기하지만 테이블 설계에 정답은 없다. 그리고 영원한것도 없다. 일단 이렇게 만들어 보자.
자 이제 제품을 등록할때 재고는 wms 테이블에 저장할것이다. 여기서 중요한것은 제품이 옵션이 있는 경우 옵션에 따라 재고가 달라질 수 있다는 것이다. 그런것을 염두에 두고 작업을 해보자.
/admin/product/product_up.php
<?php
include $_SERVER [ "DOCUMENT_ROOT" ] . "/inc/header.php" ;
if (! $_SESSION [ 'AUID' ]){
echo "<script>alert('권한이 없습니다.');history.back();</script>" ;
exit ;
}
$query = "select * from category where step=1" ;
$result = $mysqli -> query ( $query ) or die ( "query error => " . $mysqli -> error );
while ( $rs = $result -> fetch_object ()){
$cate1 []= $rs ;
}
? >
< style >
.thst {
text-align : center ;
vertical-align : middle ;
}
</ style >
< div style = " text-align:center;padding:20px; " >< H3 > 제품등록하기 </ H3 ></ div >
< form method = "post" action = "pupok.php" onsubmit = " return save () " enctype = "multipart/form-data" >
< table class = "table table-sm table-bordered" >
< tbody >
< input type = "hidden" name = "file_table_id" id = "file_table_id" value = "" >
< input type = "hidden" name = "contents" id = "contents" value = "" >
< tr >
< th scope = "row" class = "thst" > 카테고리선택 </ th >
< td >
< div class = "row g-3" >
< div class = "col-md-4" >
< select class = "form-select" name = "cate1" id = "cate1" aria-label = "Default select example" >
< option value = "" > 대분류 </ option >
<?php
foreach ( $cate1 as $c ){
? >
< option value = " <?php echo $c -> code ; ? > " > <?php echo $c -> name ; ? > </ option >
<?php } ? >
</ select >
</ div >
< div class = "col-md-4" >
< select class = "form-select" name = "cate2" id = "cate2" aria-label = "Default select example" >
< option value = "" > 중분류 </ option >
</ select >
</ div >
< div class = "col-md-4" >
< select class = "form-select" name = "cate3" id = "cate3" aria-label = "Default select example" >
< option value = "" > 소분류 </ option >
</ select >
</ div >
</ div >
</ td >
</ tr >
< tr >
< th scope = "row" class = "thst" > 제품명 </ th >
< td >< input type = "text" class = "form-control" name = "name" id = "name" ></ td >
</ tr >
< tr >
< th scope = "row" class = "thst" > 택배비 </ th >
< td >< input type = "number" style = " width:200px;text-align:right; " class = "form-control" name = "delivery_fee" id = "delivery_fee" ></ td >
</ tr >
< tr >
< th scope = "row" class = "thst" > 제품가격 </ th >
< td >< input type = "number" style = " width:200px;text-align:right; " class = "form-control" name = "price" id = "price" ></ td >
</ tr >
< tr >
< th scope = "row" class = "thst" > 세일가격 </ th >
< td >< input type = "number" style = " width:200px;text-align:right; " class = "form-control" name = "sale_price" id = "sale_price" ></ td >
</ tr >
< tr >
< th scope = "row" class = "thst" > 세일비율 </ th >
< td >< input type = "number" style = " width:200px;text-align:right; " class = "form-control" name = "sale_ratio" id = "sale_ratio" ></ td >
</ tr >
< tr >
< th scope = "row" class = "thst" > 전시옵션 </ th >
< td >
< input class = "form-check-input" type = "checkbox" name = "ismain" id = "ismain" value = "1" > 메인
< input class = "form-check-input" type = "checkbox" name = "isnew" id = "isnew" value = "1" > 신제품
< input class = "form-check-input" type = "checkbox" name = "isbest" id = "isbest" value = "1" > 베스트
< input class = "form-check-input" type = "checkbox" name = "isrecom" id = "isrecom" value = "1" > 추천
</ td >
</ tr >
< tr >
< th scope = "row" class = "thst" > 위치지정 </ th >
< td >
< select class = "form-select" name = "locate" id = "locate" aria-label = "Default select example" >
< option value = "0" > 지정안함 </ option >
< option value = "1" > 1번위치 </ option >
< option value = "2" > 2번위치 </ option >
</ select >
</ td >
</ tr >
< tr >
< th scope = "row" class = "thst" > 판매종료일 </ th >
< td >
< input type = "text" class = "form-control" style = " width: 272px; " name = "sale_end_date" id = "sale_end_date" value = " <?php echo date ( "Y-m-d" , strtotime ( "+6 month" )) ? > " >
</ td >
</ tr >
< tr >
< th scope = "row" class = "thst" > 제품상세설명 </ th >
< td >
< div id = "summernote" ></ div >
</ td >
</ tr >
< tr >
< th scope = "row" class = "thst" > 썸네일 </ th >
< td >< input type = "file" class = "form-control" name = "thumbnail" id = "thumbnail" ></ td >
</ tr >
< tr style = " max-height:100px; " >
< th scope = "row" class = "thst" > 추가이미지 </ th >
< td style = " height:100px; " >
< input type = "file" multiple name = "upfile[]" id = "upfile" style = " display:none; " >
< div id = "target_file_wrap" >
< a href = "#" onclick = " jQuery ('#upfile'). click () " class = "btn btn-primary" > 이미지선택 </ a >
</ div >
< div class = "row row-cols-1 row-cols-md-6 g-4" id = "imageArea" >
</ div >
</ td >
</ tr >
< tr >
< th scope = "row" class = "thst" >
< select class = "form-select" name = "optionCate1" id = "optionCate1" >
< option value = "컬러" selected > 컬러 </ option >
</ select >
</ th >
< td >
< table class = "table" >
< thead >
< tr >
< th scope = "col" > 옵션명 </ th >
< th scope = "col" > 가격 </ th >
< th scope = "col" > 이미지 </ th >
</ tr >
</ thead >
< tbody id = "option1" >
< tr id = "optionTr1" >
< th scope = "row" >
< input class = "form-control opname1" type = "text" style = " max-width:200px; " value = "" name = "optionName1[]" >
</ th >
< td >
< div class = "input-group" >
< input type = "text" class = "form-control" style = " max-width:100px; " value = "0" name = "optionPrice1[]" >
< span class = "input-group-text" > 원 </ span >
</ div >
</ td >
< td >
< input type = "file" class = "form-control" name = "optionImage1[]" id = "optionImage1" >
</ td >
</ tr >
</ tbody >
</ table >
< button class = "btn btn-secondary" type = "button" onclick = " opt1cp () " > 옵션추가 </ button >
</ td >
</ tr >
< tr >
< th scope = "row" class = "thst" >
< select class = "form-select" name = "optionCate2" id = "optionCate2" >
< option value = "사이즈" selected > 사이즈 </ option >
</ select >
</ th >
< td >
< table class = "table" >
< thead >
< tr >
< th scope = "col" style = " width:300px; " > 옵션명 </ th >
< th scope = "col" > 가격 </ th >
</ tr >
</ thead >
< tbody id = "option2" >
< tr id = "optionTr2" >
< th scope = "row" >
< input class = "form-control opname2" type = "text" style = " max-width:200px; " value = "" name = "optionName2[]" >
</ th >
< td >
< div class = "input-group" >
< input type = "text" class = "form-control" style = " max-width:100px; " value = "0" name = "optionPrice2[]" >
< span class = "input-group-text" > 원 </ span >
</ div >
</ td >
</ tr >
</ tbody >
</ table >
< button class = "btn btn-secondary" type = "button" onclick = " opt2cp () " > 옵션추가 </ button >
</ td >
</ tr >
< tr >
< th scope = "row" class = "thst" > 재고 </ th >
< td >
< div id = "wmsArea" >
</ div >
< button class = "btn btn-secondary" type = "button" onclick = " wmsIns () " > 재고입력 </ button >
</ td >
</ tr >
</ tbody >
</ table >
< button class = "btn btn-primary" type = "submit" > 등록완료 </ button >
</ form >
< link rel = "stylesheet" href = "//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" >
< script >
function wmsIns (){
$ ( "#wmsArea" ). html ( "" );
var addHtml = "" ;
$ ( ".opname1" ). each ( function ( idx ){
var n1 = $ ( this ). val ();
$ ( ".opname2" ). each ( function ( idx ){
var n2 = $ ( this ). val ();
if ( n1 && n2 ){
addHtml += '<li style="display:flex;padding-bottom:5px;">' + n1 + ' X ' + n2 + ' <input type="text" class="form-control" style="max-width:100px;" name="wms[]" value="0">개</li>' ;
} else if ( n1 && ! n2 ){
addHtml += '<li style="display:flex;padding-bottom:5px;">' + n1 + ' <input type="text" class="form-control" style="max-width:100px;" name="wms[]" value="0">개</li>' ;
} else if (! n1 && n2 ){
addHtml += '<li style="display:flex;padding-bottom:5px;">' + n2 + ' <input type="text" class="form-control" style="max-width:100px;" name="wms[]" value="0">개</li>' ;
} else {
addHtml += '<li style="display:flex;padding-bottom:5px;"> <input type="text" class="form-control" style="max-width:100px;" name="wms[]" value="0">개</li>' ;
}
});
});
$ ( "#wmsArea" ). append ( addHtml );
}
function opt1cp (){
var addHtml = $ ( "#optionTr1" ). html ();
var addHtml = "<tr>" + addHtml + "</tr>" ;
$ ( "#option1" ). append ( addHtml );
}
function opt2cp (){
var addHtml = $ ( "#optionTr2" ). html ();
var addHtml = "<tr>" + addHtml + "</tr>" ;
$ ( "#option2" ). append ( addHtml );
}
function save (){
var markup = $ ( '#summernote' ). summernote ( 'code' );
var contents = encodeURIComponent ( markup );
$ ( "#contents" ). val ( contents );
}
$ ( function (){
$ ( '#summernote' ). summernote ({
height: 300
});
$ ( "#sale_end_date" ). datepicker ({ dateFormat: 'yy-mm-dd' });
});
$ ( "#cate1" ). change ( function (){
var cate1 = $ ( "#cate1 option:selected" ). val ();
var data = {
cate1 : cate1
};
$ . ajax ({
async : false ,
type : 'post' ,
url : 'category2.php' ,
data : data ,
dataType : 'html' ,
error : function () {} ,
success : function ( return_data ) {
$ ( "#cate2" ). html ( return_data );
}
});
});
$ ( "#cate2" ). change ( function (){
var cate2 = $ ( "#cate2 option:selected" ). val ();
var data = {
cate2 : cate2
};
$ . ajax ({
async : false ,
type : 'post' ,
url : 'category3.php' ,
data : data ,
dataType : 'html' ,
error : function () {} ,
success : function ( return_data ) {
$ ( "#cate3" ). html ( return_data );
}
});
});
$ ( "#upfile" ). change ( function (){
var files = $ ( '#upfile' ). prop ( 'files' );
for ( var i = 0 ; i < files . length ; i ++) {
attachFile ( files [ i ]);
}
$ ( '#upfile' ). val ( '' );
});
function attachFile ( file ) {
var formData = new FormData ();
formData . append ( "savefile" , file );
$ . ajax ({
url: 'product_save_image.php' ,
data: formData ,
cache: false ,
contentType: false ,
processData: false ,
dataType : 'json' ,
type: 'POST' ,
success : function ( return_data ) {
if ( return_data . result == "member" ){
alert ( '로그인 하십시오.' );
return ;
} else if ( return_data . result == "size" ){
alert ( '10메가 이하만 첨부할 수 있습니다.' );
return ;
} else if ( return_data . result == "image" ){
alert ( '이미지 파일만 첨부할 수 있습니다.' );
return ;
} else if ( return_data . result == "error" ){
alert ( '첨부하지 못했습니다. 관리자에게 문의하십시오.' );
return ;
} else {
imgid = $ ( "#file_table_id" ). val () + return_data . imgid + "," ;
$ ( "#file_table_id" ). val ( imgid );
var html = "<div class='col' id='f_" + return_data . imgid + "'><div class='card h-100'><img src='/pdata/" + return_data . savename + "' class='card-img-top'><div class='card-body'><button type='button' class='btn btn-warning' onclick='file_del(" + return_data . imgid + ")'>삭제</button></div></div></div>" ;
$ ( "#imageArea" ). append ( html );
}
}
});
}
function file_del ( imgid ){
if (! confirm ( '삭제하시겠습니까?' )){
return false ;
}
var data = {
imgid : imgid
};
$ . ajax ({
async : false ,
type : 'post' ,
url : 'image_delete.php' ,
data : data ,
dataType : 'json' ,
error : function () {} ,
success : function ( return_data ) {
if ( return_data . result == "member" ){
alert ( '로그인 하십시오.' );
return ;
} else if ( return_data . result == "my" ){
alert ( '본인이 작성한 제품의 이미지만 삭제할 수 있습니다.' );
return ;
} else if ( return_data . result == "no" ){
alert ( '삭제하지 못했습니다. 관리자에게 문의하십시오.' );
return ;
} else {
$ ( "#f_" + imgid ). hide ();
}
}
});
}
</ script >
<?php
include $_SERVER [ "DOCUMENT_ROOT" ] . "/inc/footer.php" ;
? >
현재는 옵션이 없기때문에 재고입력이라는 버튼을 클릭하면 옵션명 없이 하나의 입력박스만 나온다. 옵션을 하나만 넣어보자.
그러면 재고입력 버튼을 클릭했을때 옵션마다 재고를 넣을수 있게 나온다. 이번엔 옵션이 두개일때를 해보자.
그러면 이렇게 조합해서 재고를 입력할 수 있게 나온다. 소스를 보면 각 재고를 배열로 입력할 수 있게 돼 있다.
<input type="text" class="form-control" style="max-width:100px;" name="wms[]" value="0">
이제 저장하는 파일에서 이 변수를 배열로 받아서 아까 만든 테이블에 코드에 맞춰서 입력해주면 된다.
/admin/product/pupok.php
<?php session_start ();
include $_SERVER [ "DOCUMENT_ROOT" ] . "/inc/dbcon.php" ;
ini_set ( 'display_errors' , '0' );
if (! $_SESSION [ 'AUID' ]){
echo "<script>alert('권한이 없습니다.');history.back();</script>" ;
exit ;
}
$cate = $_POST [ "cate1" ] . $_POST [ "cate2" ] . $_POST [ "cate3" ]; //대중소분류를 모두 저장한다.
$name = $_POST [ "name" ]; //제품명
$delivery_fee = $_POST [ "delivery_fee" ]; //택배비
$price = $_POST [ "price" ]; //가격
$sale_price = $_POST [ "sale_price" ]; //세일가
$sale_ratio = $_POST [ "sale_ratio" ]; //세일비율
$cnt = $_POST [ "cnt" ]?? 0 ; //재고
$contents = rawurldecode ( $_POST [ 'contents' ]); //제품 설명
$ismain = $_POST [ "ismain" ]; //메인
$isnew = $_POST [ "isnew" ]; //신상품
$isbest = $_POST [ "isbest" ]; //베스트
$isrecom = $_POST [ "isrecom" ]; //추천
$locate = $_POST [ "locate" ]; //위치
$sale_end_date = $_POST [ "sale_end_date" ]; //판매종료일
$file_table_id = $_POST [ "file_table_id" ]; //이미지
$file_table_id = rtrim ( $file_table_id , "," ); //오른쪽 끝에 , 삭제
$optionCate1 = $_POST [ "optionCate1" ]; //옵션분류
$optionCate2 = $_POST [ "optionCate2" ]; //옵션분류
$wms = $_REQUEST [ "wms" ]; //재고
if ( $_FILES [ "thumbnail" ][ "name" ]){ //첨부한 파일이 있으면
if ( $_FILES [ 'thumbnail' ][ 'size' ]> 10240000 ){ //10메가
echo "<script>alert('10메가 이하만 첨부할 수 있습니다.');history.back();</script>" ;
exit ;
}
if ( $_FILES [ 'thumbnail' ][ 'type' ]!= 'image/jpeg' and $_FILES [ 'thumbnail' ][ 'type' ]!= 'image/gif' and $_FILES [ 'thumbnail' ][ 'type' ]!= 'image/png' ){ //이미지가 아니면, 다른 type은 and로 추가
echo "<script>alert('이미지만 첨부할 수 있습니다.');history.back();</script>" ;
exit ;
}
$save_dir = $_SERVER [ 'DOCUMENT_ROOT' ] . "/pdata/" ; //파일을 업로드할 디렉토리
$filename = $_FILES [ "thumbnail" ][ "name" ];
$ext = pathinfo ( $filename ,PATHINFO_EXTENSION); //확장자 구하기
$newfilename = date ( "YmdHis" ) . substr ( rand (), 0 , 6 );
$thumbnail = $newfilename . "." . $ext ; //새로운 파일이름과 확장자를 합친다
if ( move_uploaded_file ( $_FILES [ "thumbnail" ][ "tmp_name" ], $save_dir . $thumbnail )){
$thumbnail = "/pdata/" . $thumbnail ;
} else {
echo "<script>alert('이미지를 등록할 수 없습니다. 관리자에게 문의해주십시오.');history.back();</script>" ;
exit ;
}
}
$sale_cnt = 0 ; //판매량
$query = " INSERT INTO products
( name , cate, content, thumbnail, price, sale_price, sale_ratio, cnt, sale_cnt, isnew, isbest, isrecom, ismain, locate , userid, sale_end_date, reg_date, delivery_fee)
VALUES (' $name '
, ' " . $cate . "'
, '" . $contents . "'
, '" . $thumbnail . "'
, '" . $price . "'
, '" . $sale_price . "'
, '" . $sale_ratio . "'
, " . $cnt . "
, " . $sale_cnt . "
, '" . $isnew . "'
, '" . $isbest . "'
, '" . $isrecom . "'
, '" . $ismain . "'
, '" . $locate . "'
, '" . $_SESSION [ 'AUID' ] . "'
, '" . $sale_end_date . "'
, now()
, '" . $delivery_fee . "'
)" ;
$rs = $mysqli -> query ( $query ) or die ( $mysqli -> error );
$pid = $mysqli -> insert_id ;
if ( $rs ){
//옵션부분
$optionName1 = $_REQUEST [ "optionName1" ]; //옵션명
$optionCnt1 = $_REQUEST [ "optionCnt1" ]; //재고
$optionPrice1 = $_REQUEST [ "optionPrice1" ]; //가격
$optionName2 = $_REQUEST [ "optionName2" ]; //옵션명
$optionCnt2 = $_REQUEST [ "optionCnt2" ]; //재고
$optionPrice2 = $_REQUEST [ "optionPrice2" ]; //가격
if ( $_FILES [ "optionImage1" ][ "name" ][ 0 ]){ //첨부한 파일이 있으면
for ( $k = 0 ; $k < count ( $_FILES [ "optionImage1" ][ "name" ]); $k ++){
if ( $_FILES [ 'optionImage1' ][ 'size' ][ $k ]> 10240000 ){ //10메가
echo "<script>alert('10메가 이하만 첨부할 수 있습니다.');history.back();</script>" ;
exit ;
}
if ( $_FILES [ 'optionImage1' ][ 'type' ][ $k ]!= 'image/jpeg' and $_FILES [ 'optionImage1' ][ 'type' ][ $k ]!= 'image/gif' and $_FILES [ 'optionImage1' ][ 'type' ][ $k ]!= 'image/png' ){ //이미지가 아니면, 다른 type은 and로 추가
echo "<script>alert('이미지만 첨부할 수 있습니다.');history.back();</script>" ;
exit ;
}
$save_dir = $_SERVER [ 'DOCUMENT_ROOT' ] . "/pdata/optiondata/" ; //파일을 업로드할 디렉토리
$filename = $_FILES [ "optionImage1" ][ "name" ][ $k ];
$ext = pathinfo ( $filename ,PATHINFO_EXTENSION); //확장자 구하기
$newfilename = date ( "YmdHis" ) . substr ( rand (), 0 , 6 );
$optionImage1 = $newfilename . "." . $ext ; //새로운 파일이름과 확장자를 합친다
if ( move_uploaded_file ( $_FILES [ "optionImage1" ][ "tmp_name" ][ $k ], $save_dir . $optionImage1 )){
$upload_option_image []= "/pdata/optiondata/" . $optionImage1 ;
}
}
}
$k = 0 ;
foreach ( $optionName1 as $on ){
if ( $on ){
$optQuery = " INSERT INTO testdb.product_options
(pid, cate, option_name, option_price, image_url)
VALUES ( " . $pid . ", '" . $optionCate1 . "', '" . $on . "', " . $optionPrice1 [ $k ] . ", '" . $upload_option_image [ $k ] . "')" ;
$ofs = $mysqli -> query ( $optQuery ) or die ( $mysqli -> error );
$poid = $mysqli -> insert_id ;
$op1 []= $poid ;
$k ++;
}
}
$k = 0 ;
foreach ( $optionName2 as $on ){
if ( $on ){
$optQuery = " INSERT INTO testdb.product_options
(pid, cate, option_name, option_price)
VALUES ( " . $pid . ", '" . $optionCate2 . "', '" . $on . "', " . $optionPrice2 [ $k ] . ")" ;
$ofs = $mysqli -> query ( $optQuery ) or die ( $mysqli -> error );
$poid = $mysqli -> insert_id ;
$op2 []= $poid ;
$k ++;
}
}
$j = 0 ;
if ( $op1 && $op2 ){
foreach ( $op1 as $c1 ){
foreach ( $op2 as $c2 ){
$wcode = $c1 . "_" . $c2 ;
$wmsQuery = " INSERT INTO testdb.wms
(pid, wcode, cnt)
VALUES ( " . $pid . ",'" . $wcode . "'," . $wms [ $j ] . ")" ;
$mysqli -> query ( $wmsQuery ) or die ( $mysqli -> error );
$j ++;
}
}
} else if ( $op1 && ! $op2 ){
foreach ( $op1 as $c1 ){
$wcode = $c1 ;
$wmsQuery = " INSERT INTO testdb.wms
(pid, wcode, cnt)
VALUES ( " . $pid . ",'" . $wcode . "'," . $wms [ $j ] . ")" ;
$mysqli -> query ( $wmsQuery ) or die ( $mysqli -> error );
$j ++;
}
} else if (! $op1 && $op2 ){
foreach ( $op2 as $c2 ){
$wcode = $c2 ;
$wmsQuery = " INSERT INTO testdb.wms
(pid, wcode, cnt)
VALUES ( " . $pid . ",'" . $wcode . "'," . $wms [ $j ] . ")" ;
$mysqli -> query ( $wmsQuery ) or die ( $mysqli -> error );
$j ++;
}
} else if (! $op1 && ! $op2 ){
$wmsQuery = " INSERT INTO testdb.wms
(pid, wcode, cnt)
VALUES ( " . $pid . ",'" . $wcode . "'," . $wms [ 0 ] . ")" ;
$mysqli -> query ( $wmsQuery ) or die ( $mysqli -> error );
}
if ( $file_table_id ){ //첨부한 이미지 테이블 업데이트
$upquery = "update product_image_table set pid=" . $pid . " where imgid in (" . $file_table_id . ")" ;
$fs = $mysqli -> query ( $upquery ) or die ( $mysqli -> error );
}
echo "<script>alert('등록했습니다.');location.href='/admin/product/product_list.php';</script>" ;
exit ;
} else {
echo "<script>alert('등록하지 못했습니다. 관리자에게 문의해주십시오.');history.back();</script>" ;
exit ;
}
? >
옵션이 몇개인가에 따라서 입력하는 방법이 달라지니 잘 확인해보자. 재고를 입력했으니 상세 화면에서 이걸 어떻게 처리할지 확인해보자.
/admin/product/product_view.php
<?php
include $_SERVER [ "DOCUMENT_ROOT" ] . "/inc/header.php" ;
if (! $_SESSION [ 'AUID' ]){
echo "<script>alert('권한이 없습니다.');history.back();</script>" ;
exit ;
}
//ini_set( 'display_errors', '1' );
$pid = $_GET [ 'pid' ];
$query = "select *, (select sum(cnt) from wms w where w.pid=p.pid) as sumcnt from products p where pid=" . $pid ;
$result = $mysqli -> query ( $query ) or die ( "query error => " . $mysqli -> error );
$rs = $result -> fetch_object ();
$query2 = "select * from product_options where cate='컬러' and pid=" . $pid ;
$result2 = $mysqli -> query ( $query2 ) or die ( "query error => " . $mysqli -> error );
while ( $rs2 = $result2 -> fetch_object ()){
$options1 []= $rs2 ;
}
$query2 = "select * from product_options where cate='사이즈' and pid=" . $pid ;
$result2 = $mysqli -> query ( $query2 ) or die ( "query error => " . $mysqli -> error );
while ( $rs2 = $result2 -> fetch_object ()){
$options2 []= $rs2 ;
}
? >
< style >
.col {
border : 1px solid #f1f1f1 ;
}
[ type = radio ] {
position : absolute ;
opacity : 0 ;
width : 0 ;
height : 0 ;
}
[ type = radio ] + span {
cursor : pointer ;
}
[ type = radio ] :checked + span {
outline : 5px solid indigo ;
}
</ style >
< div class = "container" >
< div class = "row" >
< div class = "col" style = " text-align:center; " >
< img id = "pimg" src = " <?php echo $rs -> thumbnail ; ? > " style = " max-width:200px; " >
</ div >
< div class = "col" >
< h3 > <?php echo $rs -> name ; ? > </ h3 >
< div >
가격 : < span id = "price" > <?php echo number_format ( $rs -> price ); ? > </ span > 원 < br >
재고 : < span id = "cnt" > <?php echo number_format ( $rs -> sumcnt ); ? > </ span > EA
</ div >
<?php if ( $options1 ){ ? >
<!-- <div>
옵션 :
<select name="poption" id="poption">
<option value="">선택하세요</option>
<?php foreach ( $options as $op ){ ? >
<option value=" <?php echo $op -> poid ; ? > "> <?php echo $op -> option_name ; ? > </option>
<?php } ? >
</select>
</div> -->
< br >
< div >
<?php foreach ( $options1 as $op1 ){ ? >
< input type = "radio" name = "poption1" id = "poption1_ <?php echo $op1 -> poid ; ? > " value = " <?php echo $op1 -> poid ; ? > " >
< span onclick = " jQuery ('#poption1_ <?php echo $op1 -> poid ; ? > '). click (); " style = " content:url( <?php echo $op1 -> image_url ; ? > );height:100px;width:100px; " ></ span >
</ input >
<?php } ? >
</ div >
< br >
< div >
<?php foreach ( $options2 as $op2 ){
$option_name = $op2 -> option_name ;
if ( $op2 -> option_price ) $option_name .= "(+" . number_format ( $op2 -> option_price ) . ")" ;
? >
< input type = "radio" name = "poption2" id = "poption2_ <?php echo $op2 -> poid ; ? > " value = " <?php echo $op2 -> poid ; ? > " >
< span onclick = " jQuery ('#poption2_ <?php echo $op2 -> poid ; ? > '). click (); " > <?php echo $option_name ; ? > </ span >
</ input >
<?php } ? >
</ div >
<?php } ? >
</ div >
</ div >
</ div >
< link rel = "stylesheet" href = "//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" >
< script >
$ ( "input[name='poption1']:radio,input[name='poption2']:radio" ). change ( function () {
var poid1 = $ ( 'input:radio[name="poption1"]:checked' ). val ();
var poid2 = $ ( 'input:radio[name="poption2"]:checked' ). val ();
var data = {
poid1 : poid1 ,
poid2 : poid2
};
$ . ajax ({
async : false ,
type : 'post' ,
url : 'option_change.php' ,
data : data ,
dataType : 'json' ,
error : function () {} ,
success : function ( data ) {
console . log ( data );
var price = parseInt ( data . option_price1 )+ parseInt ( data . option_price2 )+ <?php echo $rs -> price ; ? > ;
$ ( "#pimg" ). attr ( "src" , data . image_url );
$ ( "#price" ). text ( number_format ( price ));
$ ( "#cnt" ). text ( number_format ( data . cnt ));
}
});
});
function number_format ( num ){
return num . toString (). replace ( / \B (?=( \d {3} ) + (?! \d )) / g , ',' );
}
$ ( "#poption" ). change ( function (){
var poid = $ ( "#poption option:selected" ). val ();
var data = {
poid : poid
};
$ . ajax ({
async : false ,
type : 'post' ,
url : 'option_change.php' ,
data : data ,
dataType : 'json' ,
error : function () {} ,
success : function ( data ) {
var price = parseInt ( data . option_price )+ <?php echo $rs -> price ; ? > ;
$ ( "#pimg" ). attr ( "src" , data . image_url );
$ ( "#price" ). text ( number_format ( price ));
}
});
});
</ script >
<?php
include $_SERVER [ "DOCUMENT_ROOT" ] . "/inc/footer.php" ;
? >
옵션을 선택할때마다 거기에 해당하는 재고갯수와 가격을 불러와서 보여준다. 가격과 재고를 불러오는 파일을 확인해보자.
/admin/product/option_change.php
<?php session_start ();
include $_SERVER [ "DOCUMENT_ROOT" ] . "/inc/dbcon.php" ;
ini_set ( 'display_errors' , '0' );
$poid1 = $_POST [ 'poid1' ];
$poid2 = $_POST [ 'poid2' ];
$option_price1 = 0 ;
$option_price2 = 0 ;
$query = "select * from product_options where poid='" . $poid1 . "'" ;
$result = $mysqli -> query ( $query ) or die ( "query error => " . $mysqli -> error );
$rs = $result -> fetch_object ();
$image_url = $rs -> image_url ;
$option_price1 = $rs -> option_price ;
$wcode = $poid1 ;
if ( $poid2 ){
$query = "select * from product_options where poid='" . $poid2 . "'" ;
$result = $mysqli -> query ( $query ) or die ( "query error => " . $mysqli -> error );
$rs = $result -> fetch_object ();
$option_price2 = $rs -> option_price ;
$wcode = $poid1 . "_" . $poid2 ;
}
$query2 = "select cnt from wms where wcode='" . $wcode . "'" ;
$result2 = $mysqli -> query ( $query2 ) or die ( "query error => " . $mysqli -> error );
$rs2 = $result2 -> fetch_object ();
$wmscnt = $rs2 -> cnt ?? 0 ;
$data = array ( "image_url" => $image_url , "option_price1" => $option_price1 , "option_price2" => $option_price2 , "cnt" => $wmscnt );
echo json_encode ( $data );
? >
테이블에 들어 있는 값을 꺼내는 거니 넣을때보단 쉽다. 각 옵션에 맞춰 조합 후 확인하면 된다. 그리고 제품 리스트에서도 재고를 wms에서 가져오도록 수정하자.
/admin/product/product_list.php
<?php
include $_SERVER [ "DOCUMENT_ROOT" ] . "/inc/header.php" ;
if (! $_SESSION [ 'AUID' ]){
echo "<script>alert('권한이 없습니다.');history.back();</script>" ;
exit ;
}
$pageNumber = $_GET [ 'pageNumber' ]?? 1 ; //현재 페이지, 없으면 1
if ( $pageNumber < 1 ) $pageNumber = 1 ;
$pageCount = $_GET [ 'pageCount' ]?? 10 ; //페이지당 몇개씩 보여줄지, 없으면 10
$startLimit = ( $pageNumber - 1 )* $pageCount ; //쿼리의 limit 시작 부분
$firstPageNumber = $_GET [ 'firstPageNumber' ];
$cate1 = $_GET [ 'cate1' ];
$cate2 = $_GET [ 'cate2' ];
$cate3 = $_GET [ 'cate3' ];
$ismain = $_GET [ "ismain" ];
$isnew = $_GET [ "isnew" ];
$isbest = $_GET [ "isbest" ];
$isrecom = $_GET [ "isrecom" ];
$sale_end_date = $_GET [ "sale_end_date" ];
$search_keyword = $_GET [ "search_keyword" ];
$query = "select * from category where step=1" ;
$result = $mysqli -> query ( $query ) or die ( "query error => " . $mysqli -> error );
while ( $rs = $result -> fetch_object ()){
$cate1array []= $rs ;
}
if ( $cate1 ){
$query = "select * from category where step=2 and pcode='" . $cate1 . "'" ;
$result = $mysqli -> query ( $query ) or die ( "query error => " . $mysqli -> error );
while ( $rs = $result -> fetch_object ()){
$cate2array []= $rs ;
}
}
if ( $cate2 ){
$query = "select * from category where step=3 and pcode='" . $cate2 . "'" ;
$result = $mysqli -> query ( $query ) or die ( "query error => " . $mysqli -> error );
while ( $rs = $result -> fetch_object ()){
$cate3array []= $rs ;
}
}
$scate = $cate1 . $cate2 . $cate3 ; //카테고리를 모두 묶음
if ( $scate ){
$search_where = " and cate like '" . $scate . "%'" ; //like 검색으로 검색
}
if ( $ismain ){ //값이 있는 경우에만 검색 조건에 추가한다.
$search_where .= " and ismain=1" ;
}
if ( $isnew ){
$search_where .= " and isnew=1" ;
}
if ( $isbest ){
$search_where .= " and isbest=1" ;
}
if ( $isrecom ){
$search_where .= " and isrecom=1" ;
}
if ( $sale_end_date ){
$search_where .= " and sale_end_date<='" . $sale_end_date . "'" ;
}
if ( $search_keyword ){
$search_where .= " and (name like '%" . $search_keyword . "%' or content like '%" . $search_keyword . "%')" ; //like 검색으로 검색
}
$sql = "select *, (select sum(cnt) from wms w where w.pid=p.pid) as sumcnt from products p where 1=1" ;
$sql .= $search_where ;
$order = " order by pid desc" ; //마지막에 등록한걸 먼저 보여줌
$limit = " limit $startLimit , $pageCount " ;
$query = $sql . $order . $limit ;
//echo "query=>".$query."<br>";
$result = $mysqli -> query ( $query ) or die ( "query error => " . $mysqli -> error );
while ( $rs = $result -> fetch_object ()){
$rsc []= $rs ;
}
//전체게시물 수 구하기
$sqlcnt = "select count(*) as cnt from products where 1=1" ;
$sqlcnt .= $search_where ;
$countresult = $mysqli -> query ( $sqlcnt ) or die ( "query error => " . $mysqli -> error );
$rscnt = $countresult -> fetch_object ();
$totalCount = $rscnt -> cnt ; //전체 갯수를 구한다.
$totalPage = ceil ( $totalCount / $pageCount ); //전체 페이지를 구한다.
if ( $firstPageNumber < 1 ) $firstPageNumber = 1 ;
$lastPageNumber = $firstPageNumber + $pageCount - 1 ; //페이징 나오는 부분에서 레인지를 정한다.
if ( $lastPageNumber > $totalPage ) $lastPageNumber = $totalPage ;
function isStatus ( $n ){
switch ( $n ) {
case - 1 : $rs = "판매중지" ;
break ;
case 0 : $rs = "대기" ;
break ;
case 1 : $rs = "판매중" ;
break ;
}
return $rs ;
}
? >
< div style = " text-align:center; " >< h3 > 제품 리스트 </ h3 ></ div >
< form method = "get" action = " <?php echo $_SERVER [ "PHP_SELF" ] ? > " >
< div class = "row g-3" style = " padding-bottom:10px; " >
< div class = "col-md-4" >
< select class = "form-select" name = "cate1" id = "cate1" aria-label = "Default select example" >
< option value = "" > 대분류 </ option >
<?php
foreach ( $cate1array as $c ){
? >
< option value = " <?php echo $c -> code ; ? > " <?php if ( $cate1 == $c -> code ){ echo "selected" ;} ? > > <?php echo $c -> name ; ? > </ option >
<?php } ? >
</ select >
</ div >
< div class = "col-md-4" >
< select class = "form-select" name = "cate2" id = "cate2" aria-label = "Default select example" >
< option value = "" > 중분류 </ option >
<?php
foreach ( $cate2array as $c ){
? >
< option value = " <?php echo $c -> code ; ? > " <?php if ( $cate2 == $c -> code ){ echo "selected" ;} ? > > <?php echo $c -> name ; ? > </ option >
<?php } ? >
</ select >
</ div >
< div class = "col-md-4" >
< select class = "form-select" name = "cate3" id = "cate3" aria-label = "Default select example" >
< option value = "" > 소분류 </ option >
<?php
foreach ( $cate3array as $c ){
? >
< option value = " <?php echo $c -> code ; ? > " <?php if ( $cate3 == $c -> code ){ echo "selected" ;} ? > > <?php echo $c -> name ; ? > </ option >
<?php } ? >
</ select >
</ div >
</ div >
< div class = "input-group mb-12" style = " width:100%;padding-bottom:10px; " >
< input class = "form-check-input" type = "checkbox" name = "ismain" id = "ismain" value = "1" <?php if ( $ismain ){ echo "checked" ;} ? > > 메인
< input class = "form-check-input" type = "checkbox" name = "isnew" id = "isnew" value = "1" <?php if ( $isnew ){ echo "checked" ;} ? > > 신제품
< input class = "form-check-input" type = "checkbox" name = "isbest" id = "isbest" value = "1" <?php if ( $isbest ){ echo "checked" ;} ? > > 베스트
< input class = "form-check-input" type = "checkbox" name = "isrecom" id = "isrecom" value = "1" <?php if ( $isrecom ){ echo "checked" ;} ? > > 추천
판매종료일: < input type = "text" class = "form-control" style = " max-width:150px; " name = "sale_end_date" id = "sale_end_date" value = " <?php echo $sale_end_date ? > " >
< input type = "text" class = "form-control" name = "search_keyword" id = "search_keyword" placeholder = "제목과 내용에서 검색합니다." value = " <?php echo $search_keyword ; ? > " aria-label = "Recipient's username" aria-describedby = "button-addon2" >
< button class = "btn btn-outline-secondary" type = "submit" id = "search" > 검색 </ button >
</ div >
</ form >
< form method = "get" name = "plist" action = "plist_save.php" >
< div style = " text-align:right;padding:10px; " >
< button class = "btn btn-primary" type = "submit" > 변경내용저장 </ button >
</ div >
< table class = "table table-sm table-bordered" >
< thead >
< tr style = " text-align:center; " >
< th scope = "col" > 사진 </ th >
< th scope = "col" > 제품명 </ th >
< th scope = "col" > 가격 </ th >
< th scope = "col" > 재고 </ th >
< th scope = "col" > 메인 </ th >
< th scope = "col" > 신제품 </ th >
< th scope = "col" > 베스트 </ th >
< th scope = "col" > 추천 </ th >
< th scope = "col" > 상태 </ th >
</ tr >
</ thead >
< tbody >
<?php
foreach ( $rsc as $r ){
? >
< input type = "hidden" name = "pid[]" value = " <?php echo $r -> pid ; ? > " >
< tr >
< th scope = "row" style = " width:100px; " >< img src = " <?php echo $r -> thumbnail ; ? > " style = " max-width:100px; " ></ th >
< td > <?php echo $r -> name ; ? > </ td >
< td style = " text-align:right; " >< s > <?php echo number_format ( $r -> price ); ? > 원 </ s >
<?php if ( $r -> sale_price > 0 ){ ? >
< br >
<?php echo number_format ( $r -> sale_price ); ? > 원
<?php } ? >
</ td >
< td style = " text-align:right; " > <?php echo number_format ( $r -> sumcnt ); ? > EA </ td >
< td style = " text-align:center; " >< input type = "checkbox" name = "ismain[ <?php echo $r -> pid ; ? > ]" id = "ismain_ <?php echo $r -> pid ; ? > " value = "1" <?php if ( $r -> ismain ){ echo "checked" ;} ? > ></ td >
< td style = " text-align:center; " >< input type = "checkbox" name = "isnew[ <?php echo $r -> pid ; ? > ]" id = "isnew_ <?php echo $r -> pid ; ? > " value = "1" <?php if ( $r -> isnew ){ echo "checked" ;} ? > ></ td >
< td style = " text-align:center; " >< input type = "checkbox" name = "isbest[ <?php echo $r -> pid ; ? > ]" id = "isbest_ <?php echo $r -> pid ; ? > " value = "1" <?php if ( $r -> isbest ){ echo "checked" ;} ? > ></ td >
< td style = " text-align:center; " >< input type = "checkbox" name = "isrecom[ <?php echo $r -> pid ; ? > ]" id = "isrecom_ <?php echo $r -> pid ; ? > " value = "1" <?php if ( $r -> isrecom ){ echo "checked" ;} ? > ></ td >
< td style = " text-align:center; " >
< select class = "form-select" style = " max-width:120px; " name = "stat[ <?php echo $r -> pid ; ? > ]" id = "stat" aria-label = "Default select example" >
< option value = "-1" <?php if ( $r -> status ==- 1 ){ echo "selected" ;} ? > > 판매중지 </ option >
< option value = "0" <?php if ( $r -> status == 0 ){ echo "selected" ;} ? > > 대기 </ option >
< option value = "1" <?php if ( $r -> status == 1 ){ echo "selected" ;} ? > > 판매중 </ option >
</ select >
</ td >
< td >
< a href = "product_view.php?pid= <?php echo $r -> pid ; ? > " >< button class = "btn btn-primary" type = "button" > 보기 </ button ></ a >
</ td >
</ tr >
<?php } ? >
</ tbody >
</ table >
</ form >
< a href = "product_up.php" >
< button class = "btn btn-primary" type = "button" > 제품등록 </ button >
</ a >
< link rel = "stylesheet" href = "//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" >
< script >
$ ( function (){
$ ( "#sale_end_date" ). datepicker ({ dateFormat: 'yy-mm-dd' });
});
$ ( "#cate1" ). change ( function (){
var cate1 = $ ( "#cate1 option:selected" ). val ();
var data = {
cate1 : cate1
};
$ . ajax ({
async : false ,
type : 'post' ,
url : 'category2.php' ,
data : data ,
dataType : 'html' ,
error : function () {} ,
success : function ( return_data ) {
$ ( "#cate2" ). html ( return_data );
}
});
});
$ ( "#cate2" ). change ( function (){
var cate2 = $ ( "#cate2 option:selected" ). val ();
var data = {
cate2 : cate2
};
$ . ajax ({
async : false ,
type : 'post' ,
url : 'category3.php' ,
data : data ,
dataType : 'html' ,
error : function () {} ,
success : function ( return_data ) {
$ ( "#cate3" ). html ( return_data );
}
});
});
</ script >
<?php
include $_SERVER [ "DOCUMENT_ROOT" ] . "/inc/footer.php" ;
? >
이런식으로 제품별 재고를 불러 올 수 있다.
만약 WMS 시스템이랑 연동한다면 더 복잡하겠지만 원리는 이런것이란 것만 알아두자.
제품등록을 화면에서 하는걸 알아보았는데 이렇게 화면에서 입력하는 경우도 많지만 엑셀이나 api를 통해서 입력하는 경우도 많다. 다음시간엔 엑셀을 통해 한꺼번에 많은 제품을 등록하는걸 해보자.