<?php
declare(strict_types=1);

$dbFile = '/tmp/zhct-cqhw-prepay-order-e2e.sqlite';
if (is_file($dbFile)) {
    unlink($dbFile);
}

$pdo = new PDO('sqlite:' . $dbFile);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

function execSql(PDO $pdo, string $sql): void
{
    $pdo->exec($sql);
}

function one(PDO $pdo, string $sql, array $params = []): array
{
    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);
    $row = $stmt->fetch();
    return $row ?: [];
}

function runSql(PDO $pdo, string $sql, array $params = []): void
{
    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);
}

function assertTrue(bool $condition, string $message): void
{
    if (!$condition) {
        fwrite(STDERR, '[FAIL] ' . $message . PHP_EOL);
        exit(1);
    }
    echo '[PASS] ' . $message . PHP_EOL;
}

function signFor(array $params, string $appkey = '1234567890abcdef'): string
{
    $values = [$appkey, (string)$params['timestamp'], (string)$params['randstr']];
    sort($values, SORT_STRING);
    return sha1(implode('', $values));
}

function setupSchema(PDO $pdo): void
{
    execSql($pdo, "CREATE TABLE ydy_equipment (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        sn TEXT NOT NULL DEFAULT '',
        code TEXT NOT NULL DEFAULT '',
        type INTEGER NOT NULL DEFAULT 0,
        restaurant_id INTEGER NOT NULL DEFAULT 1,
        del_flag INTEGER NOT NULL DEFAULT 0
    )");
    execSql($pdo, "CREATE TABLE ydy_config (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        config_key TEXT NOT NULL DEFAULT '',
        config_value TEXT NOT NULL DEFAULT '',
        status INTEGER NOT NULL DEFAULT 1,
        restaurant_id INTEGER NOT NULL DEFAULT 1
    )");
    execSql($pdo, "CREATE TABLE ydy_prepay_order (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        source INTEGER NOT NULL DEFAULT 1,
        device_order_no TEXT NOT NULL DEFAULT '',
        machid TEXT NOT NULL DEFAULT '',
        equipment_id INTEGER NOT NULL DEFAULT 0,
        restaurant_id INTEGER NOT NULL DEFAULT 1,
        trackno TEXT NOT NULL DEFAULT '',
        goods_name TEXT NOT NULL DEFAULT '',
        price INTEGER NOT NULL DEFAULT 0,
        channelid TEXT NOT NULL DEFAULT '',
        prepay_status INTEGER NOT NULL DEFAULT 2,
        meal_order_id INTEGER NOT NULL DEFAULT 0,
        meal_order_no TEXT NOT NULL DEFAULT '',
        user_id INTEGER NOT NULL DEFAULT 0,
        ship_status INTEGER NOT NULL DEFAULT 0,
        errinfo TEXT NOT NULL DEFAULT '',
        raw_request_a TEXT,
        raw_request_c TEXT,
        raw_request_b TEXT,
        qrcode_payload TEXT,
        expire_time TEXT NOT NULL DEFAULT '2000-01-01 00:00:00',
        pay_time TEXT NOT NULL DEFAULT '2000-01-01 00:00:00',
        ship_time TEXT NOT NULL DEFAULT '2000-01-01 00:00:00',
        create_time TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
        create_by TEXT NOT NULL DEFAULT '',
        update_time TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
        update_by TEXT NOT NULL DEFAULT ''
    )");
    execSql($pdo, "CREATE INDEX idx_device_order_machid ON ydy_prepay_order(device_order_no, machid)");
    execSql($pdo, "CREATE INDEX idx_meal_order_id ON ydy_prepay_order(meal_order_id)");
    execSql($pdo, "CREATE INDEX idx_meal_order_no ON ydy_prepay_order(meal_order_no)");
    execSql($pdo, "CREATE INDEX idx_user_id ON ydy_prepay_order(user_id)");
    execSql($pdo, "CREATE TABLE ydy_meal_order (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        order_no TEXT NOT NULL DEFAULT '',
        total_price TEXT NOT NULL DEFAULT '0.00',
        ori_total_price TEXT NOT NULL DEFAULT '0.00',
        order_price TEXT NOT NULL DEFAULT '0.00',
        pay_price TEXT NOT NULL DEFAULT '0.00',
        pay_method TEXT NOT NULL DEFAULT '',
        pay_status INTEGER NOT NULL DEFAULT 10,
        pay_time TEXT NOT NULL DEFAULT '2000-01-01 00:00:00',
        meal_date TEXT NOT NULL DEFAULT '',
        meal_times INTEGER NOT NULL DEFAULT 0,
        meal_number INTEGER NOT NULL DEFAULT 1,
        bind_id INTEGER NOT NULL DEFAULT 0,
        bind_time TEXT NOT NULL DEFAULT '',
        equipment_code TEXT NOT NULL DEFAULT '',
        last_meal_time TEXT NOT NULL DEFAULT '',
        source INTEGER NOT NULL DEFAULT 1,
        user_id INTEGER NOT NULL DEFAULT 0,
        restaurant_id INTEGER NOT NULL DEFAULT 1,
        user_mobile TEXT NOT NULL DEFAULT '',
        user_name TEXT NOT NULL DEFAULT '',
        restaurant_method INTEGER NOT NULL DEFAULT 1,
        remark TEXT NOT NULL DEFAULT '',
        order_status INTEGER NOT NULL DEFAULT 10,
        cash TEXT NOT NULL DEFAULT '0.00',
        subsidy TEXT NOT NULL DEFAULT '0.00',
        remain_balance TEXT NOT NULL DEFAULT '0.00',
        create_time TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
        update_time TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
        is_delete INTEGER NOT NULL DEFAULT 0
    )");
    execSql($pdo, "CREATE TABLE ydy_user (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        ai_user_id INTEGER NOT NULL DEFAULT 0,
        name TEXT NOT NULL DEFAULT '',
        nickname TEXT NOT NULL DEFAULT '',
        mobile TEXT NOT NULL DEFAULT '',
        balance REAL NOT NULL DEFAULT 0,
        pay_money REAL NOT NULL DEFAULT 0,
        is_delete INTEGER NOT NULL DEFAULT 0
    )");
    execSql($pdo, "CREATE TABLE ydy_user_balance_log (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        scene INTEGER NOT NULL DEFAULT 20,
        describe TEXT NOT NULL DEFAULT '',
        order_id INTEGER NOT NULL DEFAULT 0,
        user_id INTEGER NOT NULL DEFAULT 0,
        money REAL NOT NULL DEFAULT 0,
        create_time INTEGER NOT NULL DEFAULT 0
    )");
}

