Skip to content

财务管理自动化 - 发票与报销流程

财务管理是企业运营的核心,但传统的财务流程往往繁琐且容易出错。今天我们来构建一个智能化的财务管理系统,实现从发票处理到费用报销的全流程自动化。

系统架构设计

财务自动化流程概览

mermaid
graph TD
    A[发票接收] --> B[OCR识别]
    B --> C[数据验证]
    C --> D[自动记账]
    D --> E[费用分类]
    E --> F[审批流程]
    F --> G[付款处理]

    H[费用报销] --> I[票据验证]
    I --> J[合规检查]
    J --> K[审批流程]
    K --> L[报销支付]

    M[预算管理] --> N[支出监控]
    N --> O[预警通知]

数据模型设计

发票数据模型

javascript
const invoiceSchema = {
  id: 'string',
  invoiceNumber: 'string',
  supplierName: 'string',
  supplierTaxId: 'string',

  // 发票信息
  issueDate: 'date',
  dueDate: 'date',
  currency: 'string',
  totalAmount: 'number',
  taxAmount: 'number',
  netAmount: 'number',

  // 明细项目
  lineItems: [{
    description: 'string',
    quantity: 'number',
    unitPrice: 'number',
    amount: 'number',
    taxRate: 'number',
    category: 'string'
  }],

  // 处理状态
  status: 'string',          // received, processed, approved, paid, rejected
  ocrResult: {},
  validationResult: {},

  createdAt: 'date',
  updatedAt: 'date'
};

发票处理自动化

发票识别和提取

OCR发票识别系统

javascript
// 发票OCR处理管理器
class InvoiceOCRProcessor {
  constructor() {
    this.ocrProviders = {
      baidu: new BaiduOCR(),
      tencent: new TencentOCR(),
      aliyun: new AliyunOCR()
    };
    this.invoiceValidator = new InvoiceValidator();
  }

  // 处理发票图片
  async processInvoiceImage(imageBuffer, imageType) {
    const processingResult = {
      success: false,
      extractedData: null,
      confidence: 0,
      errors: []
    };

    try {
      // 图片预处理
      const preprocessedImage = await this.preprocessImage(imageBuffer);

      // 多个OCR服务并行处理
      const ocrResults = await Promise.all([
        this.ocrProviders.baidu.recognizeInvoice(preprocessedImage),
        this.ocrProviders.tencent.recognizeInvoice(preprocessedImage),
        this.ocrProviders.aliyun.recognizeInvoice(preprocessedImage)
      ]);

      // 结果融合和验证
      const mergedResult = await this.mergeOCRResults(ocrResults);

      // 数据验证
      const validationResult = await this.invoiceValidator.validate(mergedResult);

      if (validationResult.isValid) {
        processingResult.success = true;
        processingResult.extractedData = mergedResult;
        processingResult.confidence = this.calculateConfidence(ocrResults);
      } else {
        processingResult.errors = validationResult.errors;
      }

    } catch (error) {
      processingResult.errors.push(error.message);
    }

    return processingResult;
  }

  // 图片预处理
  async preprocessImage(imageBuffer) {
    const sharp = require('sharp');

    return await sharp(imageBuffer)
      .resize(2000, null, { withoutEnlargement: true })
      .normalize()
      .sharpen()
      .toBuffer();
  }

  // 合并OCR结果
  async mergeOCRResults(results) {
    const mergedData = {
      invoiceNumber: this.selectBestValue(results, 'invoiceNumber'),
      supplierName: this.selectBestValue(results, 'supplierName'),
      supplierTaxId: this.selectBestValue(results, 'supplierTaxId'),
      issueDate: this.selectBestValue(results, 'issueDate'),
      totalAmount: this.selectBestValue(results, 'totalAmount'),
      taxAmount: this.selectBestValue(results, 'taxAmount'),
      lineItems: this.mergeLineItems(results)
    };

    return mergedData;
  }

  // 选择最佳值
  selectBestValue(results, field) {
    const values = results
      .map(result => result.data[field])
      .filter(value => value && value.confidence > 0.8);

    if (values.length === 0) return null;

    // 返回置信度最高的值
    return values.reduce((best, current) =>
      current.confidence > best.confidence ? current : best
    ).value;
  }
}

