SlipParser.js

6.75 KB
23/06/2025 15:09
JS
SlipParser.js
/**
 * SlipParser.js (Updated with PromptPayQRParser)
 * วิเคราะห์และแยกข้อมูลจากข้อความสลิปการโอนเงิน
 * รองรับธนาคารไทยหลักทั้งหมด และ QR Code parsing ตามมาตรฐาน
 */
class SlipParser {
  constructor() {
    // ข้อมูลธนาคารไทย
    this.banks = {
      'SCB': {
        name: 'ธนาคารไทยพาณิชย์',
        keywords: ['ไทยพาณิชย์', 'SCB', 'Siam Commercial Bank'],
        color: '#4e1a8b',
        logo: 'assets/bank-logos/scb.png'
      },
      'KBANK': {
        name: 'ธนาคารกสิกรไทย',
        keywords: ['กสิกรไทย', 'KBANK', 'Kasikorn Bank', 'K-Bank'],
        color: '#16a34a',
        logo: 'assets/bank-logos/kbank.png'
      },
      'BBL': {
        name: 'ธนาคารกรุงเทพ',
        keywords: ['กรุงเทพ', 'BBL', 'Bangkok Bank'],
        color: '#1e40af',
        logo: 'assets/bank-logos/bbl.png'
      },
      'KTB': {
        name: 'ธนาคารกรุงไทย',
        keywords: ['กรุงไทย', 'KTB', 'Krung Thai Bank'],
        color: '#1e7e34',
        logo: 'assets/bank-logos/ktb.png'
      },
      'TMB': {
        name: 'ธนาคารทหารไทย',
        keywords: ['ทหารไทย', 'TMB', 'TMB Bank'],
        color: '#6366f1',
        logo: 'assets/bank-logos/tmb.png'
      },
      'GSB': {
        name: 'ธนาคารออมสิน',
        keywords: ['ออมสิน', 'GSB', 'Government Savings Bank'],
        color: '#dc2626',
        logo: 'assets/bank-logos/gsb.png'
      },
      'BAAC': {
        name: 'ธนาคารเพื่อการเกษตรและสหกรณ์การเกษตร',
        keywords: ['เกษตรและสหกรณ์', 'BAAC', 'เกษตร'],
        color: '#059669',
        logo: 'assets/bank-logos/baac.png'
      }
    };

    // รูปแบบการค้นหาข้อมูล
    this.patterns = {
      // จำนวนเงิน
      amount: [
        /จำนวนเงิน[:\s]*฿?\s*([\d,]+\.?\d*)/i,
        /Amount[:\s]*฿?\s*([\d,]+\.?\d*)/i,
        /฿\s*([\d,]+\.?\d*)/,
        /([\d,]+\.?\d*)\s*บาท/,
        /เงิน[:\s]*([\d,]+\.?\d*)/
      ],

      // วันที่และเวลา
      datetime: [
        /(\d{1,2}\/\d{1,2}\/\d{4})\s*(\d{1,2}:\d{2})/,
        /(\d{1,2}-\d{1,2}-\d{4})\s*(\d{1,2}:\d{2})/,
        /วันที่[:\s]*(\d{1,2}\/\d{1,2}\/\d{4})/,
        /เวลา[:\s]*(\d{1,2}:\d{2})/
      ],

      // ผู้โอน
      sender: [
        /จาก[:\s]*(.+?)(?=\s*ไปยัง|\s*ถึง|\s*To|\n|$)/i,
        /From[:\s]*(.+?)(?=\s*To|\s*ไปยัง|\n|$)/i,
        /ผู้โอน[:\s]*(.+?)(?=\s*ผู้รับ|\s*ไปยัง|\n|$)/i
      ],

      // ผู้รับ
      receiver: [
        /ไปยัง[:\s]*(.+?)(?=\s*จำนวน|\s*Amount|\n|$)/i,
        /To[:\s]*(.+?)(?=\s*Amount|\s*จำนวน|\n|$)/i,
        /ผู้รับ[:\s]*(.+?)(?=\s*จำนวน|\s*Amount|\n|$)/i,
        /ถึง[:\s]*(.+?)(?=\s*จำนวน|\s*Amount|\n|$)/i
      ],

      // รหัสอ้างอิง
      reference: [
        /รหัสอ้างอิง[:\s]*(.+?)(?=\s|\n|$)/i,
        /Reference[:\s]*(.+?)(?=\s|\n|$)/i,
        /Ref[:\s]*(.+?)(?=\s|\n|$)/i,
        /อ้างอิง[:\s]*(.+?)(?=\s|\n|$)/i,
        /Transaction ID[:\s]*(.+?)(?=\s|\n|$)/i
      ]
    };
  }

  /**
   * วิเคราะห์ข้อความและแยกข้อมูลสลิป
   */
  parse(text) {
    const result = {
      amount: null,
      datetime: null,
      sender: null,
      receiver: null,
      reference: null,
      bank: null,
      confidence: 0,
      raw_text: text
    };

    if (!text || text.trim().length === 0) {
      return result;
    }

    // ระบุธนาคาร
    result.bank = this.identifyBank(text);

    // แยกข้อมูลตามรูปแบบ
    result.amount = this.extractAmount(text);
    result.datetime = this.extractDateTime(text);
    result.sender = this.extractSender(text);
    result.receiver = this.extractReceiver(text);
    result.reference = this.extractReference(text);

    // คำนวณความมั่นใจ
    result.confidence = this.calculateConfidence(result);

    return result;
  }

  /**
   * ระบุธนาคารจากข้อความ
   */
  identifyBank(text) {
    for (const [code, bank] of Object.entries(this.banks)) {
      for (const keyword of bank.keywords) {
        if (text.includes(keyword)) {
          return code;
        }
      }
    }
    return null;
  }

  /**
   * แยกจำนวนเงิน
   */
  extractAmount(text) {
    for (const pattern of this.patterns.amount) {
      const match = text.match(pattern);
      if (match) {
        const amount = parseFloat(match[1].replace(/,/g, ''));
        if (!isNaN(amount) && amount > 0) {
          return amount;
        }
      }
    }
    return null;
  }

  /**
   * แยกวันที่และเวลา
   */
  extractDateTime(text) {
    for (const pattern of this.patterns.datetime) {
      const match = text.match(pattern);
      if (match) {
        if (match.length >= 3) {
          return `${match[1]} ${match[2]}`;
        } else {
          return match[1];
        }
      }
    }
    return null;
  }

  /**
   * แยกผู้โอน
   */
  extractSender(text) {
    for (const pattern of this.patterns.sender) {
      const match = text.match(pattern);
      if (match) {
        return match[1].trim();
      }
    }
    return null;
  }

  /**
   * แยกผู้รับ
   */
  extractReceiver(text) {
    for (const pattern of this.patterns.receiver) {
      const match = text.match(pattern);
      if (match) {
        return match[1].trim();
      }
    }
    return null;
  }

  /**
   * แยกรหัสอ้างอิง
   */
  extractReference(text) {
    for (const pattern of this.patterns.reference) {
      const match = text.match(pattern);
      if (match) {
        return match[1].trim();
      }
    }
    return null;
  }

  /**
   * คำนวณความมั่นใจ
   */
  calculateConfidence(result) {
    let score = 0;
    const weights = {
      amount: 30,
      datetime: 20,
      sender: 15,
      receiver: 15,
      reference: 10,
      bank: 10
    };

    Object.keys(weights).forEach(field => {
      if (result[field]) {
        score += weights[field];
      }
    });

    return Math.min(score, 100);
  }
}