进销存技术分享

JXC - 专注于进销存软件开发

进销存系统客户信用管理与账期控制

信用管理概述

客户信用管理是进销存系统的核心模块之一,涉及客户信用评级、账期设置、应收账款管理和催收策略等功能。良好的信用管理可以有效控制坏账风险,加速资金周转。本文详细介绍客户信用管理系统的设计与实现。

信用评级体系

信用等级 信用额度 账期天数 折扣系数
AAA(优质) 50万以上 90天 0.95
AA(良好) 20-50万 60天 0.97
A(一般) 10-20万 30天 1.00
B(警惕) 5-10万 15天 1.02
C(限制) 0-5万 0天(现结) 1.05

信用评分算法

基于多维度指标计算客户信用评分:

// 信用评分服务
class CreditScoreService {
  constructor(customerModel, orderModel, paymentModel) {
    this.Customer = customerModel;
    this.Order = orderModel;
    this.Payment = paymentModel;
  }

  // 计算客户信用评分
  async calculateCreditScore(customerId) {
    const customer = await this.Customer.findById(customerId);

    // 获取各项评分指标
    const paymentScore = await this.getPaymentHistoryScore(customerId);
    const transactionScore = await this.getTransactionScore(customerId);
    const cooperationScore = await this.getCooperationScore(customer);
    const financialScore = await this.getFinancialScore(customer);

    // 加权计算总分
    const weights = {
      payment: 0.35,      # 付款记录权重
      transaction: 0.25,  # 交易活跃度权重
      cooperation: 0.20,  # 合作年限权重
      financial: 0.20     # 财务状况权重
    };

    const totalScore =
      paymentScore * weights.payment +
      transactionScore * weights.transaction +
      cooperationScore * weights.cooperation +
      financialScore * weights.financial;

    // 确定信用等级
    const creditLevel = this.getCreditLevel(totalScore);

    return {
      customerId,
      totalScore: Math.round(totalScore),
      creditLevel,
      details: {
        paymentScore,
        transactionScore,
        cooperationScore,
        financialScore
      },
      calculatedAt: new Date()
    };
  }

  // 获取付款记录评分
  async getPaymentHistoryScore(customerId, period = 365) {
    const startDate = new Date();
    startDate.setDate(startDate.getDate() - period);

    // 获取历史付款记录
    const payments = await this.Payment.find({
      customerId,
      paymentDate: { $gte: startDate }
    });

    if (payments.length === 0) return 60;  # 默认分数

    // 计算付款及时率
    const orders = await this.Order.find({
      customerId,
      createdAt: { $gte: startDate }
    });

    let onTimeCount = 0;
    let totalCount = orders.length;

    for (const order of orders) {
      const paymentsForOrder = payments.filter(p =>
        p.orderId.toString() === order._id.toString()
      );

      if (paymentsForOrder.length > 0) {
        const payment = paymentsForOrder[0];
        const dueDate = new Date(order.createdAt);
        dueDate.setDate(dueDate.getDate() + order.paymentDays);

        if (new Date(payment.paymentDate) <= dueDate) {
          onTimeCount++;
        }
      }
    }

    const onTimeRate = totalCount > 0 ? onTimeCount / totalCount : 0;

    // 计算逾期次数扣分
    const overduePayments = payments.filter(p => p.isOverdue);
    const overdueRate = payments.length > 0 ? overduePayments.length / payments.length : 0;

    // 评分计算
    let score = onTimeRate * 70 + (1 - overdueRate) * 30;
    return Math.round(score);
  }

  // 获取交易活跃度评分
  async getTransactionScore(customerId, period = 180) {
    const startDate = new Date();
    startDate.setDate(startDate.getDate() - period);

    const orders = await this.Order.find({
      customerId,
      createdAt: { $gte: startDate }
    });

    // 计算订单频率
    const days = period;
    const orderFrequency = orders.length / (days / 30);  # 月均订单数

    // 计算平均订单金额
    const totalAmount = orders.reduce((sum, o) => sum + o.totalAmount, 0);
    const avgOrderAmount = orders.length > 0 ? totalAmount / orders.length : 0;

    // 频率和金额综合评分
    const frequencyScore = Math.min(orderFrequency / 10 * 50, 50);
    const amountScore = Math.min(avgOrderAmount / 10000 * 50, 50);

    return Math.round(frequencyScore + amountScore);
  }

  // 获取合作年限评分
  getCooperationScore(customer) {
    if (!customer.cooperationStartDate) return 50;

    const years = (new Date() - new Date(customer.cooperationStartDate)) / (365 * 24 * 60 * 60 * 1000);

    // 合作年限越长分数越高,最高30分
    return Math.round(Math.min(years * 5, 30));
  }

