2026-06-01 16:15:15 +09:00
< ? php
declare ( strict_types = 1 );
namespace App\Libraries ;
/**
* LOT 수불 조회 ( 레거시 w_gd033a )
* — 바코드 ( 팩 / 박스 / 낱장 ) 또는 LOT 번호로 일자·입출고처·구분 이력
*/
class BagLotFlowBuilder
{
private \CodeIgniter\Database\BaseConnection $db ;
public function __construct ( ? \CodeIgniter\Database\BaseConnection $db = null )
{
$this -> db = $db ? ? \Config\Database :: connect ();
}
/**
* @ return array {
* ok : bool ,
* message : string ,
* barcode : string ,
* unit : string ,
* bag_code : string ,
* bag_name : string ,
* lot_no : string ,
* box_code : string ,
* pack_code : string ,
* qty_box : int ,
* qty_pack : int ,
* qty_sheet : int ,
* rows : list < array { flow_date : string , counterparty : string , flow_type : string , sort_ts : int } >
* }
*/
public function buildByBarcode ( int $lgIdx , string $barcode , bool $queried ) : array
{
$empty = $this -> emptyResult ( $barcode );
if ( ! $queried || trim ( $barcode ) === '' ) {
return $empty ;
}
$resolved = $this -> resolveBarcode ( $lgIdx , trim ( $barcode ));
if ( ! $resolved [ 'ok' ]) {
return array_merge ( $empty , [
'message' => ( string ) ( $resolved [ 'message' ] ? ? '등록되지 않은 바코드입니다.' ),
]);
}
$rows = $this -> collectFlowRows ( $lgIdx , $resolved );
usort ( $rows , static fn ( array $a , array $b ) : int => ( $a [ 'sort_ts' ] ? ? 0 ) <=> ( $b [ 'sort_ts' ] ? ? 0 ));
return array_merge ( $empty , [
'ok' => true ,
'message' => '' ,
'barcode' => ( string ) ( $resolved [ 'barcode' ] ? ? $barcode ),
'unit' => ( string ) ( $resolved [ 'unit' ] ? ? '' ),
'bag_code' => ( string ) ( $resolved [ 'bag_code' ] ? ? '' ),
'bag_name' => ( string ) ( $resolved [ 'bag_name' ] ? ? '' ),
'lot_no' => ( string ) ( $resolved [ 'lot_no' ] ? ? '' ),
'box_code' => ( string ) ( $resolved [ 'box_code' ] ? ? '' ),
'pack_code' => ( string ) ( $resolved [ 'pack_code' ] ? ? '' ),
'qty_box' => ( int ) ( $resolved [ 'qty_box' ] ? ? 0 ),
'qty_pack' => ( int ) ( $resolved [ 'qty_pack' ] ? ? 0 ),
'qty_sheet' => ( int ) ( $resolved [ 'qty_sheet' ] ? ? 0 ),
'rows' => $rows ,
]);
}
/**
* @ return array < string , mixed >
*/
public function buildByLotNo ( int $lgIdx , string $lotNo , bool $queried ) : array
{
$empty = $this -> emptyResult ( '' );
if ( ! $queried || trim ( $lotNo ) === '' ) {
return $empty ;
}
$lotNo = trim ( $lotNo );
if ( ! $this -> db -> tableExists ( 'bag_receiving_pack_code' )) {
return array_merge ( $empty , [ 'message' => '바코드(팩) 데이터가 없습니다.' ]);
}
$packRows = $this -> db -> table ( 'bag_receiving_pack_code' )
-> select ( 'brpc_pack_code, brpc_box_code, brpc_bag_code, brpc_bag_name, brpc_lot_no' )
-> where ( 'brpc_lg_idx' , $lgIdx )
-> where ( 'brpc_lot_no' , $lotNo )
-> limit ( 500 )
-> get ()
-> getResultArray ();
if ( $packRows === []) {
$order = $this -> db -> table ( 'bag_order' )
-> where ( 'bo_lg_idx' , $lgIdx )
-> where ( 'bo_lot_no' , $lotNo )
-> orderBy ( 'bo_version' , 'DESC' )
-> get ()
-> getRowArray ();
if ( ! $order ) {
return array_merge ( $empty , [ 'message' => '해당 LOT·바코드를 찾을 수 없습니다.' , 'lot_no' => $lotNo ]);
}
return $this -> buildLotFromOrderOnly ( $lgIdx , $lotNo , $order );
}
$codes = [];
$bagCode = '' ;
$bagName = '' ;
foreach ( $packRows as $p ) {
$codes [] = ( string ) ( $p [ 'brpc_pack_code' ] ? ? '' );
$box = ( string ) ( $p [ 'brpc_box_code' ] ? ? '' );
if ( $box !== '' ) {
$codes [] = $box ;
}
if ( $bagCode === '' ) {
$bagCode = ( string ) ( $p [ 'brpc_bag_code' ] ? ? '' );
$bagName = ( string ) ( $p [ 'brpc_bag_name' ] ? ? '' );
}
}
$codes = array_values ( array_unique ( array_filter ( $codes , static fn ( string $c ) : bool => $c !== '' )));
$rows = [];
foreach ( $this -> loadReceivingEventsForLot ( $lgIdx , $lotNo ) as $ev ) {
$rows [] = $ev ;
}
foreach ( $this -> loadScanEventsForCodes ( $lgIdx , $codes ) as $ev ) {
$rows [] = $ev ;
}
foreach ( $this -> loadReturnEventsForCodes ( $lgIdx , $codes ) as $ev ) {
$rows [] = $ev ;
}
usort ( $rows , static fn ( array $a , array $b ) : int => ( $a [ 'sort_ts' ] ? ? 0 ) <=> ( $b [ 'sort_ts' ] ? ? 0 ));
if ( count ( $rows ) > 500 ) {
$rows = array_slice ( $rows , - 500 );
}
return array_merge ( $empty , [
'ok' => true ,
'lot_no' => $lotNo ,
'bag_code' => $bagCode ,
'bag_name' => $bagName ,
'barcode' => $lotNo ,
'rows' => $rows ,
]);
}
/**
* @ return array < string , mixed >
*/
private function emptyResult ( string $barcode ) : array
{
return [
'ok' => false ,
'message' => '' ,
'barcode' => $barcode ,
'unit' => '' ,
'bag_code' => '' ,
'bag_name' => '' ,
'lot_no' => '' ,
'box_code' => '' ,
'pack_code' => '' ,
'qty_box' => 0 ,
'qty_pack' => 0 ,
'qty_sheet' => 0 ,
'rows' => [],
];
}
/**
* @ return array { ok : bool , message ? : string , barcode ? : string , unit ? : string , bag_code ? : string , bag_name ? : string , lot_no ? : string , box_code ? : string , pack_code ? : string , pack_ids ? : list < int > , qty_box ? : int , qty_pack ? : int , qty_sheet ? : int }
*/
private function resolveBarcode ( int $lgIdx , string $barcode ) : array
{
if ( ! $this -> db -> tableExists ( 'bag_receiving_pack_code' )) {
return [ 'ok' => false , 'message' => '바코드(팩) 데이터가 없습니다.' ];
}
$pack = $this -> db -> table ( 'bag_receiving_pack_code' )
-> where ( 'brpc_lg_idx' , $lgIdx )
-> where ( 'brpc_pack_code' , $barcode )
-> get ()
-> getRowArray ();
if ( $pack ) {
return $this -> resolvedFromPackRow ( $barcode , '팩' , $pack , 0 , 1 , ( int ) ( $pack [ 'brpc_sheet_qty' ] ? ? 0 ));
}
$boxRows = $this -> db -> table ( 'bag_receiving_pack_code' )
-> where ( 'brpc_lg_idx' , $lgIdx )
-> where ( 'brpc_box_code' , $barcode )
-> get ()
-> getResultArray ();
if ( $boxRows !== []) {
$first = $boxRows [ 0 ];
$sheetQty = 0 ;
foreach ( $boxRows as $row ) {
$sheetQty += ( int ) ( $row [ 'brpc_sheet_qty' ] ? ? 0 );
}
return $this -> resolvedFromPackRow ( $barcode , '박스' , $first , 1 , count ( $boxRows ), $sheetQty );
}
2026-06-08 00:46:51 +09:00
$exactSheet = $this -> db -> table ( 'bag_receiving_pack_code' )
-> where ( 'brpc_lg_idx' , $lgIdx )
-> where ( 'brpc_sheet_start_code' , $barcode )
-> limit ( 1 )
-> get ()
-> getRowArray ();
if ( is_array ( $exactSheet ) && $exactSheet !== []) {
return $this -> resolvedFromPackRow ( $barcode , '낱장' , $exactSheet , 0 , 0 , 1 );
}
2026-06-01 16:15:15 +09:00
$sheetRows = $this -> db -> table ( 'bag_receiving_pack_code' )
-> where ( 'brpc_lg_idx' , $lgIdx )
2026-06-08 00:46:51 +09:00
-> where ( 'brpc_sheet_start_code !=' , '' )
-> where ( 'brpc_sheet_end_code !=' , '' )
-> limit ( 200 )
2026-06-01 16:15:15 +09:00
-> get ()
-> getResultArray ();
foreach ( $sheetRows as $row ) {
$start = ( string ) ( $row [ 'brpc_sheet_start_code' ] ? ? '' );
$end = ( string ) ( $row [ 'brpc_sheet_end_code' ] ? ? '' );
if ( $this -> barcodeInRange ( $barcode , $start , $end )) {
return $this -> resolvedFromPackRow ( $barcode , '낱장' , $row , 0 , 0 , 1 );
}
}
2026-06-08 00:46:51 +09:00
$fromScan = $this -> resolveBarcodeFromScanTables ( $lgIdx , $barcode );
if ( $fromScan !== null ) {
return $fromScan ;
}
2026-06-01 16:15:15 +09:00
return [ 'ok' => false , 'message' => '등록되지 않은 바코드입니다.' ];
}
2026-06-08 00:46:51 +09:00
/**
* 판매·반품 스캔에만 있는 낱장 코드 ( 입고 팩 테이블 미등록 ) 조회
*
* @ return array { ok : true , barcode : string , unit : string , bag_code : string , bag_name : string , lot_no : string , box_code : string , pack_code : string , pack_ids : list < int > , qty_box : int , qty_pack : int , qty_sheet : int } | null
*/
private function resolveBarcodeFromScanTables ( int $lgIdx , string $barcode ) : ? array
{
$bagCode = '' ;
$bagName = '' ;
if ( $this -> db -> tableExists ( 'bag_sale_scan_code' )) {
$sale = $this -> db -> table ( 'bag_sale_scan_code' )
-> select ( 'bssc_bag_code, bssc_bag_name' )
-> where ( 'bssc_lg_idx' , $lgIdx )
-> where ( 'bssc_code' , $barcode )
-> orderBy ( 'bssc_regdate' , 'DESC' )
-> limit ( 1 )
-> get ()
-> getRowArray ();
if ( is_array ( $sale ) && $sale !== []) {
$bagCode = ( string ) ( $sale [ 'bssc_bag_code' ] ? ? '' );
$bagName = ( string ) ( $sale [ 'bssc_bag_name' ] ? ? '' );
}
}
if ( $bagCode === '' && $this -> db -> tableExists ( 'bag_return_scan_code' )) {
$ret = $this -> db -> table ( 'bag_return_scan_code' )
-> select ( 'brsc_bag_code, brsc_bag_name' )
-> where ( 'brsc_lg_idx' , $lgIdx )
-> where ( 'brsc_code' , $barcode )
-> orderBy ( 'brsc_regdate' , 'DESC' )
-> limit ( 1 )
-> get ()
-> getRowArray ();
if ( is_array ( $ret ) && $ret !== []) {
$bagCode = ( string ) ( $ret [ 'brsc_bag_code' ] ? ? '' );
$bagName = ( string ) ( $ret [ 'brsc_bag_name' ] ? ? '' );
}
}
if ( $bagCode === '' && $bagName === '' ) {
return null ;
}
$packRow = $this -> findPackRowContainingSheet ( $lgIdx , $barcode );
return [
'ok' => true ,
'barcode' => $barcode ,
'unit' => '낱장' ,
'bag_code' => $bagCode ,
'bag_name' => $bagName ,
'lot_no' => ( string ) ( $packRow [ 'brpc_lot_no' ] ? ? '' ),
'box_code' => ( string ) ( $packRow [ 'brpc_box_code' ] ? ? '' ),
'pack_code' => ( string ) ( $packRow [ 'brpc_pack_code' ] ? ? '' ),
'pack_ids' => isset ( $packRow [ 'brpc_idx' ]) ? [( int ) $packRow [ 'brpc_idx' ]] : [],
'qty_box' => 0 ,
'qty_pack' => 0 ,
'qty_sheet' => 1 ,
];
}
/**
* @ return array < string , mixed >
*/
private function findPackRowContainingSheet ( int $lgIdx , string $barcode ) : array
{
if ( ! $this -> db -> tableExists ( 'bag_receiving_pack_code' )) {
return [];
}
$exact = $this -> db -> table ( 'bag_receiving_pack_code' )
-> where ( 'brpc_lg_idx' , $lgIdx )
-> where ( 'brpc_sheet_start_code' , $barcode )
-> limit ( 1 )
-> get ()
-> getRowArray ();
if ( is_array ( $exact ) && $exact !== []) {
return $exact ;
}
foreach ( $this -> db -> table ( 'bag_receiving_pack_code' )
-> where ( 'brpc_lg_idx' , $lgIdx )
-> where ( 'brpc_sheet_start_code !=' , '' )
-> where ( 'brpc_sheet_end_code !=' , '' )
-> limit ( 200 )
-> get ()
-> getResultArray () as $row ) {
$start = ( string ) ( $row [ 'brpc_sheet_start_code' ] ? ? '' );
$end = ( string ) ( $row [ 'brpc_sheet_end_code' ] ? ? '' );
if ( $this -> barcodeInRange ( $barcode , $start , $end )) {
return $row ;
}
}
return [];
}
2026-06-01 16:15:15 +09:00
/**
* @ param array < string , mixed > $pack
* @ return array { ok : true , barcode : string , unit : string , bag_code : string , bag_name : string , lot_no : string , box_code : string , pack_code : string , pack_ids : list < int > , qty_box : int , qty_pack : int , qty_sheet : int }
*/
private function resolvedFromPackRow ( string $barcode , string $unit , array $pack , int $qtyBox , int $qtyPack , int $qtySheet ) : array
{
return [
'ok' => true ,
'barcode' => $barcode ,
'unit' => $unit ,
'bag_code' => ( string ) ( $pack [ 'brpc_bag_code' ] ? ? '' ),
'bag_name' => ( string ) ( $pack [ 'brpc_bag_name' ] ? ? '' ),
'lot_no' => ( string ) ( $pack [ 'brpc_lot_no' ] ? ? '' ),
'box_code' => ( string ) ( $pack [ 'brpc_box_code' ] ? ? '' ),
'pack_code' => ( string ) ( $pack [ 'brpc_pack_code' ] ? ? '' ),
'pack_ids' => [( int ) ( $pack [ 'brpc_idx' ] ? ? 0 )],
'qty_box' => $qtyBox ,
'qty_pack' => $qtyPack ,
'qty_sheet' => $qtySheet ,
];
}
/**
* @ param array < string , mixed > $resolved
* @ return list < array { flow_date : string , counterparty : string , flow_type : string , sort_ts : int } >
*/
private function collectFlowRows ( int $lgIdx , array $resolved ) : array
2026-06-08 00:46:51 +09:00
{
$unit = ( string ) ( $resolved [ 'unit' ] ? ? '' );
return match ( $unit ) {
'낱장' => $this -> collectFlowRowsForSheet ( $lgIdx , $resolved ),
'박스' => $this -> collectFlowRowsForBox ( $lgIdx , $resolved ),
default => $this -> collectFlowRowsForPack ( $lgIdx , $resolved ),
};
}
/**
* 낱장 : 해당 바코드 판매·반품만 + 소속 팩 입고 1 건 ( 발주·동일 LOT 전체 이력 제외 )
*
* @ param array < string , mixed > $resolved
* @ return list < array { flow_date : string , counterparty : string , flow_type : string , sort_ts : int } >
*/
private function collectFlowRowsForSheet ( int $lgIdx , array $resolved ) : array
2026-06-01 16:15:15 +09:00
{
$rows = [];
2026-06-08 00:46:51 +09:00
$barcode = trim (( string ) ( $resolved [ 'barcode' ] ? ? '' ));
if ( $barcode === '' ) {
return [];
}
$brIdx = $this -> receivingBrIdxForPackCode ( $lgIdx , ( string ) ( $resolved [ 'pack_code' ] ? ? '' ));
if ( $brIdx > 0 ) {
foreach ( $this -> loadReceivingEventsByBrIdx ( $lgIdx , $brIdx ) as $ev ) {
$rows [] = $ev ;
2026-06-01 16:15:15 +09:00
}
}
2026-06-08 00:46:51 +09:00
foreach ( $this -> loadScanEventsForCodes ( $lgIdx , [ $barcode ]) as $ev ) {
$rows [] = $ev ;
}
foreach ( $this -> loadReturnEventsForCodes ( $lgIdx , [ $barcode ]) as $ev ) {
$rows [] = $ev ;
}
return $rows ;
}
/**
* 팩 : 팩·낱장 바코드 스캔 + 입고 + LOT 발주
*
* @ param array < string , mixed > $resolved
* @ return list < array { flow_date : string , counterparty : string , flow_type : string , sort_ts : int } >
*/
private function collectFlowRowsForPack ( int $lgIdx , array $resolved ) : array
{
$rows = [];
$codes = array_values ( array_unique ( array_filter ([
( string ) ( $resolved [ 'barcode' ] ? ? '' ),
( string ) ( $resolved [ 'pack_code' ] ? ? '' ),
], static fn ( string $c ) : bool => $c !== '' )));
$brIdx = $this -> receivingBrIdxForPackCode ( $lgIdx , ( string ) ( $resolved [ 'pack_code' ] ? ? '' ));
2026-06-01 16:15:15 +09:00
if ( $brIdx > 0 ) {
foreach ( $this -> loadReceivingEventsByBrIdx ( $lgIdx , $brIdx ) as $ev ) {
$rows [] = $ev ;
}
}
foreach ( $this -> loadScanEventsForCodes ( $lgIdx , $codes ) as $ev ) {
$rows [] = $ev ;
}
foreach ( $this -> loadReturnEventsForCodes ( $lgIdx , $codes ) as $ev ) {
$rows [] = $ev ;
}
$lotNo = ( string ) ( $resolved [ 'lot_no' ] ? ? '' );
if ( $lotNo !== '' ) {
foreach ( $this -> loadOrderEventsForLot ( $lgIdx , $lotNo ) as $ev ) {
$rows [] = $ev ;
}
}
return $rows ;
}
2026-06-08 00:46:51 +09:00
/**
* 박스 : 박스·소속 팩 코드 스캔 + 입고 ( 박스 내 팩 ) + LOT 발주
*
* @ param array < string , mixed > $resolved
* @ return list < array { flow_date : string , counterparty : string , flow_type : string , sort_ts : int } >
*/
private function collectFlowRowsForBox ( int $lgIdx , array $resolved ) : array
{
$rows = [];
$boxCode = ( string ) ( $resolved [ 'box_code' ] ? ? '' );
$codes = array_values ( array_unique ( array_filter ([
( string ) ( $resolved [ 'barcode' ] ? ? '' ),
$boxCode ,
( string ) ( $resolved [ 'pack_code' ] ? ? '' ),
], static fn ( string $c ) : bool => $c !== '' )));
if ( $boxCode !== '' && $this -> db -> tableExists ( 'bag_receiving_pack_code' )) {
$packCodes = $this -> db -> table ( 'bag_receiving_pack_code' )
-> select ( 'brpc_pack_code' )
-> where ( 'brpc_lg_idx' , $lgIdx )
-> where ( 'brpc_box_code' , $boxCode )
-> get ()
-> getResultArray ();
foreach ( $packCodes as $p ) {
$pc = ( string ) ( $p [ 'brpc_pack_code' ] ? ? '' );
if ( $pc !== '' && ! in_array ( $pc , $codes , true )) {
$codes [] = $pc ;
}
}
}
$seenBr = [];
if ( $boxCode !== '' && $this -> db -> tableExists ( 'bag_receiving_pack_code' )) {
$brRows = $this -> db -> table ( 'bag_receiving_pack_code' )
-> select ( 'brpc_br_idx' )
-> distinct ()
-> where ( 'brpc_lg_idx' , $lgIdx )
-> where ( 'brpc_box_code' , $boxCode )
-> get ()
-> getResultArray ();
foreach ( $brRows as $brRow ) {
$brIdx = ( int ) ( $brRow [ 'brpc_br_idx' ] ? ? 0 );
if ( $brIdx <= 0 || isset ( $seenBr [ $brIdx ])) {
continue ;
}
$seenBr [ $brIdx ] = true ;
foreach ( $this -> loadReceivingEventsByBrIdx ( $lgIdx , $brIdx ) as $ev ) {
$rows [] = $ev ;
}
}
}
foreach ( $this -> loadScanEventsForCodes ( $lgIdx , $codes ) as $ev ) {
$rows [] = $ev ;
}
foreach ( $this -> loadReturnEventsForCodes ( $lgIdx , $codes ) as $ev ) {
$rows [] = $ev ;
}
$lotNo = ( string ) ( $resolved [ 'lot_no' ] ? ? '' );
if ( $lotNo !== '' ) {
foreach ( $this -> loadOrderEventsForLot ( $lgIdx , $lotNo ) as $ev ) {
$rows [] = $ev ;
}
}
return $rows ;
}
private function receivingBrIdxForPackCode ( int $lgIdx , string $packCode ) : int
{
if ( $packCode === '' || ! $this -> db -> tableExists ( 'bag_receiving_pack_code' )) {
return 0 ;
}
$p = $this -> db -> table ( 'bag_receiving_pack_code' )
-> select ( 'brpc_br_idx' )
-> where ( 'brpc_lg_idx' , $lgIdx )
-> where ( 'brpc_pack_code' , $packCode )
-> get ()
-> getRowArray ();
return ( int ) ( $p [ 'brpc_br_idx' ] ? ? 0 );
}
2026-06-01 16:15:15 +09:00
/**
* @ return list < array { flow_date : string , counterparty : string , flow_type : string , sort_ts : int } >
*/
private function loadReceivingEventsByBrIdx ( int $lgIdx , int $brIdx ) : array
{
$sql = "
SELECT r . br_receive_date , r . br_sender_name , r . br_regdate ,
o . bo_order_date , c . cp_name , sa . sa_name
FROM bag_receiving r
LEFT JOIN bag_order o ON o . bo_idx = r . br_bo_idx
LEFT JOIN company c ON c . cp_idx = o . bo_company_idx
LEFT JOIN sales_agency sa ON sa . sa_idx = o . bo_agency_idx
WHERE r . br_lg_idx = ? AND r . br_idx = ?
LIMIT 20
" ;
$rows = [];
foreach ( $this -> db -> query ( $sql , [ $lgIdx , $brIdx ]) -> getResultArray () as $r ) {
$rows [] = $this -> makeEvent (
( string ) ( $r [ 'br_receive_date' ] ? ? '' ),
( string ) ( $r [ 'br_regdate' ] ? ? '' ),
$this -> pickSource ( $r , '입고처' , 'sa_name' , 'cp_name' , 'br_sender_name' ),
'입고'
);
}
return $rows ;
}
/**
* @ return list < array { flow_date : string , counterparty : string , flow_type : string , sort_ts : int } >
*/
private function loadReceivingEventsForLot ( int $lgIdx , string $lotNo ) : array
{
$sql = "
SELECT r . br_receive_date , r . br_sender_name , r . br_regdate , r . br_bag_name ,
c . cp_name , sa . sa_name
FROM bag_receiving r
INNER JOIN bag_order o ON o . bo_idx = r . br_bo_idx AND o . bo_lot_no = ?
LEFT JOIN company c ON c . cp_idx = o . bo_company_idx
LEFT JOIN sales_agency sa ON sa . sa_idx = o . bo_agency_idx
WHERE r . br_lg_idx = ?
ORDER BY r . br_receive_date ASC , r . br_idx ASC
LIMIT 200
" ;
$rows = [];
foreach ( $this -> db -> query ( $sql , [ $lotNo , $lgIdx ]) -> getResultArray () as $r ) {
$label = trim (( string ) ( $r [ 'br_bag_name' ] ? ? '' ));
$rows [] = $this -> makeEvent (
( string ) ( $r [ 'br_receive_date' ] ? ? '' ),
( string ) ( $r [ 'br_regdate' ] ? ? '' ),
$this -> pickSource ( $r , '입고처' , 'sa_name' , 'cp_name' , 'br_sender_name' ) . ( $label !== '' ? ' · ' . $label : '' ),
'입고'
);
}
return $rows ;
}
/**
* @ param list < string > $codes
* @ return list < array { flow_date : string , counterparty : string , flow_type : string , sort_ts : int } >
*/
private function loadScanEventsForCodes ( int $lgIdx , array $codes ) : array
{
if ( $codes === [] || ! $this -> db -> tableExists ( 'bag_sale_scan_code' )) {
return [];
}
$placeholders = implode ( ',' , array_fill ( 0 , count ( $codes ), '?' ));
$params = array_merge ([ $lgIdx ], $codes );
$sql = "
SELECT b . bssc_regdate , b . bssc_state , b . bssc_code , d . ds_name , d . ds_shop_no
FROM bag_sale_scan_code b
LEFT JOIN designated_shop d ON d . ds_idx = b . bssc_ds_idx
WHERE b . bssc_lg_idx = ? AND b . bssc_code IN ({ $placeholders })
ORDER BY b . bssc_regdate ASC
LIMIT 200
" ;
$rows = [];
foreach ( $this -> db -> query ( $sql , $params ) -> getResultArray () as $r ) {
$state = strtolower (( string ) ( $r [ 'bssc_state' ] ? ? '' ));
$type = $state === 'in_stock' ? '반품입고' : '출고' ;
$shop = trim (( string ) ( $r [ 'ds_name' ] ? ? '' ));
if ( $shop === '' ) {
$shop = trim (( string ) ( $r [ 'ds_shop_no' ] ? ? '' ));
}
if ( $shop === '' ) {
$shop = '지정판매소' ;
}
$rows [] = $this -> makeEvent (
$this -> dateOnly (( string ) ( $r [ 'bssc_regdate' ] ? ? '' )),
( string ) ( $r [ 'bssc_regdate' ] ? ? '' ),
$shop ,
$type
);
}
return $rows ;
}
/**
* @ param list < string > $codes
* @ return list < array { flow_date : string , counterparty : string , flow_type : string , sort_ts : int } >
*/
private function loadReturnEventsForCodes ( int $lgIdx , array $codes ) : array
{
if ( $codes === [] || ! $this -> db -> tableExists ( 'bag_return_scan_code' )) {
return [];
}
$placeholders = implode ( ',' , array_fill ( 0 , count ( $codes ), '?' ));
$params = array_merge ([ $lgIdx ], $codes );
$sql = "
SELECT r . brsc_return_date , r . brsc_regdate , r . brsc_code , d . ds_name , d . ds_shop_no
FROM bag_return_scan_code r
LEFT JOIN designated_shop d ON d . ds_idx = r . brsc_ds_idx
WHERE r . brsc_lg_idx = ? AND r . brsc_code IN ({ $placeholders })
ORDER BY r . brsc_return_date ASC
LIMIT 200
" ;
$rows = [];
foreach ( $this -> db -> query ( $sql , $params ) -> getResultArray () as $r ) {
$shop = trim (( string ) ( $r [ 'ds_name' ] ? ? '' ));
if ( $shop === '' ) {
$shop = trim (( string ) ( $r [ 'ds_shop_no' ] ? ? '' ));
}
if ( $shop === '' ) {
$shop = '지정판매소' ;
}
$rows [] = $this -> makeEvent (
( string ) ( $r [ 'brsc_return_date' ] ? ? '' ),
( string ) ( $r [ 'brsc_regdate' ] ? ? '' ),
$shop ,
'반품'
);
}
return $rows ;
}
/**
* @ return list < array { flow_date : string , counterparty : string , flow_type : string , sort_ts : int } >
*/
private function loadOrderEventsForLot ( int $lgIdx , string $lotNo ) : array
{
$sql = "
SELECT o . bo_order_date , o . bo_regdate , c . cp_name , sa . sa_name
FROM bag_order o
LEFT JOIN company c ON c . cp_idx = o . bo_company_idx
LEFT JOIN sales_agency sa ON sa . sa_idx = o . bo_agency_idx
WHERE o . bo_lg_idx = ? AND o . bo_lot_no = ? AND o . bo_status = 'normal'
ORDER BY o . bo_version DESC
LIMIT 1
" ;
$r = $this -> db -> query ( $sql , [ $lgIdx , $lotNo ]) -> getRowArray ();
if ( ! $r ) {
return [];
}
return [
$this -> makeEvent (
( string ) ( $r [ 'bo_order_date' ] ? ? '' ),
( string ) ( $r [ 'bo_regdate' ] ? ? '' ),
$this -> pickSource ( $r , '제작·발주' , 'cp_name' , 'sa_name' ),
'발주'
),
];
}
/**
* @ param array < string , mixed > $order
* @ return array < string , mixed >
*/
private function buildLotFromOrderOnly ( int $lgIdx , string $lotNo , array $order ) : array
{
$rows = $this -> loadOrderEventsForLot ( $lgIdx , $lotNo );
$boIdx = ( int ) ( $order [ 'bo_idx' ] ? ? 0 );
if ( $boIdx > 0 ) {
$sql = "
SELECT r . br_receive_date , r . br_sender_name , r . br_regdate , r . br_bag_name ,
c . cp_name , sa . sa_name
FROM bag_receiving r
LEFT JOIN bag_order o ON o . bo_idx = r . br_bo_idx
LEFT JOIN company c ON c . cp_idx = o . bo_company_idx
LEFT JOIN sales_agency sa ON sa . sa_idx = o . bo_agency_idx
WHERE r . br_bo_idx = ?
ORDER BY r . br_receive_date ASC
" ;
foreach ( $this -> db -> query ( $sql , [ $boIdx ]) -> getResultArray () as $r ) {
$rows [] = $this -> makeEvent (
( string ) ( $r [ 'br_receive_date' ] ? ? '' ),
( string ) ( $r [ 'br_regdate' ] ? ? '' ),
$this -> pickSource ( $r , '입고처' , 'sa_name' , 'cp_name' , 'br_sender_name' ),
'입고'
);
}
}
usort ( $rows , static fn ( array $a , array $b ) : int => ( $a [ 'sort_ts' ] ? ? 0 ) <=> ( $b [ 'sort_ts' ] ? ? 0 ));
return array_merge ( $this -> emptyResult ( $lotNo ), [
'ok' => true ,
'lot_no' => $lotNo ,
'barcode' => $lotNo ,
'rows' => $rows ,
]);
}
/**
* @ param array < string , mixed > $row
*/
private function pickSource ( array $row , string $default , string ... $keys ) : string
{
foreach ( $keys as $key ) {
$v = trim (( string ) ( $row [ $key ] ? ? '' ));
if ( $v !== '' ) {
return $v ;
}
}
return $default ;
}
/**
* @ return array { flow_date : string , counterparty : string , flow_type : string , sort_ts : int }
*/
private function makeEvent ( string $dateYmd , string $sortDatetime , string $counterparty , string $flowType ) : array
{
$ts = strtotime ( $sortDatetime !== '' ? $sortDatetime : $dateYmd );
return [
'flow_date' => $dateYmd !== '' ? $dateYmd : ( $ts ? date ( 'Y-m-d' , $ts ) : '' ),
'counterparty' => $counterparty ,
'flow_type' => $flowType ,
'sort_ts' => $ts !== false ? $ts : 0 ,
];
}
private function dateOnly ( string $datetime ) : string
{
if ( preg_match ( '/^(\d{4}-\d{2}-\d{2})/' , $datetime , $m ) === 1 ) {
return $m [ 1 ];
}
$ts = strtotime ( $datetime );
return $ts ? date ( 'Y-m-d' , $ts ) : $datetime ;
}
/**
* LOT 수불 조회 화면 테스트용 — 등록된 바코드·LOT 샘플
*
* @ return list < array { kind : string , code : string , bag_name : string , lot_no : string , state : string , hint : string } >
*/
public function loadTestSamples ( int $lgIdx , int $limit = 80 ) : array
{
$samples = [];
$seen = [];
$push = static function ( array & $samples , array & $seen , string $kind , string $code , string $bagName , string $lotNo , string $state , string $hint ) use ( $limit ) : void {
$code = trim ( $code );
if ( $code === '' || isset ( $seen [ $code ]) || count ( $samples ) >= $limit ) {
return ;
}
$seen [ $code ] = true ;
$samples [] = [
'kind' => $kind ,
'code' => $code ,
'bag_name' => $bagName ,
'lot_no' => $lotNo ,
'state' => $state ,
'hint' => $hint ,
];
};
if ( $this -> db -> tableExists ( 'bag_receiving_pack_code' )) {
foreach ( $this -> db -> table ( 'bag_receiving_pack_code' )
-> select ( 'brpc_pack_code, brpc_box_code, brpc_sheet_start_code, brpc_bag_name, brpc_lot_no, brpc_state' )
-> where ( 'brpc_lg_idx' , $lgIdx )
-> orderBy ( 'brpc_idx' , 'DESC' )
-> limit ( 40 )
-> get ()
-> getResultArray () as $row ) {
$state = $this -> packStateLabel (( string ) ( $row [ 'brpc_state' ] ? ? '' ));
$bagName = ( string ) ( $row [ 'brpc_bag_name' ] ? ? '' );
$lotNo = ( string ) ( $row [ 'brpc_lot_no' ] ? ? '' );
$push ( $samples , $seen , '팩' , ( string ) ( $row [ 'brpc_pack_code' ] ? ? '' ), $bagName , $lotNo , $state , '입고 팩 코드' );
}
$boxRows = $this -> db -> query ( "
SELECT brpc_box_code ,
MAX ( brpc_bag_name ) AS brpc_bag_name ,
MAX ( brpc_lot_no ) AS brpc_lot_no ,
MAX ( brpc_state ) AS brpc_state
FROM bag_receiving_pack_code
WHERE brpc_lg_idx = ? AND brpc_box_code != ''
GROUP BY brpc_box_code
ORDER BY MAX ( brpc_idx ) DESC
LIMIT 15
" , [ $lgIdx ])->getResultArray();
foreach ( $boxRows as $row ) {
$push ( $samples , $seen , '박스' , ( string ) ( $row [ 'brpc_box_code' ] ? ? '' ), ( string ) ( $row [ 'brpc_bag_name' ] ? ? '' ), ( string ) ( $row [ 'brpc_lot_no' ] ? ? '' ), $this -> packStateLabel (( string ) ( $row [ 'brpc_state' ] ? ? '' )), '박스 단위 조회' );
}
$sheetRows = $this -> db -> table ( 'bag_receiving_pack_code' )
-> select ( 'brpc_sheet_start_code, brpc_bag_name, brpc_lot_no, brpc_state' )
-> where ( 'brpc_lg_idx' , $lgIdx )
-> where ( 'brpc_sheet_start_code !=' , '' )
-> orderBy ( 'brpc_idx' , 'DESC' )
-> limit ( 15 )
-> get ()
-> getResultArray ();
foreach ( $sheetRows as $row ) {
$push ( $samples , $seen , '낱장' , ( string ) ( $row [ 'brpc_sheet_start_code' ] ? ? '' ), ( string ) ( $row [ 'brpc_bag_name' ] ? ? '' ), ( string ) ( $row [ 'brpc_lot_no' ] ? ? '' ), $this -> packStateLabel (( string ) ( $row [ 'brpc_state' ] ? ? '' )), '낱장 시작 코드' );
}
$lotRows = $this -> db -> query ( "
SELECT DISTINCT brpc_lot_no
FROM bag_receiving_pack_code
WHERE brpc_lg_idx = ? AND brpc_lot_no != ''
ORDER BY brpc_lot_no DESC
LIMIT 10
" , [ $lgIdx ])->getResultArray();
foreach ( $lotRows as $row ) {
$lot = ( string ) ( $row [ 'brpc_lot_no' ] ? ? '' );
$push ( $samples , $seen , 'LOT' , $lot , '(LOT 전체)' , $lot , '—' , 'lot_no 파라미터·입력 동일' );
}
}
if ( $this -> db -> tableExists ( 'bag_sale_scan_code' )) {
foreach ( $this -> db -> table ( 'bag_sale_scan_code b' )
-> select ( 'b.bssc_code, b.bssc_bag_name, b.bssc_unit, b.bssc_state, b.bssc_regdate' )
-> where ( 'b.bssc_lg_idx' , $lgIdx )
-> orderBy ( 'b.bssc_regdate' , 'DESC' )
-> limit ( 20 )
-> get ()
-> getResultArray () as $row ) {
$state = strtolower (( string ) ( $row [ 'bssc_state' ] ? ? '' )) === 'sold' ? '판매' : '반품재고' ;
$push ( $samples , $seen , '스캔' , ( string ) ( $row [ 'bssc_code' ] ? ? '' ), ( string ) ( $row [ 'bssc_bag_name' ] ? ? '' ), '' , $state , '판매·반품 스캔 이력' );
}
}
return $samples ;
}
private function packStateLabel ( string $state ) : string
{
return match ( strtolower ( $state )) {
'in_stock' => '재고' ,
'sold' => '판매' ,
default => $state !== '' ? $state : '—' ,
};
}
private function barcodeInRange ( string $code , string $start , string $end ) : bool
{
if ( $start === '' || $end === '' ) {
return false ;
}
$extract = static function ( string $v ) : array {
if ( preg_match ( '/^(.*?)(\d+)$/' , $v , $m ) === 1 ) {
return [( string ) $m [ 1 ], ( int ) $m [ 2 ], strlen (( string ) $m [ 2 ])];
}
return [ '' , - 1 , 0 ];
};
[ $cp , $cn , $cl ] = $extract ( $code );
[ $sp , $sn , $sl ] = $extract ( $start );
[ $ep , $en , $el ] = $extract ( $end );
if ( $cn >= 0 && $sn >= 0 && $en >= 0 && $cp === $sp && $sp === $ep && $cl === $sl && $sl === $el ) {
return $cn >= $sn && $cn <= $en ;
}
return strcmp ( $code , $start ) >= 0 && strcmp ( $code , $end ) <= 0 ;
}
}