function seed(PDO $pdo): void
{
    runSql($pdo, "INSERT INTO ydy_equipment(sn, code, type, restaurant_id, del_flag) VALUES('CQHW-MACH-001', 'COFFEE-01', 60, 1, 0)");
    runSql($pdo, "INSERT INTO ydy_config(config_key, config_value, status, restaurant_id) VALUES('coffee_machine_appkey', '1234567890abcdef', 1, 1)");
    runSql($pdo, "INSERT INTO ydy_config(config_key, config_value, status, restaurant_id) VALUES('prepay_order_scan_url', 'http://127.0.0.1/api/prepay-order/scan', 1, 1)");
    runSql($pdo, "INSERT INTO ydy_user(ai_user_id, name, nickname, mobile, balance, is_delete) VALUES(90001, '重庆环卫测试用户', '测试用户', '13800000000', 100.00, 0)");
}

function configValue(PDO $pdo, string $key): string
{
    $row = one($pdo, "SELECT config_value FROM ydy_config WHERE config_key = :key AND status = 1 LIMIT 1", [':key' => $key]);
    return (string)($row['config_value'] ?? '');
}

function interfaceA(PDO $pdo, array $params): array
{
    $equipment = one($pdo, "SELECT * FROM ydy_equipment WHERE sn = :machid AND type = 60 AND del_flag = 0", [':machid' => $params['machid']]);
    if (!$equipment) {
        return ['orderid' => $params['orderid'] ?? '', 'torderid' => '', 'code' => '0', 'msg' => '设备不存在'];
    }
    if (signFor($params, configValue($pdo, 'coffee_machine_appkey')) !== strtolower((string)$params['sign'])) {
        return ['orderid' => $params['orderid'] ?? '', 'torderid' => '', 'code' => '0', 'msg' => '签名错误'];
    }

    $prepay = one($pdo, "SELECT * FROM ydy_prepay_order WHERE device_order_no = :orderid AND machid = :machid ORDER BY id DESC LIMIT 1", [
        ':orderid' => $params['orderid'],
        ':machid' => $params['machid'],
    ]);
    if (!$prepay) {
        runSql($pdo, "INSERT INTO ydy_prepay_order(source, device_order_no, machid, equipment_id, restaurant_id, trackno, goods_name, price, channelid, prepay_status, ship_status, raw_request_a, expire_time, create_by, update_by)
            VALUES(1, :orderid, :machid, :equipment_id, :restaurant_id, :trackno, :goods_name, :price, :channelid, 2, 0, :raw, :expire_time, 'api', 'api')", [
            ':orderid' => $params['orderid'],
            ':machid' => $params['machid'],
            ':equipment_id' => $equipment['id'],
            ':restaurant_id' => $equipment['restaurant_id'],
            ':trackno' => $params['trackno'] ?? '',
            ':goods_name' => $params['name'] ?? '',
            ':price' => (int)($params['price'] ?? 0),
            ':channelid' => $params['channelid'] ?? '',
            ':raw' => json_encode($params, JSON_UNESCAPED_UNICODE),
            ':expire_time' => date('Y-m-d H:i:s', strtotime('+15 minute')),
        ]);
        $prepay = one($pdo, "SELECT * FROM ydy_prepay_order WHERE id = :id", [':id' => $pdo->lastInsertId()]);
    }

    $base = configValue($pdo, 'prepay_order_scan_url') ?: 'http://127.0.0.1/api/prepay-order/scan';
    $twocode = $base . '?' . http_build_query([
        'type' => 'prepay',
        'source' => 1,
        'orderid' => $prepay['device_order_no'],
        'machid' => $prepay['machid'],
        'torderid' => $prepay['id'],
    ]);
    runSql($pdo, "UPDATE ydy_prepay_order SET qrcode_payload = :twocode, raw_request_a = :raw, update_by = 'api' WHERE id = :id", [
        ':twocode' => $twocode,
        ':raw' => json_encode($params, JSON_UNESCAPED_UNICODE),
        ':id' => $prepay['id'],
    ]);
    return ['orderid' => $prepay['device_order_no'], 'torderid' => (string)$prepay['id'], 'twocode' => $twocode, 'code' => '1', 'msg' => '成功'];
}