// 百度OCR服务
class BaiduOCR {
  async recognizeInvoice(imageBuffer) {
    const response = await fetch('https://aip.baidubce.com/rest/2.0/ocr/v1/vat_invoice', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': `Bearer ${await this.getAccessToken()}`
      },
      body: `image=${imageBuffer.toString('base64')}`
    });

    const result = await response.json();

    return {
      provider: 'baidu',
      data: this.parseBaiduResult(result),
      confidence: result.words_result_num > 0 ? 0.9 : 0.1
    };
  }

  parseBaiduResult(result) {
    const wordsResult = result.words_result;

    return {
      invoiceNumber: {
        value: wordsResult.InvoiceNum?.words,
        confidence: wordsResult.InvoiceNum?.probability?.average || 0
      },
      supplierName: {
        value: wordsResult.SellerName?.words,
        confidence: wordsResult.SellerName?.probability?.average || 0
      },
      totalAmount: {
        value: parseFloat(wordsResult.TotalAmount?.words),
        confidence: wordsResult.TotalAmount?.probability?.average || 0
      },
      issueDate: {
        value: wordsResult.InvoiceDate?.words,
        confidence: wordsResult.InvoiceDate?.probability?.average || 0
      }
    };
  }
}

发票验证系统

发票数据验证器

javascript
// 发票验证管理器
class InvoiceValidator {
  constructor() {
    this.taxAuthority = new TaxAuthorityAPI();
    this.supplierDatabase = new SupplierDatabase();
  }

  // 验证发票数据
  async validate(invoiceData) {
    const validationResult = {
      isValid: true,
      errors: [],
      warnings: [],
      verifications: {}
    };

    // 基础数据验证
    const basicValidation = await this.validateBasicData(invoiceData);
    if (!basicValidation.isValid) {
      validationResult.isValid = false;
      validationResult.errors.push(...basicValidation.errors);
    }

    // 税务验证
    const taxValidation = await this.validateWithTaxAuthority(invoiceData);
    validationResult.verifications.taxAuthority = taxValidation;

    if (!taxValidation.isValid) {
      validationResult.warnings.push('税务验证失败,请人工核实');
    }

    // 供应商验证
    const supplierValidation = await this.validateSupplier(invoiceData);
    validationResult.verifications.supplier = supplierValidation;

    // 金额计算验证
    const amountValidation = this.validateAmounts(invoiceData);
    if (!amountValidation.isValid) {
      validationResult.isValid = false;
      validationResult.errors.push(...amountValidation.errors);
    }

    return validationResult;
  }

  // 基础数据验证
  async validateBasicData(invoiceData) {
    const validation = { isValid: true, errors: [] };

    // 必填字段检查
    const requiredFields = ['invoiceNumber', 'supplierName', 'totalAmount', 'issueDate'];
    for (const field of requiredFields) {
      if (!invoiceData[field]) {
        validation.isValid = false;
        validation.errors.push(`缺少必填字段: ${field}`);
      }
    }

    // 发票号码格式验证
    if (invoiceData.invoiceNumber && !this.isValidInvoiceNumber(invoiceData.invoiceNumber)) {
      validation.isValid = false;
      validation.errors.push('发票号码格式不正确');
    }

    // 日期格式验证
    if (invoiceData.issueDate && !this.isValidDate(invoiceData.issueDate)) {
      validation.isValid = false;
      validation.errors.push('开票日期格式不正确');
    }

    // 金额范围验证
    if (invoiceData.totalAmount && (invoiceData.totalAmount <= 0 || invoiceData.totalAmount > 10000000)) {
      validation.isValid = false;
      validation.errors.push('发票金额超出合理范围');
    }

    return validation;
  }

  // 税务机关验证
  async validateWithTaxAuthority(invoiceData) {
    try {
      const verificationResult = await this.taxAuthority.verifyInvoice({
        invoiceNumber: invoiceData.invoiceNumber,
        invoiceDate: invoiceData.issueDate,
        totalAmount: invoiceData.totalAmount,
        supplierTaxId: invoiceData.supplierTaxId
      });

      return {
        isValid: verificationResult.status === 'valid',
        details: verificationResult,
        verifiedAt: new Date()
      };
    } catch (error) {
      return {
        isValid: false,
        error: error.message,
        verifiedAt: new Date()
      };
    }
  }

