个人编程网站

进销存(JXC)软件开发技术积累与分享

进销存系统供应商管理与智能比价

供应商管理概述

供应商是进销存系统的重要参与方,优质的供应商资源可以降低采购成本、提高供应链效率。本文介绍供应商管理系统的设计方案,包括供应商评估、智能比价、合同管理等功能模块的实现。

供应商评估体系

多维度供应商评分模型:

// 供应商评估模型
class SupplierEvaluator {
  constructor(weights = {}) {
    this.weights = {
      price: weights.price || 0.30,        // 价格权重 30%
      quality: weights.quality || 0.25,    // 质量权重 25%
      delivery: weights.delivery || 0.20,  // 交付权重 20%
      service: weights.service || 0.15,    // 服务权重 15%
      cooperation: weights.cooperation || 0.10, // 合作稳定性 10%
      ...weights
    };
  }

  // 评估供应商
  evaluate(supplierId, metrics) {
    const scores = {
      // 价格得分:低价得高分
      price: this.calculatePriceScore(metrics.avgPrice, metrics.marketPrice),

      // 质量得分
      quality: this.calculateQualityScore(metrics.defectRate),

      // 交付得分
      delivery: this.calculateDeliveryScore(metrics.onTimeRate, metrics.delayDays),

      // 服务得分
      service: this.calculateServiceScore(metrics.responseTime, metrics.complaintCount),

      // 合作稳定性
      cooperation: this.calculateCooperationScore(metrics.cooperationYears, metrics.orderCompletionRate)
    };

    // 加权计算总分
    const totalScore = Object.entries(scores).reduce((sum, [key, score]) => {
      return sum + score * this.weights[key];
    }, 0);

    return {
      supplierId,
      scores,
      totalScore: Math.round(totalScore * 100) / 100,
      grade: this.getGrade(totalScore)
    };
  }

  // 价格得分计算
  calculatePriceScore(avgPrice, marketPrice) {
    if (!marketPrice || marketPrice === 0) return 70;
    const ratio = (marketPrice - avgPrice) / marketPrice;
    // 低于市场价 20% 得满分,高于市场价 20% 得 0 分
    return Math.max(0, Math.min(100, 50 + ratio * 250));
  }

  // 质量得分计算
  calculateQualityScore(defectRate) {
    // 缺陷率 0% 得 100 分,每增加 1% 扣 10 分
    return Math.max(0, 100 - defectRate * 100);
  }

  // 交付得分计算
  calculateDeliveryScore(onTimeRate, avgDelayDays) {
    const onTimeScore = onTimeRate * 100;
    const delayScore = Math.max(0, 100 - avgDelayDays * 10);
    return onTimeScore * 0.7 + delayScore * 0.3;
  }

  // 服务得分计算
  calculateServiceScore(avgResponseTime, complaintCount) {
    // 响应时间评分
    let responseScore = 100;
    if (avgResponseTime > 24) responseScore = 20;
    else if (avgResponseTime > 12) responseScore = 40;
    else if (avgResponseTime > 4) responseScore = 60;
    else if (avgResponseTime > 2) responseScore = 80;

    // 投诉扣分
    const complaintScore = Math.max(0, 100 - complaintCount * 10);

    return responseScore * 0.5 + complaintScore * 0.5;
  }

  // 合作稳定性
  calculateCooperationScore(years, completionRate) {
    const yearsScore = Math.min(100, years * 20);
    const completionScore = completionRate * 100;
    return yearsScore * 0.3 + completionScore * 0.7;
  }

  // 评级
  getGrade(score) {
    if (score >= 90) return 'A+';
    if (score >= 80) return 'A';
    if (score >= 70) return 'B';
    if (score >= 60) return 'C';
    return 'D';
  }
}

// 供应商等级划分
const supplierGrades = {
  'A+': {
    label: '战略合作伙伴',
    color: '#52c41a',
    discount: 0.15,
    paymentTerms: '月结60天',
    priority: 1
  },
  'A': {
    label: '优秀供应商',
    color: '#1890ff',
    discount: 0.10,
    paymentTerms: '月结45天',
    priority: 2
  },
  'B': {
    label: '合格供应商',
    color: '#faad14',
    discount: 0.05,
    paymentTerms: '月结30天',
    priority: 3
  },
  'C': {
    label: '观察供应商',
    color: '#fa541c',
    discount: 0,
    paymentTerms: '现结',
    priority: 4
  },
  'D': {
    label: '不合格供应商',
    color: '#f5222d',
    discount: 0,
    paymentTerms: '现结',
    priority: 99,
    action: '建议淘汰'
  }
};