function scanMiniApp(PDO $pdo, string $twocode, int $aiUserId): array
{
    $query = parse_url($twocode, PHP_URL_QUERY);
    parse_str((string)$query, $params);
    $prepay = one($pdo, "SELECT * FROM ydy_prepay_order WHERE id = :id", [':id' => (int)$params['torderid']]);
    assertTrue($prepay && $prepay['device_order_no'] === $params['orderid'] && $prepay['machid'] === $params['machid'], '扫码参数 torderid/orderid/machid 匹配预扣款订单');
    assertTrue((int)$prepay['prepay_status'] === 2, '扫码前预扣款订单为等待付款 code=2');

    $user = one($pdo, "SELECT * FROM ydy_user WHERE ai_user_id = :ai_user_id AND is_delete = 0", [':ai_user_id' => $aiUserId]);
    assertTrue((bool)$user, '扫码用户能映射到智慧餐厅用户');

    $money = number_format(((int)$prepay['price']) / 100, 2, '.', '');
    $orderNo = 'E2E' . date('YmdHis') . random_int(1000, 9999);
    runSql($pdo, "INSERT INTO ydy_meal_order(order_no, total_price, ori_total_price, order_price, pay_price, pay_method, pay_status, pay_time, meal_date, meal_times, meal_number, bind_id, bind_time, equipment_code, last_meal_time, source, user_id, restaurant_id, user_mobile, user_name, restaurant_method, remark, order_status, create_time, update_time)
        VALUES(:order_no, :money, :money, :money, :money, 'balance', 10, '2000-01-01 00:00:00', :meal_date, 2, 1, 0, :now, 'COFFEE-01', :now, 8, :user_id, :restaurant_id, :mobile, :name, 1, :remark, 10, :now, :now)", [
        ':order_no' => $orderNo,
        ':money' => $money,
        ':meal_date' => date('Y-m-d'),
        ':now' => date('Y-m-d H:i:s'),
        ':user_id' => $user['id'],
        ':restaurant_id' => $prepay['restaurant_id'],
        ':mobile' => $user['mobile'],
        ':name' => $user['name'],
        ':remark' => $prepay['goods_name'] ?: '咖啡机订单',
    ]);
    $mealOrderId = (int)$pdo->lastInsertId();
    runSql($pdo, "UPDATE ydy_prepay_order SET meal_order_id = :meal_order_id, meal_order_no = :meal_order_no, user_id = :user_id, update_by = 'miniapp' WHERE id = :id AND meal_order_id = 0", [
        ':meal_order_id' => $mealOrderId,
        ':meal_order_no' => $orderNo,
        ':user_id' => $user['id'],
        ':id' => $prepay['id'],
    ]);
    return ['orderId' => $mealOrderId, 'isPay' => $money === '0.00' ? 0 : 1, 'orderNo' => $orderNo];
}

