goiintra/public_html/assets/api/daily.php

1218 lines
38 KiB
PHP

<?php
require_once getenv("DOCUMENT_ROOT")."/assets/conf.inc.php";
require_once getenv("DOCUMENT_ROOT")."/assets/dbCon.php";
class DailyService extends CONF {
public function saveDaily(array $data = [], array $opt = [])
{
$connect = $GLOBALS['conn'] ?? null;
if (!$connect) {
throw new Exception("DB connection not found");
}
$inTx = !empty($opt['in_tx']);
if (empty($data['d_orderdate']) || empty($data['d_accountno'])) {
throw new Exception("d_orderdate, d_accountno required");
}
// =========================
// KEY NORMALIZE
// =========================
$d_orderdate = preg_replace('/[^0-9]/', '', $data['d_orderdate']);
if (strlen($d_orderdate) !== 8) {
throw new Exception("invalid d_orderdate");
}
$d_accountno = mysqli_real_escape_string($connect, trim($data['d_accountno']));
if ($d_accountno === '') {
throw new Exception("invalid d_accountno");
}
$d_jobtype = mysqli_real_escape_string($connect, trim($data['d_jobtype']));
if ($d_jobtype === '') {
$d_jobtype = 'UCO';
}
$now14 = date('YmdHis');
if (!$inTx) {
mysqli_query($connect, "START TRANSACTION");
}
try {
// =========================
// EXISTING LOAD (개선됨)
// =========================
$existing = null;
// 1. d_uid 우선 (가장 안전)
if (!empty($opt['match_uid'])) {
$uid = (int)$opt['match_uid'];
$res = mysqli_query($connect, "
SELECT *
FROM tbl_daily
WHERE d_uid = '{$uid}'
LIMIT 1
");
if (!$res) throw new Exception(mysqli_error($connect));
$existing = mysqli_fetch_assoc($res);
}
// 2. old_key fallback (key 변경 대응)
if (!$existing && !empty($opt['old_key'])) {
$oldDate = preg_replace('/[^0-9]/', '', $opt['old_key']['d_orderdate'] ?? '');
$oldAcc = mysqli_real_escape_string($connect, $opt['old_key']['d_accountno'] ?? '');
$oldJob = mysqli_real_escape_string($connect, $opt['old_key']['d_jobtype'] ?? '');
if ($oldDate && $oldAcc) {
$res = mysqli_query($connect, "
SELECT *
FROM tbl_daily
WHERE d_orderdate = '{$oldDate}'
AND d_accountno = '{$oldAcc}'
AND d_jobtype = '{$oldJob}'
LIMIT 1
");
if (!$res) throw new Exception(mysqli_error($connect));
$existing = mysqli_fetch_assoc($res);
}
}
// 3. 기본 key 매칭
if (!$existing) {
$res = mysqli_query($connect, "
SELECT *
FROM tbl_daily
WHERE d_orderdate = '{$d_orderdate}'
AND d_accountno = '{$d_accountno}'
AND d_jobtype = '{$d_jobtype}'
LIMIT 1
");
if (!$res) throw new Exception(mysqli_error($connect));
$existing = mysqli_fetch_assoc($res);
}
$isUpdate = (bool)$existing;
$beforeData = $existing ?: null;
// =========================
// DUPLICATE POLICY (중요)
// =========================
if ($isUpdate && empty($opt['allow_update'])) {
if (!$inTx) mysqli_query($connect, "ROLLBACK");
return null; // skip
}
// =========================
// normalize + snapshot
// =========================
$data = $this->normalizeDailyPayload($data, $existing ?: null);
$data = $this->hydrateDailySnapshot($data, $existing ?: null);
// estquantity 자동 계산
if (empty($data['d_estquantity'])) {
$data['d_estquantity'] = $this->calculateEstQuantity($data, $existing);
}
// note 백업 (tbl_note 로 전달할 값)
$noteForUpsert = $data['d_note'] ?? '';
$pickupNoteForUpsert = $data['d_pickupnote'] ?? '';
$level = $data['d_level'] ?? 9;
// =========================
// 컬럼 필터링
// =========================
$allowed = $this->getDailyColumns();
$data = array_intersect_key($data, array_flip($allowed));
// =========================
// UPDATE
// =========================
if ($isUpdate) {
$setParts = [];
foreach ($data as $k => $v) {
if (in_array($k, ['d_orderdate','d_accountno','d_jobtype'], true)) continue;
if (!array_key_exists($k, $existing)) continue;
$setParts[] = "{$k}='" . mysqli_real_escape_string($connect, (string)$v) . "'";
}
$setParts[] = "d_modifydate='{$now14}'";
if (!empty($setParts)) {
// update는 무조건 d_uid 기준으로
$uid = (int)$existing['d_uid'];
$sql = "
UPDATE tbl_daily
SET " . implode(",", $setParts) . "
WHERE d_uid='{$uid}'
LIMIT 1
";
if (!mysqli_query($connect, $sql)) {
throw new Exception(mysqli_error($connect));
}
}
}
// =========================
// INSERT
// =========================
else {
$cols = [];
$vals = [];
foreach ($data as $k => $v) {
$cols[] = $k;
$vals[] = "'" . mysqli_real_escape_string($connect, (string)$v) . "'";
}
if (!in_array('d_modifydate', $cols)) {
$cols[] = 'd_modifydate';
$vals[] = "'{$now14}'";
}
$sql = "
INSERT INTO tbl_daily (" . implode(",", $cols) . ")
VALUES (" . implode(",", $vals) . ")
";
if (!mysqli_query($connect, $sql)) {
throw new Exception(mysqli_error($connect));
}
}
// =========================
// AFTER RELOAD (uid 기준)
// =========================
if ($isUpdate) {
$uid = (int)$existing['d_uid'];
$res = mysqli_query($connect, "
SELECT *
FROM tbl_daily
WHERE d_uid='{$uid}'
LIMIT 1
");
} else {
$res = mysqli_query($connect, "
SELECT *
FROM tbl_daily
WHERE d_orderdate='{$d_orderdate}'
AND d_accountno='{$d_accountno}'
AND d_jobtype = '{$d_jobtype}'
ORDER BY d_uid DESC
LIMIT 1
");
}
$afterData = mysqli_fetch_assoc($res);
// note
if ($noteForUpsert !== '') {
$afterData['d_note'] = $noteForUpsert;
$afterData['d_level'] = $level;
}
if ($pickupNoteForUpsert !== '') {
$afterData['d_pickupnote'] = $pickupNoteForUpsert;
$afterData['d_level'] = $level;
}
// =========================
// ERP OUTBOX
// =========================
$event_type = $isUpdate ? 'DAILY_UPDATED' : 'DAILY_CREATED';
$payload = mysqli_real_escape_string(
$connect,
json_encode([
'key' => [
'd_orderdate'=>$afterData['d_orderdate'],
'd_accountno'=>$afterData['d_accountno'],
'd_jobtype'=>$afterData['d_jobtype']
],
'before'=>$beforeData,
'after'=>$afterData
], JSON_UNESCAPED_UNICODE)
);
mysqli_query($connect, "
INSERT INTO tbl_erp_outbox
(eo_event_type, eo_key_date, eo_key_accountno, eo_key_jobtype, eo_payload, eo_status, eo_created_at)
VALUES
('{$event_type}',
'{$afterData['d_orderdate']}',
'{$afterData['d_accountno']}',
'{$afterData['d_jobtype']}',
'{$payload}',
'PENDING',
NOW())
");
// =========================
// AFTER WORK
// =========================
$this->runAfterSave($beforeData, $afterData, $opt);
// =========================
// COMMIT
// =========================
if (!$inTx) {
mysqli_query($connect, "COMMIT");
}
return $afterData;
} catch (Exception $e) {
if (!$inTx) {
mysqli_query($connect, "ROLLBACK");
}
throw $e;
}
}
private function isDuplicate($orderdate, $accountno, $jobtype): bool
{
$connect = $GLOBALS['conn'];
$res = mysqli_query($connect, "
SELECT 1
FROM tbl_daily
WHERE d_orderdate='{$orderdate}'
AND d_accountno='{$accountno}'
AND d_jobtype = '{$jobtype}'
LIMIT 1
");
return (bool)mysqli_fetch_assoc($res);
}
private function normalizeDailyPayload(array $data, ?array $existing = null): array
{
// 날짜 정리
if (isset($data['d_orderdate'])) {
$data['d_orderdate'] = preg_replace('/[^0-9]/', '', $data['d_orderdate']);
}
if (isset($data['d_visitdate'])) {
$data['d_visitdate'] = preg_replace('/[^0-9]/', '', $data['d_visitdate']);
}
// 숫자 필드 기본값
$intFields = [
'd_quantity',
'd_sludge'
];
foreach ($intFields as $f) {
if (isset($data[$f])) {
$data[$f] = ($data[$f] === '' || $data[$f] === null)
? 0
: (int)$data[$f];
}
}
// 문자열 trim
$strFields = [
'd_pickupnote',
'd_note'
];
foreach ($strFields as $f) {
if (isset($data[$f])) {
$data[$f] = trim((string)$data[$f]);
}
}
return $data;
}
private function hydrateDailySnapshot(array $data, ?array $existing = null): array
{
$connect = $GLOBALS['conn'] ?? null;
if (!$connect) {
throw new Exception("DB connection not found");
}
// =========================
// DRIVER SNAPSHOT
// =========================
$druid = isset($data['d_druid'])
? (int)$data['d_druid']
: (int)($existing['d_druid'] ?? 0);
// fallback: legacy member uid -> current driver uid
if ($druid <= 0) {
$driverUid = isset($data['d_driveruid'])
? (int)$data['d_driveruid']
: (int)($existing['d_driveruid'] ?? 0);
if ($driverUid > 0) {
$sqMap = qry("
SELECT
m.m_currentdriver AS dr_uid,
d.dr_initial
FROM tbl_member m
LEFT JOIN tbl_driver d
ON d.dr_uid = m.m_currentdriver
WHERE m.m_uid = '{$driverUid}'
LIMIT 1
");
$map = fetch_array($sqMap);
if ($map && (int)$map['dr_uid'] > 0) {
$druid = (int)$map['dr_uid'];
$data['d_druid'] = $druid;
$data['d_drinitial'] = $map['dr_initial'] ?? '';
}
}
}
// druid가 있으면 driver snapshot 확정
if ($druid > 0) {
$sqDriver = qry("
SELECT dr_initial
FROM tbl_driver
WHERE dr_uid = '{$druid}'
LIMIT 1
");
$driver = fetch_array($sqDriver);
if ($driver && !empty($driver['dr_initial'])) {
$data['d_druid'] = $druid;
$data['d_drinitial'] = $driver['dr_initial'];
} elseif ($existing) {
$data['d_druid'] = $existing['d_druid'] ?? 0;
$data['d_drinitial'] = $existing['d_drinitial'] ?? '';
}
}
// =========================
// CUSTOMER SNAPSHOT (확장)
// =========================
$customerUid = isset($data['d_customeruid'])
? (int)$data['d_customeruid']
: (int)($existing['d_customeruid'] ?? 0);
if ($customerUid > 0) {
$sqCustomer = qry("
SELECT
c_regionuid,
c_region,
c_fullcycle,
c_fullcycleforced,
c_fullcycleflag,
c_lastpickupdate,
c_lastpickupquantity,
c_lastpaiddate,
c_name,
c_paymenttype,
c_paymentcycle,
c_rate,
c_form_eu,
c_form_corsia,
c_maincontainer,
c_container,
c_location,
c_phone,
c_address,
c_city,
c_postal,
c_area
FROM tbl_customer
WHERE c_uid = '{$customerUid}'
LIMIT 1
");
$customer = fetch_array($sqCustomer);
if ($customer) {
$data['d_name'] = $customer['c_name'] ?? '';
$data['d_form_eu'] = $customer['c_form_eu'] ?? '';
$data['d_form_corsia'] = $customer['c_form_corsia'] ?? '';
$data['d_maincontainer'] = $customer['c_maincontainer'] ?? '';
$data['d_container'] = $customer['c_container'] ?? '';
$data['d_location'] = $customer['c_location'] ?? '';
$data['d_phone'] = $customer['c_phone'] ?? '';
$data['d_address'] = $customer['c_address'] ?? '';
$data['d_city'] = $customer['c_city'] ?? '';
$data['d_postal'] = $customer['c_postal'] ?? '';
$data['d_area'] = $customer['c_area'] ?? '';
$data['d_regionuid'] = (int)($customer['c_regionuid'] ?? 0);
$data['d_region'] = $customer['c_region'] ?? '';
$data['d_fullcycle'] = $customer['c_fullcycle'] ?? 0;
$data['d_fullcycleforced'] = $customer['c_fullcycleforced'] ?? 0;
$data['d_fullcycleflag'] = $customer['c_fullcycleflag'] ?? 0;
$data['d_lastpickupdate'] = $customer['c_lastpickupdate'] ?? '';
$data['d_lastpickupquantity'] = $customer['c_lastpickupquantity'] ?? 0;
$data['d_lastpaiddate'] = $customer['c_lastpaiddate'] ?? '';
$data['d_paymenttype'] = $customer['c_paymenttype'] ?? '';
$data['d_cycle'] = $customer['c_paymentcycle'] ?? '';
$data['d_rate'] = $customer['c_rate'] ?? '';
if (!isset($data['d_oil_2y'])) $data['d_oil_2y'] = 0;
if (!isset($data['d_oil_1y'])) $data['d_oil_1y'] = 0;
if (!isset($data['d_oil_0y'])) $data['d_oil_0y'] = 0;
}
}
return $data;
}
private function getDailyColumns(): array
{
return [
'd_uid',
// key
'd_orderdate',
'd_accountno',
'd_customeruid',
'd_jobtype',
// driver / region
'd_driveruid',
'd_druid',
'd_drinitial',
'd_regionuid',
'd_region',
// basic status
'd_ordertype',
'd_visitdate',
'd_visit',
'd_status',
// qty / sludge / payment
'd_quantity',
'd_sludge',
'd_paymenttype',
'd_payamount',
'd_payeename',
'd_paystatus',
// customer snapshot
'd_name',
'd_form_eu',
'd_form_corsia',
'd_maincontainer',
'd_container',
'd_location',
'd_phone',
'd_address',
'd_city',
'd_postal',
'd_area',
// oil / cycle history snapshot
'd_oil_2y',
'd_oil_1y',
'd_oil_0y',
'd_fullcycle',
'd_fullcycleforced',
'd_fullcycleflag',
'd_lastpickupdate',
'd_lastpickupquantity',
'd_lastpaiddate',
// pricing / estimate
'd_cycle',
'd_rate',
'd_estquantity',
// audit
'd_createruid',
'd_createddate',
'd_inputdate',
'd_modifydate',
'd_ruid',
// misc
'd_payeesign',
'd_is_transfer'
];
}
private function calculateEstQuantity(array $data, ?array $existing = null): int
{
$customerUid = $data['d_customeruid'] ?? ($existing['d_customeruid'] ?? 0);
$orderdate = $data['d_orderdate'] ?? ($existing['d_orderdate'] ?? '');
if (!$customerUid || !$orderdate) return 0;
$sqCus = qry("
SELECT c_fullquantity, c_fullquantitydaily
FROM tbl_customer
WHERE c_uid = '{$customerUid}'
LIMIT 1
");
$customer = fetch_array($sqCus);
if (!$customer) return 0;
$today = new DateTime(date("Y-m-d"));
$searchDate = new DateTime(substr($orderdate,0,4)."-".substr($orderdate,4,2)."-".substr($orderdate,6,2));
$interval = $today->diff($searchDate);
$days = (int)$interval->days;
return max(
0,
($customer['c_fullquantity'] - $customer['c_fullquantitydaily']) +
($days * $customer['c_fullquantitydaily'])
);
}
private function runAfterSave(?array $before, array $after, array $opt = []): void
{
$this->updateCustomerFromDaily($before, $after);
$this->updateRequestFromDaily($after);
$this->upsertDailyNote($after);
$this->handlePickupCleanup($before, $after);
$this->handlePickupReset($before, $after);
}
private function runAfterDelete(array $before, array $opt = []): void
{
$connect = $GLOBALS['conn'];
if (empty($before['d_customeruid'])) {
return;
}
$customerUid = mysqli_real_escape_string($connect, $before['d_customeruid']);
$orderdate = mysqli_real_escape_string($connect, $before['d_orderdate'] ?? '');
// 1) REQUEST 삭제
$this->deleteRequestByDaily($before);
// 2) CUSTOMER 재계산 (lastpick, lastpaid 등 포함)
$this->recalcCustomerFromDailyHistory($customerUid);
// 3) GHOST 재판정
$this->reEvaluateGhost($customerUid);
}
private function deleteRequestByDaily(array $before): void
{
$connect = $GLOBALS['conn'];
$customerUid = (int)($before['d_customeruid'] ?? 0);
$orderdate = preg_replace('/[^0-9]/', '', $before['d_orderdate'] ?? '');
if ($customerUid <= 0 || $orderdate === '') {
return;
}
mysqli_query($connect, "
DELETE FROM tbl_request
WHERE r_customeruid = '{$customerUid}'
AND r_requestdate = '{$orderdate}'
");
}
private function updateCustomerFromDaily($before, $after)
{
$connect = $GLOBALS['conn'];
if (empty($after['d_customeruid'])) return;
$customer_uid = mysqli_real_escape_string($connect, $after['d_customeruid']);
// 고객 현재 상태 조회
$qr = mysqli_query($connect, "
SELECT
c_paymenttype,
c_is_top,
c_fpickup,
c_schedule,
c_scheduleday
FROM tbl_customer
WHERE c_uid = '{$customer_uid}'
LIMIT 1
");
$customer = mysqli_fetch_assoc($qr);
if (!$customer) return;
$updateFields = [];
$ordertype = $after['d_ordertype'] ?? 'N';
$orderdate = $after['d_orderdate'] ?? '';
$visitdate = $after['d_visitdate'] ?? '';
$quantity = (int)($after['d_quantity'] ?? 0);
$paystatus = $after['d_paystatus'] ?? '';
$paymenttype = $after['d_paymenttype'] ?? '';
$isTop = $customer['c_is_top'] ?? '';
// --------------------------------------------------
// 0) Ghost Check
// --------------------------------------------------
if ($quantity < 10 && $isTop !== 'G') {
$updateFields[] = "c_is_top = 'G'";
}
if ($isTop === 'G' && $quantity >= 10) {
$updateFields[] = "c_is_top = ''";
}
// --------------------------------------------------
// 1) c_fpickup 처리
// --------------------------------------------------
if (!empty($orderdate)) {
$currentFpickup = $customer['c_fpickup'] ?? '';
if (empty($currentFpickup) || $currentFpickup < $orderdate) {
$updateFields[] = "c_fpickup = '{$orderdate}'";
}
}
// --------------------------------------------------
// 2) orderflag 처리
// --------------------------------------------------
if (!empty($after['d_visit']) && $after['d_visit'] === 'Y') {
$updateFields[] = "c_orderdate = ''";
$updateFields[] = "c_orderflag = 0";
} else {
$updateFields[] = "c_orderdate = '{$orderdate}'";
$updateFields[] = "c_orderflag = 1";
}
// --------------------------------------------------
// 3) Scheduled 처리 (d_ordertype == 'S')
// --------------------------------------------------
if ($ordertype === 'S' && !empty($visitdate)) {
$schedule = $customer['c_schedule'] ?? '';
$scheduleDay = $customer['c_scheduleday'] ?? '';
if ($schedule > '1W' && $schedule <= '6W') {
$weekCount = (int)substr($schedule, 0, 1);
if ($weekCount > 0 && !empty($scheduleDay)) {
$dayParts = explode('|', $scheduleDay);
$dayOfWeek = $dayParts[0] ?? '';
$calcStr = "+{$weekCount} week {$dayOfWeek}";
$nextDate = date('Ymd', strtotime($calcStr, strtotime($visitdate)));
$updateFields[] = "c_schedulebasic = '{$nextDate}'";
}
}
}
// --------------------------------------------------
// UPDATE 실행
// --------------------------------------------------
if (!empty($updateFields)) {
mysqli_query($connect, "
UPDATE tbl_customer
SET " . implode(",", $updateFields) . "
WHERE c_uid = '{$customer_uid}'
LIMIT 1
");
}
}
private function updateRequestFromDaily(array $after): void
{
$connect = $GLOBALS['conn'];
if (empty($after['d_ordertype']) || $after['d_ordertype'] !== 'R') {
return;
}
if (empty($after['d_ruid'])) {
return;
}
// pickup 완료 조건 (방문 완료 + 상태 F)
if (
empty($after['d_visit']) ||
$after['d_visit'] !== 'Y' ||
empty($after['d_status']) ||
$after['d_status'] !== 'F'
) {
return;
}
$r_uid = mysqli_real_escape_string($connect, $after['d_ruid']);
mysqli_query($connect, "
UPDATE tbl_request
SET r_status = 'F'
WHERE r_uid = '{$r_uid}'
LIMIT 1
");
}
private function upsertDailyNote(array $after): void
{
$connect = $GLOBALS['conn'];
if (empty($after['d_uid'])) return;
// note는 saveDaily payload에 포함되어 있어야 함
if (empty($after['d_pickupnote']) && empty($after['d_note'])) {
return;
}
$noteText = trim($after['d_pickupnote'] ?? $after['d_note'] ?? '');
if (strlen($noteText) <= 1) return;
$dailyuid = mysqli_real_escape_string($connect, $after['d_uid']);
$customeruid = mysqli_real_escape_string($connect, $after['d_customeruid'] ?? '');
$memberuid = mysqli_real_escape_string($connect, $after['d_driveruid'] ?? '');
$noteEsc = mysqli_real_escape_string($connect, $noteText);
$now14 = date('YmdHis');
$level = mysqli_real_escape_string($connect, $after['d_level'] ?? 9);
// 기존 note 존재 여부 확인
$qr = mysqli_query($connect, "
SELECT n_uid
FROM tbl_note
WHERE n_dailyuid = '{$dailyuid}'
LIMIT 1
");
$existing = mysqli_fetch_assoc($qr);
if ($existing) {
// UPDATE
mysqli_query($connect, "
UPDATE tbl_note
SET
n_memberuid = '{$memberuid}',
n_customeruid = '{$customeruid}',
n_type = 'D',
n_level = {$level},
n_view = 1,
n_note = '{$noteEsc}',
n_createddate = '{$now14}'
WHERE n_dailyuid = '{$dailyuid}'
LIMIT 1
");
} else {
// INSERT
mysqli_query($connect, "
INSERT INTO tbl_note (
n_memberuid,
n_customeruid,
n_dailyuid,
n_type,
n_level,
n_view,
n_note,
n_createddate
) VALUES (
'{$memberuid}',
'{$customeruid}',
'{$dailyuid}',
'D',
{$level},
1,
'{$noteEsc}',
'{$now14}'
)
");
}
}
private function handlePickupCleanup(?array $before, array $after): void
{
$connect = $GLOBALS['conn'];
$beforeQty = (int)($before['d_quantity'] ?? 0);
$afterQty = (int)($after['d_quantity'] ?? 0);
$status = $after['d_status'] ?? '';
$visit = $after['d_visit'] ?? '';
// 최초 pickup
$isFirstPickup = ($beforeQty < 10 && $afterQty >= 10);
if (!$isFirstPickup) return;
if ($status !== 'F' || $visit !== 'Y') return;
$customerUid = mysqli_real_escape_string($connect, $after['d_customeruid']);
$today = date('Ymd');
$jobtype = mysqli_real_escape_string($connect, $after['d_jobtype'] ?? 'UCO');
// =========================
// 삭제 대상 조회
// =========================
$res = mysqli_query($connect, "
SELECT d_orderdate, d_accountno, d_jobtype
FROM tbl_daily
WHERE d_customeruid = '{$customerUid}'
AND d_orderdate > '{$today}'
AND d_status = 'A'
AND d_jobtype = '{$jobtype}'
");
if (!$res) {
throw new Exception(mysqli_error($connect));
}
// =========================
// 하나씩 deleteDaily 호출
// =========================
while ($row = mysqli_fetch_assoc($res)) {
try {
$this->deleteDaily(
$row['d_orderdate'],
$row['d_accountno'],
$row['d_jobtype'],
['in_tx' => true]
);
} catch (Exception $e) {
// 여기서 실패하면 전체 rollback 유도
throw $e;
}
}
error_log("[PickupCleanup] ERP-safe delete completed for customer={$customerUid}");
}
private function handlePickupReset(?array $before, array $after): void
{
$connect = $GLOBALS['conn'];
$beforeQty = (int)($before['d_quantity'] ?? 0);
$afterQty = (int)($after['d_quantity'] ?? 0);
$status = $after['d_status'] ?? '';
$visit = $after['d_visit'] ?? '';
$isFirstPickup = ($beforeQty < 10 && $afterQty >= 10);
if (!$isFirstPickup) return;
if ($status !== 'F' || $visit !== 'Y') return;
$customerUid = mysqli_real_escape_string($connect, $after['d_customeruid']);
$orderdate = mysqli_real_escape_string($connect, $after['d_orderdate']);
$sql = "
UPDATE tbl_customer
SET
c_fullquantity = 0,
c_lastpickupdate = '{$orderdate}',
c_lastpickupquantity = '{$afterQty}'
WHERE c_uid = '{$customerUid}'
";
mysqli_query($connect, $sql);
error_log("[PickupReset] customer={$customerUid} reset fullquantity + lastpickupdate={$orderdate}");
}
public function deleteDaily(string $orderdate, string $accountno, string $jobtype, array $opt = [])
{
$connect = $GLOBALS['conn'] ?? null;
if (!$connect) {
throw new Exception("DB connection not found");
}
$inTx = !empty($opt['in_tx']);
// =========================
// KEY NORMALIZE
// =========================
$orderdate = preg_replace('/[^0-9]/', '', $orderdate);
if (strlen($orderdate) !== 8) {
throw new Exception("invalid orderdate");
}
$accountno = mysqli_real_escape_string($connect, trim($accountno));
if ($accountno === '') {
throw new Exception("invalid accountno");
}
$jobtype = mysqli_real_escape_string($connect, trim($jobtype));
if ($jobtype === '') {
$jobtype = 'UCO';
}
if (!$inTx) {
mysqli_query($connect, "START TRANSACTION");
}
try {
// =========================
// 1. 기존 데이터 조회
// =========================
$res = mysqli_query($connect, "
SELECT *
FROM tbl_daily
WHERE d_orderdate='{$orderdate}'
AND d_accountno='{$accountno}'
AND d_jobtype = '{$jobtype}'
LIMIT 1
");
if (!$res) throw new Exception(mysqli_error($connect));
$existing = mysqli_fetch_assoc($res);
if (!$existing) {
throw new Exception("Daily record not found");
}
// =========================
// 2. ERP OUTBOX 기록
// =========================
$payload = mysqli_real_escape_string(
$connect,
json_encode([
'key'=>[
'd_orderdate'=>$orderdate,
'd_accountno'=>$accountno,
'd_jobtype' =>$jobtype
],
'before'=>$existing
], JSON_UNESCAPED_UNICODE)
);
if (!mysqli_query($connect, "
INSERT INTO tbl_erp_outbox
(eo_event_type, eo_key_date, eo_key_accountno, eo_key_jobtype, eo_payload, eo_status, eo_created_at)
VALUES
('DAILY_DELETED','{$orderdate}','{$accountno}','{$jobtype}','{$payload}','PENDING',NOW())
")) {
throw new Exception(mysqli_error($connect));
}
// =========================
// 3. 물리 삭제
// =========================
if (!mysqli_query($connect, "
DELETE FROM tbl_daily
WHERE d_orderdate='{$orderdate}'
AND d_accountno='{$accountno}'
AND d_jobtype = '{$jobtype}'
LIMIT 1
")) {
throw new Exception(mysqli_error($connect));
}
if (mysqli_affected_rows($connect) === 0) {
throw new Exception("Delete failed");
}
// =========================
// AFTER WORK 중앙화
// =========================
$this->runAfterDelete($existing, $opt);
// =========================
// COMMIT
// =========================
if (!$inTx) {
mysqli_query($connect, "COMMIT");
}
return true;
} catch (Exception $e) {
if (!$inTx) {
mysqli_query($connect, "ROLLBACK");
}
throw $e;
}
}
private function reEvaluateGhost(int $customerUid): void
{
$connect = $GLOBALS['conn'];
$res = mysqli_query($connect, "
SELECT d_quantity
FROM tbl_daily
WHERE d_customeruid = '{$customerUid}'
AND d_status = 'F'
ORDER BY d_orderdate DESC
LIMIT 1
");
$row = mysqli_fetch_assoc($res);
if (!$row) {
// 데이터 없으면 ghost 해제
mysqli_query($connect, "
UPDATE tbl_customer
SET c_is_top = ''
WHERE c_uid = '{$customerUid}'
");
return;
}
$qty = (int)$row['d_quantity'];
if ($qty < 10) {
mysqli_query($connect, "
UPDATE tbl_customer
SET c_is_top = 'G'
WHERE c_uid = '{$customerUid}'
");
} else {
mysqli_query($connect, "
UPDATE tbl_customer
SET c_is_top = ''
WHERE c_uid = '{$customerUid}'
");
}
}
private function recalcCustomerFromDailyHistory(string $customerUid): void
{
$connect = $GLOBALS['conn'];
$customerUidEsc = mysqli_real_escape_string($connect, $customerUid);
// 0) "오늘 포함 이후" 오더장 존재 여부 체크 (남아있으면 리셋 금지)
$today = date('Ymd');
$resFuture = mysqli_query($connect, "
SELECT 1
FROM tbl_daily
WHERE d_customeruid = '{$customerUidEsc}'
AND d_orderdate >= '{$today}'
AND d_status = 'A'
LIMIT 1
");
if (!$resFuture) {
throw new Exception(mysqli_error($connect));
}
$hasFutureOrder = (bool)mysqli_fetch_assoc($resFuture);
// 1) 마지막 완료 주문(F) 기준으로 last pickup 재계산
$res = mysqli_query($connect, "
SELECT
d_orderdate,
d_quantity,
d_sludge,
d_paymenttype,
d_paystatus
FROM tbl_daily
WHERE d_customeruid = '{$customerUidEsc}'
AND d_status = 'F'
ORDER BY d_orderdate DESC
LIMIT 1
");
if (!$res) {
throw new Exception(mysqli_error($connect));
}
$last = mysqli_fetch_assoc($res);
$lastPickupDate = '';
$lastPickupQty = 0;
$lastSludge = '';
$lastPaidDate = '';
if ($last) {
$lastPickupDate = $last['d_orderdate'];
$lastPickupQty = (int)$last['d_quantity'];
$lastSludge = (string)$last['d_sludge'];
if ($last['d_paymenttype'] === 'CA' && $last['d_paystatus'] === 'P') {
$lastPaidDate = $last['d_orderdate'];
}
}
// 2) 마지막 주문이 cash paid가 아니면, cash paid 마지막을 다시 찾음
if ($lastPaidDate === '') {
$res2 = mysqli_query($connect, "
SELECT d_orderdate
FROM tbl_daily
WHERE d_customeruid = '{$customerUidEsc}'
AND d_status = 'F'
AND d_paymenttype = 'CA'
AND d_paystatus = 'P'
ORDER BY d_orderdate DESC
LIMIT 1
");
if (!$res2) {
throw new Exception(mysqli_error($connect));
}
$paid = mysqli_fetch_assoc($res2);
if ($paid) {
$lastPaidDate = $paid['d_orderdate'];
}
}
// 3) UPDATE 구성
$setParts = [];
$setParts[] = "c_lastpickupdate=" . ($lastPickupDate ? "'{$lastPickupDate}'" : "''");
$setParts[] = "c_lastpickupquantity='{$lastPickupQty}'";
$setParts[] = "c_lastpaiddate=" . ($lastPaidDate ? "'{$lastPaidDate}'" : "''");
$setParts[] = "c_sludge='" . mysqli_real_escape_string($connect, $lastSludge) . "'";
// 4) orderflag/orderdate 리셋 정책 반영
// - 오늘 포함 이후 오더장이 남아있으면 유지 (아무것도 안함)
// - 없으면 리셋
if (!$hasFutureOrder) {
$setParts[] = "c_orderdate=''";
$setParts[] = "c_orderflag=0";
}
$sql = "
UPDATE tbl_customer
SET " . implode(",", $setParts) . "
WHERE c_uid = '{$customerUidEsc}'
LIMIT 1
";
if (!mysqli_query($connect, $sql)) {
throw new Exception(mysqli_error($connect));
}
}
/* ===============================
* 공통 JSON 응답
* =============================== */
private function jsonSuccess($data = [])
{
return json_encode([
'result' => 'success',
'data' => $data
]);
}
private function jsonError($msg)
{
return json_encode([
'result' => 'error',
'message'=> $msg
]);
}
}