  // 金额计算验证
  validateAmounts(invoiceData) {
    const validation = { isValid: true, errors: [] };

    if (invoiceData.lineItems && invoiceData.lineItems.length > 0) {
      // 计算明细总额
      const calculatedNet = invoiceData.lineItems.reduce((sum, item) =>
        sum + (item.quantity * item.unitPrice), 0
      );

      const calculatedTax = invoiceData.lineItems.reduce((sum, item) =>
        sum + (item.quantity * item.unitPrice * item.taxRate / 100), 0
      );

      const calculatedTotal = calculatedNet + calculatedTax;

      // 允许小额误差(1分钱)
      const tolerance = 0.01;

      if (Math.abs(calculatedTotal - invoiceData.totalAmount) > tolerance) {
        validation.isValid = false;
        validation.errors.push(`金额计算不匹配,计算值: ${calculatedTotal}, 发票值: ${invoiceData.totalAmount}`);
      }
    }

    return validation;
  }

  // 发票号码格式验证
  isValidInvoiceNumber(invoiceNumber) {
    // 中国增值税发票号码格式验证
    const pattern = /^\d{8}$/;
    return pattern.test(invoiceNumber);
  }

  // 日期格式验证
  isValidDate(dateString) {
    const date = new Date(dateString);
    return date instanceof Date && !isNaN(date);
  }
}

报销流程自动化

费用报销是企业日常财务管理的重要环节,我们需要建立高效的自动化报销系统。

报销申请处理

费用报销管理器

javascript
// 费用报销管理器
class ExpenseReimbursementManager {
  constructor() {
    this.receiptProcessor = new ReceiptProcessor();
    this.policyEngine = new ExpensePolicyEngine();
    this.approvalWorkflow = new ApprovalWorkflow();
    this.paymentProcessor = new PaymentProcessor();
  }

  // 处理报销申请
  async processExpenseApplication(applicationData) {
    const processResult = {
      applicationId: this.generateApplicationId(),
      status: 'processing',
      validationResults: [],
      approvalStatus: 'pending',
      errors: []
    };

    try {
      // 创建报销申请
      const application = await this.createExpenseApplication(applicationData);
      processResult.applicationId = application.id;

      // 处理票据
      const receiptResults = await this.processReceipts(application.receipts);
      processResult.receiptProcessing = receiptResults;

      // 政策合规检查
      const policyCheck = await this.policyEngine.validateExpenses(application);
      processResult.validationResults = policyCheck.results;

      if (policyCheck.hasViolations) {
        processResult.status = 'rejected';
        processResult.errors = policyCheck.violations;
        return processResult;
      }

      // 启动审批流程
      const approvalResult = await this.approvalWorkflow.startApproval(application);
      processResult.approvalStatus = approvalResult.status;
      processResult.approvalWorkflowId = approvalResult.workflowId;

      processResult.status = 'submitted';

    } catch (error) {
      processResult.status = 'failed';
      processResult.errors.push(error.message);
    }

    return processResult;
  }

  // 创建报销申请
  async createExpenseApplication(data) {
    const application = {
      id: this.generateApplicationId(),
      employeeId: data.employeeId,
      employeeName: data.employeeName,
      department: data.department,
      title: data.title,
      description: data.description,
      totalAmount: 0,
      currency: data.currency || 'CNY',
      expenseDate: data.expenseDate,
      expenses: [],
      receipts: data.receipts || [],
      status: 'draft',
      createdAt: new Date(),
      updatedAt: new Date()
    };

    // 处理费用明细
    for (const expense of data.expenses) {
      const processedExpense = {
        id: this.generateExpenseId(),
        category: expense.category,
        subcategory: expense.subcategory,
        amount: parseFloat(expense.amount),
        description: expense.description,
        merchant: expense.merchant,
        location: expense.location,
        receiptId: expense.receiptId
      };

      application.expenses.push(processedExpense);
      application.totalAmount += processedExpense.amount;
    }

    // 保存到数据库
    await this.saveExpenseApplication(application);

    return application;
  }