function payMealOrder(PDO $pdo, int $mealOrderId): void
{
    $order = one($pdo, "SELECT * FROM ydy_meal_order WHERE id = :id", [':id' => $mealOrderId]);
    assertTrue($order && (int)$order['pay_status'] === 10 && (int)$order['source'] === 8, '支付前正式订单为咖啡机待支付订单');
    $payPrice = (float)$order['pay_price'];
    runSql($pdo, "UPDATE ydy_user SET balance = balance - :money, pay_money = pay_money + :money WHERE id = :user_id", [
        ':money' => $payPrice,
        ':user_id' => $order['user_id'],
    ]);
    runSql($pdo, "INSERT INTO ydy_user_balance_log(scene, describe, order_id, user_id, money, create_time) VALUES(20, :desc, :order_id, :user_id, :money, :time)", [
        ':desc' => '订单消费：' . $order['order_no'],
        ':order_id' => $mealOrderId,
        ':user_id' => $order['user_id'],
        ':money' => -$payPrice,
        ':time' => time(),
    ]);
    runSql($pdo, "UPDATE ydy_meal_order SET pay_status = 20, order_status = 30, pay_time = :now, cash = :cash, remain_balance = (SELECT printf('%.2f', balance) FROM ydy_user WHERE id = :user_id), update_time = :now WHERE id = :id", [
        ':now' => date('Y-m-d H:i:s'),
        ':cash' => number_format($payPrice, 2, '.', ''),
        ':user_id' => $order['user_id'],
        ':id' => $mealOrderId,
    ]);
    runSql($pdo, "UPDATE ydy_prepay_order SET prepay_status = 1, pay_time = :now, update_by = 'pay_success' WHERE meal_order_id = :meal_order_id AND prepay_status = 2", [
        ':now' => date('Y-m-d H:i:s'),
        ':meal_order_id' => $mealOrderId,
    ]);
}

function interfaceC(PDO $pdo, array $params): array
{
    $prepay = one($pdo, "SELECT * FROM ydy_prepay_order WHERE id = :id", [':id' => (int)$params['torderid']]);
    if (!$prepay || $prepay['device_order_no'] !== $params['orderid'] || $prepay['machid'] !== $params['machid']) {
        return ['code' => '0', 'msg' => '预扣款订单参数不匹配'];
    }
    runSql($pdo, "UPDATE ydy_prepay_order SET raw_request_c = :raw, update_by = 'api' WHERE id = :id", [
        ':raw' => json_encode($params, JSON_UNESCAPED_UNICODE),
        ':id' => $prepay['id'],
    ]);
    return ['orderid' => $prepay['device_order_no'], 'torderid' => (string)$prepay['id'], 'code' => (string)$prepay['prepay_status'], 'msg' => ''];
}

