前情回顾与本节目标

在上一节中,我们完成了学习卡功能,实现了课时余额展示和签到扣课时。至此,学员端的核心功能已经基本完善。

本节我们将目光转向财务管理模块,实现发票申请功能。在MBA培训业务中,企业客户完成订单支付后,通常需要开具增值税发票用于财务报销。传统模式下,销售需要线下沟通、手动填写开票信息,财务再手工录入开票系统,流程繁琐且容易出错。

本节我们将打通销售前端与财务后端,实现从"销售发起开票申请 → 财务审核开票"的完整闭环。

本节核心目标:

  • 数据模型设计:创建发票表,扩展客户开票信息字段
  • 销售端开票申请:销售选择客户后自动填充企业开票信息,提交开票申请
  • 财务端开票审核:财务查看待开票列表,审核通过后更新发票状态

第一步:数据模型准备

1.1 发票表(MBA_Invoices)

创建发票表,用于记录开票申请和发票信息:

字段名称 字段标识 字段类型 说明
发票ID _id 文本 主键,系统自动生成
发票号 invoice_no 文本 发票编号,如 INV20250001
关联订单 rel_order_id 关联关系 关联 MBA_Orders 表
关联客户 rel_customer_id 关联关系 关联 MBA_Customer 表
开票金额 amount 数字 开票金额
发票类型 invoice_type 枚举 1-增值税专用发票、2-增值税普通发票、3-电子发票
开票内容 invoice_content 枚举 1-教育服务费、2-培训费、3-咨询服务费、4-其他
企业全称 company_name 文本 发票抬头
纳税人识别号 tax_number 文本 税号
企业地址 company_address 文本 企业注册地址
企业电话 company_phone 文本 企业联系电话
开户银行 bank_name 文本 开户银行名称
银行账号 bank_account 文本 银行账号
接收邮箱 email 文本 电子发票接收邮箱
开票状态 status 枚举 1-待开票、2-已开票、3-已驳回
申请人 rel_applicant_id 关联关系 关联 MBA_Users 表(销售)
审核人 rel_reviewer_id 关联关系 关联 MBA_Users 表(财务)
审核意见 review_remark 文本 财务审核意见
申请时间 apply_time 日期时间 申请时间
开票时间 issue_time 日期时间 实际开票时间
创建时间 created_at 日期时间 自动生成
更新时间 updated_at 日期时间 自动更新

1.2 客户表扩展字段(MBA_Customer)

在客户表中增加开票相关字段,方便销售发起开票时自动填充:

字段名称 字段标识 字段类型 说明
企业全称 company_name 文本 发票抬头
纳税人识别号 tax_number 文本 税号
企业地址 company_address 文本 企业注册地址
企业电话 company_phone 文本 企业联系电话
开户银行 bank_name 文本 开户银行名称
银行账号 bank_account 文本 银行账号
开票邮箱 invoice_email 文本 电子发票接收邮箱

第二步:销售端发起开票申请

2.1 创建开票管理页面

点击创建页面图标,输入"开票管理",选择销售布局
在这里插入图片描述

切换到布局管理,选择销售布局,添加平级菜单,添加"开票管理"菜单
在这里插入图片描述

2.2 页面整体布局

切换回页面设计,在销售布局的内容插槽下添加布局组件,修改标题为"开票管理"
在这里插入图片描述

添加数据表格组件,数据模型选择发票表(MBA_Invoices),勾选场景
在这里插入图片描述

2.3 配置查询条件

点击筛选器,给表格配置查询条件:

  • 发票号(模糊搜索)
  • 客户名称(关联选择)
  • 开票状态(下拉选择:待开票/已开票/已驳回)
  • 发票类型(下拉选择)

在这里插入图片描述

2.4 配置操作列

在数据表格的操作列配置功能按钮,配置条件展示,只有开票状态是待开票才可以编辑和删除申请信息
在这里插入图片描述

2.5 配置表单布局

因为发票需要填写比较多的内容,我们把表单的布局改为三列显示
在这里插入图片描述
修改了布局会清空表单容器的默认事件,我们将表单容器的表单场景恢复默认配置
在这里插入图片描述
然后配置表单提交成功之后的事件,增加关闭弹窗和刷新表格
在这里插入图片描述

2.6 客户选择与信息自动填充

创建自定义方法 onCustomerChange,当用户选择客户后自动将相关的信息带入到对应的字段中:

export default async function onCustomerChange({ event, data }) {
  const customerId = data.target;
  
  if (!customerId) return;
  
  try {
    // 查询客户的开票信息
    const customerRes = await $w.cloud.callDataSource({
      dataSourceName: 'MBA_Customers',
      methodName: 'wedaGetItemV2',
      params: {
        filter: { where: { _id: { $eq: customerId } } },
        select: { $master: true }
      }
    });
    
    const customer = customerRes;
    
    // 自动填充开票信息
    $w.form2.setValue({
      company_name: customer.company_name || '',
      tax_number: customer.tax_number || '',
      company_address: customer.company_address || '',
      company_phone: customer.company_phone || '',
      bank_name: customer.bank_name || '',
      bank_account: customer.bank_account || '',
      email: customer.invoice_email || ''
    });
    
    $w.utils.showToast({ title: '企业信息已自动填充', icon: 'success' });
    
  } catch (error) {
    console.error('获取客户信息失败:', error);
  }
}