  // 处理票据
  async processReceipts(receipts) {
    const results = [];

    for (const receipt of receipts) {
      try {
        const processingResult = await this.receiptProcessor.processReceipt(receipt);
        results.push({
          receiptId: receipt.id,
          success: true,
          extractedData: processingResult.data,
          confidence: processingResult.confidence
        });
      } catch (error) {
        results.push({
          receiptId: receipt.id,
          success: false,
          error: error.message
        });
      }
    }

    return results;
  }
}

// 票据处理器
class ReceiptProcessor {
  constructor() {
    this.ocrService = new OCRService();
    this.receiptValidator = new ReceiptValidator();
  }

  async processReceipt(receiptImage) {
    // OCR识别
    const ocrResult = await this.ocrService.recognizeReceipt(receiptImage);

    // 数据验证
    const validationResult = await this.receiptValidator.validate(ocrResult);

    if (!validationResult.isValid) {
      throw new Error(`票据验证失败: ${validationResult.errors.join(', ')}`);
    }

    return {
      data: ocrResult,
      confidence: ocrResult.confidence,
      validationResult: validationResult
    };
  }
}

费用政策引擎

费用政策验证器

javascript
// 费用政策引擎
class ExpensePolicyEngine {
  constructor() {
    this.policies = this.loadExpensePolicies();
  }

  // 验证费用合规性
  async validateExpenses(application) {
    const validationResult = {
      isValid: true,
      hasViolations: false,
      results: [],
      violations: []
    };

    for (const expense of application.expenses) {
      const expenseValidation = await this.validateSingleExpense(expense, application);
      validationResult.results.push(expenseValidation);

      if (!expenseValidation.isValid) {
        validationResult.isValid = false;
        validationResult.hasViolations = true;
        validationResult.violations.push(...expenseValidation.violations);
      }
    }

    // 总额验证
    const totalValidation = this.validateTotalAmount(application);
    if (!totalValidation.isValid) {
      validationResult.isValid = false;
      validationResult.hasViolations = true;
      validationResult.violations.push(...totalValidation.violations);
    }

    return validationResult;
  }

  // 验证单个费用项目
  async validateSingleExpense(expense, application) {
    const validation = {
      expenseId: expense.id,
      isValid: true,
      violations: [],
      warnings: []
    };

    const policy = this.policies[expense.category];
    if (!policy) {
      validation.isValid = false;
      validation.violations.push(`未找到费用类别 ${expense.category} 的政策`);
      return validation;
    }

    // 单笔金额限制
    if (policy.maxAmount && expense.amount > policy.maxAmount) {
      validation.isValid = false;
      validation.violations.push(
        `${expense.category} 单笔金额 ${expense.amount} 超过限额 ${policy.maxAmount}`
      );
    }

    // 月度累计限制
    if (policy.monthlyLimit) {
      const monthlyTotal = await this.getMonthlyExpenseTotal(
        application.employeeId,
        expense.category
      );

      if (monthlyTotal + expense.amount > policy.monthlyLimit) {
        validation.isValid = false;
        validation.violations.push(
          `${expense.category} 月度累计金额将超过限额 ${policy.monthlyLimit}`
        );
      }
    }

    // 票据要求
    if (policy.requireReceipt && !expense.receiptId) {
      validation.isValid = false;
      validation.violations.push(`${expense.category} 需要提供票据`);
    }

    // 特殊规则验证
    if (policy.specialRules) {
      const specialValidation = await this.validateSpecialRules(
        expense,
        policy.specialRules,
        application
      );

      if (!specialValidation.isValid) {
        validation.isValid = false;
        validation.violations.push(...specialValidation.violations);
      }
    }

    return validation;
  }

  // 加载费用政策
  loadExpensePolicies() {
    return {
      travel: {
        maxAmount: 5000,
        monthlyLimit: 20000,
        requireReceipt: true,
        specialRules: ['domestic_travel_rate', 'accommodation_standard']
      },
      meal: {
        maxAmount: 200,
        monthlyLimit: 2000,
        requireReceipt: true,
        specialRules: ['meal_standard_by_city']
      },
      office: {
        maxAmount: 1000,
        monthlyLimit: 5000,
        requireReceipt: true,
        specialRules: ['office_supply_approval']
      },
      training: {
        maxAmount: 10000,
        monthlyLimit: 50000,
        requireReceipt: true,
        specialRules: ['training_pre_approval']
      }
    };
  }