function interfaceB(PDO $pdo, array $params): array
{
    $prepay = one($pdo, "SELECT * FROM ydy_prepay_order WHERE id = :id", [':id' => (int)$params['torderid']]);
    if (!$prepay || $prepay['device_order_no'] !== $params['orderid'] || $prepay['machid'] !== $params['machid']) {
        return ['code' => '0', 'msg' => '预扣款订单参数不匹配'];
    }
    $success = (int)$params['status'] === 1;
    runSql($pdo, "UPDATE ydy_prepay_order SET prepay_status = :prepay_status, ship_status = :ship_status, errinfo = :errinfo, raw_request_b = :raw, ship_time = :now, update_by = 'api' WHERE id = :id", [
        ':prepay_status' => $success ? 5 : $prepay['prepay_status'],
        ':ship_status' => $success ? 1 : 2,
        ':errinfo' => $params['errinfo'] ?? '',
        ':raw' => json_encode($params, JSON_UNESCAPED_UNICODE),
        ':now' => date('Y-m-d H:i:s'),
        ':id' => $prepay['id'],
    ]);
    return ['orderid' => $prepay['device_order_no'], 'torderid' => (string)$prepay['id'], 'code' => '1', 'msg' => '成功'];
}

function expirePendingMealOrders(PDO $pdo, int $minutes): void
{
    $before = date('Y-m-d H:i:s', strtotime('-' . $minutes . ' minute'));
    $rows = $pdo->query("SELECT id FROM ydy_meal_order WHERE pay_status = 10 AND order_status = 10 AND is_delete = 0 AND source = 8 AND bind_time <= " . $pdo->quote($before))->fetchAll();
    foreach ($rows as $row) {
        runSql($pdo, "UPDATE ydy_meal_order SET order_status = 20, update_time = :now WHERE id = :id", [
            ':now' => date('Y-m-d H:i:s'),
            ':id' => $row['id'],
        ]);
        runSql($pdo, "UPDATE ydy_prepay_order SET prepay_status = 3, update_by = 'cron' WHERE meal_order_id = :meal_order_id AND prepay_status = 2", [
            ':meal_order_id' => $row['id'],
        ]);
    }
}

setupSchema($pdo);
seed($pdo);

$paramsA = [
    'orderid' => 'MCH-ORDER-10001',
    'machid' => 'CQHW-MACH-001',
    'trackno' => 'LATTE-01',
    'name' => '拿铁',
    'price' => 1200,
    'channelid' => 'wxapp',
    'timestamp' => (string)time(),
    'randstr' => 'abc123',
];
$paramsA['sign'] = signFor($paramsA);

$a = interfaceA($pdo, $paramsA);
assertTrue($a['code'] === '1', '接口A取码成功 code=1');
assertTrue(strpos($a['twocode'], '/api/prepay-order/scan?') !== false, '二维码指向通用预扣款扫码入口');
assertTrue(strpos($a['twocode'], 'orderid=MCH-ORDER-10001') !== false && strpos($a['twocode'], 'machid=CQHW-MACH-001') !== false && strpos($a['twocode'], 'torderid=') !== false, '二维码包含设备订单号、machid、torderid');

$prepay = one($pdo, "SELECT * FROM ydy_prepay_order WHERE id = :id", [':id' => (int)$a['torderid']]);
assertTrue((int)$prepay['prepay_status'] === 2 && (int)$prepay['meal_order_id'] === 0, '接口A创建等待付款预扣款订单，尚未生成正式订单');

$scan = scanMiniApp($pdo, $a['twocode'], 90001);
assertTrue($scan['isPay'] === 1 && $scan['orderId'] > 0, '小程序扫码生成待支付 ydy_meal_order');
$bound = one($pdo, "SELECT p.*, m.pay_status, m.source AS meal_source FROM ydy_prepay_order p JOIN ydy_meal_order m ON p.meal_order_id = m.id WHERE p.id = :id", [':id' => (int)$a['torderid']]);
assertTrue((int)$bound['meal_source'] === 8 && (int)$bound['pay_status'] === 10, '正式订单 source=8 且 pay_status=10');