// 供应商分类
const supplierCategories = [
  { id: 'raw', name: '原材料', criticality: 'high' },
  { id: 'parts', name: '零部件', criticality: 'high' },
  { id: 'pack', name: '包装材料', criticality: 'medium' },
  { id: 'consumable', name: '辅料耗材', criticality: 'low' }
];

智能比价系统

自动获取多供应商报价并比较:

// 智能比价系统
class PriceComparisonSystem {
  constructor() {
    this.priceHistory = new Map(); // supplierId:productId -> [prices]
  }

  // 发起询价
  async createInquiry(inquiryData) {
    const inquiry = {
      id: this.generateId(),
      products: inquiryData.products, // [{ productId, quantity, spec }]
      suppliers: inquiryData.suppliers,
      deadline: inquiryData.deadline,
      status: 'pending',
      createdAt: new Date()
    };

    // 向所有供应商发送询价请求
    for (const supplierId of inquiry.suppliers) {
      await this.sendInquiryRequest(supplierId, inquiry);
    }

    return inquiry;
  }

  // 收集报价
  async collectQuotations(inquiryId) {
    const quotations = [];

    for (const supplierId of this.getInquirySuppliers(inquiryId)) {
      const quote = await this.getSupplierQuote(supplierId, inquiryId);
      if (quote) {
        quotations.push(quote);
      }
    }

    return quotations;
  }

  // 比价分析
  async comparePrices(inquiryId, quotations) {
    const productAnalysis = {};

    // 按产品分组分析
    for (const quote of quotations) {
      for (const item of quote.items) {
        const productId = item.productId;

        if (!productAnalysis[productId]) {
          productAnalysis[productId] = {
            productId,
            quotations: [],
            lowestPrice: null,
            avgPrice: null,
            recommendation: null
          };
        }

        productAnalysis[productId].quotations.push({
          supplierId: quote.supplierId,
          supplierName: quote.supplierName,
          price: item.unitPrice,
          totalPrice: item.unitPrice * item.quantity,
          deliveryDate: item.deliveryDate,
          validUntil: item.validUntil,
          remarks: item.remarks
        });
      }
    }

    // 计算各项指标并推荐
    for (const productId in productAnalysis) {
      const analysis = productAnalysis[productId];
      const prices = analysis.quotations.map(q => q.price);

      analysis.lowestPrice = Math.min(...prices);
      analysis.avgPrice = prices.reduce((s, p) => s + p, 0) / prices.length;
      analysis.priceDifference = ((analysis.avgPrice - analysis.lowestPrice) / analysis.avgPrice * 100).toFixed(2);

      // 综合推荐(考虑价格、质量、交期)
      analysis.recommendation = this.getBestRecommendation(analysis.quotations);
    }

    return productAnalysis;
  }

  // 综合推荐
  getBestRecommendation(quotations) {
    // 过滤有效报价
    const valid = quotations.filter(q =>
      new Date(q.validUntil) > new Date()
    );

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

    // 评分计算
    const scored = valid.map(q => {
      const priceScore = 100 - (q.price / Math.max(...valid.map(v => v.price)) * 50);
      // 假设交期越早越好
      const deliveryScore = Math.max(0, 100 - (new Date(q.deliveryDate) - new Date()) / (1000 * 60 * 60 * 24));

      return {
        ...q,
        score: priceScore * 0.6 + deliveryScore * 0.4
      };
    });

    // 排序返回最佳
    scored.sort((a, b) => b.score - a.score);

    return {
      supplierId: scored[0].supplierId,
      supplierName: scored[0].supplierName,
      price: scored[0].price,
      reason: `价格优势 ${(100 - scored[0].price / scored[scored.length - 1].price * 100).toFixed(1)}%`
    };
  }

  // 历史价格分析
  analyzePriceHistory(productId, supplierId) {
    const history = this.priceHistory.get(`${supplierId}:${productId}`) || [];

    if (history.length < 2) return null;

    const prices = history.map(p => p.price);
    const trend = prices[prices.length - 1] > prices[0] ? 'up' : 'down';
    const volatility = this.calculateVolatility(prices);

    return {
      supplierId,
      productId,
      minPrice: Math.min(...prices),
      maxPrice: Math.max(...prices),
      avgPrice: prices.reduce((s, p) => s + p, 0) / prices.length,
      trend,
      volatility,
      latestPrice: prices[prices.length - 1],
      priceCount: prices.length
    };
  }