  // 验证特殊规则
  async validateSpecialRules(expense, rules, application) {
    const validation = { isValid: true, violations: [] };

    for (const rule of rules) {
      const ruleResult = await this.executeRule(rule, expense, application);
      if (!ruleResult.isValid) {
        validation.isValid = false;
        validation.violations.push(ruleResult.message);
      }
    }

    return validation;
  }

  // 执行规则
  async executeRule(ruleName, expense, application) {
    switch (ruleName) {
      case 'domestic_travel_rate':
        return this.validateDomesticTravelRate(expense);

      case 'meal_standard_by_city':
        return this.validateMealStandardByCity(expense, application);

      case 'training_pre_approval':
        return this.validateTrainingPreApproval(expense, application);

      default:
        return { isValid: true };
    }
  }
}

审批流程引擎

智能审批工作流

javascript
// 审批工作流管理器
class ApprovalWorkflow {
  constructor() {
    this.approvalRules = this.loadApprovalRules();
    this.notificationService = new NotificationService();
  }

  // 启动审批流程
  async startApproval(application) {
    const workflow = {
      id: this.generateWorkflowId(),
      applicationId: application.id,
      status: 'active',
      currentLevel: 1,
      approvalLevels: [],
      startedAt: new Date()
    };

    // 确定审批层级
    workflow.approvalLevels = await this.determineApprovalLevels(application);

    // 启动第一级审批
    const firstLevel = workflow.approvalLevels[0];
    await this.startApprovalLevel(workflow, firstLevel);

    // 保存工作流
    await this.saveApprovalWorkflow(workflow);

    return {
      workflowId: workflow.id,
      status: 'started',
      currentApprover: firstLevel.approver,
      estimatedDuration: this.estimateApprovalDuration(workflow.approvalLevels)
    };
  }

  // 确定审批层级
  async determineApprovalLevels(application) {
    const levels = [];
    const amount = application.totalAmount;
    const department = application.department;
    const category = application.expenses[0]?.category;

    // 直接主管审批(所有报销都需要)
    levels.push({
      level: 1,
      type: 'direct_manager',
      approver: await this.getDirectManager(application.employeeId),
      required: true,
      autoApprove: amount < 100 // 小额自动通过
    });

    // 部门经理审批(中等金额)
    if (amount > 1000) {
      levels.push({
        level: 2,
        type: 'department_manager',
        approver: await this.getDepartmentManager(department),
        required: true,
        autoApprove: false
      });
    }

    // 财务审批(大额或特殊类别)
    if (amount > 5000 || ['training', 'equipment'].includes(category)) {
      levels.push({
        level: 3,
        type: 'finance_manager',
        approver: await this.getFinanceManager(),
        required: true,
        autoApprove: false
      });
    }

    // 总经理审批(超大额)
    if (amount > 20000) {
      levels.push({
        level: 4,
        type: 'general_manager',
        approver: await this.getGeneralManager(),
        required: true,
        autoApprove: false
      });
    }

    return levels;
  }

  // 处理审批决定
  async processApprovalDecision(workflowId, decision) {
    const workflow = await this.getApprovalWorkflow(workflowId);
    const currentLevel = workflow.approvalLevels[workflow.currentLevel - 1];

    // 记录审批决定
    currentLevel.status = decision.approved ? 'approved' : 'rejected';
    currentLevel.approvedAt = new Date();
    currentLevel.comments = decision.comments;
    currentLevel.approver = decision.approverId;

    if (decision.approved) {
      // 检查是否还有下一级审批
      if (workflow.currentLevel < workflow.approvalLevels.length) {
        // 进入下一级审批
        workflow.currentLevel++;
        const nextLevel = workflow.approvalLevels[workflow.currentLevel - 1];
        await this.startApprovalLevel(workflow, nextLevel);

        workflow.status = 'active';
      } else {
        // 所有审批完成
        workflow.status = 'approved';
        workflow.completedAt = new Date();

        // 触发支付流程
        await this.triggerPaymentProcess(workflow.applicationId);
      }
    } else {
      // 审批被拒绝
      workflow.status = 'rejected';
      workflow.completedAt = new Date();

      // 通知申请人
      await this.notifyRejection(workflow, decision);
    }

    // 更新工作流状态
    await this.updateApprovalWorkflow(workflow);

    return workflow;
  }

