description: "Task list for 用户发票抬头管理"
Input: Design documents from /specs/014-invoice-profile/
Prerequisites: spec.md ✅, data-model.md ✅, contracts/api.md ✅, plan.md ✅
范围: 仅后端 App 端 CRUD(实体 / Mapper / Service / Controller + SQL)。无前端、无 i18n、无后台端。
测试: 轻量手测(curl/Postman),按 contracts/api.md。
[ID] [P?] Descriptionruoyi-system/src/main/java/com/ruoyi/system/...ruoyi-admin/src/main/java/com/ruoyi/app/order/InfoInvoiceController.javaupdatesql/sql.mdupdatesql/sql.md 追加 2026-07-24 段:CREATE TABLE info_invoice(字段 / 类型 / 注释见 data-model.md,含 KEY idx_user(user_id),引擎 InnoDB / utf8mb4)。无 sys_menu(本期无后台端)。InfoInvoice 实体(ruoyi-system/.../domain/InfoInvoice.java):@Data @TableName("info_invoice") @EqualsAndHashCode(callSuper=false),@TableId(type=IdType.AUTO);字段 id / userId / titleName / category / buyerName / buyerUbn / buyerEmail / carrierType / carrierNum / createTime / updateTime(注释对齐 data-model;create_time/update_time 由 DB DEFAULT/ON UPDATE 自动维护,无 createBy/updateBy)。参考 InfoAddress.java 风格。InfoInvoiceMapper 接口(ruoyi-system/.../mapper/InfoInvoiceMapper.java)继承 BaseMapper<InfoInvoice>,空体无自定义方法、无 XML——App 端仅用 MyBatis-Plus IService CRUD(list/saveOrUpdate/getById/removeById,字段驼峰自动映射 info_invoice 列);本期无后台端,故无需自定义查询。IInfoInvoiceService(ruoyi-system/.../service/IInfoInvoiceService.java,继承 IService<InfoInvoice>,方法 listByUserId / saveOrUpdateMine / getMine / deleteMine)+ InfoInvoiceServiceImpl(.../service/impl/InfoInvoiceServiceImpl.java,extends ServiceImpl<InfoInvoiceMapper, InfoInvoice>)。实现私有 validateInvoiceProfile(InfoInvoice)(按 contracts 校验矩阵:titleName / buyerName 非空、category ∈ {B2C,B2B}、B2B 统编 ^\d{8}$ + 邮箱必填 + 载具空、B2C 载具按类型正则 + 统编空 + 邮箱仅会员载具必填),非法抛 ServiceException。saveOrUpdateMine 内强制 setUserId + 校验 + 更新时归属校验;getMine/deleteMine 越权返回 null/false。依赖 T002、T003。Checkpoint: 表 + 实体 + mapper + service(含校验)就绪。
InfoInvoiceController(ruoyi-admin/.../app/order/InfoInvoiceController.java,@RequestMapping("/system/invoice"),extends BaseController,注入 IInfoInvoiceService):① GET /getinvoice(@Anonymous @Auth + @RequestHeader token → getusid → QueryWrapper.eq("user_id") → list);② POST /invoice(token + @RequestBody InfoInvoice → setUserId 强制覆盖 → validateInvoiceProfile → 更新时校验归属 → saveOrUpdate);③ GET /getinvoicexq?id=(getById + 归属校验);④ GET /deleinvoice?id=(归属校验 → removeById)。注解 / 工具类照搬 InfoAddressController。依赖 T004。Checkpoint: 4 接口可用,curl 跑通。
/ 开头、自然人凭证格式错、B2B 带载具、B2C 带统编、必填空)均拦截;越权(A 操作 B 的 id)拒绝。MEMORY.md:加一行指向 specs/014-invoice-profile/spec.md(参考 010 写法)。