开发文档包说明 README.md
废品回收平台若依开发文档包
适用技术栈假设:RuoYi-Vue3 / Vue3 / Vite / Element Plus / Spring Boot / MyBatis / MySQL。若实际采用 RuoYi-Cloud 或 RuoYi-Vue-Plus,可复用业务表与接口语义,按对应框架调整包名、权限注解、分页和代码生成模板。
文件清单
01-refined-requirements.md:重新梳理后的需求与字段盘点。02-database-design.md:数据模型说明、表关系和状态字典。03-api-design.md:接口定义,按若依 Controller 模块划分。04-ruoyi-development-guide.md:若依开发落地说明。05-dict-and-permission.md:字典、菜单、权限标识建议。06-vue3-frontend-guide.md:RuoYi-Vue3 前端页面、路由、API 文件建议。07-tax-policy-and-quota.md:反向开票政策口径、税费与额度配置建议。08-backend-code-skeleton.md:若依后端核心代码骨架和开发任务拆分。sql/recycle_platform_schema.sql:业务表结构 SQL。sql/recycle_platform_dict_menu_seed.sql:字典和菜单权限种子 SQL 示例。
重要假设
- 平台为封闭平台,不开放公众注册。
- 平台统一管理资金、数据和反向开票,回收点负责采集真实业务。
- 售卖者仅支持自然人个人。
- 第一版付款为付款记录登记;现金不扣回收点平台余额,非现金扣减或冻结回收点余额。
- 第一版反向开票按一单一票设计。
- 身份证图片、付款凭证、现场照片使用附件表统一管理,也可以替换为若依 OSS/文件模块。
- 税务政策按当前公开政策整理,最终上线前仍需由客户财税顾问和主管税务机关确认。
需求与字段盘点 01-refined-requirements.md
废品回收平台需求重梳理 V2.0
1. 业务角色
| 角色 | 来源 | 数据范围 | 主要动作 |
|---|---|---|---|
| 平台管理员 | 若依 sys_user | 全平台 | 回收点管理、订单监管、余额监管、充值审核、付款流水、反向开票、财务报表、系统设置 |
| 平台财务 | 若依 sys_user | 全平台资金票据 | 后台加款、线下转账入账、付款复核、冲正、反向开票、红冲作废 |
| 平台运营审核员 | 若依 sys_user | 全平台业务 | 回收点资料、售卖者资料、订单抽查、异常处理 |
| 回收点管理员 | 若依 sys_user + 回收点绑定 | 本回收点 | 员工、分类、商品、单位、价格、订单、余额、加款申请 |
| 回收点员工 | 若依 sys_user + 回收点绑定 | 本人或本站 | 移动录单、售卖者建档、身份证上传、订单查询、付款登记 |
2. 核心业务闭环
- 平台创建回收点。
- 回收点创建员工。
- 回收点维护分类、单位、商品和价格。
- 员工录入个人售卖者资料,支持身份证 OCR、手工录入和后续补图。
- 员工录入回收订单,订单必须关联个人售卖者身份证号。
- 系统做额度校验:当月额度、连续 12 个月额度。
- 订单提交审核。
- 审核通过后进入待付款登记。
- 现金付款只登记付款记录,不扣余额;微信/支付宝/银行卡等非现金付款登记扣减或冻结回收点余额。
- 付款完成后,资料完整订单进入反向开票池。
- 平台按订单逐单反向开票,发票抬头开给平台。
- 已开票订单如需作废,走红冲和付款冲正流程。
2.1 反向开票和额度口径
- 售卖者仅支持自然人个人,系统必须采集身份证号 Hash、脱敏号、正反面图片或待补图状态。
- 连续 12 个月反向开票累计销售额默认配置为 500 万元,不含增值税,超过后阻断录入或提交审核。
- 个人当月 10 万元默认作为税费处理提示线,不直接等同于禁止开票;平台可在额度配置中设置为预警或阻断。
- 2026-07-01 起如接入“三流合一反向开票”,年销售额 60 万元以内部分可按较低个税预缴率配置;第一版未接在线支付时只预留字段。
- 每笔订单独立生成反向开票记录,一单一票,便于订单、付款、开票三方对账。
3. 字段补充原则
为了方便后续审计、对账、风控和若依代码生成,字段适当冗余:
- 订单表冗余回收点名称、售卖者姓名脱敏、身份证号 Hash、订单金额、付款状态、开票状态。
- 订单明细表冗余商品名称、分类名称、单位名称、下单单价,避免商品后续改名改价影响历史订单。
- 付款记录冗余付款方式、外部流水号、第三方支付流水号、凭证附件、余额影响金额。
- 反向开票表冗余订单号、回收点名称、售卖者姓名、身份证号 Hash、开票金额、税费金额。
- 所有业务表保留若依通用审计字段:create_by、create_time、update_by、update_time、remark、del_flag。
4. 回收点字段
| 字段 | 说明 |
|---|---|
| station_id | 主键 |
| station_code | 回收点编号,平台生成 |
| station_name | 回收点名称 |
| contact_name/contact_phone | 联系人和手机号 |
| province/city/district/address | 地址 |
| business_status | 经营状态:0停用、1启用 |
| account_status | 余额账户状态:normal/frozen/disabled |
| manager_user_id | 默认负责人用户 ID |
| license_no | 可选,营业执照或内部备案号 |
| settle_bank_* | 回收点打款账户信息,后续退款或线下核对使用 |
5. 员工字段
员工仍使用若依 sys_user 登录体系,业务侧增加回收点用户绑定表。
| 字段 | 说明 |
|---|---|
| user_id | 若依用户 ID |
| station_id | 所属回收点 |
| employee_no | 员工编号 |
| station_role | station_admin/station_staff |
| data_scope | self/station |
| id_card_no | 可选,员工实名管理 |
| status | 0停用、1启用 |
6. 售卖者字段
| 字段 | 说明 |
|---|---|
| seller_id | 主键 |
| seller_name | 个人姓名 |
| mobile | 手机号 |
| id_card_no_encrypt | 身份证号密文 |
| id_card_no_hash | 身份证号 Hash,用于去重和额度统计 |
| id_card_mask | 脱敏身份证号 |
| id_card_front_file_id/back_file_id | 身份证正反面附件 |
| id_card_image_status | complete/pending |
| ocr_status | none/success/fail/manual |
| receive_type | cash/wechat/alipay/bank |
| receive_account | 收款账号密文或脱敏 |
| bank_name/bank_card_no_encrypt/bank_card_mask | 银行卡信息 |
| invoice_consent_flag | 是否同意反向开票 |
| risk_status | normal/black/limited |
7. 分类、单位、商品、价格字段
分类:
- station_id、category_code、category_name、parent_id、sort_no、status。
单位:
- station_id、unit_code、unit_name、decimal_scale、status。
商品:
- station_id、category_id、product_code、product_name、unit_id、default_price、price_status、status、sort_no。
价格记录:
- product_id、unit_id、old_price、new_price、change_source、order_id、change_reason、change_by、change_time。
8. 订单字段
订单主表:
| 字段 | 说明 |
|---|---|
| order_id/order_no | 主键和订单号 |
| station_id/station_name | 回收点 |
| employee_user_id/employee_name | 录单员工 |
| seller_id/seller_name/seller_id_card_hash/seller_id_card_mask | 售卖者快照 |
| order_amount | 订单总金额 |
| payable_amount | 应付金额 |
| paid_amount | 已付金额 |
| invoice_amount | 拟开票金额 |
| item_count | 商品行数 |
| order_status | draft/pending_audit/audit_pass/audit_reject/void |
| payment_status | not_required/pending/confirming/paid/cancel/reversed |
| invoice_status | not_enter/waiting/applying/invoiced/reding/reded/void |
| id_card_image_status | 身份证图片状态快照 |
| quota_check_status | pass/fail/warn |
| quota_check_msg | 超额提示 |
| print_count | 打印次数 |
订单明细:
- product_id、product_name、category_id、category_name、unit_id、unit_name、quantity、unit_price、default_price、manual_price_flag、amount。
9. 付款字段
付款记录:
| 字段 | 说明 |
|---|---|
| payment_id/payment_no | 主键和付款单号 |
| order_id/order_no | 订单 |
| station_id/station_name | 回收点 |
| seller_id/seller_name | 售卖者 |
| payment_method | cash/wechat/alipay/bank |
| payment_amount | 付款金额 |
| balance_affect_flag | 是否影响余额 |
| balance_flow_id | 余额流水 |
| external_trade_no | 外部转账流水或备注 |
| third_trade_no/third_order_no/channel | 后续在线支付预留 |
| voucher_file_id | 付款凭证 |
| payment_status | pending/confirmed/failed/reversed |
| paid_time | 付款时间 |
余额账户:
- station_id、available_balance、frozen_balance、total_recharge、total_pay、total_refund、account_status。
余额流水:
- flow_no、station_id、biz_type、biz_id、direction、amount、before_balance、after_balance、frozen_amount、operator_user_id。
10. 充值/加款字段
| 字段 | 说明 |
|---|---|
| recharge_id/recharge_no | 主键和申请单号 |
| station_id/station_name | 回收点 |
| recharge_type | backend_add/offline_transfer/wechat/alipay/online_bank |
| apply_amount/approved_amount | 申请金额/通过金额 |
| voucher_file_id | 打款凭证 |
| audit_status | pending/pass/reject/accounted/cancel |
| audit_user_id/audit_time | 审核 |
| account_flow_id | 入账流水 |
11. 反向开票字段
| 字段 | 说明 |
|---|---|
| invoice_id/invoice_no | 主键和内部开票单号 |
| order_id/order_no | 一单一票 |
| station_id/station_name | 回收点 |
| seller_id/seller_name/seller_id_card_hash | 售卖者 |
| buyer_name/buyer_tax_no | 平台公司抬头 |
| invoice_amount | 开票金额 |
| vat_amount/additional_tax_amount/personal_tax_amount | 税费 |
| tax_calc_rule | normal/triple_flow |
| tax_report_period/tax_report_status | 代办税费所属期和申报状态 |
| invoice_status | waiting/applying/invoiced/failed/reding/reded/void |
| tax_invoice_code/tax_invoice_no | 税票号码 |
| e_invoice_file_id | 电子发票 |
| red_invoice_id/red_reason | 红冲 |
12. 附件字段
统一附件表记录身份证、付款凭证、现场照片、发票文件:
- file_id、biz_type、biz_id、file_type、file_name、file_url、storage_type、mime_type、file_size、hash、upload_user_id。
13. 状态字典
详见 05-dict-and-permission.md。
数据库设计 02-database-design.md
数据库设计说明
1. 设计约定
- 数据库:MySQL 8.x,字符集 utf8mb4。
- 金额字段统一使用
decimal(18,2)。 - 数量字段使用
decimal(18,4)。 - 主键使用
bigint unsigned auto_increment,若项目使用雪花 ID,可改为bigint手动赋值。 - 若依代码生成建议字段:create_by、create_time、update_by、update_time、remark、del_flag。
- 敏感字段不要明文存储,SQL 中保留 encrypt/hash/mask 三类字段。
2. 表清单
| 表名 | 中文名 | 说明 |
|---|---|---|
| rec_station | 回收点表 | 平台维护回收点 |
| rec_station_user | 回收点用户绑定表 | 绑定若依 sys_user |
| rec_seller | 个人售卖者表 | 身份证、收款信息、授权 |
| rec_category | 回收分类表 | 回收点自定义分类 |
| rec_unit | 计量单位表 | 回收点自定义单位 |
| rec_product | 回收商品表 | 商品、单位、默认价 |
| rec_product_price_log | 商品价格记录表 | 调价和订单改价留痕 |
| rec_order | 回收订单主表 | 订单头、金额、状态 |
| rec_order_item | 回收订单明细表 | 商品明细快照 |
| rec_order_audit_log | 订单审核记录表 | 审核通过/驳回 |
| rec_order_change_log | 订单修改记录表 | 修改、作废、红冲关联 |
| rec_payment_record | 付款记录表 | 现金/非现金付款登记 |
| rec_balance_account | 回收点余额账户表 | 可用、冻结、累计 |
| rec_balance_flow | 余额流水表 | 加款、扣款、冻结、冲正 |
| rec_recharge_apply | 加款申请表 | 线下转账、后台加款 |
| rec_reverse_invoice | 反向开票表 | 一单一票和红冲 |
| rec_quota_config | 额度配置表 | 月提示线、12个月硬限制、三流合一个税优惠线 |
| rec_quota_usage_log | 额度占用记录表 | 订单额度计算留痕 |
| rec_attachment | 附件表 | 身份证、凭证、照片、发票 |
| rec_print_log | 打印记录表 | 订单打印留痕 |
3. 核心关系
- rec_station 1:N rec_station_user。
- rec_station 1:N rec_category / rec_unit / rec_product。
- rec_seller 1:N rec_order。
- rec_order 1:N rec_order_item。
- rec_order 1:N rec_payment_record,但正常业务建议 1:1,冲正/补付时可多条。
- rec_station 1:1 rec_balance_account。
- rec_balance_account 1:N rec_balance_flow。
- rec_order 1:1 rec_reverse_invoice,一单一票。
- rec_attachment 通过 biz_type + biz_id 关联任意业务。
4. 冗余字段说明
订单、付款、开票表存在 station_name、seller_name、order_no 等冗余字段,是为了:
- 历史快照不受基础资料修改影响。
- 列表查询减少联表。
- 导出和审计更稳定。
- 对接第三方支付、票务接口时减少上下文丢失。
5. 索引建议
- 身份证统计使用
id_card_no_hash,不要用密文字段。 - 订单列表常用索引:station_id、seller_id、order_no、order_status、payment_status、invoice_status、order_time。
- 财务流水常用索引:station_id、biz_type、biz_id、flow_time。
- 开票池常用索引:invoice_status、order_id、seller_id。
6. 额度和税费配置建议
PERSON_MONTH_TAX_FREE_AMOUNT:个人当月销售额 10 万元提示线,默认预警,是否阻断由平台配置。PERSON_ROLLING_12_REVERSE_LIMIT:个人连续 12 个月反向开票累计 500 万元硬限制,默认阻断。PERSON_YEAR_TRIPLE_FLOW_TAX_BREAK:三流合一反向开票年度 60 万元个税优惠分段,第一版预留,接入线上支付后启用。- 额度判断以身份证 Hash 维度汇总,统计范围排除已作废、已红冲且业务撤销的订单。
接口定义 03-api-design.md
接口定义
1. 统一约定
- 前缀:
/recycle - 返回:若依 AjaxResult / TableDataInfo。
- 分页:
pageNum、pageSize。 - 导出:若依 ExcelUtil。
- 权限:
@PreAuthorize("@ss.hasPermi('recycle:xxx:yyy')")。 - 金额字段:字符串或 decimal,前端展示保留 2 位。
- 附件上传:可先复用若依通用上传接口,也可提供
/recycle/attachment/upload。
2. 回收点管理
| 方法 | 地址 | 说明 | 权限 |
|---|---|---|---|
| GET | /recycle/station/list | 回收点分页 | recycle:station:list |
| GET | /recycle/station/{stationId} | 详情 | recycle:station:query |
| POST | /recycle/station | 新增 | recycle:station:add |
| PUT | /recycle/station | 修改 | recycle:station:edit |
| DELETE | /recycle/station/{stationIds} | 删除/停用 | recycle:station:remove |
| PUT | /recycle/station/{stationId}/status | 启用停用 | recycle:station:edit |
| POST | /recycle/station/{stationId}/initAccount | 初始化余额账户 | recycle:station:account |
新增参数示例:
{
"stationCode": "CD001",
"stationName": "城东再生资源站",
"contactName": "周经理",
"contactPhone": "13900000000",
"province": "浙江省",
"city": "杭州市",
"district": "上城区",
"address": "工业路18号",
"managerUserId": 101
}
3. 回收点员工
| 方法 | 地址 | 说明 | 权限 |
|---|---|---|---|
| GET | /recycle/stationUser/list | 员工绑定列表 | recycle:stationUser:list |
| POST | /recycle/stationUser | 绑定/新增员工 | recycle:stationUser:add |
| PUT | /recycle/stationUser | 修改站点角色 | recycle:stationUser:edit |
| PUT | /recycle/stationUser/{id}/status | 启停用 | recycle:stationUser:edit |
4. 售卖者
| 方法 | 地址 | 说明 | 权限 |
|---|---|---|---|
| GET | /recycle/seller/list | 售卖者列表 | recycle:seller:list |
| GET | /recycle/seller/{sellerId} | 售卖者详情 | recycle:seller:query |
| GET | /recycle/seller/idCard/{hash} | 按身份证Hash查询 | recycle:seller:query |
| POST | /recycle/seller | 新增售卖者 | recycle:seller:add |
| PUT | /recycle/seller | 修改售卖者 | recycle:seller:edit |
| POST | /recycle/seller/ocr | 身份证OCR识别 | recycle:seller:ocr |
| POST | /recycle/seller/{sellerId}/idCardImage | 补传身份证图片 | recycle:seller:edit |
5. 分类、单位、商品、价格
| 方法 | 地址 | 说明 | 权限 |
|---|---|---|---|
| GET | /recycle/category/list | 分类列表 | recycle:category:list |
| POST | /recycle/category | 新增分类 | recycle:category:add |
| PUT | /recycle/category | 修改分类 | recycle:category:edit |
| GET | /recycle/unit/list | 单位列表 | recycle:unit:list |
| POST | /recycle/unit | 新增单位 | recycle:unit:add |
| PUT | /recycle/unit | 修改单位 | recycle:unit:edit |
| GET | /recycle/product/list | 商品列表 | recycle:product:list |
| POST | /recycle/product | 新增商品 | recycle:product:add |
| PUT | /recycle/product | 修改商品 | recycle:product:edit |
| PUT | /recycle/product/changePrice | 商品调价 | recycle:product:price |
| GET | /recycle/product/{productId}/priceTrend | 价格走势图 | recycle:product:query |
调价参数:
{
"productId": 1,
"newPrice": 1.25,
"changeReason": "市场价调整"
}
6. 回收订单
| 方法 | 地址 | 说明 | 权限 |
|---|---|---|---|
| GET | /recycle/order/list | 订单列表 | recycle:order:list |
| GET | /recycle/order/{orderId} | 订单详情 | recycle:order:query |
| POST | /recycle/order | 创建订单 | recycle:order:add |
| PUT | /recycle/order | 修改未开票订单 | recycle:order:edit |
| POST | /recycle/order/{orderId}/submit | 提交审核 | recycle:order:submit |
| POST | /recycle/order/{orderId}/audit | 审核通过/驳回 | recycle:order:audit |
| POST | /recycle/order/{orderId}/void | 作废订单 | recycle:order:void |
| GET | /recycle/order/{orderId}/print | 打印订单数据 | recycle:order:print |
| GET | /recycle/order/export | 导出订单 | recycle:order:export |
创建订单参数:
{
"stationId": 1,
"sellerId": 10,
"items": [
{
"productId": 100,
"quantity": 128.4,
"unitPrice": 1.25,
"manualPriceFlag": "0"
},
{
"productId": 101,
"quantity": 18,
"unitPrice": 7.20,
"manualPriceFlag": "1",
"changeReason": "现场议价"
}
],
"sceneFileIds": [9001],
"remark": "现场回收"
}
审核参数:
{
"auditAction": "pass",
"auditRemark": "资料完整,金额无误"
}
7. 付款记录
| 方法 | 地址 | 说明 | 权限 |
|---|---|---|---|
| GET | /recycle/payment/list | 付款记录列表 | recycle:payment:list |
| GET | /recycle/payment/{paymentId} | 详情 | recycle:payment:query |
| POST | /recycle/payment/register | 登记付款 | recycle:payment:add |
| POST | /recycle/payment/{paymentId}/confirm | 确认付款 | recycle:payment:confirm |
| POST | /recycle/payment/{paymentId}/reverse | 付款冲正 | recycle:payment:reverse |
| GET | /recycle/payment/export | 导出付款记录 | recycle:payment:export |
登记付款参数:
{
"orderId": 10001,
"paymentMethod": "bank",
"paymentAmount": 620.50,
"externalTradeNo": "BANK202608060001",
"voucherFileId": 9011,
"paidTime": "2026-08-06 10:20:00",
"remark": "银行卡转账登记"
}
业务规则:
- cash:不生成余额扣减流水。
- wechat/alipay/bank:校验回收点可用余额,余额不足阻断。
- confirmed 后订单 payment_status 变为 paid。
8. 余额账户和加款
| 方法 | 地址 | 说明 | 权限 |
|---|---|---|---|
| GET | /recycle/account/list | 平台查看余额账户 | recycle:account:list |
| GET | /recycle/account/{stationId} | 回收点余额详情 | recycle:account:query |
| GET | /recycle/account/flow/list | 余额流水 | recycle:account:flow |
| POST | /recycle/recharge/apply | 回收点发起加款 | recycle:recharge:add |
| GET | /recycle/recharge/list | 加款申请列表 | recycle:recharge:list |
| POST | /recycle/recharge/{rechargeId}/audit | 平台审核入账 | recycle:recharge:audit |
| POST | /recycle/account/backendAdd | 后台加款 | recycle:account:add |
| POST | /recycle/account/adjust | 人工调账 | recycle:account:adjust |
9. 反向开票
| 方法 | 地址 | 说明 | 权限 |
|---|---|---|---|
| GET | /recycle/invoice/pool | 待开票池 | recycle:invoice:list |
| GET | /recycle/invoice/list | 开票记录 | recycle:invoice:list |
| POST | /recycle/invoice/createByOrder/{orderId} | 按订单生成开票申请 | recycle:invoice:add |
| POST | /recycle/invoice/{invoiceId}/confirm | 录入发票号码/文件 | recycle:invoice:confirm |
| POST | /recycle/invoice/{invoiceId}/fail | 开票失败 | recycle:invoice:edit |
| POST | /recycle/invoice/{invoiceId}/red | 发票红冲 | recycle:invoice:red |
| GET | /recycle/invoice/export | 导出开票数据 | recycle:invoice:export |
10. 额度配置
| 方法 | 地址 | 说明 | 权限 |
|---|---|---|---|
| GET | /recycle/quota/list | 额度配置 | recycle:quota:list |
| PUT | /recycle/quota | 修改额度 | recycle:quota:edit |
| GET | /recycle/quota/check | 按身份证和金额试算额度 | recycle:quota:query |
11. 附件
| 方法 | 地址 | 说明 | 权限 |
|---|---|---|---|
| POST | /recycle/attachment/upload | 上传附件 | recycle:attachment:add |
| GET | /recycle/attachment/list | 附件列表 | recycle:attachment:list |
| GET | /recycle/attachment/{fileId} | 查看/下载 | recycle:attachment:query |
若依开发落地 04-ruoyi-development-guide.md
若依 Vue3 开发落地说明
1. 模块建议
RuoYi-Vue3 后端建议新增业务模块:
ruoyi-recycle
└── com.ruoyi.recycle
├── controller
├── domain
├── mapper
├── service
└── service.impl
也可以直接放在 ruoyi-admin 中,但不建议,后续业务会变重。前端按 RuoYi-Vue3 的 src/views、src/api、src/router、src/components 组织。
2. 包和类命名
| 业务 | Controller | Domain | Service | Mapper |
|---|---|---|---|---|
| 回收点 | RecStationController | RecStation | IRecStationService | RecStationMapper |
| 员工绑定 | RecStationUserController | RecStationUser | IRecStationUserService | RecStationUserMapper |
| 售卖者 | RecSellerController | RecSeller | IRecSellerService | RecSellerMapper |
| 分类 | RecCategoryController | RecCategory | IRecCategoryService | RecCategoryMapper |
| 单位 | RecUnitController | RecUnit | IRecUnitService | RecUnitMapper |
| 商品 | RecProductController | RecProduct | IRecProductService | RecProductMapper |
| 订单 | RecOrderController | RecOrder | IRecOrderService | RecOrderMapper |
| 付款 | RecPaymentController | RecPaymentRecord | IRecPaymentService | RecPaymentRecordMapper |
| 余额 | RecBalanceController | RecBalanceAccount | IRecBalanceService | RecBalanceAccountMapper |
| 加款 | RecRechargeController | RecRechargeApply | IRecRechargeService | RecRechargeApplyMapper |
| 开票 | RecInvoiceController | RecReverseInvoice | IRecInvoiceService | RecReverseInvoiceMapper |
| 额度 | RecQuotaController | RecQuotaConfig | IRecQuotaService | RecQuotaConfigMapper |
3. 若依代码生成建议
适合直接代码生成的单表:
- rec_station
- rec_station_user
- rec_seller
- rec_category
- rec_unit
- rec_product
- rec_product_price_log
- rec_recharge_apply
- rec_reverse_invoice
- rec_quota_config
不建议完全依赖代码生成,需要手写业务逻辑:
- rec_order + rec_order_item:主子表、金额计算、额度校验。
- rec_payment_record + rec_balance_flow:事务扣减余额。
- rec_balance_account:并发更新余额。
- rec_reverse_invoice:开票前置校验和红冲。
4. 事务边界
必须使用 @Transactional(rollbackFor = Exception.class) 的场景:
- 创建订单:订单主表、明细表、价格改价记录、额度占用记录。
- 订单审核:订单状态、审核记录。
- 登记非现金付款:付款记录、余额扣减/冻结、余额流水、订单付款状态。
- 付款冲正:付款记录、余额流水、订单付款状态。
- 加款审核入账:加款申请、余额账户、余额流水。
- 开票确认:开票记录、订单开票状态。
- 红冲作废:开票记录、订单状态、付款冲正、变更日志。
5. 余额并发控制
非现金付款扣减余额时,建议 SQL 条件更新:
UPDATE rec_balance_account
SET available_balance = available_balance - #{amount},
total_pay = total_pay + #{amount},
update_time = NOW()
WHERE station_id = #{stationId}
AND available_balance >= #{amount}
AND account_status = 'normal';
返回影响行数为 0 时,提示余额不足或账户不可用。
6. 身份证和银行卡安全
- 明文只在请求入参短暂存在,不落库。
- 入库保存 encrypt、hash、mask 三份。
- hash 用于唯一性和额度统计。
- mask 用于列表展示。
- encrypt 用于确需还原的场景,需后端权限控制。
- 身份证图片下载必须记录操作日志。
7. 订单金额计算
后端必须重新计算:
- 明细小计 = quantity * unit_price。
- 订单总额 = 明细小计汇总。
- 前端传入金额只作展示,不作为最终可信值。
8. 额度和税费校验建议
提交审核前校验:
- 当月累计:按 id_card_no_hash + order_time 当月 + 未作废订单,默认只提示税费处理风险。
- 连续 12 个月累计:按 id_card_no_hash + 最近 12 个月 + 未作废订单,默认超过 500 万元阻断。
- 三流合一年累计:按 id_card_no_hash + 自然年 + 已完成三流合一付款订单,第一版预留。
- 是否阻断读取 rec_quota_config.control_action/block_flag,不写死在代码里。
9. 权限和数据范围
平台角色:
- 查看所有 station_id。
回收点管理员:
- station_id = 当前绑定回收点。
回收点员工:
- 默认 employee_user_id = 当前登录用户。
- 若配置 data_scope=station,可查看本站全部订单。
实现方式:
- 在 Service 查询条件中注入 stationId/userId。
- 不建议只依赖前端隐藏菜单。
10. Vue3 前端页面建议
平台端:
- 回收点管理
- 订单监管
- 余额账户
- 加款审核
- 付款记录
- 反向开票
- 财务报表
- 系统设置/额度设置
回收点 PC:
- 工作台
- 员工管理
- 分类管理
- 商品管理
- 单位管理
- 价格管理
- 订单查询
- 余额中心
- 加款申请
移动端 H5/uni-app:
- 首页
- 录入订单
- 订单列表
- 站点信息
- 我的明细
- 分类信息
- 商品信息
Vue3 页面、API 封装、权限按钮和字典使用详见 06-vue3-frontend-guide.md。
11. 开发优先级建议
第一阶段后端:
- 回收点、员工绑定、分类、单位、商品、价格。
- 售卖者、附件、身份证资料。
- 订单主流程。
- 余额账户、加款、付款登记。
- 反向开票手工记录。
- 报表和导出。
第二阶段:
- 在线支付。
- OCR 服务商。
- 电子发票服务商。
- 自动对账。
- 风控黑名单。
字典和权限 05-dict-and-permission.md
字典和权限设计
1. 字典类型
| 字典类型 | 字典名称 | 值 |
|---|---|---|
| rec_business_status | 经营状态 | 1启用、0停用 |
| rec_account_status | 余额账户状态 | normal正常、frozen冻结、disabled禁用 |
| rec_station_role | 回收点角色 | station_admin回收点管理员、station_staff员工 |
| rec_data_scope | 回收点数据范围 | self本人、station本站 |
| rec_id_card_image_status | 身份证图片状态 | pending待补全、complete完整 |
| rec_ocr_status | OCR状态 | none未识别、success成功、fail失败、manual人工录入 |
| rec_receive_type | 收款方式 | cash现金、wechat微信、alipay支付宝、bank银行卡 |
| rec_order_status | 订单状态 | draft草稿、pending_audit待审核、audit_pass审核通过、audit_reject审核驳回、void已作废 |
| rec_payment_status | 付款状态 | not_required未到付款、pending待登记、confirming待确认、paid已支付、cancel已取消、reversed已冲正 |
| rec_payment_method | 付款方式 | cash现金、wechat微信、alipay支付宝、bank银行卡 |
| rec_invoice_status | 开票状态 | not_enter未进入、waiting待开票、applying申请中、invoiced已开票、failed失败、reding红冲中、reded已红冲、void已作废 |
| rec_recharge_type | 加款方式 | backend_add后台加款、offline_transfer线下转账、wechat微信充值、alipay支付宝充值、online_bank网银 |
| rec_recharge_status | 加款状态 | pending待审核、pass已通过、reject已驳回、accounted已入账、cancel已取消 |
| rec_balance_biz_type | 余额流水类型 | recharge充值、pay付款、freeze冻结、unfreeze解冻、reverse冲正、refund退款、adjust调账 |
| rec_quota_period | 额度周期 | month当月、rolling_12_month连续12个月、year年度 |
2. 菜单权限
平台端:
- recycle:station:list/query/add/edit/remove/account
- recycle:order:list/query/audit/void/print/export
- recycle:account:list/query/flow/add/adjust
- recycle:recharge:list/query/audit/export
- recycle:payment:list/query/add/confirm/reverse/export
- recycle:invoice:list/query/add/confirm/red/export
- recycle:quota:list/query/edit
回收点端:
- recycle:stationUser:list/add/edit
- recycle:category:list/add/edit/remove
- recycle:unit:list/add/edit/remove
- recycle:product:list/add/edit/remove/price
- recycle:order:list/query/add/edit/submit/print/export
- recycle:recharge:add/list/query
- recycle:account:query/flow
移动端:
- recycle:mobile:home
- recycle:mobile:order:add/list/query
- recycle:mobile:seller:add/query/ocr
- recycle:mobile:station:query
- recycle:mobile:product:list
Vue3 前端说明 06-vue3-frontend-guide.md
RuoYi-Vue3 前端开发说明
1. 技术栈约定
- Vue 3
- Vite
- Element Plus
- 若依 Vue3 风格的
src/api/**接口封装 - 若依权限指令:
v-hasPermi - 列表页沿用
queryParams、getList、handleQuery、resetQuery、handleAdd、handleUpdate、handleDelete、handleExport的写法
2. 前端目录建议
src/
api/
recycle/
station.js
stationUser.js
seller.js
category.js
unit.js
product.js
order.js
payment.js
account.js
recharge.js
invoice.js
quota.js
attachment.js
views/
recycle/
platform/
station/index.vue
order/index.vue
account/index.vue
recharge/index.vue
payment/index.vue
invoice/index.vue
report/index.vue
quota/index.vue
station/
dashboard/index.vue
staff/index.vue
category/index.vue
unit/index.vue
product/index.vue
price/index.vue
order/index.vue
balance/index.vue
recharge/index.vue
components/
SellerSelect.vue
ProductItemEditor.vue
PaymentRegisterDialog.vue
OrderPrintDialog.vue
AttachmentUpload.vue
PriceTrend.vue
3. API 封装示例
// src/api/recycle/order.js
import request from '@/utils/request'
export function listOrder(query) {
return request({
url: '/recycle/order/list',
method: 'get',
params: query
})
}
export function getOrder(orderId) {
return request({
url: '/recycle/order/' + orderId,
method: 'get'
})
}
export function addOrder(data) {
return request({
url: '/recycle/order',
method: 'post',
data
})
}
export function updateOrder(data) {
return request({
url: '/recycle/order',
method: 'put',
data
})
}
export function submitOrder(orderId) {
return request({
url: '/recycle/order/' + orderId + '/submit',
method: 'post'
})
}
export function auditOrder(orderId, data) {
return request({
url: '/recycle/order/' + orderId + '/audit',
method: 'post',
data
})
}
4. 列表页 Vue3 写法示例
<script setup>
import { ref, reactive, toRefs, getCurrentInstance } from 'vue'
import { listOrder } from '@/api/recycle/order'
const { proxy } = getCurrentInstance()
const loading = ref(false)
const total = ref(0)
const orderList = ref([])
const data = reactive({
queryParams: {
pageNum: 1,
pageSize: 10,
orderNo: undefined,
stationId: undefined,
orderStatus: undefined,
paymentStatus: undefined,
invoiceStatus: undefined
}
})
const { queryParams } = toRefs(data)
function getList() {
loading.value = true
listOrder(queryParams.value).then(res => {
orderList.value = res.rows
total.value = res.total
loading.value = false
})
}
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
function resetQuery() {
proxy.resetForm('queryRef')
handleQuery()
}
getList()
</script>
5. 页面设计建议
平台管理后台
| 页面 | 主要组件 | 说明 |
|---|---|---|
| 回收点管理 | el-table + el-dialog | 管理回收点、初始化余额账户 |
| 订单监管 | el-table + el-drawer | 全平台订单查询、审核、打印 |
| 余额账户 | el-table + el-descriptions | 回收点余额、流水、后台加款 |
| 充值审核 | el-table + audit dialog | 线下转账审核入账 |
| 付款记录 | el-table + voucher preview | 现金/非现金付款登记和冲正 |
| 反向开票 | el-table + el-drawer | 待开票池、一单一票、红冲 |
| 财务报表 | el-card + charts | 金额、付款、开票统计 |
| 额度设置 | el-form | 月额度、12个月额度、阻断开关 |
回收点 PC 后台
| 页面 | 主要组件 | 说明 |
|---|---|---|
| 工作台 | 指标卡 + 表格 | 本站订单、余额、商品概览 |
| 员工管理 | el-table | 员工绑定和启停用 |
| 分类管理 | el-table/tree | 本站分类 |
| 商品管理 | el-table | 商品、单位、默认价 |
| 单位管理 | el-table | 公斤、斤、吨、个等 |
| 价格管理 | PriceTrend | 调价记录和趋势图 |
| 订单查询 | el-table + drawer | 本站订单筛选、打印 |
| 余额中心 | el-descriptions + el-table | 余额和流水 |
| 加款申请 | el-form + upload | 线下转账加款 |
6. 字典使用
Vue3 页面使用若依字典 hook:
const { rec_order_status, rec_payment_status, rec_invoice_status } = proxy.useDict(
'rec_order_status',
'rec_payment_status',
'rec_invoice_status'
)
表格显示:
<dict-tag :options="rec_order_status" :value="scope.row.orderStatus" />
7. 权限按钮
<el-button
type="primary"
plain
icon="Plus"
v-hasPermi="['recycle:order:add']"
@click="handleAdd"
>
新增
</el-button>
8. 移动端说明
员工端准备用 uni-app,不建议塞进 RuoYi-Vue3 后台前端。建议作为独立 H5/小程序项目,共用后端接口,登录可对接若依 Token 或单独移动端登录接口。
税务与额度 07-tax-policy-and-quota.md
反向开票政策口径和额度配置
1. 政策口径摘要
本系统不是税务判断工具,开发上只把政策口径做成可配置参数、校验提示和留痕。上线前需要由客户财税顾问按企业所在地区和主管税务机关要求确认。
| 控制项 | 建议系统配置 | 默认动作 | 说明 |
|---|---|---|---|
| 个人当月销售额提示线 | 10万元 | 预警 | 用于提示增值税、附加税和代办税费处理,不建议直接当作“禁止开票”硬规则 |
| 个人连续12个月反向开票上限 | 500万元 | 阻断 | 超过后自然人不再符合资源回收企业反向开票条件 |
| 三流合一个税优惠年度额度 | 60万元 | 税费分段 | 2026-07-01 后接入三流合一反向开票时启用,第一版预留 |
2. 官方来源
- 国家税务总局公告2024年第5号:关于资源回收企业向自然人报废产品出售者“反向开票”有关事项的公告,https://fgk.chinatax.gov.cn/zcfgk/c100012/c5223305/content.html
- 国家税务总局公告2026年第12号:关于“三流合一反向开票”个人所得税有关征管事项的公告,https://fgk.chinatax.gov.cn/zcfgk/c100012/c5250556/content.html
- 财政部、税务总局关于小规模纳税人增值税优惠政策的现行口径:月销售额10万元以下增值税优惠。
3. 系统额度配置
建议使用 rec_quota_config 做统一配置,不在代码里写死金额。
| quota_code | 用途 | 周期 | 金额 | control_action |
|---|---|---|---|---|
| PERSON_MONTH_TAX_FREE_AMOUNT | 当月销售额提示线 | month | 100000.00 | warn |
| PERSON_ROLLING_12_REVERSE_LIMIT | 连续12个月反向开票上限 | rolling_12_month | 5000000.00 | block |
| PERSON_YEAR_TRIPLE_FLOW_TAX_BREAK | 三流合一个税优惠年度额度 | year | 600000.00 | tax_calc |
4. 订单校验时点
| 时点 | 校验内容 | 失败处理 |
|---|---|---|
| 创建草稿 | 售卖者身份证是否存在、商品单价和金额计算 | 草稿可保存,但提示资料待补 |
| 提交审核 | 身份证 Hash、额度、订单金额、明细完整性 | 超过 block 额度则不允许提交 |
| 审核通过 | 再次校验订单金额和售卖者状态 | 不通过则驳回 |
| 登记付款 | 非现金校验回收点余额 | 余额不足不允许登记非现金付款 |
| 生成开票 | 付款完成、未作废、未开票、授权和身份证信息完整 | 不满足则不进入开票池 |
5. 税费字段预留
反向开票表保留:
- vat_amount:增值税金额。
- additional_tax_amount:附加税费。
- personal_tax_amount:个人所得税。
- tax_calc_rule:normal/triple_flow。
- tax_report_period:代办税费所属期。
- tax_report_status:代办税费申报状态。
- tax_report_no:代办税费报告编号。
6. 开发注意
- 额度统计按身份证 Hash,不按 seller_id,因为同一自然人可能在多个回收点发生交易。
- 统计金额建议以已审核或已支付订单为准,具体口径由平台配置。
- 已作废订单不计入额度;已红冲订单是否扣减额度需按财务最终处理状态确定。
- 额度日志 rec_quota_usage_log 需要记录 before_amount、order_amount、after_amount、quota_amount 和 check_status,便于客户解释为什么被阻断。
后端代码骨架 08-backend-code-skeleton.md
若依后端代码骨架
1. 开发包结构
ruoyi-recycle
src/main/java/com/ruoyi/recycle
controller
domain
mapper
service
service/impl
dto
vo
enums
util
src/main/resources/mapper/recycle
如果先不拆模块,也可以放在 ruoyi-admin 下,但包名仍建议保持 com.ruoyi.recycle,后续迁移成本更低。
2. 订单 Controller 示例
@RestController
@RequestMapping("/recycle/order")
public class RecOrderController extends BaseController {
@Autowired
private IRecOrderService recOrderService;
@PreAuthorize("@ss.hasPermi('recycle:order:list')")
@GetMapping("/list")
public TableDataInfo list(RecOrderQuery query) {
startPage();
return getDataTable(recOrderService.selectRecOrderList(query));
}
@PreAuthorize("@ss.hasPermi('recycle:order:add')")
@PostMapping
public AjaxResult add(@RequestBody RecOrderCreateDto dto) {
return success(recOrderService.createOrder(dto));
}
@PreAuthorize("@ss.hasPermi('recycle:order:submit')")
@PostMapping("/{orderId}/submit")
public AjaxResult submit(@PathVariable Long orderId) {
recOrderService.submitOrder(orderId);
return success();
}
@PreAuthorize("@ss.hasPermi('recycle:order:audit')")
@PostMapping("/{orderId}/audit")
public AjaxResult audit(@PathVariable Long orderId, @RequestBody RecOrderAuditDto dto) {
recOrderService.auditOrder(orderId, dto);
return success();
}
}
3. 订单 Service 事务方法
@Transactional(rollbackFor = Exception.class)
public Long createOrder(RecOrderCreateDto dto) {
RecSeller seller = sellerService.selectById(dto.getSellerId());
Assert.notNull(seller, "售卖者不存在");
RecOrder order = buildOrderSnapshot(dto, seller);
recOrderMapper.insertRecOrder(order);
for (RecOrderItemDto itemDto : dto.getItems()) {
RecOrderItem item = buildItemSnapshot(order, itemDto);
recOrderItemMapper.insertRecOrderItem(item);
if ("1".equals(item.getManualPriceFlag())) {
priceLogService.recordOrderPriceChange(order, item, itemDto.getChangeReason());
}
}
recOrderMapper.updateOrderAmount(order.getOrderId(), recalcOrderAmount(order.getOrderId()));
quotaService.checkAndRecord(order.getOrderId());
return order.getOrderId();
}
4. 余额扣减 Mapper SQL
<update id="deductAvailableBalance">
UPDATE rec_balance_account
SET available_balance = available_balance - #{amount},
total_pay = total_pay + #{amount},
update_time = NOW()
WHERE station_id = #{stationId}
AND available_balance >= #{amount}
AND account_status = 'normal'
</update>
Service 中判断影响行数:
int rows = recBalanceAccountMapper.deductAvailableBalance(stationId, amount);
if (rows == 0) {
throw new ServiceException("回收点余额不足或账户不可用");
}
5. 付款登记流程
1. 校验订单状态 = audit_pass。
2. 校验付款金额 = 订单应付金额或允许补付金额。
3. cash:只写 rec_payment_record,不写余额扣减流水。
4. wechat/alipay/bank:先扣余额,再写 rec_balance_flow,再写 rec_payment_record。
5. 更新订单 paid_amount/payment_status。
6. paid 后可进入反向开票池。
6. 额度校验伪代码
public QuotaCheckResult checkAndRecord(Long orderId) {
RecOrder order = orderMapper.selectRecOrderByOrderId(orderId);
List<RecQuotaConfig> configs = quotaMapper.selectEnabledConfigs();
for (RecQuotaConfig config : configs) {
BigDecimal beforeAmount = quotaMapper.sumSellerAmount(
order.getSellerIdCardHash(),
config.getPeriodType(),
order.getOrderTime()
);
BigDecimal afterAmount = beforeAmount.add(order.getPayableAmount());
String status = resolveQuotaStatus(config, afterAmount);
quotaUsageLogMapper.insert(buildLog(order, config, beforeAmount, afterAmount, status));
if ("block".equals(config.getControlAction()) && "fail".equals(status)) {
throw new ServiceException(config.getQuotaName() + "已超限");
}
}
return QuotaCheckResult.pass();
}
7. DTO 建议
| DTO | 字段 |
|---|---|
| RecOrderCreateDto | stationId、sellerId、items、sceneFileIds、remark |
| RecOrderItemDto | productId、quantity、unitPrice、manualPriceFlag、changeReason |
| RecOrderAuditDto | auditAction、auditRemark |
| RecPaymentRegisterDto | orderId、paymentMethod、paymentAmount、externalTradeNo、voucherFileId、paidTime、remark |
| RecRechargeAuditDto | auditAction、approvedAmount、auditRemark |
| RecInvoiceConfirmDto | invoiceId、taxInvoiceCode、taxInvoiceNo、invoiceDate、eInvoiceFileId、taxAmount fields |
8. 开发任务拆分
| 模块 | 后端任务 | 前端 Vue3 任务 |
|---|---|---|
| 基础资料 | 回收点、员工绑定、分类、单位、商品、价格日志 | 平台回收点、回收点资料维护页面 |
| 售卖者 | 身份证 Hash/脱敏/加密、OCR 接口适配、附件 | 售卖者选择、身份证上传、补图 |
| 订单 | 主子表、审核、修改、作废、打印 | 订单录入、订单列表、详情抽屉、打印 |
| 财务 | 余额账户、余额流水、加款审核、付款登记 | 余额中心、充值审核、付款流水 |
| 开票 | 待开票池、一单一票、红冲字段 | 反向开票列表、开票确认、红冲 |
| 报表 | 订单/付款/开票统计接口 | 财务报表图表和导出 |
9. 必做测试
- 同一身份证跨回收点额度累计。
- 现金付款不扣余额。
- 非现金余额不足阻断。
- 手动改价写入价格记录。
- 未开票订单允许修改,已开票订单必须走作废/红冲。
- 一单只生成一条有效反向开票记录。
- 回收点员工只能看到本人或本站数据,不能越权查看其他回收点。
业务表 SQL sql/recycle_platform_schema.sql
CREATE DATABASE IF NOT EXISTS recycle_platform DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
USE recycle_platform;
DROP TABLE IF EXISTS rec_station;
CREATE TABLE rec_station (
station_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '回收点ID',
station_code VARCHAR(32) NOT NULL COMMENT '回收点编号',
station_name VARCHAR(100) NOT NULL COMMENT '回收点名称',
contact_name VARCHAR(50) DEFAULT NULL COMMENT '联系人',
contact_phone VARCHAR(30) DEFAULT NULL COMMENT '联系电话',
province VARCHAR(50) DEFAULT NULL COMMENT '省',
city VARCHAR(50) DEFAULT NULL COMMENT '市',
district VARCHAR(50) DEFAULT NULL COMMENT '区县',
address VARCHAR(255) DEFAULT NULL COMMENT '详细地址',
longitude DECIMAL(12,6) DEFAULT NULL COMMENT '经度',
latitude DECIMAL(12,6) DEFAULT NULL COMMENT '纬度',
manager_user_id BIGINT DEFAULT NULL COMMENT '默认负责人用户ID',
license_no VARCHAR(80) DEFAULT NULL COMMENT '备案/营业执照号',
settle_bank_name VARCHAR(100) DEFAULT NULL COMMENT '结算开户行',
settle_bank_account_mask VARCHAR(80) DEFAULT NULL COMMENT '结算账号脱敏',
business_status CHAR(1) NOT NULL DEFAULT '1' COMMENT '经营状态 1启用 0停用',
account_status VARCHAR(20) NOT NULL DEFAULT 'normal' COMMENT '余额账户状态 normal/frozen/disabled',
create_by VARCHAR(64) DEFAULT '' COMMENT '创建者',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_by VARCHAR(64) DEFAULT '' COMMENT '更新者',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
del_flag CHAR(1) NOT NULL DEFAULT '0' COMMENT '删除标志 0正常 2删除',
PRIMARY KEY (station_id),
UNIQUE KEY uk_station_code (station_code),
KEY idx_station_name (station_name)
) ENGINE=InnoDB COMMENT='回收点表';
DROP TABLE IF EXISTS rec_station_user;
CREATE TABLE rec_station_user (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
station_id BIGINT UNSIGNED NOT NULL COMMENT '回收点ID',
user_id BIGINT NOT NULL COMMENT '若依用户ID',
employee_no VARCHAR(32) DEFAULT NULL COMMENT '员工编号',
station_role VARCHAR(30) NOT NULL COMMENT '站点角色 station_admin/station_staff',
data_scope VARCHAR(20) NOT NULL DEFAULT 'self' COMMENT '数据范围 self/station',
status CHAR(1) NOT NULL DEFAULT '1' COMMENT '状态 1启用 0停用',
create_by VARCHAR(64) DEFAULT '',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64) DEFAULT '',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
remark VARCHAR(500) DEFAULT NULL,
del_flag CHAR(1) NOT NULL DEFAULT '0',
PRIMARY KEY (id),
UNIQUE KEY uk_station_user (station_id, user_id),
KEY idx_user_id (user_id)
) ENGINE=InnoDB COMMENT='回收点用户绑定表';
DROP TABLE IF EXISTS rec_seller;
CREATE TABLE rec_seller (
seller_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '售卖者ID',
seller_name VARCHAR(60) NOT NULL COMMENT '姓名',
mobile VARCHAR(30) DEFAULT NULL COMMENT '手机号',
id_card_no_encrypt VARCHAR(255) DEFAULT NULL COMMENT '身份证号密文',
id_card_no_hash CHAR(64) NOT NULL COMMENT '身份证号Hash',
id_card_mask VARCHAR(32) DEFAULT NULL COMMENT '身份证脱敏',
id_card_front_file_id BIGINT DEFAULT NULL COMMENT '身份证正面附件ID',
id_card_back_file_id BIGINT DEFAULT NULL COMMENT '身份证反面附件ID',
id_card_image_status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT '身份证图片状态 pending/complete',
ocr_status VARCHAR(20) NOT NULL DEFAULT 'none' COMMENT 'OCR状态 none/success/fail/manual',
ocr_raw_json TEXT DEFAULT NULL COMMENT 'OCR原始结果',
receive_type VARCHAR(20) DEFAULT NULL COMMENT '收款方式 cash/wechat/alipay/bank',
receive_account_encrypt VARCHAR(255) DEFAULT NULL COMMENT '收款账号密文',
receive_account_mask VARCHAR(80) DEFAULT NULL COMMENT '收款账号脱敏',
bank_name VARCHAR(100) DEFAULT NULL COMMENT '开户行',
bank_card_no_encrypt VARCHAR(255) DEFAULT NULL COMMENT '银行卡密文',
bank_card_mask VARCHAR(80) DEFAULT NULL COMMENT '银行卡脱敏',
invoice_consent_flag CHAR(1) NOT NULL DEFAULT '0' COMMENT '是否同意反向开票',
consent_file_id BIGINT DEFAULT NULL COMMENT '授权/同意材料附件',
risk_status VARCHAR(20) NOT NULL DEFAULT 'normal' COMMENT '风险状态 normal/black/limited',
first_order_time DATETIME DEFAULT NULL COMMENT '首次交易时间',
last_order_time DATETIME DEFAULT NULL COMMENT '最近交易时间',
create_by VARCHAR(64) DEFAULT '',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64) DEFAULT '',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
remark VARCHAR(500) DEFAULT NULL,
del_flag CHAR(1) NOT NULL DEFAULT '0',
PRIMARY KEY (seller_id),
UNIQUE KEY uk_id_card_hash (id_card_no_hash),
KEY idx_mobile (mobile),
KEY idx_seller_name (seller_name)
) ENGINE=InnoDB COMMENT='个人售卖者表';
DROP TABLE IF EXISTS rec_category;
CREATE TABLE rec_category (
category_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
station_id BIGINT UNSIGNED NOT NULL,
parent_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
category_code VARCHAR(32) DEFAULT NULL,
category_name VARCHAR(80) NOT NULL,
sort_no INT NOT NULL DEFAULT 0,
status CHAR(1) NOT NULL DEFAULT '1',
create_by VARCHAR(64) DEFAULT '',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64) DEFAULT '',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
remark VARCHAR(500) DEFAULT NULL,
del_flag CHAR(1) NOT NULL DEFAULT '0',
PRIMARY KEY (category_id),
KEY idx_station_category (station_id, category_name)
) ENGINE=InnoDB COMMENT='回收分类表';
DROP TABLE IF EXISTS rec_unit;
CREATE TABLE rec_unit (
unit_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
station_id BIGINT UNSIGNED NOT NULL,
unit_code VARCHAR(32) DEFAULT NULL,
unit_name VARCHAR(40) NOT NULL,
decimal_scale TINYINT NOT NULL DEFAULT 2 COMMENT '小数位',
status CHAR(1) NOT NULL DEFAULT '1',
create_by VARCHAR(64) DEFAULT '',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64) DEFAULT '',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
remark VARCHAR(500) DEFAULT NULL,
del_flag CHAR(1) NOT NULL DEFAULT '0',
PRIMARY KEY (unit_id),
KEY idx_station_unit (station_id, unit_name)
) ENGINE=InnoDB COMMENT='计量单位表';
DROP TABLE IF EXISTS rec_product;
CREATE TABLE rec_product (
product_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
station_id BIGINT UNSIGNED NOT NULL,
category_id BIGINT UNSIGNED NOT NULL,
unit_id BIGINT UNSIGNED NOT NULL,
product_code VARCHAR(32) DEFAULT NULL,
product_name VARCHAR(100) NOT NULL,
default_price DECIMAL(18,4) NOT NULL DEFAULT 0 COMMENT '默认单价',
price_status VARCHAR(20) NOT NULL DEFAULT 'normal' COMMENT '价格状态 normal/changed',
sort_no INT NOT NULL DEFAULT 0,
status CHAR(1) NOT NULL DEFAULT '1',
create_by VARCHAR(64) DEFAULT '',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64) DEFAULT '',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
remark VARCHAR(500) DEFAULT NULL,
del_flag CHAR(1) NOT NULL DEFAULT '0',
PRIMARY KEY (product_id),
KEY idx_station_product (station_id, product_name),
KEY idx_category_id (category_id)
) ENGINE=InnoDB COMMENT='回收商品表';
DROP TABLE IF EXISTS rec_product_price_log;
CREATE TABLE rec_product_price_log (
price_log_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
station_id BIGINT UNSIGNED NOT NULL,
product_id BIGINT UNSIGNED NOT NULL,
unit_id BIGINT UNSIGNED DEFAULT NULL,
old_price DECIMAL(18,4) DEFAULT NULL,
new_price DECIMAL(18,4) NOT NULL,
change_source VARCHAR(30) NOT NULL COMMENT 'backend/order',
order_id BIGINT UNSIGNED DEFAULT NULL,
change_reason VARCHAR(255) DEFAULT NULL,
change_user_id BIGINT DEFAULT NULL,
change_time DATETIME DEFAULT CURRENT_TIMESTAMP,
create_by VARCHAR(64) DEFAULT '',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500) DEFAULT NULL,
PRIMARY KEY (price_log_id),
KEY idx_product_time (product_id, change_time),
KEY idx_station_time (station_id, change_time)
) ENGINE=InnoDB COMMENT='商品价格记录表';
DROP TABLE IF EXISTS rec_order;
CREATE TABLE rec_order (
order_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
order_no VARCHAR(40) NOT NULL,
station_id BIGINT UNSIGNED NOT NULL,
station_name VARCHAR(100) NOT NULL,
employee_user_id BIGINT DEFAULT NULL,
employee_name VARCHAR(60) DEFAULT NULL,
seller_id BIGINT UNSIGNED NOT NULL,
seller_name VARCHAR(60) NOT NULL,
seller_mobile VARCHAR(30) DEFAULT NULL,
seller_id_card_hash CHAR(64) NOT NULL,
seller_id_card_mask VARCHAR(32) DEFAULT NULL,
order_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
item_count INT NOT NULL DEFAULT 0,
order_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
payable_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
paid_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
invoice_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
order_status VARCHAR(30) NOT NULL DEFAULT 'draft',
payment_status VARCHAR(30) NOT NULL DEFAULT 'not_required',
invoice_status VARCHAR(30) NOT NULL DEFAULT 'not_enter',
id_card_image_status VARCHAR(20) NOT NULL DEFAULT 'pending',
quota_check_status VARCHAR(20) NOT NULL DEFAULT 'pass',
quota_check_msg VARCHAR(500) DEFAULT NULL,
audit_user_id BIGINT DEFAULT NULL,
audit_time DATETIME DEFAULT NULL,
audit_remark VARCHAR(500) DEFAULT NULL,
void_flag CHAR(1) NOT NULL DEFAULT '0',
void_time DATETIME DEFAULT NULL,
print_count INT NOT NULL DEFAULT 0,
create_by VARCHAR(64) DEFAULT '',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64) DEFAULT '',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
remark VARCHAR(500) DEFAULT NULL,
del_flag CHAR(1) NOT NULL DEFAULT '0',
PRIMARY KEY (order_id),
UNIQUE KEY uk_order_no (order_no),
KEY idx_station_time (station_id, order_time),
KEY idx_seller_time (seller_id, order_time),
KEY idx_status (order_status, payment_status, invoice_status),
KEY idx_id_card_hash (seller_id_card_hash)
) ENGINE=InnoDB COMMENT='回收订单主表';
DROP TABLE IF EXISTS rec_order_item;
CREATE TABLE rec_order_item (
item_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
order_id BIGINT UNSIGNED NOT NULL,
order_no VARCHAR(40) NOT NULL,
station_id BIGINT UNSIGNED NOT NULL,
category_id BIGINT UNSIGNED DEFAULT NULL,
category_name VARCHAR(80) DEFAULT NULL,
product_id BIGINT UNSIGNED DEFAULT NULL,
product_name VARCHAR(100) NOT NULL,
unit_id BIGINT UNSIGNED DEFAULT NULL,
unit_name VARCHAR(40) NOT NULL,
quantity DECIMAL(18,4) NOT NULL DEFAULT 0,
default_price DECIMAL(18,4) DEFAULT NULL,
unit_price DECIMAL(18,4) NOT NULL DEFAULT 0,
manual_price_flag CHAR(1) NOT NULL DEFAULT '0',
amount DECIMAL(18,2) NOT NULL DEFAULT 0,
sort_no INT NOT NULL DEFAULT 0,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500) DEFAULT NULL,
PRIMARY KEY (item_id),
KEY idx_order_id (order_id),
KEY idx_product_id (product_id)
) ENGINE=InnoDB COMMENT='回收订单明细表';
DROP TABLE IF EXISTS rec_order_audit_log;
CREATE TABLE rec_order_audit_log (
audit_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
order_id BIGINT UNSIGNED NOT NULL,
order_no VARCHAR(40) NOT NULL,
audit_action VARCHAR(30) NOT NULL COMMENT 'submit/pass/reject/void',
before_status VARCHAR(30) DEFAULT NULL,
after_status VARCHAR(30) DEFAULT NULL,
audit_user_id BIGINT DEFAULT NULL,
audit_user_name VARCHAR(60) DEFAULT NULL,
audit_time DATETIME DEFAULT CURRENT_TIMESTAMP,
audit_remark VARCHAR(500) DEFAULT NULL,
PRIMARY KEY (audit_id),
KEY idx_order_id (order_id)
) ENGINE=InnoDB COMMENT='订单审核记录表';
DROP TABLE IF EXISTS rec_order_change_log;
CREATE TABLE rec_order_change_log (
change_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
order_id BIGINT UNSIGNED NOT NULL,
order_no VARCHAR(40) NOT NULL,
change_type VARCHAR(30) NOT NULL COMMENT 'edit/void/red/reverse',
before_json TEXT DEFAULT NULL,
after_json TEXT DEFAULT NULL,
change_reason VARCHAR(500) DEFAULT NULL,
change_user_id BIGINT DEFAULT NULL,
change_user_name VARCHAR(60) DEFAULT NULL,
change_time DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (change_id),
KEY idx_order_id (order_id)
) ENGINE=InnoDB COMMENT='订单修改记录表';
DROP TABLE IF EXISTS rec_balance_account;
CREATE TABLE rec_balance_account (
account_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
station_id BIGINT UNSIGNED NOT NULL,
available_balance DECIMAL(18,2) NOT NULL DEFAULT 0,
frozen_balance DECIMAL(18,2) NOT NULL DEFAULT 0,
total_recharge DECIMAL(18,2) NOT NULL DEFAULT 0,
total_pay DECIMAL(18,2) NOT NULL DEFAULT 0,
total_refund DECIMAL(18,2) NOT NULL DEFAULT 0,
account_status VARCHAR(20) NOT NULL DEFAULT 'normal',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
remark VARCHAR(500) DEFAULT NULL,
PRIMARY KEY (account_id),
UNIQUE KEY uk_station_id (station_id)
) ENGINE=InnoDB COMMENT='回收点余额账户表';
DROP TABLE IF EXISTS rec_balance_flow;
CREATE TABLE rec_balance_flow (
flow_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
flow_no VARCHAR(40) NOT NULL,
station_id BIGINT UNSIGNED NOT NULL,
account_id BIGINT UNSIGNED NOT NULL,
biz_type VARCHAR(40) NOT NULL COMMENT 'recharge/pay/freeze/unfreeze/reverse/refund/adjust',
biz_id BIGINT UNSIGNED DEFAULT NULL,
direction VARCHAR(10) NOT NULL COMMENT 'in/out/freeze/unfreeze',
amount DECIMAL(18,2) NOT NULL DEFAULT 0,
before_balance DECIMAL(18,2) NOT NULL DEFAULT 0,
after_balance DECIMAL(18,2) NOT NULL DEFAULT 0,
before_frozen DECIMAL(18,2) NOT NULL DEFAULT 0,
after_frozen DECIMAL(18,2) NOT NULL DEFAULT 0,
operator_user_id BIGINT DEFAULT NULL,
flow_time DATETIME DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500) DEFAULT NULL,
PRIMARY KEY (flow_id),
UNIQUE KEY uk_flow_no (flow_no),
KEY idx_station_time (station_id, flow_time),
KEY idx_biz (biz_type, biz_id)
) ENGINE=InnoDB COMMENT='余额流水表';
DROP TABLE IF EXISTS rec_payment_record;
CREATE TABLE rec_payment_record (
payment_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
payment_no VARCHAR(40) NOT NULL,
order_id BIGINT UNSIGNED NOT NULL,
order_no VARCHAR(40) NOT NULL,
station_id BIGINT UNSIGNED NOT NULL,
station_name VARCHAR(100) NOT NULL,
seller_id BIGINT UNSIGNED NOT NULL,
seller_name VARCHAR(60) NOT NULL,
payment_method VARCHAR(20) NOT NULL COMMENT 'cash/wechat/alipay/bank',
payment_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
balance_affect_flag CHAR(1) NOT NULL DEFAULT '0',
balance_flow_id BIGINT UNSIGNED DEFAULT NULL,
external_trade_no VARCHAR(100) DEFAULT NULL,
third_channel VARCHAR(40) DEFAULT NULL,
third_order_no VARCHAR(100) DEFAULT NULL,
third_trade_no VARCHAR(100) DEFAULT NULL,
third_callback_time DATETIME DEFAULT NULL,
voucher_file_id BIGINT DEFAULT NULL,
payment_status VARCHAR(30) NOT NULL DEFAULT 'pending',
paid_time DATETIME DEFAULT NULL,
reverse_payment_id BIGINT UNSIGNED DEFAULT NULL,
create_by VARCHAR(64) DEFAULT '',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64) DEFAULT '',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
remark VARCHAR(500) DEFAULT NULL,
del_flag CHAR(1) NOT NULL DEFAULT '0',
PRIMARY KEY (payment_id),
UNIQUE KEY uk_payment_no (payment_no),
KEY idx_order_id (order_id),
KEY idx_station_time (station_id, create_time),
KEY idx_status (payment_status)
) ENGINE=InnoDB COMMENT='付款记录表';
DROP TABLE IF EXISTS rec_recharge_apply;
CREATE TABLE rec_recharge_apply (
recharge_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
recharge_no VARCHAR(40) NOT NULL,
station_id BIGINT UNSIGNED NOT NULL,
station_name VARCHAR(100) NOT NULL,
recharge_type VARCHAR(30) NOT NULL COMMENT 'backend_add/offline_transfer/wechat/alipay/online_bank',
apply_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
approved_amount DECIMAL(18,2) DEFAULT NULL,
voucher_file_id BIGINT DEFAULT NULL,
apply_user_id BIGINT DEFAULT NULL,
apply_time DATETIME DEFAULT CURRENT_TIMESTAMP,
audit_status VARCHAR(30) NOT NULL DEFAULT 'pending',
audit_user_id BIGINT DEFAULT NULL,
audit_time DATETIME DEFAULT NULL,
audit_remark VARCHAR(500) DEFAULT NULL,
account_flow_id BIGINT UNSIGNED DEFAULT NULL,
create_by VARCHAR(64) DEFAULT '',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64) DEFAULT '',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
remark VARCHAR(500) DEFAULT NULL,
del_flag CHAR(1) NOT NULL DEFAULT '0',
PRIMARY KEY (recharge_id),
UNIQUE KEY uk_recharge_no (recharge_no),
KEY idx_station_time (station_id, apply_time),
KEY idx_status (audit_status)
) ENGINE=InnoDB COMMENT='加款申请表';
DROP TABLE IF EXISTS rec_reverse_invoice;
CREATE TABLE rec_reverse_invoice (
invoice_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
invoice_apply_no VARCHAR(40) NOT NULL COMMENT '内部开票申请号',
order_id BIGINT UNSIGNED NOT NULL,
order_no VARCHAR(40) NOT NULL,
station_id BIGINT UNSIGNED NOT NULL,
station_name VARCHAR(100) NOT NULL,
seller_id BIGINT UNSIGNED NOT NULL,
seller_name VARCHAR(60) NOT NULL,
seller_id_card_hash CHAR(64) NOT NULL,
buyer_name VARCHAR(150) NOT NULL COMMENT '平台公司抬头',
buyer_tax_no VARCHAR(50) DEFAULT NULL COMMENT '平台税号',
invoice_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
vat_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
additional_tax_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
personal_tax_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
tax_calc_rule VARCHAR(30) DEFAULT NULL COMMENT 'normal/triple_flow',
tax_report_period VARCHAR(20) DEFAULT NULL COMMENT '代办税费所属期 yyyy-MM',
tax_report_status VARCHAR(30) NOT NULL DEFAULT 'not_reported' COMMENT 'not_reported/reported',
tax_report_no VARCHAR(80) DEFAULT NULL COMMENT '代办税费报告编号',
invoice_status VARCHAR(30) NOT NULL DEFAULT 'waiting',
tax_invoice_code VARCHAR(80) DEFAULT NULL,
tax_invoice_no VARCHAR(80) DEFAULT NULL,
invoice_date DATE DEFAULT NULL,
e_invoice_file_id BIGINT DEFAULT NULL,
fail_reason VARCHAR(500) DEFAULT NULL,
red_invoice_id BIGINT UNSIGNED DEFAULT NULL,
red_reason VARCHAR(500) DEFAULT NULL,
create_by VARCHAR(64) DEFAULT '',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64) DEFAULT '',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
remark VARCHAR(500) DEFAULT NULL,
del_flag CHAR(1) NOT NULL DEFAULT '0',
PRIMARY KEY (invoice_id),
UNIQUE KEY uk_invoice_apply_no (invoice_apply_no),
UNIQUE KEY uk_order_id (order_id),
KEY idx_seller (seller_id_card_hash),
KEY idx_status (invoice_status)
) ENGINE=InnoDB COMMENT='反向开票表';
DROP TABLE IF EXISTS rec_quota_config;
CREATE TABLE rec_quota_config (
quota_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
quota_code VARCHAR(40) NOT NULL,
quota_name VARCHAR(100) NOT NULL,
quota_type VARCHAR(30) NOT NULL DEFAULT 'amount' COMMENT 'amount/tax/invoice',
period_type VARCHAR(30) NOT NULL COMMENT 'month/rolling_12_month/year',
quota_amount DECIMAL(18,2) NOT NULL,
control_action VARCHAR(20) NOT NULL DEFAULT 'warn' COMMENT 'warn/block/tax_calc',
block_flag CHAR(1) NOT NULL DEFAULT '1',
warning_ratio DECIMAL(6,4) DEFAULT 0.8,
effective_start DATE DEFAULT NULL,
effective_end DATE DEFAULT NULL,
policy_basis VARCHAR(255) DEFAULT NULL,
status CHAR(1) NOT NULL DEFAULT '1',
create_by VARCHAR(64) DEFAULT '',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64) DEFAULT '',
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
remark VARCHAR(500) DEFAULT NULL,
PRIMARY KEY (quota_id),
UNIQUE KEY uk_quota_code (quota_code)
) ENGINE=InnoDB COMMENT='额度配置表';
DROP TABLE IF EXISTS rec_quota_usage_log;
CREATE TABLE rec_quota_usage_log (
usage_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
seller_id BIGINT UNSIGNED NOT NULL,
id_card_no_hash CHAR(64) NOT NULL,
order_id BIGINT UNSIGNED NOT NULL,
order_no VARCHAR(40) NOT NULL,
quota_code VARCHAR(40) NOT NULL,
before_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
order_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
after_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
quota_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
check_status VARCHAR(20) NOT NULL COMMENT 'pass/warn/fail',
check_time DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (usage_id),
KEY idx_seller_quota (id_card_no_hash, quota_code, check_time),
KEY idx_order_id (order_id)
) ENGINE=InnoDB COMMENT='额度占用记录表';
DROP TABLE IF EXISTS rec_attachment;
CREATE TABLE rec_attachment (
file_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
biz_type VARCHAR(40) NOT NULL,
biz_id BIGINT UNSIGNED NOT NULL,
file_type VARCHAR(40) NOT NULL COMMENT 'id_front/id_back/payment_voucher/order_scene/invoice/consent',
file_name VARCHAR(255) NOT NULL,
file_url VARCHAR(500) NOT NULL,
storage_type VARCHAR(30) NOT NULL DEFAULT 'local',
mime_type VARCHAR(80) DEFAULT NULL,
file_size BIGINT DEFAULT NULL,
file_hash CHAR(64) DEFAULT NULL,
upload_user_id BIGINT DEFAULT NULL,
upload_time DATETIME DEFAULT CURRENT_TIMESTAMP,
del_flag CHAR(1) NOT NULL DEFAULT '0',
PRIMARY KEY (file_id),
KEY idx_biz (biz_type, biz_id),
KEY idx_file_type (file_type)
) ENGINE=InnoDB COMMENT='业务附件表';
DROP TABLE IF EXISTS rec_print_log;
CREATE TABLE rec_print_log (
print_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
order_id BIGINT UNSIGNED NOT NULL,
order_no VARCHAR(40) NOT NULL,
station_id BIGINT UNSIGNED NOT NULL,
print_type VARCHAR(30) NOT NULL DEFAULT 'order',
print_user_id BIGINT DEFAULT NULL,
print_time DATETIME DEFAULT CURRENT_TIMESTAMP,
print_snapshot TEXT DEFAULT NULL,
PRIMARY KEY (print_id),
KEY idx_order_id (order_id),
KEY idx_station_time (station_id, print_time)
) ENGINE=InnoDB COMMENT='打印记录表';
INSERT INTO rec_quota_config (quota_code, quota_name, quota_type, period_type, quota_amount, control_action, block_flag, warning_ratio, effective_start, policy_basis, remark)
VALUES
('PERSON_MONTH_TAX_FREE_AMOUNT', '个人当月销售额提示线', 'tax', 'month', 100000.00, 'warn', '0', 0.8, '2023-01-01', '小规模纳税人月销售额10万元以下增值税优惠口径', '默认10万元,建议预警,不建议直接按政策硬阻断'),
('PERSON_ROLLING_12_REVERSE_LIMIT', '个人连续12个月反向开票上限', 'invoice', 'rolling_12_month', 5000000.00, 'block', '1', 0.8, '2024-04-29', '国家税务总局公告2024年第5号', '默认500万元,超过后自然人不再符合反向开票条件'),
('PERSON_YEAR_TRIPLE_FLOW_TAX_BREAK', '三流合一个税优惠年度额度', 'tax', 'year', 600000.00, 'tax_calc', '0', 0.8, '2026-07-01', '国家税务总局公告2026年第12号', '接入三流合一反向开票后启用,第一版预留');
字典菜单 SQL sql/recycle_platform_dict_menu_seed.sql
-- 字典和菜单种子示例:请按实际 sys_dict_type/sys_dict_data/sys_menu 主键策略调整
INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark)
SELECT '回收订单状态', 'rec_order_status', '0', 'admin', NOW(), '废品回收平台'
WHERE NOT EXISTS (SELECT 1 FROM sys_dict_type WHERE dict_type = 'rec_order_status');
INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
VALUES
(1, '草稿', 'draft', 'rec_order_status', NULL, 'default', 'Y', '0', 'admin', NOW(), NULL),
(2, '待审核', 'pending_audit', 'rec_order_status', NULL, 'warning', 'N', '0', 'admin', NOW(), NULL),
(3, '审核通过', 'audit_pass', 'rec_order_status', NULL, 'success', 'N', '0', 'admin', NOW(), NULL),
(4, '审核驳回', 'audit_reject', 'rec_order_status', NULL, 'danger', 'N', '0', 'admin', NOW(), NULL),
(5, '已作废', 'void', 'rec_order_status', NULL, 'info', 'N', '0', 'admin', NOW(), NULL);
INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark)
SELECT '回收付款方式', 'rec_payment_method', '0', 'admin', NOW(), '废品回收平台'
WHERE NOT EXISTS (SELECT 1 FROM sys_dict_type WHERE dict_type = 'rec_payment_method');
INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark)
VALUES
(1, '现金', 'cash', 'rec_payment_method', NULL, 'info', 'Y', '0', 'admin', NOW(), NULL),
(2, '微信', 'wechat', 'rec_payment_method', NULL, 'success', 'N', '0', 'admin', NOW(), NULL),
(3, '支付宝', 'alipay', 'rec_payment_method', NULL, 'primary', 'N', '0', 'admin', NOW(), NULL),
(4, '银行卡', 'bank', 'rec_payment_method', NULL, 'warning', 'N', '0', 'admin', NOW(), NULL);
-- 菜单示例,只提供权限标识清单,实际 menu_id/parent_id 建议在若依后台或迁移脚本中确认
-- 平台端:recycle:station:list, recycle:order:list, recycle:account:list, recycle:recharge:list, recycle:payment:list, recycle:invoice:list, recycle:quota:list
-- 回收点端:recycle:category:list, recycle:unit:list, recycle:product:list, recycle:order:list, recycle:account:query, recycle:recharge:list