  // 启动审批级别
  async startApprovalLevel(workflow, level) {
    // 自动审批检查
    if (level.autoApprove) {
      level.status = 'approved';
      level.approvedAt = new Date();
      level.comments = '系统自动审批';
      return;
    }

    // 发送审批通知
    await this.notificationService.sendApprovalNotification({
      approverId: level.approver,
      workflowId: workflow.id,
      applicationId: workflow.applicationId,
      level: level.level,
      type: level.type
    });

    // 设置超时提醒
    this.scheduleApprovalReminder(workflow.id, level);
  }

  // 设置审批提醒
  scheduleApprovalReminder(workflowId, level) {
    // 24小时后发送提醒
    setTimeout(async () => {
      const workflow = await this.getApprovalWorkflow(workflowId);
      if (workflow.status === 'active' && workflow.currentLevel === level.level) {
        await this.notificationService.sendApprovalReminder({
          approverId: level.approver,
          workflowId: workflowId,
          overdueDays: 1
        });
      }
    }, 24 * 60 * 60 * 1000);
  }
}

财务数据集成

财务系统需要与多个外部系统集成,实现数据的自动同步和处理。

ERP 系统集成

ERP集成管理器

javascript
// ERP系统集成管理器
class ERPIntegrationManager {
  constructor() {
    this.erpConnectors = {
      sap: new SAPConnector(),
      oracle: new OracleConnector(),
      kingdee: new KingdeeConnector(),
      ufida: new UFidaConnector()
    };
    this.dataMapper = new DataMapper();
  }

  // 同步发票数据到ERP
  async syncInvoiceToERP(invoice, erpSystem) {
    const connector = this.erpConnectors[erpSystem];
    if (!connector) {
      throw new Error(`不支持的ERP系统: ${erpSystem}`);
    }

    try {
      // 数据映射
      const erpData = await this.dataMapper.mapInvoiceToERP(invoice, erpSystem);

      // 同步到ERP
      const syncResult = await connector.createInvoice(erpData);

      // 更新本地记录
      await this.updateInvoiceERPInfo(invoice.id, {
        erpSystem: erpSystem,
        erpId: syncResult.id,
        syncedAt: new Date(),
        status: 'synced'
      });

      return syncResult;

    } catch (error) {
      // 记录同步失败
      await this.logSyncError(invoice.id, erpSystem, error);
      throw error;
    }
  }

  // 同步费用报销到ERP
  async syncExpenseToERP(expense, erpSystem) {
    const connector = this.erpConnectors[erpSystem];

    // 数据映射
    const erpData = await this.dataMapper.mapExpenseToERP(expense, erpSystem);

    // 创建会计凭证
    const voucherResult = await connector.createAccountingVoucher({
      date: expense.expenseDate,
      description: expense.description,
      entries: this.generateAccountingEntries(expense)
    });

    return voucherResult;
  }

  // 生成会计分录
  generateAccountingEntries(expense) {
    const entries = [];

    for (const item of expense.expenses) {
      // 借方:费用科目
      entries.push({
        account: this.getExpenseAccount(item.category),
        debit: item.amount,
        credit: 0,
        description: item.description,
        department: expense.department
      });
    }

    // 贷方:应付账款或现金
    entries.push({
      account: expense.payment.method === 'cash' ? '1001' : '2202',
      debit: 0,
      credit: expense.totalAmount,
      description: `${expense.employeeName}报销`,
      department: expense.department
    });

    return entries;
  }

  // 获取费用科目
  getExpenseAccount(category) {
    const accountMapping = {
      travel: '6601',      // 差旅费
      meal: '6602',        // 业务招待费
      office: '6603',      // 办公费
      training: '6604',    // 培训费
      communication: '6605' // 通讯费
    };

    return accountMapping[category] || '6699'; // 其他费用
  }
}

// 金蝶ERP连接器
class KingdeeConnector {
  constructor() {
    this.baseUrl = process.env.KINGDEE_API_URL;
    this.sessionId = null;
  }