给客户选择组件配置值改变事件,调用 onCustomerChange 方法,传入入参。

在这里插入图片描述

2.7 配置默认值

除了自动带出相关信息,比如发票状态我们需要设置成待开票
在这里插入图片描述
申请人绑定为当前登录对象的用户标识
在这里插入图片描述
申请时间设置为系统当前时间
在这里插入图片描述


第三步:财务端开票审核

3.1 创建财务审核页面

点击创建页面图标,输入"开票审核",选择财务布局
在这里插入图片描述

切换到布局管理,选择财务布局,添加平级菜单,添加"开票审核"菜单
在这里插入图片描述

3.2 页面整体布局

切换回页面设计,在财务布局的内容插槽下添加布局组件,修改标题为"开票审核"
在这里插入图片描述

添加顶部选项卡,标签改为"待审核"、“已审核”
在这里插入图片描述

添加数据表格组件,数据模型选择发票表(MBA_Invoices)
在这里插入图片描述

3.3 配置数据筛选

在"待审核"选项卡下,设置数据筛选条件为:开票状态 = 待开票(1)
在这里插入图片描述

在"已审核"选项卡下,设置数据筛选条件为:开票状态 ≠ 待开票(1)
在这里插入图片描述

3.4 配置操作列

在数据表格的操作列配置功能按钮:

按钮名称 功能说明 显示条件
查看详情 查看发票详细信息 全部显示
审核通过 确认开票,更新状态为已开票 状态 = 待开票
驳回 驳回开票申请 状态 = 待开票

在这里插入图片描述

3.5 审核通过功能

创建自定义方法 approveInvoice

export default async function approveInvoice({ event, data }) {
  const invoiceId = data.target._id;
  const currentUser = $w.app.dataset.state.currentUser;
  
  try {
    $w.utils.showLoading({ title: '审核中...' });
    
    await $w.cloud.callDataSource({
      dataSourceName: 'MBA_Invoices',
      methodName: 'wedaUpdateV2',
      params: {
        filter: { where: { _id: { $eq: invoiceId } } },
        data: {
          status: '2',
          rel_reviewer_id: { _id: currentUser._id },
          issue_time: Date.now(),
          updated_at: Date.now()
        }
      }
    });
    
    $w.utils.hideLoading();
    $w.utils.showToast({ title: '审核通过,已开票', icon: 'success' });
    $w.table1.refresh();
    
  } catch (error) {
    console.error('审核失败:', error);
    $w.utils.hideLoading();
    $w.utils.showToast({ title: '审核失败,请重试', icon: 'error' });
  }
}

给审核通过按钮配置点击事件,调用方法,传入所在行的数据标识
在这里插入图片描述

3.6 驳回功能

在页面组件下添加弹窗组件,修改标题为"驳回开票申请"
在这里插入图片描述

在弹窗内容区域添加单行输入组件,用于填写驳回原因。
在这里插入图片描述

创建自定义方法 rejectInvoice

export default async function rejectInvoice({ event, data }) {
  const invoiceId = data.target;
  const currentUser = $w.app.dataset.state.currentUser;
  const rejectReason = $w.input1.value;
  
  if (!rejectReason) {
    return $w.utils.showToast({ title: '请填写驳回原因', icon: 'error' });
  }
  
  try {
    $w.utils.showLoading({ title: '处理中...' });
    
    await $w.cloud.callDataSource({
      dataSourceName: 'MBA_Invoices',
      methodName: 'wedaUpdateV2',
      params: {
        filter: { where: { _id: { $eq: invoiceId } } },
        data: {
          status: '3',
          rel_reviewer_id: { _id: currentUser._id },
          review_remark: rejectReason,
        }
      }
    });
    
    $w.utils.hideLoading();
    $w.utils.showToast({ title: '已驳回', icon: 'success' });
    $w.modal1.close({});
    $w.table1.refresh();
    
  } catch (error) {
    console.error('驳回失败:', error);
    $w.utils.hideLoading();
    $w.utils.showToast({ title: '操作失败,请重试', icon: 'error' });
  }
}

给驳回按钮配置点击事件,打开弹窗,传入所在行的数据标识
在这里插入图片描述
给弹窗的确认按钮配置点击事件,调用我们的自定义方法,传入弹窗的入参
在这里插入图片描述


最终效果

销售端在开票管理页面,点击"新增"按钮,选择客户后系统自动填充企业开票信息,填写开票金额和发票类型后提交申请。
在这里插入图片描述

财务端在开票审核页面,查看待审核的开票申请,可以查看详情、审核通过或驳回。审核通过后发票状态更新为"已开票",驳回时需填写驳回原因。
在这里插入图片描述


总结

本节完成了智能开票功能的实现:

  1. 数据模型设计:创建发票表(MBA_Invoices),扩展客户表开票信息字段
  2. 销售端开票申请:选择客户自动填充企业信息,提交开票申请
  3. 财务端开票审核:财务查看待审核列表,审核通过或驳回

通过本节的学习,我们打通了销售前端与财务后端的开票流程,实现了从申请到审核的完整闭环。下一节我们将继续完善财务管理模块的其他功能。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