<?php
ob_start();
require("dbconnect.php");
require("config.php");
require("function.php");

header('Content-Type: application/json');

// PHP 8.1+ makes mysqli throw a fatal mysqli_sql_exception on any query error
// by default, instead of the classic "returns false, check it yourself" style
// this whole codebase is written in (or die(mysqli_error($conn)), if(!$ok)...).
// A fatal error here would dump HTML into what's supposed to be a JSON AJAX
// response, which is exactly what makes jQuery report "Request failed." with
// no useful detail. Restore the classic behaviour so real errors come back
// as a proper JSON message instead of crashing the response.
if (function_exists('mysqli_report')) { mysqli_report(MYSQLI_REPORT_OFF); }

if (!isset($_SESSION["username_".$dbname])) {
    echo json_encode(['success'=>false,'message'=>'Session expired. Please re-login.']);
    exit;
}

$zdb = $_SESSION["zdbyear_".$dbname];
mysqli_select_db($conn, $zdb);

// ── Defensive auto-migrate (in case saleorder.php hasn't run yet / a different
//    financial-year DB than the one saleorder.php last migrated) ───────────
foreach ([
    'dispatchdate'   => "DATE NULL",
    'dispatchby'     => "VARCHAR(50) NOT NULL DEFAULT ''",
    'lrno'           => "VARCHAR(50) NOT NULL DEFAULT ''",
    'transporter'    => "VARCHAR(100) NOT NULL DEFAULT ''",
    'lrdate'         => "DATE NULL",
    'transportmode'  => "VARCHAR(30) NOT NULL DEFAULT ''",
    'invoiceno'      => "INT(11) NOT NULL DEFAULT 0",
    'invoicedate'    => "DATE NULL",
    'godown'         => "INT(11) NOT NULL DEFAULT 0",
] as $col => $def) {
    $chk = mysqli_query($conn, "SHOW COLUMNS FROM `saleorder` LIKE '$col'");
    if ($chk && mysqli_num_rows($chk) == 0)
        mysqli_query($conn, "ALTER TABLE `saleorder` ADD COLUMN `$col` $def");
}

