-- =============================================\n-- 智慧水务管理系统 - 支付功能增强\n-- 版本: V2\n-- =============================================\n\n-- 增强缴费记录表，添加更多支付渠道信息\nALTER TABLE rev_payment ADD COLUMN IF NOT EXISTS transaction_id VARCHAR(100);\nALTER TABLE rev_payment ADD COLUMN IF NOT EXISTS operator_id BIGINT;\nALTER TABLE rev_payment ADD COLUMN IF NOT EXISTS remark VARCHAR(500);\n\n-- 创建支付方式枚举\nCREATE TABLE IF NOT EXISTS rev_payment_method (\n    id BIGSERIAL PRIMARY KEY,\n    method_code VARCHAR(20) UNIQUE NOT NULL,\n    method_name VARCHAR(50) NOT NULL,\n    method_type VARCHAR(20), -- cash/electronic/bank\n    enabled BOOLEAN DEFAULT true,\n    description TEXT,\n    created_at TIMESTAMP DEFAULT NOW(),\n    updated_at TIMESTAMP DEFAULT NOW()\n);\n\n-- 创建支付渠道表\nCREATE TABLE IF NOT EXISTS rev_payment_channel (\n    id BIGSERIAL PRIMARY KEY,\n    method_code VARCHAR(20) NOT NULL,\n    channel_code VARCHAR(30) UNIQUE NOT NULL,\n    channel_name VARCHAR(50) NOT NULL,\n    channel_type VARCHAR(20), -- pos/app/web/mini/counter\n    config JSONB, -- 渠道配置信息\n    enabled BOOLEAN DEFAULT true,\n    created_at TIMESTAMP DEFAULT NOW(),\n    updated_at TIMESTAMP DEFAULT NOW()\n);\n\n-- 创建支付统计表\nCREATE TABLE IF NOT EXISTS rev_payment_stat (\n    id BIGSERIAL PRIMARY KEY,\n    date DATE NOT NULL,\n    method_code VARCHAR(20),\n    channel_code VARCHAR(30),\n    payment_count BIGINT DEFAULT 0,\n    payment_amount DECIMAL(15,2) DEFAULT 0,\n    success_count BIGINT DEFAULT 0,\n    success_amount DECIMAL(15,2) DEFAULT 0,\n    fail_count BIGINT DEFAULT 0,\n    fail_amount DECIMAL(15,2) DEFAULT 0,\n    created_at TIMESTAMP DEFAULT NOW(),\n    updated_at TIMESTAMP DEFAULT NOW(),\n    UNIQUE(date, method_code, channel_code)\n);\n\n-- 添加支付方式枚举数据\nINSERT INTO rev_payment_method (method_code, method_name, method_type, description) VALUES \n('counter', '柜台支付', 'cash', '营业厅柜台现金支付'),\n('pos', 'POS支付', 'electronic', 'POS机刷卡支付'),\n('alipay', '支付宝', 'electronic', '支付宝移动支付'),\n('wechat', '微信支付', 'electronic', '微信移动支付'),\n('bank_transfer', '银行转账', 'bank', '银行转账支付')\nON CONFLICT (method_code) DO NOTHING;\n\n-- 添加支付渠道数据\nINSERT INTO rev_payment_channel (method_code, channel_code, channel_name, channel_type) VALUES \n('counter', 'counter_cash', '柜台现金', 'counter'),\n('counter', 'counter_card', '柜台刷卡', 'counter'),\n('pos', 'pos_counter', '柜台POS', 'pos'),\n('pos', 'pos_mobile', '移动POS', 'pos'),\n('alipay', 'alipay_app', '支付宝APP', 'app'),\n('alipay', 'alipay_wap', '支付宝网页', 'web'),\n('alipay', 'alipay_qr', '支付宝二维码', 'pos'),\n('wechat', 'wechat_app', '微信APP', 'app'),\n('wechat', 'wechat_wap', '微信网页', 'web'),\n('wechat', 'wechat_qr', '微信二维码', 'pos'),\n('wechat', 'wechat_mini', '微信小程序', 'mini'),\n('bank_transfer', 'counter_transfer', '柜台转账', 'counter'),\n('bank_transfer', 'online_transfer', '网上银行', 'web')\nON CONFLICT (channel_code) DO NOTHING;\n\n-- 创建支付流水表\nCREATE TABLE IF NOT EXISTS rev_payment_flow (\n    id BIGSERIAL PRIMARY KEY,\n    payment_no VARCHAR(50) UNIQUE NOT NULL,\n    order_no VARCHAR(100),\n    method_code VARCHAR(20),\n    channel_code VARCHAR(30),\n    amount DECIMAL(10,2) NOT NULL,\n    status VARCHAR(20) NOT NULL, -- pending/success/failed/cancelled\n    request_data JSONB,\n    response_data JSONB,\n    error_message TEXT,\n    created_at TIMESTAMP DEFAULT NOW(),\n    updated_at TIMESTAMP DEFAULT NOW()\n);\n\n-- 创建账单状态变更日志表\nCREATE TABLE IF NOT EXISTS rev_bill_status_log (\n    id BIGSERIAL PRIMARY KEY,\n    bill_id BIGINT NOT NULL,\n    old_status VARCHAR(20),\n    new_status VARCHAR(20) NOT NULL,\n    operator_id BIGINT,\n    remark TEXT,\n    created_at TIMESTAMP DEFAULT NOW(),\n    FOREIGN KEY (bill_id) REFERENCES rev_bill(id)\n);\n\n-- 添加索引\nCREATE INDEX IF NOT EXISTS idx_payment_method ON rev_payment(method_code);\nCREATE INDEX IF NOT EXISTS idx_payment_channel ON rev_payment(channel_code);\nCREATE INDEX IF NOT EXISTS idx_payment_date ON rev_payment(paid_at);\nCREATE INDEX IF NOT EXISTS idx_bill_status_log_bill ON rev_bill_status_log(bill_id);\nCREATE INDEX IF NOT EXISTS idx_payment_flow_status ON rev_payment_flow(status);\n\n-- 创建触发器：账单状态变更时自动记录日志\nCREATE OR REPLACE FUNCTION bill_status_changed()\nRETURNS TRIGGER AS $$\nBEGIN\n    IF OLD.status IS DISTINCT FROM NEW.status THEN\n        INSERT INTO rev_bill_status_log (bill_id, old_status, new_status, operator_id, remark)\n        VALUES (NEW.id, OLD.status, NEW.status, NEW.updated_by, '自动更新状态');\n    END IF;\n    RETURN NEW;\nEND;\n$$ LANGUAGE plpgsql;\n\n-- 创建触发器：当账单状态变更时自动触发\nCREATE TRIGGER trg_bill_status_changed\n    AFTER UPDATE ON rev_bill\n    FOR EACH ROW\n    EXECUTE FUNCTION bill_status_changed();\n\n-- 创建视图：客户缴费综合信息\nCREATE OR REPLACE VIEW v_customer_payment_summary AS\nSELECT \n    c.customer_id,\n    c.customer_no,\n    c.customer_name,\n    c.area,\n    c.phone,\n    COUNT(DISTINCT p.id) as payment_count,\n    SUM(p.amount) as total_amount,\n    COUNT(CASE WHEN p.status = 'success' THEN 1 END) as success_count,\n    SUM(CASE WHEN p.status = 'success' THEN p.amount END) as success_amount,\n    COUNT(CASE WHEN p.status = 'failed' THEN 1 END) as failed_count,\n    SUM(CASE WHEN p.status = 'failed' THEN p.amount END) as failed_amount,\n    MAX(p.paid_at) as last_payment_date\nFROM rev_customer c\nLEFT JOIN rev_payment p ON c.id = p.customer_id\nGROUP BY c.customer_id, c.customer_no, c.customer_name, c.area, c.phone;\n\n-- 创建视图：支付渠道统计\nCREATE OR REPLACE VIEW v_payment_channel_stats AS\nSELECT \n    pc.method_code,\n    pm.method_name,\n    pc.channel_code,\n    pc.channel_name,\n    COUNT(p.id) as transaction_count,\n    SUM(p.amount) as total_amount,\n    AVG(p.amount) as avg_amount,\n    MIN(p.paid_at) as first_payment,\n    MAX(p.paid_at) as last_payment\nFROM rev_payment p\nJOIN rev_payment_channel pc ON p.pay_channel = pc.channel_code\nJOIN rev_payment_method pm ON pc.method_code = pm.method_code\nGROUP BY pc.method_code, pm.method_name, pc.channel_code, pc.channel_name\nORDER BY pc.method_code, total_amount DESC;\n\n-- 插入示例数据：测试支付渠道配置\nINSERT INTO rev_payment_method (method_code, method_name, method_type, description) VALUES \n('test_method', '测试支付方式', 'electronic', '用于测试的支付方式')\nON CONFLICT (method_code) DO NOTHING;\n\nINSERT INTO rev_payment_channel (method_code, channel_code, channel_name, channel_type, config) VALUES \n('test_method', 'test_counter', '测试柜台', 'counter', '{\"terminal_id\": \"TEST001\"}'),\n('test_method', 'test_online', '测试在线', 'web', '{\"api_url\": \"https://test.example.com/pay\"}')\nON CONFLICT (channel_code) DO NOTHING;\n\n-- 创建存储过程：批量生成账单\nCREATE OR REPLACE PROCEDURE generate_bills_by_period(p_period VARCHAR)\nLANGUAGE plpgsql\nAS $$\nDECLARE\n    v_reading_count BIGINT;\n    v_bill_count BIGINT;\nBEGIN\n    -- 获取需要生成账单的抄表记录数量\n    SELECT COUNT(*) INTO v_reading_count\n    FROM rev_reading r\n    WHERE r.reading_period = p_period AND r.verified = 1\n    AND NOT EXISTS (SELECT 1 FROM rev_bill b WHERE b.reading_id = r.id);\n    \n    -- 生成账单\n    INSERT INTO rev_bill (bill_no, customer_id, meter_id, reading_id, bill_period, \n                         prev_reading, curr_reading, consumption, water_fee, sewage_fee, total_fee, status, due_date)\n    SELECT \n        'BILL-' || EXTRACT(EPOCH FROM NOW())::BIGINT || '-' || r.id,\n        m.customer_id,\n        r.meter_id,\n        r.id,\n        r.reading_period,\n        r.prev_reading,\n        r.curr_reading,\n        r.consumption,\n        -- 计算水费（这里简化处理，实际应该根据阶梯水价计算）\n        r.consumption * 0.45, -- 假设单价0.45元/立方米\n        -- 污水处理费（按用水量的80%计算）\n        r.consumption * 0.45 * 0.8,\n        -- 总费用\n        r.consumption * 0.45 + r.consumption * 0.45 * 0.8,\n        'pending',\n        CURRENT_DATE + INTERVAL '30 days'\n    FROM rev_reading r\n    JOIN rev_meter m ON r.meter_id = m.id\n    WHERE r.reading_period = p_period AND r.verified = 1\n    AND NOT EXISTS (SELECT 1 FROM rev_bill b WHERE b.reading_id = r.id);\n    \n    -- 获取生成的账单数量\n    GET DIAGNOSTICS v_bill_count = ROW_COUNT;\n    \n    -- 输出结果\n    RAISE NOTICE 'Period: %, Readings: %, Bills Generated: %', p_period, v_reading_count, v_bill_count;\nEND;\n$$;\n\n-- 创建存储过程：批量处理欠费账单\nCREATE OR REPLACE PROCEDURE process_overdue_bills()\nLANGUAGE plpgsql\nAS $$\nBEGIN\n    UPDATE rev_bill \n    SET status = 'overdue', \n        updated_at = CURRENT_TIMESTAMP\n    WHERE status = 'pending' \n    AND due_date < CURRENT_DATE;\n    \n    RAISE NOTICE 'Processed overdue bills';\nEND;\n$$;\n\n-- 创建存储过程：批量退款\nCREATE OR REPLACE PROCEDURE batch_refund(p_bill_ids BIGINT[], p_reason VARCHAR)\nLANGUAGE plpgsql\nAS $$\nDECLARE\n    v_bill_record RECORD;\nBEGIN\n    FOR v_bill_record IN SELECT * FROM unnest(p_bill_ids) AS id\n                         LEFT JOIN rev_bill ON id = rev_bill.id\n    LOOP\n        IF v_bill_record.rev_bill_id IS NOT NULL THEN\n            -- 更新账单状态\n            UPDATE rev_bill \n            SET status = 'refunded', \n                paid_fee = 0,\n                updated_at = CURRENT_TIMESTAMP\n            WHERE id = v_bill_record.id;\n            \n            -- 添加退款记录\n            INSERT INTO rev_payment (bill_id, customer_id, payment_no, amount, pay_method, pay_channel, remark)\n            SELECT id, customer_id, 'REFUND-' || EXTRACT(EPOCH FROM NOW())::BIGINT, paid_fee, 'refund', 'system', p_reason\n            FROM rev_bill \n            WHERE id = v_bill_record.id;\n        END IF;\n    END LOOP;\n    \n    RAISE NOTICE 'Processed % refunds', array_length(p_bill_ids, 1);\nEND;\n$$;\n\n-- 授权（如果需要）\n-- GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO water_revenue_user;\n-- GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO water_revenue_user;\n\n-- 创建索引优化查询性能\nCREATE INDEX IF NOT EXISTS idx_bill_period_customer ON rev_bill(bill_period, customer_id);\nCREATE INDEX IF NOT EXISTS idx_bill_amount ON rev_bill(total_fee);\nCREATE INDEX IF NOT EXISTS idx_payment_amount ON rev_payment(amount);\n\n-- 添加注释\nCOMMENT ON TABLE rev_payment_method IS '支付方式配置表';\nCOMMENT ON TABLE rev_payment_channel IS '支付渠道配置表';\nCOMMENT ON TABLE rev_payment_stat IS '支付统计表';\nCOMMENT ON TABLE rev_payment_flow IS '支付流水表';\nCOMMENT ON TABLE rev_bill_status_log IS '账单状态变更日志表';\nCOMMENT ON VIEW v_customer_payment_summary IS '客户缴费综合信息视图';\nCOMMENT ON VIEW v_payment_channel_stats IS '支付渠道统计视图';\n\n-- 添加示例测试数据\n-- 测试支付记录\nINSERT INTO rev_payment (bill_id, customer_id, payment_no, amount, pay_method, pay_channel, paid_at) \nSELECT id, customer_id, 'PAY-TEST-' || EXTRACT(EPOCH FROM NOW())::BIGINT || i, 50.00, 'counter', 'counter_cash', CURRENT_DATE - INTERVAL '1 day'\nFROM rev_bill \nWHERE status = 'paid' AND id <= 10\nON CONFLICT (payment_no) DO NOTHING;\n\n-- 测试支付宝支付记录\nINSERT INTO rev_payment (bill_id, customer_id, payment_no, amount, pay_method, pay_channel, paid_at) \nSELECT id, customer_id, 'PAY-ALI-' || EXTRACT(EPOCH FROM NOW())::BIGINT || i, 80.00, 'alipay', 'alipay_app', CURRENT_DATE - INTERVAL '2 days'\nFROM rev_bill \nWHERE status = 'paid' AND id BETWEEN 11 AND 20\nON CONFLICT (payment_no) DO NOTHING;\n\n-- 测试微信支付记录\nINSERT INTO rev_payment (bill_id, customer_id, payment_no, amount, pay_method, pay_channel, paid_at) \nSELECT id, customer_id, 'PAY-WX-' || EXTRACT(EPOCH FROM NOW())::BIGINT || i, 120.00, 'wechat', 'wechat_qr', CURRENT_DATE - INTERVAL '3 days'\nFROM rev_bill \nWHERE status = 'paid' AND id BETWEEN 21 AND 30\nON CONFLICT (payment_no) DO NOTHING;\n\n-- 完成升级\n-- 升级完成时间记录\nINSERT INTO sys_upgrade_log (version, description, upgrade_time) \nVALUES ('V2', '支付功能增强 - 支持多渠道支付、自动账单生成、支付统计', NOW())\nON CONFLICT (version) DO NOTHING;\n\n-- 输出升级完成信息\nRAISE NOTICE 'Payment enhancement upgrade completed successfully!';\nRAISE NOTICE 'Added tables: rev_payment_method, rev_payment_channel, rev_payment_stat, rev_payment_flow, rev_bill_status_log';\nRAISE NOTICE 'Added views: v_customer_payment_summary, v_payment_channel_stats';\nRAISE NOTICE 'Added procedures: generate_bills_by_period, process_overdue_bills, batch_refund';\nRAISE NOTICE 'Added triggers: trg_bill_status_changed';\nRAISE NOTICE 'Added indexes for performance optimization';\n