  // 登录获取会话
  async login() {
    const response = await fetch(`${this.baseUrl}/K3Cloud/Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUser.common.kdsvc`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        acctID: process.env.KINGDEE_ACCT_ID,
        username: process.env.KINGDEE_USERNAME,
        password: process.env.KINGDEE_PASSWORD,
        lcid: 2052
      })
    });

    const result = await response.json();
    if (result.LoginResultType === 1) {
      this.sessionId = result.Context.SessionId;
      return true;
    }

    throw new Error('金蝶ERP登录失败');
  }

  // 创建发票
  async createInvoice(invoiceData) {
    if (!this.sessionId) {
      await this.login();
    }

    const response = await fetch(`${this.baseUrl}/K3Cloud/Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Save.common.kdsvc`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Cookie': `kdservice-sessionid=${this.sessionId}`
      },
      body: JSON.stringify({
        formid: 'AP_Payable',
        data: {
          FBillNo: invoiceData.invoiceNumber,
          FSupplierID: { FNumber: invoiceData.supplierCode },
          FDate: invoiceData.issueDate,
          FPayableAmountFor: invoiceData.totalAmount,
          FTaxAmountFor: invoiceData.taxAmount,
          FBillEntry: invoiceData.lineItems.map(item => ({
            FMaterialID: { FNumber: item.materialCode },
            FQty: item.quantity,
            FPrice: item.unitPrice,
            FAmount: item.amount
          }))
        }
      })
    });

    const result = await response.json();

    if (result.Result.ResponseStatus.IsSuccess) {
      return {
        id: result.Result.Id,
        billNo: result.Result.Number
      };
    }

    throw new Error(`创建发票失败: ${result.Result.ResponseStatus.Errors[0].Message}`);
  }
}

银行对账自动化

银行对账管理器

javascript
// 银行对账管理器
class BankReconciliationManager {
  constructor() {
    this.bankConnectors = {
      icbc: new ICBCConnector(),
      ccb: new CCBConnector(),
      abc: new ABCConnector(),
      boc: new BOCConnector()
    };
    this.reconciliationEngine = new ReconciliationEngine();
  }

  // 执行银行对账
  async performReconciliation(accountId, reconciliationDate) {
    const reconciliation = {
      id: this.generateReconciliationId(),
      accountId: accountId,
      reconciliationDate: reconciliationDate,
      status: 'processing',
      startTime: new Date(),
      results: {
        matched: [],
        unmatched: [],
        bankOnly: [],
        bookOnly: []
      }
    };

    try {
      // 获取银行流水
      const bankStatements = await this.getBankStatements(accountId, reconciliationDate);

      // 获取账面记录
      const bookRecords = await this.getBookRecords(accountId, reconciliationDate);

      // 执行匹配
      const matchingResult = await this.reconciliationEngine.match(
        bankStatements,
        bookRecords
      );

      reconciliation.results = matchingResult;
      reconciliation.status = 'completed';

      // 生成对账报告
      const report = await this.generateReconciliationReport(reconciliation);
      reconciliation.reportId = report.id;

      // 处理未匹配项目
      await this.handleUnmatchedItems(reconciliation.results.unmatched);

    } catch (error) {
      reconciliation.status = 'failed';
      reconciliation.error = error.message;
    } finally {
      reconciliation.endTime = new Date();
      await this.saveReconciliation(reconciliation);
    }

    return reconciliation;
  }

  // 获取银行流水
  async getBankStatements(accountId, date) {
    const account = await this.getBankAccount(accountId);
    const connector = this.bankConnectors[account.bankCode];

    if (!connector) {
      throw new Error(`不支持的银行: ${account.bankCode}`);
    }

    const statements = await connector.getStatements({
      accountNumber: account.accountNumber,
      startDate: date,
      endDate: date
    });

    return statements.map(stmt => ({
      id: stmt.transactionId,
      date: stmt.transactionDate,
      amount: stmt.amount,
      description: stmt.description,
      balance: stmt.balance,
      type: stmt.type, // debit, credit
      reference: stmt.reference
    }));
  }

  // 获取账面记录
  async getBookRecords(accountId, date) {
    const query = `
      SELECT
        id,
        transaction_date,
        amount,
        description,
        reference_number,
        transaction_type
      FROM accounting_transactions
      WHERE account_id = ?
        AND transaction_date = ?
        AND status = 'posted'
      ORDER BY transaction_date, amount
    `;

    const records = await this.executeQuery(query, [accountId, date]);

    return records.map(record => ({
      id: record.id,
      date: record.transaction_date,
      amount: record.amount,
      description: record.description,
      reference: record.reference_number,
      type: record.transaction_type
    }));
  }
}