// ── Ensure transacn table exists (product stock ledger) ───────────────────
mysqli_query($conn, "CREATE TABLE IF NOT EXISTS `transacn` (
    `srl` INT(11) NOT NULL AUTO_INCREMENT,
    `vouchdt` DATE NULL,
    `source` VARCHAR(10) NOT NULL DEFAULT '',
    `vouchno` INT(11) NOT NULL DEFAULT 0,
    `godown` INT(11) NOT NULL DEFAULT 0,
    `product` INT(11) NOT NULL DEFAULT 0,
    `qty` DOUBLE NOT NULL DEFAULT 0,
    `cost` DOUBLE NOT NULL DEFAULT 0,
    `adduser` VARCHAR(50) NOT NULL DEFAULT '',
    `adddate` DATE NULL,
    `addtime` TIME NULL,
    PRIMARY KEY (`srl`),
    KEY `vouchno` (`vouchno`),
    KEY `product` (`product`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

// ── Ensure notifications table exists (bell menu — see includes/notifications.php) ──
mysqli_query($conn, "CREATE TABLE IF NOT EXISTS `notifications` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `vouchno` INT(11) NOT NULL DEFAULT 0,
    `reftype` VARCHAR(20) NOT NULL DEFAULT '',
    `audience` VARCHAR(30) NOT NULL DEFAULT '',
    `action` VARCHAR(20) NOT NULL DEFAULT '',
    `message` VARCHAR(255) NOT NULL DEFAULT '',
    `readflag` VARCHAR(1) NOT NULL DEFAULT '',
    `createduser` VARCHAR(50) NOT NULL DEFAULT '',
    `createddate` DATE NULL,
    `createdtime` TIME NULL,
    PRIMARY KEY (`id`),
    KEY `audience` (`audience`),
    KEY `vouchno` (`vouchno`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

try {

$vouchno = isset($_POST['vouchno']) ? (int)$_POST['vouchno'] : 0;
if ($vouchno <= 0) {
    echo json_encode(['success'=>false,'message'=>'Invalid sale order.']);
    exit;
}

$chk = mysqli_query($conn, "SELECT vouchno FROM `saleorder` WHERE vouchno='$vouchno'");
if (!$chk || mysqli_num_rows($chk) == 0) {
    echo json_encode(['success'=>false,'message'=>'Sale order not found.']);
    exit;
}

$dispatchdate  = mysqli_real_escape_string($conn, trim($_POST['dispatchdate']  ?? ''));
$dispatchby    = mysqli_real_escape_string($conn, trim($_POST['dispatchby']    ?? ''));
$transportmode = mysqli_real_escape_string($conn, trim($_POST['transportmode'] ?? ''));
$lrno          = mysqli_real_escape_string($conn, trim($_POST['lrno']         ?? ''));
$lrdate        = mysqli_real_escape_string($conn, trim($_POST['lrdate']       ?? ''));
$transporter   = mysqli_real_escape_string($conn, trim($_POST['transporter']  ?? ''));

if ($dispatchdate === '') {
    echo json_encode(['success'=>false,'message'=>'Dispatch date is required.']);
    exit;
}

$dispatchdateSql = "'$dispatchdate'";
$lrdateSql = $lrdate !== '' ? "'$lrdate'" : 'NULL';

$audituser = audituser();

$ok = mysqli_query($conn, "UPDATE `saleorder` SET
    `dispatchdate`=$dispatchdateSql,
    `dispatchby`='$dispatchby',
    `transportmode`='$transportmode',
    `lrno`='$lrno',
    `lrdate`=$lrdateSql,
    `transporter`='$transporter',
    `edituser`='$audituser', `editdate`=CURDATE(), `edittime`=CURTIME()
    WHERE `vouchno`='$vouchno'");

if (!$ok) {
    echo json_encode(['success'=>false,'message'=>mysqli_error($conn)]);
    exit;
}

// ── Post stock-OUT (transacn) and accounting (actran) for the dispatched sale
// order, both under source='DSP', vouchno=<this sale order's vouchno>.
//
// Actran is posted ONCE for the dispatch total, not once per line item.
// If this sale order later gets invoiced (sale.php / Generate Invoice), the
// invoice reuses this exact same key (source='DSP', vouchno=this saleorder's
// vouchno — see sale.php's `soref` handling) so its delete-then-insert lands
// on this same row instead of adding a second entry; whichever of dispatch
// or invoice was saved most recently is what actran reflects.
$hdrRes = mysqli_query($conn, "SELECT `customer`,`godown`,`salesman` FROM `saleorder` WHERE `vouchno`='$vouchno'");
$hdr    = $hdrRes ? mysqli_fetch_assoc($hdrRes) : null;

if ($hdr) {
    $customer = (int)$hdr['customer'];
    $godown   = (int)$hdr['godown'];
    $salesman = (int)($hdr['salesman'] ?? 0);

    $dtlRes = mysqli_query($conn, "SELECT `product`,`qty`,`amount` FROM `saleorderdtl` WHERE `vouchno`='$vouchno'");
    $dtl = [];
    if ($dtlRes) while ($r = mysqli_fetch_assoc($dtlRes)) $dtl[] = $r;

    // Stock OUT → transacn (delete+reinsert for idempotency on re-dispatch/edit)
    mysqli_query($conn, "DELETE FROM `transacn` WHERE `source`='DSP' AND `vouchno`='$vouchno'");
    foreach ($dtl as $ln) {
        $prod = (int)$ln['product'];
        $qty  = (float)$ln['qty'];
        if ($prod > 0 && $qty != 0) {
            $negQty = $qty * -1;
            mysqli_query($conn, "INSERT INTO `transacn`
                (`vouchdt`,`source`,`vouchno`,`godown`,`product`,`qty`,`cost`,`adduser`,`adddate`,`addtime`)
                VALUES ('$dispatchdate','DSP','$vouchno','$godown','$prod','$negQty','0','$audituser',CURDATE(),CURTIME())");
        }
    }

    // Actran — debit customer / credit Sale account (accode 15), posted once
    // for the dispatch total (not per line item).
    mysqli_query($conn, "DELETE FROM `actran` WHERE `source`='DSP' AND `vouchno`='$vouchno'");
    $dispatchTotal = 0;
    foreach ($dtl as $ln) { $dispatchTotal += (float)$ln['amount']; }
    if ($dispatchTotal > 0 && $customer > 0) {
        $dr = $dispatchTotal * -1;
        mysqli_query($conn, "INSERT INTO `actran`(`vouchdt`,`date`,`vouchno`,`source`,`trnno`,`accode`,`grpcode`,`feamt`,`roe`,`amount`,`prodtype`,`actamt`,`narr`)
            VALUES ('$dispatchdate','$dispatchdate','$vouchno','DSP','001','$customer','010','$dr','1','$dr','','$dr','Sale Amount')");
        mysqli_query($conn, "INSERT INTO `actran`(`vouchdt`,`date`,`vouchno`,`source`,`trnno`,`accode`,`grpcode`,`feamt`,`roe`,`amount`,`prodtype`,`actamt`,`narr`)
            VALUES ('$dispatchdate','$dispatchdate','$vouchno','DSP','002','15','005','$dispatchTotal','1','$dispatchTotal','','$dispatchTotal','Sale Amount')");
    }

    // ── Notify: Sale Order Dispatched ───────────────────────────────────────
    $custNameRow = mysqli_fetch_assoc(mysqli_query($conn, "SELECT `name` FROM `accmast` WHERE `accode`='$customer'"));
    $custName    = $custNameRow['name'] ?? '';
    $dispDisp    = date('d-m-Y', strtotime($dispatchdate));
    $msgDispatch = mysqli_real_escape_string($conn,
        "Sale Order #$vouchno" . ($custName ? " ($custName)" : '') . " was dispatched by $audituser on $dispDisp — invoice pending.");

    mysqli_query($conn, "INSERT INTO `notifications`
        (`vouchno`,`reftype`,`audience`,`action`,`message`,`createduser`,`createddate`,`createdtime`)
        VALUES ('$vouchno','saleorder','admin','info','$msgDispatch','$audituser',CURDATE(),CURTIME())");

    if ($salesman > 0) {
        mysqli_query($conn, "INSERT INTO `notifications`
            (`vouchno`,`reftype`,`audience`,`action`,`message`,`createduser`,`createddate`,`createdtime`)
            VALUES ('$vouchno','saleorder','salesman_$salesman','info','$msgDispatch','$audituser',CURDATE(),CURTIME())");
    }
}

if (ob_get_level() > 0) { ob_clean(); }
echo json_encode(['success'=>true]);

} catch (\Throwable $e) {
    // Belt-and-suspenders: whatever the failure, still return valid JSON so
    // the front-end shows a real message instead of a bare "Request failed."
    if (ob_get_level() > 0) { ob_clean(); }
    echo json_encode(['success'=>false, 'message'=>$e->getMessage()]);
}