payMealOrder($pdo, $scan['orderId']);
$paid = one($pdo, "SELECT p.prepay_status, m.pay_status, m.order_status, u.balance FROM ydy_prepay_order p JOIN ydy_meal_order m ON p.meal_order_id = m.id JOIN ydy_user u ON p.user_id = u.id WHERE p.id = :id", [':id' => (int)$a['torderid']]);
assertTrue((int)$paid['pay_status'] === 20 && (int)$paid['order_status'] === 30, '现有手机端订单支付后正式订单已付款/已完成');
assertTrue((int)$paid['prepay_status'] === 1, '支付成功后预扣款订单 code=1');
assertTrue(abs(((float)$paid['balance']) - 88.00) < 0.001, '余额扣款 12.00 元完成');

$c = interfaceC($pdo, [
    'orderid' => 'MCH-ORDER-10001',
    'machid' => 'CQHW-MACH-001',
    'torderid' => $a['torderid'],
    'timestamp' => (string)time(),
    'randstr' => 'c-query',
    'sign' => signFor(['timestamp' => (string)time(), 'randstr' => 'c-query']),
]);
assertTrue($c['code'] === '1', '接口C查扣款返回 code=1，咖啡机可开始制作');

$b = interfaceB($pdo, [
    'orderid' => 'MCH-ORDER-10001',
    'machid' => 'CQHW-MACH-001',
    'torderid' => $a['torderid'],
    'status' => 1,
    'timestamp' => (string)time(),
    'randstr' => 'b-result',
    'sign' => signFor(['timestamp' => (string)time(), 'randstr' => 'b-result']),
]);
assertTrue($b['code'] === '1', '接口B出货结果回传成功');
$done = one($pdo, "SELECT prepay_status, ship_status FROM ydy_prepay_order WHERE id = :id", [':id' => (int)$a['torderid']]);
assertTrue((int)$done['prepay_status'] === 5 && (int)$done['ship_status'] === 1, '出货完成后预扣款订单 code=5 且履约成功');

$paramsTimeout = $paramsA;
$paramsTimeout['orderid'] = 'MCH-ORDER-10002';
$paramsTimeout['timestamp'] = (string)time();
$paramsTimeout['randstr'] = 'timeout';
$paramsTimeout['sign'] = signFor($paramsTimeout);
$timeoutA = interfaceA($pdo, $paramsTimeout);
$timeoutScan = scanMiniApp($pdo, $timeoutA['twocode'], 90001);
runSql($pdo, "UPDATE ydy_meal_order SET bind_time = :old_time WHERE id = :id", [
    ':old_time' => date('Y-m-d H:i:s', strtotime('-20 minute')),
    ':id' => $timeoutScan['orderId'],
]);

$paramsUnscanned = $paramsA;
$paramsUnscanned['orderid'] = 'MCH-ORDER-10003';
$paramsUnscanned['timestamp'] = (string)time();
$paramsUnscanned['randstr'] = 'unscanned';
$paramsUnscanned['sign'] = signFor($paramsUnscanned);
$unscannedA = interfaceA($pdo, $paramsUnscanned);

expirePendingMealOrders($pdo, 15);
$expired = one($pdo, "SELECT p.prepay_status, m.order_status FROM ydy_prepay_order p JOIN ydy_meal_order m ON p.meal_order_id = m.id WHERE p.id = :id", [':id' => (int)$timeoutA['torderid']]);
$unscanned = one($pdo, "SELECT prepay_status, meal_order_id FROM ydy_prepay_order WHERE id = :id", [':id' => (int)$unscannedA['torderid']]);
assertTrue((int)$expired['prepay_status'] === 3 && (int)$expired['order_status'] === 20, '已扫码但超时未支付订单被关闭并更新预扣款 code=3');
assertTrue((int)$unscanned['prepay_status'] === 2 && (int)$unscanned['meal_order_id'] === 0, '仅创建预扣款但未扫码的订单保持等待付款，不由超时脚本处理');

echo PHP_EOL . 'E2E summary:' . PHP_EOL;
echo json_encode([
    'db' => $dbFile,
    'qrcode' => $a['twocode'],
    'paid_prepay_status' => 1,
    'fulfilled_prepay_status' => 5,
    'expired_prepay_status' => 3,
    'unscanned_prepay_status' => 2,
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . PHP_EOL;