// 对账匹配引擎
class ReconciliationEngine {
  // 执行匹配
  async match(bankStatements, bookRecords) {
    const result = {
      matched: [],
      unmatched: [],
      bankOnly: [...bankStatements],
      bookOnly: [...bookRecords]
    };

    // 精确匹配(金额、日期、参考号)
    await this.exactMatch(result);

    // 金额和日期匹配
    await this.amountDateMatch(result);

    // 模糊匹配
    await this.fuzzyMatch(result);

    return result;
  }

  // 精确匹配
  async exactMatch(result) {
    const bankRemaining = [];
    const bookRemaining = [];

    for (const bankItem of result.bankOnly) {
      let matched = false;

      for (const bookItem of result.bookOnly) {
        if (this.isExactMatch(bankItem, bookItem)) {
          result.matched.push({
            bankItem: bankItem,
            bookItem: bookItem,
            matchType: 'exact',
            confidence: 1.0
          });
          matched = true;
          break;
        }
      }

      if (!matched) {
        bankRemaining.push(bankItem);
      }
    }

    // 更新未匹配列表
    result.bankOnly = bankRemaining;
    result.bookOnly = result.bookOnly.filter(book =>
      !result.matched.some(match => match.bookItem.id === book.id)
    );
  }

  // 判断是否精确匹配
  isExactMatch(bankItem, bookItem) {
    return Math.abs(bankItem.amount - bookItem.amount) < 0.01 &&
           bankItem.date.toDateString() === bookItem.date.toDateString() &&
           (bankItem.reference === bookItem.reference ||
            this.isSimilarDescription(bankItem.description, bookItem.description));
  }

  // 描述相似度判断
  isSimilarDescription(desc1, desc2) {
    if (!desc1 || !desc2) return false;

    const similarity = this.calculateStringSimilarity(
      desc1.toLowerCase(),
      desc2.toLowerCase()
    );

    return similarity > 0.8;
  }

  // 计算字符串相似度
  calculateStringSimilarity(str1, str2) {
    const longer = str1.length > str2.length ? str1 : str2;
    const shorter = str1.length > str2.length ? str2 : str1;

    if (longer.length === 0) return 1.0;

    const editDistance = this.levenshteinDistance(longer, shorter);
    return (longer.length - editDistance) / longer.length;
  }

  // 计算编辑距离
  levenshteinDistance(str1, str2) {
    const matrix = [];

    for (let i = 0; i <= str2.length; i++) {
      matrix[i] = [i];
    }

    for (let j = 0; j <= str1.length; j++) {
      matrix[0][j] = j;
    }

    for (let i = 1; i <= str2.length; i++) {
      for (let j = 1; j <= str1.length; j++) {
        if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
          matrix[i][j] = matrix[i - 1][j - 1];
        } else {
          matrix[i][j] = Math.min(
            matrix[i - 1][j - 1] + 1,
            matrix[i][j - 1] + 1,
            matrix[i - 1][j] + 1
          );
        }
      }
    }

    return matrix[str2.length][str1.length];
  }
}

小结

通过本文的财务管理自动化实战,我们学会了:

  1. 发票处理自动化:利用OCR技术实现发票识别和数据提取
  2. 发票验证系统:建立多层次的发票真实性和合规性验证
  3. 费用报销流程:构建智能化的报销申请和审批系统
  4. 费用政策引擎:自动化费用合规性检查和政策执行
  5. 审批工作流:实现灵活的多级审批和智能路由
  6. ERP系统集成:与主流ERP系统的数据同步和集成
  7. 银行对账自动化:自动化银行流水和账面记录的匹配

这个财务管理系统展示了如何将复杂的财务流程完全自动化,大大提升了财务工作的效率和准确性。

关键要点:

  • 数据准确性:OCR识别结合多重验证确保数据质量
  • 合规性控制:通过政策引擎自动执行企业财务制度
  • 流程标准化:建立标准化的审批流程和操作规范
  • 系统集成:与现有ERP和银行系统的无缝集成

下一篇文章我们将学习HR管理自动化,了解如何自动化人力资源管理流程。