From f3dbebb04e2c7ce2d0ebaa89496956e4c8c96284 Mon Sep 17 00:00:00 2001
From: khy <2908249413@qq.com>
Date: Thu, 24 Apr 2025 17:55:31 +0800
Subject: [PATCH] =?UTF-8?q?=E5=8F=91=E7=A5=A8=E7=AE=A1=E7=90=86=E5=92=8C?=
=?UTF-8?q?=E5=8F=91=E7=A5=A8=E6=8A=AC=E5=A4=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/api/mall/trade/invoice/index.ts | 56 ++++
.../src/api/mall/trade/invoiceheader/index.ts | 48 ++++
.../views/mall/trade/invoice/InvoiceForm.vue | 258 ++++++++++++++++++
.../src/views/mall/trade/invoice/index.vue | 233 ++++++++++++++++
.../trade/invoiceheader/InvoiceHeaderForm.vue | 141 ++++++++++
.../views/mall/trade/invoiceheader/index.vue | 247 +++++++++++++++++
.../admin/invoice/InvoiceController.java | 148 ++++++++++
.../admin/invoice/vo/InvoicePageReqVO.java | 56 ++++
.../admin/invoice/vo/InvoiceRespVO.java | 93 +++++++
.../admin/invoice/vo/InvoiceSaveReqVO.java | 56 ++++
.../InvoiceHeaderController.java | 94 +++++++
.../vo/InvoiceHeaderPageReqVO.java | 55 ++++
.../invoiceheader/vo/InvoiceHeaderRespVO.java | 63 +++++
.../vo/InvoiceHeaderSaveReqVO.java | 50 ++++
.../app/invoice/AppInvoiceController.java | 117 ++++++++
.../app/invoice/vo/AppInvoicePageReqVO.java | 52 ++++
.../app/invoice/vo/AppInvoiceRespVO.java | 72 +++++
.../AppInvoiceHeaderController.java | 72 +++++
.../trade/convert/invoice/InvoiceConvert.java | 50 ++++
.../dal/dataobject/invoice/InvoiceDO.java | 78 ++++++
.../invoiceheader/InvoiceHeaderDO.java | 71 +++++
.../dal/mysql/invoice/InvoiceMapper.java | 31 +++
.../invoiceheader/InvoiceHeaderMapper.java | 33 +++
.../trade/service/invoice/InvoiceService.java | 65 +++++
.../service/invoice/InvoiceServiceImpl.java | 165 +++++++++++
.../invoiceheader/InvoiceHeaderService.java | 63 +++++
.../InvoiceHeaderServiceImpl.java | 129 +++++++++
27 files changed, 2596 insertions(+)
create mode 100644 yudao-admin-vue3/src/api/mall/trade/invoice/index.ts
create mode 100644 yudao-admin-vue3/src/api/mall/trade/invoiceheader/index.ts
create mode 100644 yudao-admin-vue3/src/views/mall/trade/invoice/InvoiceForm.vue
create mode 100644 yudao-admin-vue3/src/views/mall/trade/invoice/index.vue
create mode 100644 yudao-admin-vue3/src/views/mall/trade/invoiceheader/InvoiceHeaderForm.vue
create mode 100644 yudao-admin-vue3/src/views/mall/trade/invoiceheader/index.vue
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/InvoiceController.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/vo/InvoicePageReqVO.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/vo/InvoiceRespVO.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/vo/InvoiceSaveReqVO.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/InvoiceHeaderController.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/vo/InvoiceHeaderPageReqVO.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/vo/InvoiceHeaderRespVO.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/vo/InvoiceHeaderSaveReqVO.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoice/AppInvoiceController.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoice/vo/AppInvoicePageReqVO.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoice/vo/AppInvoiceRespVO.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoiceheader/AppInvoiceHeaderController.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/invoice/InvoiceConvert.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/invoice/InvoiceDO.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/invoiceheader/InvoiceHeaderDO.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/invoice/InvoiceMapper.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/invoiceheader/InvoiceHeaderMapper.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoice/InvoiceService.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoice/InvoiceServiceImpl.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoiceheader/InvoiceHeaderService.java
create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoiceheader/InvoiceHeaderServiceImpl.java
diff --git a/yudao-admin-vue3/src/api/mall/trade/invoice/index.ts b/yudao-admin-vue3/src/api/mall/trade/invoice/index.ts
new file mode 100644
index 0000000..6e3e9ba
--- /dev/null
+++ b/yudao-admin-vue3/src/api/mall/trade/invoice/index.ts
@@ -0,0 +1,56 @@
+import request from '@/config/axios'
+
+// 发票管理 VO
+export interface InvoiceVO {
+ id: number // id
+ userId: number // 用户编号
+ bizId: string // 业务编号
+ bizType: number // 业务类型:1-订单,2-提现
+ type: number // 发票类型
+ price: number // 金额
+ headerType: number // 发票抬头类型
+ status: number // 状态:0-未开票,1-已开票
+ name: string //发票名称
+ no: string //订单流水号
+ orderTime: Date// 订单时间
+ tradeOrderStatus: number // 订单状态
+ taxNumber: string // 税号
+
+ headerId: number // 发票抬头编号
+
+ headerName: string // 发票抬头名称
+
+}
+
+// 发票管理 API
+export const InvoiceApi = {
+ // 查询发票管理分页
+ getInvoicePage: async (params: any) => {
+ return await request.get({ url: `/trade/invoice/page`, params })
+ },
+
+ // 查询发票管理详情
+ getInvoice: async (id: number) => {
+ return await request.get({ url: `/trade/invoice/get?id=` + id })
+ },
+
+ // 新增发票管理
+ createInvoice: async (data: InvoiceVO) => {
+ return await request.post({ url: `/trade/invoice/create`, data })
+ },
+
+ // 修改发票管理
+ updateInvoice: async (data: InvoiceVO) => {
+ return await request.put({ url: `/trade/invoice/update`, data })
+ },
+
+ // 删除发票管理
+ deleteInvoice: async (id: number) => {
+ return await request.delete({ url: `/trade/invoice/delete?id=` + id })
+ },
+
+ // 导出发票管理 Excel
+ exportInvoice: async (params) => {
+ return await request.download({ url: `/trade/invoice/export-excel`, params })
+ },
+}
diff --git a/yudao-admin-vue3/src/api/mall/trade/invoiceheader/index.ts b/yudao-admin-vue3/src/api/mall/trade/invoiceheader/index.ts
new file mode 100644
index 0000000..960188c
--- /dev/null
+++ b/yudao-admin-vue3/src/api/mall/trade/invoiceheader/index.ts
@@ -0,0 +1,48 @@
+import request from '@/config/axios'
+
+// 发票抬头 VO
+export interface InvoiceHeaderVO {
+ id: number // id
+ userId: number // 用户编号
+ name: string // 购方名称
+ taxNumber: string // 纳税人识别号
+ companyAddress: string // 公司地址
+ companyTel: string // 公司电话
+ bankName: string // 开户银行
+ bankAccount: string // 发票
+ isDefault: boolean // 是否默认
+ type: boolean // 抬头类型
+}
+
+// 发票抬头 API
+export const InvoiceHeaderApi = {
+ // 查询发票抬头分页
+ getInvoiceHeaderPage: async (params: any) => {
+ return await request.get({ url: `/trade/invoice-header/page`, params })
+ },
+
+ // 查询发票抬头详情
+ getInvoiceHeader: async (id: number) => {
+ return await request.get({ url: `/trade/invoice-header/get?id=` + id })
+ },
+
+ // 新增发票抬头
+ createInvoiceHeader: async (data: InvoiceHeaderVO) => {
+ return await request.post({ url: `/trade/invoice-header/create`, data })
+ },
+
+ // 修改发票抬头
+ updateInvoiceHeader: async (data: InvoiceHeaderVO) => {
+ return await request.put({ url: `/trade/invoice-header/update`, data })
+ },
+
+ // 删除发票抬头
+ deleteInvoiceHeader: async (id: number) => {
+ return await request.delete({ url: `/trade/invoice-header/delete?id=` + id })
+ },
+
+ // 导出发票抬头 Excel
+ exportInvoiceHeader: async (params) => {
+ return await request.download({ url: `/trade/invoice-header/export-excel`, params })
+ },
+}
\ No newline at end of file
diff --git a/yudao-admin-vue3/src/views/mall/trade/invoice/InvoiceForm.vue b/yudao-admin-vue3/src/views/mall/trade/invoice/InvoiceForm.vue
new file mode 100644
index 0000000..f26ad3b
--- /dev/null
+++ b/yudao-admin-vue3/src/views/mall/trade/invoice/InvoiceForm.vue
@@ -0,0 +1,258 @@
+
+
+
+
+
+
diff --git a/yudao-admin-vue3/src/views/mall/trade/invoice/index.vue b/yudao-admin-vue3/src/views/mall/trade/invoice/index.vue
new file mode 100644
index 0000000..b543e89
--- /dev/null
+++ b/yudao-admin-vue3/src/views/mall/trade/invoice/index.vue
@@ -0,0 +1,233 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+
+
+
+
+ 导出
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 编辑
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/yudao-admin-vue3/src/views/mall/trade/invoiceheader/InvoiceHeaderForm.vue b/yudao-admin-vue3/src/views/mall/trade/invoiceheader/InvoiceHeaderForm.vue
new file mode 100644
index 0000000..2df89f0
--- /dev/null
+++ b/yudao-admin-vue3/src/views/mall/trade/invoiceheader/InvoiceHeaderForm.vue
@@ -0,0 +1,141 @@
+
+
+
+
diff --git a/yudao-admin-vue3/src/views/mall/trade/invoiceheader/index.vue b/yudao-admin-vue3/src/views/mall/trade/invoiceheader/index.vue
new file mode 100644
index 0000000..a30611d
--- /dev/null
+++ b/yudao-admin-vue3/src/views/mall/trade/invoiceheader/index.vue
@@ -0,0 +1,247 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 编辑
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/InvoiceController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/InvoiceController.java
new file mode 100644
index 0000000..6eaf667
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/InvoiceController.java
@@ -0,0 +1,148 @@
+package cn.iocoder.yudao.module.trade.controller.admin.invoice;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.trade.controller.admin.invoice.vo.InvoicePageReqVO;
+import cn.iocoder.yudao.module.trade.controller.admin.invoice.vo.InvoiceRespVO;
+import cn.iocoder.yudao.module.trade.controller.admin.invoice.vo.InvoiceSaveReqVO;
+import cn.iocoder.yudao.module.trade.convert.invoice.InvoiceConvert;
+import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
+import cn.iocoder.yudao.module.trade.dal.dataobject.invoice.InvoiceDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO;
+import cn.iocoder.yudao.module.trade.service.invoice.InvoiceService;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderLogService;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "管理后台 - 发票管理")
+@RestController
+@RequestMapping("/trade/invoice")
+@Validated
+public class InvoiceController {
+
+ @Resource
+ private InvoiceService invoiceService;
+ @Resource
+ private TradeOrderQueryService tradeOrderQueryService;
+
+ @Resource
+ private MemberUserApi memberUserApi;
+
+ @Resource
+ private TradeOrderLogService tradeOrderLogService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建发票管理")
+ @PreAuthorize("@ss.hasPermission('trade:invoice:create')")
+ public CommonResult createInvoice(@Valid @RequestBody InvoiceSaveReqVO createReqVO) {
+ return success(invoiceService.createInvoice(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新发票管理")
+ @PreAuthorize("@ss.hasPermission('trade:invoice:update')")
+ public CommonResult updateInvoice(@Valid @RequestBody InvoiceSaveReqVO updateReqVO) {
+ invoiceService.updateInvoice(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除发票管理")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('trade:invoice:delete')")
+ public CommonResult deleteInvoice(@RequestParam("id") Integer id) {
+ invoiceService.deleteInvoice(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得发票管理")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('trade:invoice:query')")
+ public CommonResult getInvoice(@RequestParam("id") Integer id) {
+ InvoiceDO invoice = invoiceService.getInvoice(id);
+ // 查询订单
+ TradeOrderDO order = tradeOrderQueryService.getOrder(Long.valueOf(invoice.getBizId()));
+ if (order == null) {
+ return success(BeanUtils.toBean(invoice, InvoiceRespVO.class));
+ }
+ InvoiceRespVO respVO = BeanUtils.toBean(invoice, InvoiceRespVO.class);
+ // 查询订单项
+ List orderItems = tradeOrderQueryService.getOrderItemListByOrderId(Long.valueOf(invoice.getBizId()));
+
+ // 拼接数据
+ MemberUserRespDTO user = memberUserApi.getUser(order.getUserId());
+ MemberUserRespDTO brokerageUser = order.getBrokerageUserId() != null ?
+ memberUserApi.getUser(order.getBrokerageUserId()) : null;
+ List orderLogs = tradeOrderLogService.getOrderLogListByOrderId(Long.valueOf(invoice.getBizId()));
+ respVO.setTradeOrder(TradeOrderConvert.INSTANCE.convert(order, orderItems, orderLogs, user, brokerageUser));
+ return success(respVO);
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得发票管理分页")
+ @PreAuthorize("@ss.hasPermission('trade:invoice:query')")
+ public CommonResult> getInvoicePage(@Valid InvoicePageReqVO pageReqVO) {
+ PageResult pageResult = invoiceService.getInvoicePage(pageReqVO);
+
+ //拼接订单信息
+ Set bizIds = convertSet(pageResult.getList(), InvoiceDO::getBizId);
+ Map map = invoiceService.getInvoiceRespMap(bizIds);
+
+ //拼接抬头信息
+ Set headerIds = convertSet(pageResult.getList(), InvoiceDO::getHeaderId);
+ Map headerMap = invoiceService.getHeaderMap(headerIds);
+
+ return success(InvoiceConvert.INSTANCE.convertPage(pageResult, map,headerMap));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "导出发票管理 Excel")
+ @PreAuthorize("@ss.hasPermission('trade:invoice:export')")
+ @ApiAccessLog(operateType = EXPORT)
+ public void exportInvoiceExcel(@Valid InvoicePageReqVO pageReqVO,
+ HttpServletResponse response) throws IOException {
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+ PageResult pageResult = invoiceService.getInvoicePage(pageReqVO);
+
+ //拼接订单信息
+ Set bizIds = convertSet(pageResult.getList(), InvoiceDO::getBizId);
+ Map map = invoiceService.getInvoiceRespMap(bizIds);
+
+ //拼接抬头信息
+ Set headerIds = convertSet(pageResult.getList(), InvoiceDO::getHeaderId);
+ Map headerMap = invoiceService.getHeaderMap(headerIds);
+
+ PageResult page = InvoiceConvert.INSTANCE.convertPage(pageResult, map,headerMap);
+ // 导出 Excel
+ ExcelUtils.write(response, "发票管理.xls", "数据", InvoiceRespVO.class,
+ page.getList());
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/vo/InvoicePageReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/vo/InvoicePageReqVO.java
new file mode 100644
index 0000000..ce2eb4a
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/vo/InvoicePageReqVO.java
@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.trade.controller.admin.invoice.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 发票管理分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class InvoicePageReqVO extends PageParam {
+
+ @Schema(description = "用户编号", example = "22458")
+ private Long userId;
+
+ @Schema(description = "业务编号", example = "31817")
+ private String bizId;
+
+ @Schema(description = "业务类型:1-订单,2-提现", example = "2")
+ private Integer bizType;
+
+ @Schema(description = "发票类型", example = "2")
+ private Integer type;
+
+ @Schema(description = "金额", example = "22110")
+ private Integer price;
+
+
+ @Schema(description = "状态:0-未开票,1-已开票", example = "2")
+ private Integer status;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+ @Schema(description = "发票名称", example = "2")
+ private String name;
+
+ @Schema(description = "发票附件", example = "2")
+ private String invoice;
+
+
+ @Schema(description = "邮箱", example = "2")
+ private String email;
+
+ @Schema(description = "发票抬头id", example = "2")
+ private Long headerId;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/vo/InvoiceRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/vo/InvoiceRespVO.java
new file mode 100644
index 0000000..d1d5893
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/vo/InvoiceRespVO.java
@@ -0,0 +1,93 @@
+package cn.iocoder.yudao.module.trade.controller.admin.invoice.vo;
+
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import cn.iocoder.yudao.framework.excel.core.convert.MoneyConvert;
+import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDetailRespVO;
+import cn.iocoder.yudao.module.trade.enums.DictTypeConstants;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 发票管理 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class InvoiceRespVO {
+
+ @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "15728")
+ @ExcelProperty("id")
+ private Integer id;
+
+ @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22458")
+ private Long userId;
+
+ @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31817")
+ private String bizId;
+
+ @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ private Integer bizType;
+
+ @Schema(description = "发票类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ @ExcelProperty(value = "发票类型", converter = DictConvert.class)
+ @DictFormat(DictTypeConstants.INVOICE_TYPE)
+ private Integer type;
+
+ @Schema(description = "金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "22110")
+ @ExcelProperty(value = "订单金额",converter = MoneyConvert.class)
+ private Integer price;
+
+
+ @Schema(description = "状态:0-未开票,1-已开票", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ @ExcelProperty(value = "状态", converter = DictConvert.class)
+ @DictFormat(DictTypeConstants.INVOICE_STATUS)
+ private Integer status;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+ @Schema(description = "发票名称", example = "2")
+ @ExcelProperty("发票名称")
+ private String name;
+
+ @Schema(description = "发票附件", example = "2")
+ @ExcelProperty("发票附件")
+ private String invoice;
+
+
+ @Schema(description = "邮箱", example = "2")
+ private String email;
+
+ @Schema(description = "订单号", example = "2")
+ private String no;
+
+ @Schema(description = "下单时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("下单时间")
+ private LocalDateTime orderTime;
+
+ @Schema(description = "交易订单状态", requiredMode = Schema.RequiredMode.REQUIRED)
+ private Integer tradeOrderStatus;
+
+ @Schema(description = "交易订单详情", requiredMode = Schema.RequiredMode.REQUIRED)
+ private TradeOrderDetailRespVO tradeOrder;
+
+ @Schema(description = "发票抬头id", example = "2")
+ private Long headerId;
+
+ @Schema(description = "发票抬头", example = "2")
+ @ExcelProperty("发票抬头")
+ private String headerName;
+
+ @Schema(description = "发票抬头类型", example = "2")
+ @ExcelProperty(value = "发票抬头类型", converter = DictConvert.class)
+ @DictFormat(DictTypeConstants.INVOICE_TITLE_TYPE)
+ private Boolean headerType;
+
+
+ @Schema(description = "纳税人识别号", example = "2")
+ @ExcelProperty("纳税人识别号")
+ private String taxNumber;
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/vo/InvoiceSaveReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/vo/InvoiceSaveReqVO.java
new file mode 100644
index 0000000..690f424
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoice/vo/InvoiceSaveReqVO.java
@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.trade.controller.admin.invoice.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+
+@Schema(description = "管理后台 - 发票管理新增/修改 Request VO")
+@Data
+public class InvoiceSaveReqVO {
+
+ @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "15728")
+ private Integer id;
+
+ @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22458")
+// @NotNull(message = "用户编号不能为空")
+ private Long userId;
+
+ @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31817")
+ @NotEmpty(message = "业务编号不能为空")
+ private String bizId;
+
+ @Schema(description = "业务类型:1-订单,2-提现", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+// @NotNull(message = "业务类型:1-订单,2-提现不能为空")
+ private Integer bizType;
+
+ @Schema(description = "发票类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+// @NotNull(message = "发票类型不能为空")
+ private Integer type;
+
+ @Schema(description = "金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "22110")
+// @NotNull(message = "金额不能为空")
+ private Integer price;
+
+ @Schema(description = "状态:0-未开票,1-已开票", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+// @NotNull(message = "状态:0-未开票,1-已开票不能为空")
+ private Integer status;
+
+ @Schema(description = "发票名称", example = "2")
+// @NotNull(message = "发票名称不能为空")
+ private String name;
+
+ @Schema(description = "发票附件", example = "2")
+// @NotNull(message = "发票附件不能为空")
+ private String invoice;
+
+
+ @Schema(description = "邮箱", example = "2")
+// @NotNull(message = "邮箱不能为空")
+ private String email;
+
+ @Schema(description = "发票抬头id", example = "2")
+ private Long headerId;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/InvoiceHeaderController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/InvoiceHeaderController.java
new file mode 100644
index 0000000..8548fb4
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/InvoiceHeaderController.java
@@ -0,0 +1,94 @@
+package cn.iocoder.yudao.module.trade.controller.admin.invoiceheader;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.trade.controller.admin.invoiceheader.vo.InvoiceHeaderPageReqVO;
+import cn.iocoder.yudao.module.trade.controller.admin.invoiceheader.vo.InvoiceHeaderRespVO;
+import cn.iocoder.yudao.module.trade.controller.admin.invoiceheader.vo.InvoiceHeaderSaveReqVO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.invoiceheader.InvoiceHeaderDO;
+import cn.iocoder.yudao.module.trade.service.invoiceheader.InvoiceHeaderService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 发票抬头")
+@RestController
+@RequestMapping("/trade/invoice-header")
+@Validated
+public class InvoiceHeaderController {
+
+ @Resource
+ private InvoiceHeaderService invoiceHeaderService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建发票抬头")
+ @PreAuthorize("@ss.hasPermission('trade:invoice-header:create')")
+ public CommonResult createInvoiceHeader(@Valid @RequestBody InvoiceHeaderSaveReqVO createReqVO) {
+ return success(invoiceHeaderService.createInvoiceHeader(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新发票抬头")
+ @PreAuthorize("@ss.hasPermission('trade:invoice-header:update')")
+ public CommonResult updateInvoiceHeader(@Valid @RequestBody InvoiceHeaderSaveReqVO updateReqVO) {
+ invoiceHeaderService.updateInvoiceHeader(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除发票抬头")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('trade:invoice-header:delete')")
+ public CommonResult deleteInvoiceHeader(@RequestParam("id") Long id) {
+ invoiceHeaderService.deleteInvoiceHeader(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得发票抬头")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('trade:invoice-header:query')")
+ public CommonResult getInvoiceHeader(@RequestParam("id") Long id) {
+ InvoiceHeaderDO invoiceHeader = invoiceHeaderService.getInvoiceHeader(id);
+ return success(BeanUtils.toBean(invoiceHeader, InvoiceHeaderRespVO.class));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得发票抬头分页")
+ @PreAuthorize("@ss.hasPermission('trade:invoice-header:query')")
+ public CommonResult> getInvoiceHeaderPage(@Valid InvoiceHeaderPageReqVO pageReqVO) {
+ PageResult pageResult = invoiceHeaderService.getInvoiceHeaderPage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, InvoiceHeaderRespVO.class));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "导出发票抬头 Excel")
+ @PreAuthorize("@ss.hasPermission('trade:invoice-header:export')")
+ @ApiAccessLog(operateType = EXPORT)
+ public void exportInvoiceHeaderExcel(@Valid InvoiceHeaderPageReqVO pageReqVO,
+ HttpServletResponse response) throws IOException {
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+ List list = invoiceHeaderService.getInvoiceHeaderPage(pageReqVO).getList();
+ // 导出 Excel
+ ExcelUtils.write(response, "发票抬头.xls", "数据", InvoiceHeaderRespVO.class,
+ BeanUtils.toBean(list, InvoiceHeaderRespVO.class));
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/vo/InvoiceHeaderPageReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/vo/InvoiceHeaderPageReqVO.java
new file mode 100644
index 0000000..819a37c
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/vo/InvoiceHeaderPageReqVO.java
@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.trade.controller.admin.invoiceheader.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 发票抬头分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class InvoiceHeaderPageReqVO extends PageParam {
+
+ @Schema(description = "用户编号", example = "4889")
+ private Long userId;
+
+ @Schema(description = "购方名称", example = "李四")
+ private String name;
+
+ @Schema(description = "纳税人识别号")
+ private String taxNumber;
+
+ @Schema(description = "公司地址")
+ private String companyAddress;
+
+ @Schema(description = "公司电话")
+ private String companyTel;
+
+ @Schema(description = "开户银行", example = "赵六")
+ private String bankName;
+
+ @Schema(description = "发票", example = "27501")
+ private String bankAccount;
+
+ @Schema(description = "是否默认")
+ private Boolean isDefault;
+
+ @Schema(description = "抬头类型", example = "1")
+ private Boolean type;
+
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+ @Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private String email;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/vo/InvoiceHeaderRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/vo/InvoiceHeaderRespVO.java
new file mode 100644
index 0000000..303685d
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/vo/InvoiceHeaderRespVO.java
@@ -0,0 +1,63 @@
+package cn.iocoder.yudao.module.trade.controller.admin.invoiceheader.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 发票抬头 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class InvoiceHeaderRespVO {
+
+ @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "29034")
+ @ExcelProperty("id")
+ private Long id;
+
+ @Schema(description = "用户编号", example = "4889")
+ @ExcelProperty("用户编号")
+ private Long userId;
+
+ @Schema(description = "购方名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+ @ExcelProperty("购方名称")
+ private String name;
+
+ @Schema(description = "纳税人识别号", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("纳税人识别号")
+ private String taxNumber;
+
+ @Schema(description = "公司地址", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("公司地址")
+ private String companyAddress;
+
+ @Schema(description = "公司电话")
+ @ExcelProperty("公司电话")
+ private String companyTel;
+
+ @Schema(description = "开户银行", example = "赵六")
+ @ExcelProperty("开户银行")
+ private String bankName;
+
+ @Schema(description = "发票", example = "27501")
+ @ExcelProperty("发票")
+ private String bankAccount;
+
+ @Schema(description = "是否默认")
+ @ExcelProperty("是否默认")
+ private Boolean isDefault;
+
+ @Schema(description = "抬头类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @ExcelProperty("抬头类型")
+ private Boolean type;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+ @Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @ExcelProperty("邮箱")
+ private String email;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/vo/InvoiceHeaderSaveReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/vo/InvoiceHeaderSaveReqVO.java
new file mode 100644
index 0000000..75d3b30
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/invoiceheader/vo/InvoiceHeaderSaveReqVO.java
@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.module.trade.controller.admin.invoiceheader.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 发票抬头新增/修改 Request VO")
+@Data
+public class InvoiceHeaderSaveReqVO {
+
+ @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "29034")
+ private Long id;
+
+ @Schema(description = "用户编号", example = "4889")
+ private Long userId;
+
+ @Schema(description = "购方名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+ @NotEmpty(message = "购方名称不能为空")
+ private String name;
+
+ @Schema(description = "纳税人识别号", requiredMode = Schema.RequiredMode.REQUIRED)
+// @NotEmpty(message = "纳税人识别号不能为空")
+ private String taxNumber;
+
+ @Schema(description = "公司地址", requiredMode = Schema.RequiredMode.REQUIRED)
+// @NotEmpty(message = "公司地址不能为空")
+ private String companyAddress;
+
+ @Schema(description = "公司电话")
+ private String companyTel;
+
+ @Schema(description = "开户银行", example = "赵六")
+ private String bankName;
+
+ @Schema(description = "发票", example = "27501")
+ private String bankAccount;
+
+ @Schema(description = "是否默认")
+ private Boolean isDefault;
+
+ @Schema(description = "抬头类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "抬头类型不能为空")
+ private Boolean type;
+
+ @Schema(description = "邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private String email;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoice/AppInvoiceController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoice/AppInvoiceController.java
new file mode 100644
index 0000000..28a68e0
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoice/AppInvoiceController.java
@@ -0,0 +1,117 @@
+package cn.iocoder.yudao.module.trade.controller.app.invoice;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.trade.controller.admin.invoice.vo.InvoicePageReqVO;
+import cn.iocoder.yudao.module.trade.controller.admin.invoice.vo.InvoiceSaveReqVO;
+import cn.iocoder.yudao.module.trade.controller.app.invoice.vo.AppInvoicePageReqVO;
+import cn.iocoder.yudao.module.trade.controller.app.invoice.vo.AppInvoiceRespVO;
+import cn.iocoder.yudao.module.trade.convert.invoice.InvoiceConvert;
+import cn.iocoder.yudao.module.trade.dal.dataobject.invoice.InvoiceDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.invoiceheader.InvoiceHeaderDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
+import cn.iocoder.yudao.module.trade.service.invoice.InvoiceService;
+import cn.iocoder.yudao.module.trade.service.invoiceheader.InvoiceHeaderService;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.Map;
+import java.util.Set;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+@Tag(name = "用户 App - 发票管理")
+@RestController
+@RequestMapping("/trade/invoice")
+@Validated
+public class AppInvoiceController {
+
+ @Resource
+ private InvoiceService invoiceService;
+
+ @Resource
+ private InvoiceHeaderService invoiceHeaderService;
+
+ @Resource
+ private TradeOrderQueryService tradeOrderQueryService;
+
+ @Resource
+ private TradeOrderUpdateService tradeOrderUpdateService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建发票管理")
+ public CommonResult createInvoice(@Valid @RequestBody InvoiceSaveReqVO createReqVO) {
+ if(createReqVO.getUserId() == null){
+ createReqVO.setUserId(getLoginUserId());
+ }
+ if(createReqVO.getHeaderId() == null){
+ InvoiceHeaderDO invoiceHeaderDO = invoiceHeaderService.getDefaultInvoiceHeader(getLoginUserId());
+ if (invoiceHeaderDO != null){
+ createReqVO.setHeaderId(invoiceHeaderDO.getId());
+ }
+ else {
+ return error(400, "请先设置默认发票抬头");
+ }
+ }
+ //查询订单,修改订单状态为已开票
+ TradeOrderDO tradeOrderDO = tradeOrderQueryService.getOrder(Long.valueOf(createReqVO.getBizId()));
+ if(tradeOrderDO != null){
+ tradeOrderDO.setInvoiceStatus(1);
+ tradeOrderUpdateService.updateTradeOrder(tradeOrderDO);
+ if(createReqVO.getPrice() == null){
+ createReqVO.setPrice(tradeOrderDO.getPayPrice());
+ }
+ }
+ return success(invoiceService.createInvoice(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新发票管理")
+ public CommonResult updateInvoice(@Valid @RequestBody InvoiceSaveReqVO updateReqVO) {
+ if(updateReqVO.getUserId() == null){
+ updateReqVO.setUserId(getLoginUserId());
+ }
+ invoiceService.updateInvoice(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除发票管理")
+ @Parameter(name = "id", description = "编号", required = true)
+ public CommonResult deleteInvoice(@RequestParam("id") Integer id) {
+ invoiceService.deleteInvoice(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得发票管理")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ public CommonResult getInvoice(@RequestParam("id") Integer id) {
+ InvoiceDO invoice = invoiceService.getInvoice(id);
+ return success(BeanUtils.toBean(invoice, AppInvoiceRespVO.class));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得发票管理分页")
+ public CommonResult> getInvoicePage(@Valid AppInvoicePageReqVO pageReqVO) {
+ pageReqVO.setUserId(getLoginUserId());
+ PageResult pageResult = invoiceService.getInvoicePage(BeanUtils.toBean(pageReqVO, InvoicePageReqVO.class));
+ //拼接订单信息
+ Set bizIds = convertSet(pageResult.getList(), InvoiceDO::getBizId);
+ Map map = invoiceService.getAppInvoiceRespMap(bizIds);
+ return success(InvoiceConvert.INSTANCE.convertPage01(pageResult, map));
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoice/vo/AppInvoicePageReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoice/vo/AppInvoicePageReqVO.java
new file mode 100644
index 0000000..3588569
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoice/vo/AppInvoicePageReqVO.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.trade.controller.app.invoice.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 发票管理分页 Request VO")
+@Data
+public class AppInvoicePageReqVO extends PageParam {
+
+ @Schema(description = "用户编号", example = "22458")
+ private Long userId;
+
+ @Schema(description = "业务编号", example = "31817")
+ private String bizId;
+
+ @Schema(description = "业务类型:1-订单,2-提现", example = "2")
+ private Integer bizType;
+
+ @Schema(description = "发票类型", example = "2")
+ private Integer type;
+
+ @Schema(description = "金额", example = "22110")
+ private Integer price;
+
+ @Schema(description = "状态:0-未开票,1-已开票", example = "2")
+ private Integer status;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+ @Schema(description = "发票名称", example = "2")
+ private String name;
+
+
+ @Schema(description = "发票附件", example = "2")
+ private String invoice;
+
+
+ @Schema(description = "邮箱", example = "2")
+ private String email;
+
+ @Schema(description = "抬头id", example = "2")
+ private Long headerId;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoice/vo/AppInvoiceRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoice/vo/AppInvoiceRespVO.java
new file mode 100644
index 0000000..cdccd9d
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoice/vo/AppInvoiceRespVO.java
@@ -0,0 +1,72 @@
+package cn.iocoder.yudao.module.trade.controller.app.invoice.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 发票管理 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class AppInvoiceRespVO {
+
+ @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "15728")
+ @ExcelProperty("id")
+ private Integer id;
+
+ @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22458")
+ @ExcelProperty("用户编号")
+ private Long userId;
+
+ @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31817")
+ @ExcelProperty("业务编号")
+ private String bizId;
+
+ @Schema(description = "业务类型:1-订单,2-提现", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ @ExcelProperty("业务类型:1-订单,2-提现")
+ private Integer bizType;
+
+ @Schema(description = "发票类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ @ExcelProperty("发票类型")
+ private Integer type;
+
+ @Schema(description = "金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "22110")
+ @ExcelProperty("金额")
+ private Integer price;
+
+ @Schema(description = "状态:0-未开票,1-已开票", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ @ExcelProperty("状态:0-未开票,1-已开票")
+ private Integer status;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+ @Schema(description = "发票名称", example = "2")
+ @ExcelProperty("发票名称")
+ private String name;
+
+ @Schema(description = "发票附件", example = "2")
+ @ExcelProperty("发票附件")
+ private String invoice;
+
+
+ @Schema(description = "邮箱", example = "2")
+ @ExcelProperty("邮箱")
+ private String email;
+
+ @Schema(description = "抬头id", example = "2")
+ @ExcelProperty("抬头id")
+ private String headerId;
+
+ @Schema(description = "商品图片", example = "2")
+ @ExcelProperty("商品图片")
+ private String picUrl;
+
+ @Schema(description = "商品名称", example = "2")
+ @ExcelProperty("商品名称")
+ private String spuName;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoiceheader/AppInvoiceHeaderController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoiceheader/AppInvoiceHeaderController.java
new file mode 100644
index 0000000..d18df78
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/invoiceheader/AppInvoiceHeaderController.java
@@ -0,0 +1,72 @@
+package cn.iocoder.yudao.module.trade.controller.app.invoiceheader;
+
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.trade.controller.admin.invoiceheader.vo.InvoiceHeaderRespVO;
+import cn.iocoder.yudao.module.trade.controller.admin.invoiceheader.vo.InvoiceHeaderSaveReqVO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.invoiceheader.InvoiceHeaderDO;
+import cn.iocoder.yudao.module.trade.service.invoiceheader.InvoiceHeaderService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+@Tag(name = "用户 App - 发票管理")
+@RestController
+@RequestMapping("/trade/invoice-header")
+@Validated
+public class AppInvoiceHeaderController {
+
+
+ @Resource
+ private InvoiceHeaderService invoiceHeaderService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建发票抬头")
+ public CommonResult createInvoiceHeader(@Valid @RequestBody InvoiceHeaderSaveReqVO createReqVO) {
+ createReqVO.setUserId(getLoginUserId());
+ return success(invoiceHeaderService.createInvoiceHeader(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新发票抬头")
+ public CommonResult updateInvoiceHeader(@Valid @RequestBody InvoiceHeaderSaveReqVO updateReqVO) {
+ updateReqVO.setUserId(getLoginUserId());
+ invoiceHeaderService.updateInvoiceHeader(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除发票抬头")
+ @Parameter(name = "id", description = "编号", required = true)
+ public CommonResult deleteInvoiceHeader(@RequestParam("id") Long id) {
+ invoiceHeaderService.deleteInvoiceHeader(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得发票抬头")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ public CommonResult getInvoiceHeader(@RequestParam("id") Long id) {
+ InvoiceHeaderDO invoiceHeader = invoiceHeaderService.getInvoiceHeader(id);
+ return success(BeanUtils.toBean(invoiceHeader, InvoiceHeaderRespVO.class));
+ }
+
+ @GetMapping("/list")
+ @Operation(summary = "获得发票抬头列表")
+ public CommonResult> getInvoiceHeaderList() {
+ List list = invoiceHeaderService.selectOneByUserId(getLoginUserId());
+ return success(BeanUtils.toBean(list, InvoiceHeaderRespVO.class));
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/invoice/InvoiceConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/invoice/InvoiceConvert.java
new file mode 100644
index 0000000..07e64ed
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/invoice/InvoiceConvert.java
@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.module.trade.convert.invoice;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.trade.controller.admin.invoice.vo.InvoiceRespVO;
+import cn.iocoder.yudao.module.trade.controller.app.invoice.vo.AppInvoiceRespVO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.invoice.InvoiceDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.Map;
+import java.util.Optional;
+
+@Mapper
+public interface InvoiceConvert {
+
+ InvoiceConvert INSTANCE = Mappers.getMapper(InvoiceConvert.class);
+
+ PageResult convertPage(PageResult pageResult);
+
+ default PageResult convertPage(PageResult pageResult, Map map,
+ Map headerMap) {
+ PageResult result = convertPage(pageResult);
+ for (InvoiceRespVO respVO : result.getList()){
+ Optional.ofNullable(map.get(respVO.getBizId())).ifPresent(item ->
+ respVO.setBizType(item.getBizType())
+ .setNo(item.getNo())
+ .setOrderTime(item.getOrderTime())
+ .setTradeOrderStatus(item.getTradeOrderStatus()));
+ Optional.ofNullable(headerMap.get(respVO.getHeaderId())).ifPresent(item ->
+ respVO.setTaxNumber(item.getTaxNumber())
+ .setHeaderType(item.getHeaderType())
+ .setHeaderName(item.getHeaderName()));
+ }
+
+ return result;
+ }
+ PageResult convertPage01(PageResult pageResult);
+
+ //小程序拼接
+ default PageResult convertPage01(PageResult pageResult, Map map) {
+ PageResult result = convertPage01(pageResult);
+ for (AppInvoiceRespVO respVO : result.getList()){
+ Optional.ofNullable(map.get(respVO.getBizId())).ifPresent(item ->
+ respVO.setSpuName(item.getSpuName())
+ .setPicUrl(item.getPicUrl()));
+ }
+ return result;
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/invoice/InvoiceDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/invoice/InvoiceDO.java
new file mode 100644
index 0000000..97ba85e
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/invoice/InvoiceDO.java
@@ -0,0 +1,78 @@
+package cn.iocoder.yudao.module.trade.dal.dataobject.invoice;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * 发票管理 DO
+ *
+ * @author 东方好果
+ */
+@TableName("trade_invoice")
+@KeySequence("trade_invoice_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class InvoiceDO extends BaseDO {
+
+ /**
+ * id
+ */
+ @TableId
+ private Integer id;
+ /**
+ * 用户编号
+ */
+ private Long userId;
+ /**
+ * 业务编号
+ */
+ private String bizId;
+ /**
+ * 业务类型:1-订单,2-提现
+ */
+ private Integer bizType;
+ /**
+ * 发票类型
+ */
+ private Integer type;
+ /**
+ * 金额
+ */
+ private Integer price;
+
+ /**
+ * 状态:0-未开票,1-已开票
+ */
+ private Integer status;
+
+ /*
+ * 发票名称
+ * */
+ private String name;
+
+
+ /*
+ * 发票附件
+ * */
+ private String invoice;
+
+
+ /*
+ * 邮箱
+ * */
+ private String email;
+
+ /*
+ *
+ * 发票抬头id
+ * */
+ private Long headerId;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/invoiceheader/InvoiceHeaderDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/invoiceheader/InvoiceHeaderDO.java
new file mode 100644
index 0000000..f74e67c
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/invoiceheader/InvoiceHeaderDO.java
@@ -0,0 +1,71 @@
+package cn.iocoder.yudao.module.trade.dal.dataobject.invoiceheader;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * 发票抬头 DO
+ *
+ * @author 东方好果
+ */
+@TableName("trade_invoice_header")
+@KeySequence("trade_invoice_header_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class InvoiceHeaderDO extends BaseDO {
+
+ /**
+ * id
+ */
+ @TableId
+ private Long id;
+ /**
+ * 用户编号
+ */
+ private Long userId;
+ /**
+ * 购方名称
+ */
+ private String name;
+ /**
+ * 纳税人识别号
+ */
+ private String taxNumber;
+ /**
+ * 公司地址
+ */
+ private String companyAddress;
+ /**
+ * 公司电话
+ */
+ private String companyTel;
+ /**
+ * 开户银行
+ */
+ private String bankName;
+ /**
+ * 发票
+ */
+ private String bankAccount;
+ /**
+ * 是否默认
+ */
+ private Boolean isDefault;
+ /**
+ * 抬头类型
+ */
+ private Boolean type;
+
+ /*
+ * 邮箱
+ * */
+ private String email;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/invoice/InvoiceMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/invoice/InvoiceMapper.java
new file mode 100644
index 0000000..b329d10
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/invoice/InvoiceMapper.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.trade.dal.mysql.invoice;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.trade.controller.admin.invoice.vo.*;
+import cn.iocoder.yudao.module.trade.dal.dataobject.invoice.InvoiceDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 发票管理 Mapper
+ *
+ * @author 东方好果
+ */
+@Mapper
+public interface InvoiceMapper extends BaseMapperX {
+
+ default PageResult selectPage(InvoicePageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .eqIfPresent(InvoiceDO::getUserId, reqVO.getUserId())
+ .eqIfPresent(InvoiceDO::getBizId, reqVO.getBizId())
+ .eqIfPresent(InvoiceDO::getBizType, reqVO.getBizType())
+ .eqIfPresent(InvoiceDO::getType, reqVO.getType())
+ .eqIfPresent(InvoiceDO::getPrice, reqVO.getPrice())
+ .eqIfPresent(InvoiceDO::getStatus, reqVO.getStatus())
+ .likeIfPresent(InvoiceDO::getName, reqVO.getName())
+ .betweenIfPresent(InvoiceDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(InvoiceDO::getId));
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/invoiceheader/InvoiceHeaderMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/invoiceheader/InvoiceHeaderMapper.java
new file mode 100644
index 0000000..87dffee
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/invoiceheader/InvoiceHeaderMapper.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.trade.dal.mysql.invoiceheader;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.trade.controller.admin.invoiceheader.vo.*;
+import cn.iocoder.yudao.module.trade.dal.dataobject.invoiceheader.InvoiceHeaderDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 发票抬头 Mapper
+ *
+ * @author 东方好果
+ */
+@Mapper
+public interface InvoiceHeaderMapper extends BaseMapperX {
+
+ default PageResult selectPage(InvoiceHeaderPageReqVO reqVO) {
+ return selectPage(reqVO, new LambdaQueryWrapperX()
+ .eqIfPresent(InvoiceHeaderDO::getUserId, reqVO.getUserId())
+ .likeIfPresent(InvoiceHeaderDO::getName, reqVO.getName())
+ .eqIfPresent(InvoiceHeaderDO::getTaxNumber, reqVO.getTaxNumber())
+ .eqIfPresent(InvoiceHeaderDO::getCompanyAddress, reqVO.getCompanyAddress())
+ .eqIfPresent(InvoiceHeaderDO::getCompanyTel, reqVO.getCompanyTel())
+ .likeIfPresent(InvoiceHeaderDO::getBankName, reqVO.getBankName())
+ .eqIfPresent(InvoiceHeaderDO::getBankAccount, reqVO.getBankAccount())
+ .eqIfPresent(InvoiceHeaderDO::getIsDefault, reqVO.getIsDefault())
+ .eqIfPresent(InvoiceHeaderDO::getType, reqVO.getType())
+ .betweenIfPresent(InvoiceHeaderDO::getCreateTime, reqVO.getCreateTime())
+ .orderByDesc(InvoiceHeaderDO::getId));
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoice/InvoiceService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoice/InvoiceService.java
new file mode 100644
index 0000000..d5d2f88
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoice/InvoiceService.java
@@ -0,0 +1,65 @@
+package cn.iocoder.yudao.module.trade.service.invoice;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.trade.controller.admin.invoice.vo.InvoicePageReqVO;
+import cn.iocoder.yudao.module.trade.controller.admin.invoice.vo.InvoiceRespVO;
+import cn.iocoder.yudao.module.trade.controller.admin.invoice.vo.InvoiceSaveReqVO;
+import cn.iocoder.yudao.module.trade.controller.app.invoice.vo.AppInvoiceRespVO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.invoice.InvoiceDO;
+
+
+import javax.validation.Valid;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 发票管理 Service 接口
+ *
+ * @author 东方好果
+ */
+public interface InvoiceService {
+
+ /**
+ * 创建发票管理
+ *
+ * @param createReqVO 创建信息
+ * @return 编号
+ */
+ Integer createInvoice(@Valid InvoiceSaveReqVO createReqVO);
+
+ /**
+ * 更新发票管理
+ *
+ * @param updateReqVO 更新信息
+ */
+ void updateInvoice(@Valid InvoiceSaveReqVO updateReqVO);
+
+ /**
+ * 删除发票管理
+ *
+ * @param id 编号
+ */
+ void deleteInvoice(Integer id);
+
+ /**
+ * 获得发票管理
+ *
+ * @param id 编号
+ * @return 发票管理
+ */
+ InvoiceDO getInvoice(Integer id);
+
+ /**
+ * 获得发票管理分页
+ *
+ * @param pageReqVO 分页查询
+ * @return 发票管理分页
+ */
+ PageResult getInvoicePage(InvoicePageReqVO pageReqVO);
+
+ Map getInvoiceRespMap(Set bizIds);
+
+ Map getHeaderMap(Set headerIds);
+
+ Map getAppInvoiceRespMap(Set bizIds);
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoice/InvoiceServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoice/InvoiceServiceImpl.java
new file mode 100644
index 0000000..d58d59f
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoice/InvoiceServiceImpl.java
@@ -0,0 +1,165 @@
+package cn.iocoder.yudao.module.trade.service.invoice;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.trade.controller.admin.invoice.vo.InvoicePageReqVO;
+import cn.iocoder.yudao.module.trade.controller.admin.invoice.vo.InvoiceRespVO;
+import cn.iocoder.yudao.module.trade.controller.admin.invoice.vo.InvoiceSaveReqVO;
+import cn.iocoder.yudao.module.trade.controller.app.invoice.vo.AppInvoiceRespVO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.invoice.InvoiceDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.invoiceheader.InvoiceHeaderDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
+import cn.iocoder.yudao.module.trade.dal.mysql.invoice.InvoiceMapper;
+import cn.iocoder.yudao.module.trade.service.invoiceheader.InvoiceHeaderService;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.*;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.INVOICE_NOT_EXISTS;
+
+/**
+ * 发票管理 Service 实现类
+ *
+ * @author 东方好果
+ */
+@Service
+@Validated
+public class InvoiceServiceImpl implements InvoiceService {
+
+ @Resource
+ private InvoiceMapper invoiceMapper;
+
+ @Resource
+ private TradeOrderQueryService tradeOrderQueryService;
+
+ @Resource
+ private InvoiceHeaderService invoiceHeaderService;
+
+ @Resource
+ private TradeOrderUpdateService tradeOrderUpdateService;
+
+
+ @Override
+ public Integer createInvoice(InvoiceSaveReqVO createReqVO) {
+ // 插入
+ InvoiceDO invoice = BeanUtils.toBean(createReqVO, InvoiceDO.class);
+ invoiceMapper.insert(invoice);
+ // 返回
+ return invoice.getId();
+ }
+
+ @Override
+ public void updateInvoice(InvoiceSaveReqVO updateReqVO) {
+ // 校验存在
+ validateInvoiceExists(updateReqVO.getId());
+ // 更新
+ InvoiceDO updateObj = BeanUtils.toBean(updateReqVO, InvoiceDO.class);
+ if(updateObj.getStatus() == 1){
+ TradeOrderDO tradeOrderDO = tradeOrderQueryService.getOrder(Long.valueOf(updateObj.getBizId()));
+ if(tradeOrderDO != null){
+ tradeOrderDO.setInvoiceStatus(2);
+ tradeOrderUpdateService.updateTradeOrder(tradeOrderDO);
+ }
+ }
+ invoiceMapper.updateById(updateObj);
+ }
+
+ @Override
+ public void deleteInvoice(Integer id) {
+ // 校验存在
+ validateInvoiceExists(id);
+ // 删除
+ invoiceMapper.deleteById(id);
+ }
+
+ private void validateInvoiceExists(Integer id) {
+ if (invoiceMapper.selectById(id) == null) {
+ throw exception(INVOICE_NOT_EXISTS);
+ }
+ }
+
+ @Override
+ public InvoiceDO getInvoice(Integer id) {
+ return invoiceMapper.selectById(id);
+ }
+
+ @Override
+ public PageResult getInvoicePage(InvoicePageReqVO pageReqVO) {
+ return invoiceMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ public Map getInvoiceRespMap(Set bizIds) {
+ if (bizIds.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ Map map = new HashMap<>();
+ bizIds.forEach(bizId -> {
+ Long id = Long.valueOf(bizId);
+ TradeOrderDO order = tradeOrderQueryService.getOrder(id);
+ if(order != null){
+ InvoiceRespVO invoiceRespVO = new InvoiceRespVO();
+ invoiceRespVO.setBizId(bizId);
+ invoiceRespVO.setBizType(order.getType());
+ invoiceRespVO.setNo(order.getNo());
+ invoiceRespVO.setOrderTime(order.getCreateTime());
+ invoiceRespVO.setTradeOrderStatus(order.getStatus());
+
+ map.put(bizId, invoiceRespVO);
+ }
+ });
+ return map;
+ }
+
+ @Override
+ public Map getHeaderMap(Set headerIds) {
+ if (headerIds.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ Map map = new HashMap<>();
+ headerIds.forEach(headerId -> {
+ InvoiceHeaderDO invoice = invoiceHeaderService.getInvoiceHeader(headerId);
+ if (invoice != null) {
+ InvoiceRespVO invoiceRespVO = new InvoiceRespVO();
+ invoiceRespVO.setHeaderId(headerId);
+ invoiceRespVO.setHeaderType(invoice.getType());
+ invoiceRespVO.setHeaderName(invoice.getName());
+ invoiceRespVO.setTaxNumber(invoice.getTaxNumber());
+ map.put(headerId, invoiceRespVO);
+ }
+ });
+ return map;
+ }
+
+ @Override
+ public Map getAppInvoiceRespMap(Set bizIds) {
+ if (bizIds.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ Map map = new HashMap<>();
+ bizIds.forEach(bizId -> {
+ Long id = Long.valueOf(bizId);
+ TradeOrderDO order = tradeOrderQueryService.getOrder(id);
+ if(order != null){
+ AppInvoiceRespVO appInvoiceRespVO = new AppInvoiceRespVO();
+ appInvoiceRespVO.setBizId(bizId);
+ appInvoiceRespVO.setBizType(order.getType());
+ List list = tradeOrderQueryService.getOrderItemListByOrderId(order.getId());
+ if(list.size() != 0){
+ appInvoiceRespVO.setSpuName(list.get(0).getSpuName());
+ appInvoiceRespVO.setPicUrl(list.get(0).getPicUrl());
+ map.put(bizId, appInvoiceRespVO);
+ }
+
+ }
+ });
+ return map;
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoiceheader/InvoiceHeaderService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoiceheader/InvoiceHeaderService.java
new file mode 100644
index 0000000..7937afc
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoiceheader/InvoiceHeaderService.java
@@ -0,0 +1,63 @@
+package cn.iocoder.yudao.module.trade.service.invoiceheader;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.trade.controller.admin.invoiceheader.vo.InvoiceHeaderPageReqVO;
+import cn.iocoder.yudao.module.trade.controller.admin.invoiceheader.vo.InvoiceHeaderSaveReqVO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.invoiceheader.InvoiceHeaderDO;
+
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 发票抬头 Service 接口
+ *
+ * @author 东方好果
+ */
+public interface InvoiceHeaderService {
+
+ /**
+ * 创建发票抬头
+ *
+ * @param createReqVO 创建信息
+ * @return 编号
+ */
+ Long createInvoiceHeader(@Valid InvoiceHeaderSaveReqVO createReqVO);
+
+ /**
+ * 更新发票抬头
+ *
+ * @param updateReqVO 更新信息
+ */
+ void updateInvoiceHeader(@Valid InvoiceHeaderSaveReqVO updateReqVO);
+
+ /**
+ * 删除发票抬头
+ *
+ * @param id 编号
+ */
+ void deleteInvoiceHeader(Long id);
+
+ /**
+ * 获得发票抬头
+ *
+ * @param id 编号
+ * @return 发票抬头
+ */
+ InvoiceHeaderDO getInvoiceHeader(Long id);
+
+ /**
+ * 获得发票抬头分页
+ *
+ * @param pageReqVO 分页查询
+ * @return 发票抬头分页
+ */
+ PageResult getInvoiceHeaderPage(InvoiceHeaderPageReqVO pageReqVO);
+
+// 查询当前默认抬头列表
+ List selectOneByUserIdAndIsDefault(Long loginUserId);
+
+ List selectOneByUserId(Long loginUserId);
+
+ InvoiceHeaderDO getDefaultInvoiceHeader(Long userId);
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoiceheader/InvoiceHeaderServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoiceheader/InvoiceHeaderServiceImpl.java
new file mode 100644
index 0000000..7e1ba20
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/invoiceheader/InvoiceHeaderServiceImpl.java
@@ -0,0 +1,129 @@
+package cn.iocoder.yudao.module.trade.service.invoiceheader;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.trade.controller.admin.invoiceheader.vo.InvoiceHeaderPageReqVO;
+import cn.iocoder.yudao.module.trade.controller.admin.invoiceheader.vo.InvoiceHeaderSaveReqVO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.invoiceheader.InvoiceHeaderDO;
+import cn.iocoder.yudao.module.trade.dal.mysql.invoiceheader.InvoiceHeaderMapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.INVOICE_HEADER_NOT_EXISTS;
+
+/**
+ * 发票抬头 Service 实现类
+ *
+ * @author 东方好果
+ */
+@Service
+@Validated
+public class InvoiceHeaderServiceImpl implements InvoiceHeaderService {
+
+ @Resource
+ private InvoiceHeaderMapper invoiceHeaderMapper;
+
+ @Override
+ public Long createInvoiceHeader(InvoiceHeaderSaveReqVO createReqVO) {
+ // 插入
+ InvoiceHeaderDO invoiceHeader = BeanUtils.toBean(createReqVO, InvoiceHeaderDO.class);
+ if(createReqVO.getIsDefault().equals(true)) {
+ List invoiceHeaderDOS = invoiceHeaderMapper.selectList(new LambdaQueryWrapper()
+ .eq(InvoiceHeaderDO::getUserId, createReqVO.getUserId())
+ .eq(InvoiceHeaderDO::getIsDefault, true)
+ .eq(InvoiceHeaderDO::getDeleted, false));
+ if (invoiceHeaderDOS.size() != 0) {
+ invoiceHeaderDOS.forEach(invoiceHeaderDO -> {
+ invoiceHeaderDO.setIsDefault(false);
+ invoiceHeaderMapper.updateById(invoiceHeaderDO);
+ });
+ }
+ }
+ invoiceHeaderMapper.insert(invoiceHeader);
+ // 返回
+ return invoiceHeader.getId();
+ }
+
+ @Override
+ public void updateInvoiceHeader(InvoiceHeaderSaveReqVO updateReqVO) {
+ // 校验存在
+ validateInvoiceHeaderExists(updateReqVO.getId());
+ if(updateReqVO.getIsDefault().equals(true)){
+ List invoiceHeaderDOS = invoiceHeaderMapper.selectList(new LambdaQueryWrapper()
+ .eq(InvoiceHeaderDO::getUserId,updateReqVO.getUserId())
+ .eq(InvoiceHeaderDO::getIsDefault, true)
+ .eq(InvoiceHeaderDO::getDeleted, false));
+ if(invoiceHeaderDOS.size() != 0){
+ invoiceHeaderDOS.forEach(invoiceHeaderDO -> {
+ invoiceHeaderDO.setIsDefault(false);
+ invoiceHeaderMapper.updateById(invoiceHeaderDO);
+ });
+ }
+ }
+ // 更新
+ InvoiceHeaderDO updateObj = BeanUtils.toBean(updateReqVO, InvoiceHeaderDO.class);
+ invoiceHeaderMapper.updateById(updateObj);
+ }
+
+ @Override
+ public void deleteInvoiceHeader(Long id) {
+ // 校验存在
+ validateInvoiceHeaderExists(id);
+ // 删除
+ invoiceHeaderMapper.deleteById(id);
+ }
+
+ private void validateInvoiceHeaderExists(Long id) {
+ if (invoiceHeaderMapper.selectById(id) == null) {
+ throw exception(INVOICE_HEADER_NOT_EXISTS);
+ }
+ }
+
+ @Override
+ public InvoiceHeaderDO getInvoiceHeader(Long id) {
+ return invoiceHeaderMapper.selectById(id);
+ }
+
+ @Override
+ public PageResult getInvoiceHeaderPage(InvoiceHeaderPageReqVO pageReqVO) {
+ return invoiceHeaderMapper.selectPage(pageReqVO);
+ }
+
+ @Override
+ public List selectOneByUserIdAndIsDefault(Long loginUserId) {
+ if (loginUserId != null) {
+ return invoiceHeaderMapper.selectList(new LambdaUpdateWrapper()
+ .eq(InvoiceHeaderDO::getUserId, loginUserId)
+ .eq(InvoiceHeaderDO::getIsDefault, true)
+ .eq(InvoiceHeaderDO::getDeleted, false));
+ }
+ return null;
+ }
+
+ @Override
+ public List selectOneByUserId(Long loginUserId) {
+ if (loginUserId != null) {
+ return invoiceHeaderMapper.selectList(new LambdaUpdateWrapper()
+ .eq(InvoiceHeaderDO::getUserId, loginUserId)
+ .eq(InvoiceHeaderDO::getDeleted, false));
+ }
+ return null;
+ }
+
+ @Override
+ public InvoiceHeaderDO getDefaultInvoiceHeader(Long userId) {
+ InvoiceHeaderDO invoiceHeaderDO = invoiceHeaderMapper.selectOne(new LambdaUpdateWrapper()
+ .eq(InvoiceHeaderDO::getUserId, userId)
+ .eq(InvoiceHeaderDO::getIsDefault, true)
+ .eq(InvoiceHeaderDO::getDeleted, false));
+ return invoiceHeaderDO;
+ }
+
+}