  calculateVolatility(prices) {
    const avg = prices.reduce((s, p) => s + p, 0) / prices.length;
    const variance = prices.reduce((s, p) => s + Math.pow(p - avg, 2), 0) / prices.length;
    return Math.sqrt(variance) / avg;
  }
}

合同管理

采购合同的生命周期管理:

// 采购合同管理
class PurchaseContractManager {
  constructor() {
    this.contracts = new Map();
  }

  // 创建合同
  async createContract(contractData) {
    const contract = {
      id: this.generateId(),
      contractNo: this.generateContractNo(contractData.supplierId),
      supplierId: contractData.supplierId,
      supplierName: contractData.supplierName,
      items: contractData.items,
      totalAmount: contractData.items.reduce((sum, item) =>
        sum + item.price * item.quantity, 0),
      paymentTerms: contractData.paymentTerms,
      deliveryTerms: contractData.deliveryTerms,
      startDate: contractData.startDate,
      endDate: contractData.endDate,
      status: 'draft',
      attachments: [],
      createdBy: contractData.userId,
      createdAt: new Date()
    };

    // 合同条款校验
    await this.validateContract(contract);

    this.contracts.set(contract.id, contract);
    return contract;
  }

  // 合同审批流程
  async submitForApproval(contractId, approvers) {
    const contract = this.contracts.get(contractId);
    contract.status = 'pending_approval';
    contract.approvers = approvers.map((userId, index) => ({
      userId,
      step: index + 1,
      status: 'pending',
      comment: ''
    }));
    contract.currentApprover = approvers[0];

    // 发送审批通知
    await this.sendApprovalNotification(approvers[0], contract);

    return contract;
  }

  // 审批通过
  async approve(contractId, userId, comment = '') {
    const contract = this.contracts.get(contractId);
    const approver = contract.approvers.find(a => a.userId === userId);

    if (!approver) throw new Error('无审批权限');
    approver.status = 'approved';
    approver.comment = comment;
    approver.approvedAt = new Date();

    // 检查是否所有审批人都已通过
    const allApproved = contract.approvers.every(a => a.status === 'approved');

    if (allApproved) {
      contract.status = 'active';
      contract.approvedAt = new Date();

      // 通知创建人
      await this.notifyContractCreated(contract);
    } else {
      // 进入下一步审批
      const nextApprover = contract.approvers.find(a => a.status === 'pending');
      if (nextApprover) {
        contract.currentApprover = nextApprover.userId;
        await this.sendApprovalNotification(nextApprover.userId, contract);
      }
    }

    return contract;
  }

  // 合同履约跟踪
  async trackPerformance(contractId) {
    const contract = this.contracts.get(contractId);
    const deliveries = await this.getDeliveryRecords(contractId);

    const performance = {
      contractId,
      totalItems: contract.items.length,
      deliveredItems: deliveries.filter(d => d.status === 'delivered').length,
      pendingItems: deliveries.filter(d => d.status === 'pending').length,
      overdueDeliveries: deliveries.filter(d =>
        d.status === 'pending' && new Date(d.plannedDate) < new Date()
      ).length,
      totalOrderValue: contract.totalAmount,
      deliveredValue: deliveries.reduce((sum, d) => sum + d.value, 0),
      completionRate: 0
    };

    performance.completionRate = performance.deliveredItems / performance.totalItems * 100;

    return performance;
  }
}

// 合同到期提醒
class ContractExpirationMonitor {
  constructor(contractManager) {
    this.contractManager = contractManager;
  }

  // 检查即将到期的合同
  checkExpiringContracts(daysThreshold = 30) {
    const threshold = new Date();
    threshold.setDate(threshold.getDate() + daysThreshold);

    const expiring = [];

    for (const [id, contract] of this.contractManager.contracts) {
      if (contract.status === 'active' && contract.endDate <= threshold) {
        expiring.push({
          contractId: id,
          contractNo: contract.contractNo,
          supplierName: contract.supplierName,
          endDate: contract.endDate,
          daysRemaining: Math.ceil((contract.endDate - new Date()) / (1000 * 60 * 60 * 24))
        });
      }
    }

    return expiring.sort((a, b) => a.daysRemaining - b.daysRemaining);
  }

  // 发送提醒
  async sendExpirationReminder(contract) {
    console.log(`合同即将到期提醒:${contract.contractNo}`);
    // 发送邮件/消息通知
  }
}

总结

供应商管理与智能比价系统是采购管理的核心:

通过系统化管理,可以显著降低采购成本,提高供应链稳定性。

← 下一篇:进销存系统智能补货算法与库存优化