  // 获取财务状况评分
  async getFinancialScore(customer) {
    // 根据客户规模给定基础分
    let baseScore = 50;

    if (customer.enterpriseType === 'large') baseScore = 80;
    else if (customer.enterpriseType === 'medium') baseScore = 65;
    else if (customer.enterpriseType === 'small') baseScore = 50;
    else baseScore = 40;

    // 根据注册资本调整
    if (customer.registeredCapital) {
      if (customer.registeredCapital > 10000000) baseScore += 10;
      else if (customer.registeredCapital > 1000000) baseScore += 5;
    }

    return Math.min(baseScore, 100);
  }

  // 确定信用等级
  getCreditLevel(score) {
    if (score >= 90) return { level: 'AAA', label: '优质客户' };
    if (score >= 80) return { level: 'AA', label: '良好客户' };
    if (score >= 70) return { level: 'A', label: '一般客户' };
    if (score >= 60) return { level: 'B', label: '警惕客户' };
    return { level: 'C', label: '限制客户' };
  }
}

账期控制机制

智能账期控制和超期预警:

// 账期管理服务
class PaymentTermService {
  constructor(customerModel, orderModel, receivableModel) {
    this.Customer = customerModel;
    this.Order = orderModel;
    this.Receivable = receivableModel;
  }

  // 检查客户是否可以下单
  async checkCreditLimit(customerId, orderAmount) {
    const customer = await this.Customer.findById(customerId);
    const creditInfo = await this.getCustomerCreditInfo(customerId);

    // 计算当前可用信用额度
    const usedCredit = await this.getUsedCredit(customerId);
    const availableCredit = creditInfo.creditLimit - usedCredit;

    // 检查是否超额度
    if (orderAmount > availableCredit) {
      return {
        allowed: false,
        reason: '超出信用额度',
        availableCredit,
        requiredCredit: orderAmount,
        deficit: orderAmount - availableCredit
      };
    }

    // 检查是否有超期应收账款
    const overdueReceivables = await this.getOverdueReceivables(customerId);
    if (overdueReceivables.length > 0) {
      const overdueAmount = overdueReceivables.reduce((sum, r) => sum + r.amount, 0);

      // 超期金额超过信用额度的20%,限制下单
      if (overdueAmount > creditInfo.creditLimit * 0.2) {
        return {
          allowed: false,
          reason: '存在超期应收账款',
          overdueAmount,
          overdueDays: overdueReceivables[0].overdueDays
        };
      }
    }

    return {
      allowed: true,
      availableCredit,
      creditLevel: creditInfo.creditLevel
    };
  }

  // 获取客户信用信息
  async getCustomerCreditInfo(customerId) {
    const customer = await this.Customer.findById(customerId);

    // 如果没有信用记录,创建默认信用信息
    if (!customer.creditInfo) {
      return {
        creditLimit: 50000,
        creditLevel: 'C',
        paymentDays: 0
      };
    }

    return customer.creditInfo;
  }

  // 获取已使用信用额度(未结清订单+应收账款)
  async getUsedCredit(customerId) {
    // 未结清订单金额
    const pendingOrders = await this.Order.find({
      customerId,
      status: { $in: ['pending', 'processing', 'shipped'] }
    });
    const pendingAmount = pendingOrders.reduce((sum, o) => sum + o.totalAmount, 0);

    // 未收款金额
    const receivables = await this.Receivable.find({
      customerId,
      status: { $in: ['pending', 'partial'] }
    });
    const receivableAmount = receivables.reduce((sum, r) => sum + r.balance, 0);

    return pendingAmount + receivableAmount;
  }

  // 获取超期应收账款
  async getOverdueReceivables(customerId) {
    const today = new Date();

    return this.Receivable.aggregate([
      {
        $match: {
          customerId,
          status: { $in: ['pending', 'partial'] },
          dueDate: { $lt: today }
        }
      },
      {
        $project: {
          orderNo: 1,
          amount: 1,
          balance: 1,
          dueDate: 1,
          overdueDays: {
            $divide: [
              { $subtract: [today, '$dueDate'] },
              1000 * 60 * 60 * 24  # 转换为天数
            ]
          }
        }
      },
      { $sort: { overdueDays: -1 } }
    ]);
  }

  // 自动计算并调整信用等级
  async autoAdjustCreditLevel(customerId) {
    const creditScore = await this.calculateCreditScore(customerId);
    const customer = await this.Customer.findById(customerId);

    // 计算新的信用额度
    const newCreditLimit = this.calculateCreditLimit(creditScore.totalScore, customer);

    // 计算新的账期
    const newPaymentDays = this.calculatePaymentDays(creditScore.creditLevel.level);

    // 更新客户信用信息
    await this.Customer.updateOne(
      { _id: customerId },
      {
        'creditInfo.creditLevel': creditScore.creditLevel.level,
        'creditInfo.creditScore': creditScore.totalScore,
        'creditInfo.creditLimit': newCreditLimit,
        'creditInfo.paymentDays': newPaymentDays,
        'creditInfo.lastAdjustDate': new Date()
      }
    );

    return {
      oldLevel: customer.creditInfo?.creditLevel,
      newLevel: creditScore.creditLevel.level,
      oldLimit: customer.creditInfo?.creditLimit,
      newLimit: newCreditLimit,
      oldDays: customer.creditInfo?.paymentDays,
      newDays: newPaymentDays
    };
  }

