674 lines
25 KiB
PHP
674 lines
25 KiB
PHP
|
|
<?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);
|
||
|
|
}
|
||
|
|
|
||
|
|
$sheetRows = $this->db->table('bag_receiving_pack_code')
|
||
|
|
->where('brpc_lg_idx', $lgIdx)
|
||
|
|
->where('brpc_sheet_start_code <=', $barcode)
|
||
|
|
->where('brpc_sheet_end_code >=', $barcode)
|
||
|
|
->limit(50)
|
||
|
|
->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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return ['ok' => false, 'message' => '등록되지 않은 바코드입니다.'];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @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
|
||
|
|
{
|
||
|
|
$rows = [];
|
||
|
|
$codes = [$resolved['barcode']];
|
||
|
|
if (($resolved['pack_code'] ?? '') !== '' && ! in_array($resolved['pack_code'], $codes, true)) {
|
||
|
|
$codes[] = $resolved['pack_code'];
|
||
|
|
}
|
||
|
|
if (($resolved['box_code'] ?? '') !== '' && ! in_array($resolved['box_code'], $codes, true)) {
|
||
|
|
$codes[] = $resolved['box_code'];
|
||
|
|
}
|
||
|
|
|
||
|
|
$brIdx = 0;
|
||
|
|
if ($this->db->tableExists('bag_receiving_pack_code')) {
|
||
|
|
$packCode = (string) ($resolved['pack_code'] ?? '');
|
||
|
|
if ($packCode !== '') {
|
||
|
|
$p = $this->db->table('bag_receiving_pack_code')
|
||
|
|
->select('brpc_br_idx')
|
||
|
|
->where('brpc_lg_idx', $lgIdx)
|
||
|
|
->where('brpc_pack_code', $packCode)
|
||
|
|
->get()
|
||
|
|
->getRowArray();
|
||
|
|
$brIdx = (int) ($p['brpc_br_idx'] ?? 0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @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;
|
||
|
|
}
|
||
|
|
}
|