发票管理和发票抬头

This commit is contained in:
khy 2025-04-24 17:55:31 +08:00
parent 975f8d855e
commit f3dbebb04e
27 changed files with 2596 additions and 0 deletions

View File

@ -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 })
},
}

View File

@ -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 })
},
}

View File

@ -0,0 +1,258 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="70%">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
<el-form-item label="用户编号" prop="userId">
<el-input v-model="formData.userId" placeholder="请输入用户编号" />
</el-form-item>
<!-- <el-form-item label="发票名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入发票名称" />
</el-form-item>-->
<el-form-item label="发票类型" prop="type">
<el-select v-model="formData.type" placeholder="请选择发票类型">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.INVOICE_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<!-- <el-form-item label="金额" prop="price">
<el-input v-model="formData.price" placeholder="请输入金额" />
</el-form-item>
<el-form-item label="发票抬头类型" prop="titleType">
<el-select v-model="formData.titleType" placeholder="请选择发票抬头类型">
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>-->
<!-- <el-form-item label="纳税人识别号" prop="tin">
<el-input v-model="formData.tin" placeholder="请输入纳税人识别号" />
</el-form-item>-->
<!-- <el-form-item label="业务编号" prop="bizId">
<el-input v-model="formData.bizId" placeholder="请输入业务编号" />
</el-form-item>
<el-form-item label="业务类型1-订单2-提现" prop="bizType">
<el-select v-model="formData.bizType" placeholder="请选择业务类型1-订单2-提现">
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
<el-form-item label="发票抬头类型" prop="titleType">
<el-select v-model="formData.titleType" placeholder="请选择发票抬头类型">
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>-->
<!-- <el-form-item label="发票抬头类型" prop="titleType">-->
<!-- <el-select v-model="formData.titleType" placeholder="请选择发票抬头类型">-->
<!-- <el-option label="请选择字典生成" value="" />-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- 商品信息 -->
<el-form-item label="商品信息">
<el-row :gutter="20">
<el-col :span="24">
<el-table :data="orderData.items" border style="width: 100%">
<el-table-column label="商品" prop="spuName" width="auto">
<template #default="{ row }">
{{ row.spuName }}
<el-tag v-for="property in row.properties" :key="property.propertyId">
{{ property.propertyName }}: {{ property.valueName }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="商品原价" prop="price" width="150">
<template #default="{ row }">{{ fenToYuan(row.price) }}</template>
</el-table-column>
<el-table-column label="数量" prop="count" width="100" />
<el-table-column label="合计" prop="payPrice" width="150">
<template #default="{ row }">{{ fenToYuan(row.payPrice) }}</template>
</el-table-column>
<el-table-column label="售后状态" prop="afterSaleStatus" width="120">
<template #default="{ row }">
<dict-tag
:type="DICT_TYPE.TRADE_ORDER_ITEM_AFTER_SALE_STATUS"
:value="row.afterSaleStatus"
/>
</template>
</el-table-column>
</el-table>
</el-col>
<el-col :span="10" />
</el-row>
</el-form-item>
<el-form-item label="发票" prop="invoice">
<div class="upload-wrapper">
<LocalUploadFile
v-model="formData.invoice"
:file-type="['pdf']"
:limit="1"
:drag="false"
:is-show-tip="false"
:disabled="false"
/>
<p class="tip-text">请上传 PDF 格式发票文件</p>
</div>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input
v-model="formData.email"
placeholder="请输入邮箱"
clearable
/>
</el-form-item>
<el-form-item label="开票状态" prop="status">
<el-select
v-model="formData.status"
placeholder="请选择开票状态"
clearable
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.INVOICE_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { InvoiceApi, InvoiceVO } from '@/api/mall/trade/invoice'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import * as TradeOrderApi from '@/api/mall/trade/order'
import { fenToYuan } from '@/utils'
/** 发票管理 表单 */
defineOptions({ name: 'InvoiceForm' })
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
userId: undefined,
bizId: undefined,
bizType: undefined,
type: undefined,
price: undefined,
titleType: undefined,
invoice: undefined,
status: 0,
tradeOrder: {},
email: undefined,
})
//
const orderData = ref<TradeOrderApi.OrderVO>({
logs: []
})
const formRules = reactive({
userId: [{ required: true, message: '用户编号不能为空', trigger: 'blur' }],
bizId: [{ required: true, message: '业务编号不能为空', trigger: 'blur' }],
bizType: [{ required: true, message: '业务类型1-订单2-提现不能为空', trigger: 'change' }],
type: [{ required: true, message: '发票类型不能为空', trigger: 'change' }],
price: [{ required: true, message: '金额不能为空', trigger: 'blur' }],
titleType: [{ required: true, message: '发票抬头类型不能为空', trigger: 'change' }],
status: [{ required: true, message: '状态0-未开票1-已开票不能为空', trigger: 'blur' }],
})
const formRef = ref() // Ref
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
formData.value = await InvoiceApi.getInvoice(id)
orderData.value = await formData.value.tradeOrder
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
const checkPdf = (file) => {
// 1. PDF type
const isPdfType = file.type === 'application/pdf'; // MIME
const isPdfExt = /\.pdf$/i.test(file.name); //
if (!isPdfType || !isPdfExt) {
message.error('仅支持 PDF 格式文件!');
return false; //
}
// 2. 30MB MB
const maxSizeMB = 30;
const isLt30M = file.size / 1024 / 1024 < maxSizeMB;
if (!isLt30M) {
message.error(`文件大小不能超过 ${maxSizeMB}MB`);
return false; //
}
return true; //
}
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = formData.value as unknown as InvoiceVO
if (formType.value === 'create') {
await InvoiceApi.createInvoice(data)
message.success(t('common.createSuccess'))
} else {
await InvoiceApi.updateInvoice(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
userId: undefined,
bizId: undefined,
bizType: undefined,
type: undefined,
price: undefined,
titleType: undefined,
status: undefined,
}
formRef.value?.resetFields()
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,233 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="开票状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择开票状态"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.INVOICE_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-220px"
/>
</el-form-item>
<el-form-item label="发票名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入发票名称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<!--&lt;!&ndash; <el-button-->
<!-- type="primary"-->
<!-- plain-->
<!-- @click="openForm('create')"-->
<!-- v-hasPermi="['trade:invoice:create']"-->
<!-- >-->
<!-- <Icon icon="ep:plus" class="mr-5px" /> 新增-->
<!-- </el-button>&ndash;&gt;-->
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['trade:invoice:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="id" align="center" prop="id" />
<!-- <el-table-column label="订单号" align="center" prop="no" />-->
<el-table-column label="纳税人识别号" align="center" prop="taxNumber" />
<el-table-column label="发票名称" align="center" prop="headerName" />
<el-table-column label="订单金额" align="center" prop="price" :formatter="fenToYuanFormat"/>
<el-table-column label="发票类型" align="center" prop="type" >
<template #default="scope">
<dict-tag :type="DICT_TYPE.INVOICE_TYPE" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column label="发票抬头类型" align="center" prop="headerType" >
<template #default="scope">
<dict-tag :type="DICT_TYPE.INVOICE_TITLE_TYPE" :value="scope.row.headerType ? 1 : 0 " />
</template>
</el-table-column>
<el-table-column label="下单时间" align="center" prop="orderTime" :formatter="dateFormatter" width="180px"/>
<el-table-column label="开票状态" align="center" prop="status" >
<template #default="scope">
<dict-tag :type="DICT_TYPE.INVOICE_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<!-- <el-table-column label="订单状态" align="center" prop="tradeOrderStatus" />-->
<!-- <el-table-column label="业务编号" align="center" prop="bizId" />
<el-table-column label="业务类型1-订单2-提现" align="center" prop="bizType" />-->
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center" min-width="120px">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['trade:invoice:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['trade:invoice:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<InvoiceForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { InvoiceApi, InvoiceVO } from '@/api/mall/trade/invoice'
import InvoiceForm from './InvoiceForm.vue'
import { fenToYuanFormat } from '@/utils/formatter'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
/** 发票管理 列表 */
defineOptions({ name: 'Invoice' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<InvoiceVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
userId: undefined,
bizId: undefined,
bizType: undefined,
type: undefined,
price: undefined,
titleType: undefined,
status: undefined,
name: undefined,
createTime: [],
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await InvoiceApi.getInvoicePage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await InvoiceApi.deleteInvoice(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await InvoiceApi.exportInvoice(queryParams)
download.excel(data, '发票管理.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -0,0 +1,141 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
<el-form-item label="用户编号" prop="userId">
<el-input v-model="formData.userId" placeholder="请输入用户编号" />
</el-form-item>
<el-form-item label="购方名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入购方名称" />
</el-form-item>
<el-form-item label="纳税人识别号" prop="taxNumber">
<el-input v-model="formData.taxNumber" placeholder="请输入纳税人识别号" />
</el-form-item>
<el-form-item label="公司地址" prop="companyAddress">
<el-input v-model="formData.companyAddress" placeholder="请输入公司地址" />
</el-form-item>
<el-form-item label="公司电话" prop="companyTel">
<el-input v-model="formData.companyTel" placeholder="请输入公司电话" />
</el-form-item>
<el-form-item label="开户银行" prop="bankName">
<el-input v-model="formData.bankName" placeholder="请输入开户银行" />
</el-form-item>
<el-form-item label="银行账号" prop="bankAccount">
<el-input v-model="formData.bankAccount" placeholder="请输入银行账号" />
</el-form-item>
<el-form-item label="是否默认" prop="isDefault">
<el-radio-group v-model="formData.isDefault">
<el-radio :value="true">默认</el-radio>
<el-radio :value="false">非默认</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="抬头类型" prop="type">
<el-radio-group v-model="formData.type">
<el-radio :value="true">企业</el-radio>
<el-radio :value="false">个人</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { InvoiceHeaderApi, InvoiceHeaderVO } from '@/api/mall/trade/invoiceheader'
/** 发票抬头 表单 */
defineOptions({ name: 'InvoiceHeaderForm' })
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
userId: undefined,
name: undefined,
taxNumber: undefined,
companyAddress: undefined,
companyTel: undefined,
bankName: undefined,
bankAccount: undefined,
isDefault: undefined,
type: undefined,
})
const formRules = reactive({
name: [{ required: true, message: '购方名称不能为空', trigger: 'blur' }],
// taxNumber: [{ required: true, message: '', trigger: 'blur' }],
// companyAddress: [{ required: true, message: '', trigger: 'blur' }],
type: [{ required: true, message: '抬头类型不能为空', trigger: 'blur' }],
})
const formRef = ref() // Ref
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
formData.value = await InvoiceHeaderApi.getInvoiceHeader(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = formData.value as unknown as InvoiceHeaderVO
if (formType.value === 'create') {
await InvoiceHeaderApi.createInvoiceHeader(data)
message.success(t('common.createSuccess'))
} else {
await InvoiceHeaderApi.updateInvoiceHeader(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
userId: undefined,
name: undefined,
taxNumber: undefined,
companyAddress: undefined,
companyTel: undefined,
bankName: undefined,
bankAccount: undefined,
isDefault: undefined,
type: undefined,
}
formRef.value?.resetFields()
}
</script>

View File

@ -0,0 +1,247 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="购方名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入购方名称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="识别号" prop="taxNumber">
<el-input
v-model="queryParams.taxNumber"
placeholder="请输入纳税人识别号"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="是否默认" prop="isDefault">
<el-select
v-model="queryParams.isDefault"
placeholder="请选择是否默认"
clearable
class="!w-240px"
>
<el-option v-for="dict in getIntDictOptions(DICT_TYPE.INVOICE_HEADER_DEFAULT)"
:key="dict.value"
:label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="抬头类型" prop="type">
<el-select
v-model="queryParams.type"
placeholder="请选择抬头类型"
clearable
class="!w-240px"
>
<el-option v-for="dict in getIntDictOptions(DICT_TYPE.INVOICE_TITLE_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-220px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<!-- <el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['trade:invoice-header:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['trade:invoice-header:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>-->
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="id" align="center" prop="id" />
<el-table-column label="用户编号" align="center" prop="userId" />
<el-table-column label="购方名称" align="center" prop="name" />
<el-table-column label="纳税人识别号" align="center" prop="taxNumber" />
<el-table-column label="公司地址" align="center" prop="companyAddress" />
<el-table-column label="公司电话" align="center" prop="companyTel" />
<el-table-column label="开户银行" align="center" prop="bankName" />
<el-table-column label="银行账号" align="center" prop="bankAccount" />
<el-table-column label="是否默认" align="center" prop="isDefault">
<template #default="scope">
<dict-tag :type="DICT_TYPE.INVOICE_HEADER_DEFAULT" :value="scope.row.isDefault ? 1 : 0 " />
</template>
</el-table-column>
<el-table-column label="抬头类型" align="center" prop="type" >
<template #default="scope">
<dict-tag :type="DICT_TYPE.INVOICE_TITLE_TYPE" :value="scope.row.type ? 1 : 0 " />
</template>
</el-table-column>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center" min-width="120px">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['trade:invoice-header:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['trade:invoice-header:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<InvoiceHeaderForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { InvoiceHeaderApi, InvoiceHeaderVO } from '@/api/mall/trade/invoiceheader'
import InvoiceHeaderForm from './InvoiceHeaderForm.vue'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
/** 发票抬头 列表 */
defineOptions({ name: 'InvoiceHeader' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<InvoiceHeaderVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
userId: undefined,
name: undefined,
taxNumber: undefined,
companyAddress: undefined,
companyTel: undefined,
bankName: undefined,
bankAccount: undefined,
isDefault: undefined,
type: undefined,
createTime: [],
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await InvoiceHeaderApi.getInvoiceHeaderPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await InvoiceHeaderApi.deleteInvoiceHeader(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await InvoiceHeaderApi.exportInvoiceHeader(queryParams)
download.excel(data, '发票抬头.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -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<Integer> createInvoice(@Valid @RequestBody InvoiceSaveReqVO createReqVO) {
return success(invoiceService.createInvoice(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新发票管理")
@PreAuthorize("@ss.hasPermission('trade:invoice:update')")
public CommonResult<Boolean> 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<Boolean> 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<InvoiceRespVO> 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<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(Long.valueOf(invoice.getBizId()));
// 拼接数据
MemberUserRespDTO user = memberUserApi.getUser(order.getUserId());
MemberUserRespDTO brokerageUser = order.getBrokerageUserId() != null ?
memberUserApi.getUser(order.getBrokerageUserId()) : null;
List<TradeOrderLogDO> 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<PageResult<InvoiceRespVO>> getInvoicePage(@Valid InvoicePageReqVO pageReqVO) {
PageResult<InvoiceDO> pageResult = invoiceService.getInvoicePage(pageReqVO);
//拼接订单信息
Set<String> bizIds = convertSet(pageResult.getList(), InvoiceDO::getBizId);
Map<String , InvoiceRespVO> map = invoiceService.getInvoiceRespMap(bizIds);
//拼接抬头信息
Set<Long> headerIds = convertSet(pageResult.getList(), InvoiceDO::getHeaderId);
Map<Long, InvoiceRespVO> 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<InvoiceDO> pageResult = invoiceService.getInvoicePage(pageReqVO);
//拼接订单信息
Set<String> bizIds = convertSet(pageResult.getList(), InvoiceDO::getBizId);
Map<String , InvoiceRespVO> map = invoiceService.getInvoiceRespMap(bizIds);
//拼接抬头信息
Set<Long> headerIds = convertSet(pageResult.getList(), InvoiceDO::getHeaderId);
Map<Long, InvoiceRespVO> headerMap = invoiceService.getHeaderMap(headerIds);
PageResult<InvoiceRespVO> page = InvoiceConvert.INSTANCE.convertPage(pageResult, map,headerMap);
// 导出 Excel
ExcelUtils.write(response, "发票管理.xls", "数据", InvoiceRespVO.class,
page.getList());
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<Long> createInvoiceHeader(@Valid @RequestBody InvoiceHeaderSaveReqVO createReqVO) {
return success(invoiceHeaderService.createInvoiceHeader(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新发票抬头")
@PreAuthorize("@ss.hasPermission('trade:invoice-header:update')")
public CommonResult<Boolean> 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<Boolean> 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<InvoiceHeaderRespVO> 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<PageResult<InvoiceHeaderRespVO>> getInvoiceHeaderPage(@Valid InvoiceHeaderPageReqVO pageReqVO) {
PageResult<InvoiceHeaderDO> 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<InvoiceHeaderDO> list = invoiceHeaderService.getInvoiceHeaderPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "发票抬头.xls", "数据", InvoiceHeaderRespVO.class,
BeanUtils.toBean(list, InvoiceHeaderRespVO.class));
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<Integer> 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<Boolean> 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<Boolean> 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<AppInvoiceRespVO> getInvoice(@RequestParam("id") Integer id) {
InvoiceDO invoice = invoiceService.getInvoice(id);
return success(BeanUtils.toBean(invoice, AppInvoiceRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得发票管理分页")
public CommonResult<PageResult<AppInvoiceRespVO>> getInvoicePage(@Valid AppInvoicePageReqVO pageReqVO) {
pageReqVO.setUserId(getLoginUserId());
PageResult<InvoiceDO> pageResult = invoiceService.getInvoicePage(BeanUtils.toBean(pageReqVO, InvoicePageReqVO.class));
//拼接订单信息
Set<String> bizIds = convertSet(pageResult.getList(), InvoiceDO::getBizId);
Map<String , AppInvoiceRespVO> map = invoiceService.getAppInvoiceRespMap(bizIds);
return success(InvoiceConvert.INSTANCE.convertPage01(pageResult, map));
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<Long> createInvoiceHeader(@Valid @RequestBody InvoiceHeaderSaveReqVO createReqVO) {
createReqVO.setUserId(getLoginUserId());
return success(invoiceHeaderService.createInvoiceHeader(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新发票抬头")
public CommonResult<Boolean> 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<Boolean> 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<InvoiceHeaderRespVO> getInvoiceHeader(@RequestParam("id") Long id) {
InvoiceHeaderDO invoiceHeader = invoiceHeaderService.getInvoiceHeader(id);
return success(BeanUtils.toBean(invoiceHeader, InvoiceHeaderRespVO.class));
}
@GetMapping("/list")
@Operation(summary = "获得发票抬头列表")
public CommonResult<List<InvoiceHeaderRespVO>> getInvoiceHeaderList() {
List<InvoiceHeaderDO> list = invoiceHeaderService.selectOneByUserId(getLoginUserId());
return success(BeanUtils.toBean(list, InvoiceHeaderRespVO.class));
}
}

View File

@ -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<InvoiceRespVO> convertPage(PageResult<InvoiceDO> pageResult);
default PageResult<InvoiceRespVO> convertPage(PageResult<InvoiceDO> pageResult, Map<String , InvoiceRespVO> map,
Map<Long, InvoiceRespVO> headerMap) {
PageResult<InvoiceRespVO> 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<AppInvoiceRespVO> convertPage01(PageResult<InvoiceDO> pageResult);
//小程序拼接
default PageResult<AppInvoiceRespVO> convertPage01(PageResult<InvoiceDO> pageResult, Map<String , AppInvoiceRespVO> map) {
PageResult<AppInvoiceRespVO> 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;
}
}

View File

@ -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") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 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;
}

View File

@ -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") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 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;
}

View File

@ -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<InvoiceDO> {
default PageResult<InvoiceDO> selectPage(InvoicePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<InvoiceDO>()
.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));
}
}

View File

@ -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<InvoiceHeaderDO> {
default PageResult<InvoiceHeaderDO> selectPage(InvoiceHeaderPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<InvoiceHeaderDO>()
.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));
}
}

View File

@ -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<InvoiceDO> getInvoicePage(InvoicePageReqVO pageReqVO);
Map<String, InvoiceRespVO> getInvoiceRespMap(Set<String> bizIds);
Map<Long, InvoiceRespVO> getHeaderMap(Set<Long> headerIds);
Map<String, AppInvoiceRespVO> getAppInvoiceRespMap(Set<String> bizIds);
}

View File

@ -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<InvoiceDO> getInvoicePage(InvoicePageReqVO pageReqVO) {
return invoiceMapper.selectPage(pageReqVO);
}
@Override
public Map<String, InvoiceRespVO> getInvoiceRespMap(Set<String> bizIds) {
if (bizIds.isEmpty()) {
return Collections.emptyMap();
}
Map<String, InvoiceRespVO> 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<Long, InvoiceRespVO> getHeaderMap(Set<Long> headerIds) {
if (headerIds.isEmpty()) {
return Collections.emptyMap();
}
Map<Long, InvoiceRespVO> 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<String, AppInvoiceRespVO> getAppInvoiceRespMap(Set<String> bizIds) {
if (bizIds.isEmpty()) {
return Collections.emptyMap();
}
Map<String, AppInvoiceRespVO> 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<TradeOrderItemDO> 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;
}
}

View File

@ -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<InvoiceHeaderDO> getInvoiceHeaderPage(InvoiceHeaderPageReqVO pageReqVO);
// 查询当前默认抬头列表
List<InvoiceHeaderDO> selectOneByUserIdAndIsDefault(Long loginUserId);
List<InvoiceHeaderDO> selectOneByUserId(Long loginUserId);
InvoiceHeaderDO getDefaultInvoiceHeader(Long userId);
}

View File

@ -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<InvoiceHeaderDO> invoiceHeaderDOS = invoiceHeaderMapper.selectList(new LambdaQueryWrapper<InvoiceHeaderDO>()
.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<InvoiceHeaderDO> invoiceHeaderDOS = invoiceHeaderMapper.selectList(new LambdaQueryWrapper<InvoiceHeaderDO>()
.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<InvoiceHeaderDO> getInvoiceHeaderPage(InvoiceHeaderPageReqVO pageReqVO) {
return invoiceHeaderMapper.selectPage(pageReqVO);
}
@Override
public List<InvoiceHeaderDO> selectOneByUserIdAndIsDefault(Long loginUserId) {
if (loginUserId != null) {
return invoiceHeaderMapper.selectList(new LambdaUpdateWrapper<InvoiceHeaderDO>()
.eq(InvoiceHeaderDO::getUserId, loginUserId)
.eq(InvoiceHeaderDO::getIsDefault, true)
.eq(InvoiceHeaderDO::getDeleted, false));
}
return null;
}
@Override
public List<InvoiceHeaderDO> selectOneByUserId(Long loginUserId) {
if (loginUserId != null) {
return invoiceHeaderMapper.selectList(new LambdaUpdateWrapper<InvoiceHeaderDO>()
.eq(InvoiceHeaderDO::getUserId, loginUserId)
.eq(InvoiceHeaderDO::getDeleted, false));
}
return null;
}
@Override
public InvoiceHeaderDO getDefaultInvoiceHeader(Long userId) {
InvoiceHeaderDO invoiceHeaderDO = invoiceHeaderMapper.selectOne(new LambdaUpdateWrapper<InvoiceHeaderDO>()
.eq(InvoiceHeaderDO::getUserId, userId)
.eq(InvoiceHeaderDO::getIsDefault, true)
.eq(InvoiceHeaderDO::getDeleted, false));
return invoiceHeaderDO;
}
}