  // 计算信用额度
  calculateCreditLimit(score, customer) {
    const baseLimit = 50000;
    const maxLimit = 500000;

    // 根据评分调整额度
    let limit = baseLimit + (score - 60) * 5000;

    // 根据客户类型调整
    if (customer.enterpriseType === 'large') limit *= 3;
    else if (customer.enterpriseType === 'medium') limit *= 1.5;

    return Math.min(Math.max(limit, baseLimit), maxLimit);
  }

  // 计算账期天数
  calculatePaymentDays(level) {
    const paymentDaysMap = {
      'AAA': 90,
      'AA': 60,
      'A': 30,
      'B': 15,
      'C': 0
    };
    return paymentDaysMap[level] || 0;
  }
}

应收账款管理

全面的应收账款跟踪和预警:

// 应收账款管理服务
class ReceivableService {
  constructor(orderModel, paymentModel, receivableModel, notificationService) {
    this.Order = orderModel;
    this.Payment = paymentModel;
    this.Receivable = receivableModel;
    this.Notification = notificationService;
  }

  // 生成应收账款(订单完成后)
  async createReceivable(orderId) {
    const order = await this.Order.findById(orderId);

    // 检查是否需要生成应收账款(如果有账期)
    if (order.paymentDays === 0) {
      return null;  # 现结订单不需要应收账款
    }

    const receivable = await this.Receivable.create({
      orderId: order._id,
      customerId: order.customerId,
      saleDate: order.createdAt,
      dueDate: this.calculateDueDate(order.createdAt, order.paymentDays),
      amount: order.totalAmount,
      balance: order.totalAmount,
      status: 'pending',
      paymentDays: order.paymentDays
    });

    // 发送账期提醒
    await this.Notification.sendReminder(order.customerId, receivable);

    return receivable;
  }

  // 计算到期日
  calculateDueDate(saleDate, paymentDays) {
    const dueDate = new Date(saleDate);
    dueDate.setDate(dueDate.getDate() + paymentDays);
    return dueDate;
  }

  // 收款处理
  async receivePayment(receivableId, paymentAmount, paymentMethod, paymentDate = new Date()) {
    const receivable = await this.Receivable.findById(receivableId);
    const receivableBefore = receivable.balance;

    // 更新应收账款
    receivable.balance -= paymentAmount;
    if (receivable.balance <= 0) {
      receivable.status = 'paid';
      receivable.paidDate = paymentDate;
    } else {
      receivable.status = 'partial';
    }

    await receivable.save();

    // 记录付款明细
    await this.Payment.create({
      receivableId,
      orderId: receivable.orderId,
      customerId: receivable.customerId,
      paymentAmount,
      paymentMethod,
      paymentDate,
      isOverdue: paymentDate > receivable.dueDate
    });

    return { receivable, receivedAmount: paymentAmount, remainingBalance: receivable.balance };
  }

  // 应收账款预警
  async sendPaymentReminder() {
    const today = new Date();
    const threeDaysLater = new Date(today.getTime() + 3 * 24 * 60 * 60 * 1000);

    // 查找即将到期的应收账款(3天内)
    const soonDue = await this.Receivable.find({
      status: 'pending',
      dueDate: { $gte: today, $lte: threeDaysLater }
    });

    for (const receivable of soonDue) {
      await this.Notification.send({
        customerId: receivable.customerId,
        type: 'payment_reminder',
        title: '应收账款到期提醒',
        content: `您有一笔金额为 ${receivable.balance} 元的账款将于 ${receivable.dueDate.toLocaleDateString()} 到期,请及时付款。`
      });
    }

    // 查找已超期的应收账款
    const overdue = await this.Receivable.find({
      status: { $in: ['pending', 'partial'] },
      dueDate: { $lt: today }
    });

    for (const receivable of overdue) {
      const overdueDays = Math.floor((today - receivable.dueDate) / (24 * 60 * 60 * 1000));

      // 根据超期天数发送不同级别的催收通知
      if (overdueDays === 1) {
        await this.Notification.sendFirstReminder(receivable);
      } else if (overdueDays === 7) {
        await this.Notification.sendSecondReminder(receivable);
      } else if (overdueDays === 30) {
        await this.Notification.sendUrgentReminder(receivable);
      }
    }

    return { soonDueCount: soonDue.length, overdueCount: overdue.length };
  }
}

总结

客户信用管理系统是进销存系统控制经营风险的重要模块,核心价值包括:

通过信用管理系统的实施,企业可以实现销售与风险的最佳平衡。

← 下一篇:进销存系统智能补货策略与算法实现