feat(invoice): 添加红冲功能和相关审批流程
- 修改ApplyInvoice组件支持红冲操作,添加isRedRush属性控制红冲逻辑 - 在输入验证中修复数字验证正则表达式,支持负数输入 - 添加applyRefund API接口用于提交红冲申请 - 实现红冲审批流程,包括待审批和已审批页面 - 更新发票详情显示组件支持负数金额显示 - 在发票列表页面添加红冲按钮和相关状态判断 - 修改后端applyRefund接口接收完整对象参数 - 实现发票明细项导出功能 - 添加红冲状态和发票类型的字典数据支持 - 优化金额转中文大写函数支持负数显示 - 添加发票详情导出PDF功能dev_1.0.1
parent
f0294212b2
commit
695c77ca60
|
|
@ -51,6 +51,15 @@ export function redRush(id) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 申请红冲 (提交表单)
|
||||||
|
export function applyRefund(data) {
|
||||||
|
return request({
|
||||||
|
url: '/finance/invoice/applyRefund',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 退回销售收票单
|
// 退回销售收票单
|
||||||
export function returnInvoice(id) {
|
export function returnInvoice(id) {
|
||||||
return request({
|
return request({
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,11 @@ export const constantRoutes = [
|
||||||
component: () => import('@/views/approve/finance/receivableInvoice/approved/index.vue'),
|
component: () => import('@/views/approve/finance/receivableInvoice/approved/index.vue'),
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'receivableInvoiceRefundLog',
|
||||||
|
component: () => import('@/views/approve/finance/receivableInvoiceRefund/approved/index.vue'),
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -33,28 +33,43 @@
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="section" style="margin-top: 20px;" v-if="attachments && attachments.length > 0">
|
<div class="section" style="margin-top: 20px;" v-if="excelList && excelList.length > 0">
|
||||||
<div class="el-descriptions__title">附件信息</div>
|
<div class="el-descriptions__title">附件信息</div>
|
||||||
<el-table :data="attachments" border style="width: 100%; margin-top: 10px;">
|
<el-table :data="excelList" border style="width: 100%; margin-top: 10px;">
|
||||||
<el-table-column prop="fileName" label="附件名称" align="center"></el-table-column>
|
<el-table-column prop="fileName" label="附件名称" align="center"></el-table-column>
|
||||||
<el-table-column prop="createUserName" label="上传人" align="center"></el-table-column>
|
<el-table-column prop="createUserName" label="上传信息" align="center"></el-table-column>
|
||||||
<el-table-column prop="createTime" label="上传时间" align="center"></el-table-column>
|
<el-table-column prop="createTime" label="生成时间" align="center"></el-table-column>
|
||||||
<el-table-column label="操作" align="center">
|
<el-table-column label="操作" align="center">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button size="mini" type="text" icon="el-icon-view" @click="handlePreview(scope.row)">预览</el-button>
|
<el-button size="mini" type="text" icon="el-icon-download" @click="handleDownload(scope.row)">下载</el-button>
|
||||||
<el-button size="mini" type="text" icon="el-icon-download" @click="handleDownload(scope.row)">下载</el-button>
|
</template>
|
||||||
</template>
|
</el-table-column>
|
||||||
</el-table-column>
|
</el-table>
|
||||||
</el-table>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-dialog :visible.sync="pdfPreviewVisible" width="80%" append-to-body top="5vh" title="PDF预览">
|
|
||||||
<iframe :src="currentPdfUrl" width="100%" height="600px" frameborder="0"></iframe>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<el-dialog :visible.sync="imagePreviewVisible" width="60%" append-to-body top="5vh" title="图片预览">
|
<!-- <div class="section" style="margin-top: 20px;" v-if="attachments && attachments.length > 0">-->
|
||||||
<img :src="currentImageUrl" style="width: 100%;" />
|
<!-- <div class="el-descriptions__title">附件信息</div>-->
|
||||||
</el-dialog>
|
<!-- <el-table :data="attachments" border style="width: 100%; margin-top: 10px;">-->
|
||||||
|
<!-- <el-table-column prop="fileName" label="附件名称" align="center"></el-table-column>-->
|
||||||
|
<!-- <el-table-column prop="createUserName" label="上传人" align="center"></el-table-column>-->
|
||||||
|
<!-- <el-table-column prop="createTime" label="上传时间" align="center"></el-table-column>-->
|
||||||
|
<!-- <el-table-column label="操作" align="center">-->
|
||||||
|
<!-- <template slot-scope="scope">-->
|
||||||
|
<!-- <el-button size="mini" type="text" icon="el-icon-view" @click="handlePreview(scope.row)">预览</el-button>-->
|
||||||
|
<!-- <el-button size="mini" type="text" icon="el-icon-download" @click="handleDownload(scope.row)">下载</el-button>-->
|
||||||
|
<!-- </template>-->
|
||||||
|
<!-- </el-table-column>-->
|
||||||
|
<!-- </el-table>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
|
||||||
|
<!-- <el-dialog :visible.sync="pdfPreviewVisible" width="80%" append-to-body top="5vh" title="PDF预览">-->
|
||||||
|
<!-- <iframe :src="currentPdfUrl" width="100%" height="600px" frameborder="0"></iframe>-->
|
||||||
|
<!-- </el-dialog>-->
|
||||||
|
|
||||||
|
<!-- <el-dialog :visible.sync="imagePreviewVisible" width="60%" append-to-body top="5vh" title="图片预览">-->
|
||||||
|
<!-- <img :src="currentImageUrl" style="width: 100%;" />-->
|
||||||
|
<!-- </el-dialog>-->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -77,6 +92,7 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
attachments: [],
|
attachments: [],
|
||||||
|
excelList: [],
|
||||||
pdfPreviewVisible: false,
|
pdfPreviewVisible: false,
|
||||||
currentPdfUrl: '',
|
currentPdfUrl: '',
|
||||||
imagePreviewVisible: false,
|
imagePreviewVisible: false,
|
||||||
|
|
@ -84,7 +100,20 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
data: {
|
||||||
|
handler(val) {
|
||||||
|
if (val && val.updateTime) {
|
||||||
|
this.excelList = [{
|
||||||
|
fileName: '电子发票--购买方公司信息.xlsx',
|
||||||
|
createUserName: '系统生成',
|
||||||
|
createTime: val.updateTime,
|
||||||
|
isSystemGenerated: true
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true,
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
|
|
@ -112,6 +141,15 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleDownload(row) {
|
handleDownload(row) {
|
||||||
|
if (row.isSystemGenerated) {
|
||||||
|
request({
|
||||||
|
url: '/finance/invoice/export/' + this.data.invoiceBillCode,
|
||||||
|
method: 'get'
|
||||||
|
}).then(res => {
|
||||||
|
window.location.href = process.env.VUE_APP_BASE_API + "/common/download?fileName=" + encodeURIComponent(res.msg) + "&delete=true";
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
link.href = this.getImageUrl(row.filePath);
|
link.href = this.getImageUrl(row.filePath);
|
||||||
link.download = row.fileName || 'attachment';
|
link.download = row.fileName || 'attachment';
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,215 @@
|
||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="120px">
|
||||||
|
<el-form-item label="开票编号" prop="invoiceBillCode">
|
||||||
|
<el-input v-model="queryParams.invoiceBillCode" placeholder="请输入开票编号" clearable @keyup.enter.native="handleQuery"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="客户" prop="partnerName">
|
||||||
|
<el-input v-model="queryParams.partnerName" placeholder="请输入客户" clearable @keyup.enter.native="handleQuery"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="项目名称" prop="projectName">
|
||||||
|
<el-input v-model="queryParams.projectName" placeholder="请输入项目名称" clearable @keyup.enter.native="handleQuery"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="提交日期">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange"
|
||||||
|
style="width: 240px"
|
||||||
|
value-format="yyyy-MM-dd"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="-"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<el-table v-loading="loading" :data="invoiceList">
|
||||||
|
<el-table-column label="序号" type="index" width="50" align="center" />
|
||||||
|
<el-table-column label="开票编号" align="center" prop="invoiceBillCode" />
|
||||||
|
<el-table-column label="客户" align="center" prop="partnerName" />
|
||||||
|
<el-table-column label="金额" align="center" prop="totalPriceWithTax">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span :style="scope.row.totalPriceWithTax < 0 ? 'color: red' : ''">{{ scope.row.totalPriceWithTax }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="提交日期" align="center" prop="applyTime" width="180">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ parseTime(scope.row.applyTime) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="审批节点" align="center" prop="approveNode" />
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="200">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row)">详情</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"/>
|
||||||
|
|
||||||
|
<!-- 详情对话框 -->
|
||||||
|
<el-dialog title="开票单详情" :visible.sync="detailDialogVisible" width="80%" append-to-body>
|
||||||
|
<div v-loading="detailLoading" style="max-height: 70vh; overflow-y: auto; padding: 20px;">
|
||||||
|
<div style="display: flex;flex-direction: row-reverse; margin-bottom: 10px;">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
icon="el-icon-download"
|
||||||
|
@click="exportPDF"
|
||||||
|
:loading="pdfExporting"
|
||||||
|
>导出PDF</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="approve-container" :class="{ 'exporting-pdf': pdfExporting }">
|
||||||
|
<ApproveLayout ref="approveLayout" title="开票单详情">
|
||||||
|
<receivable-invoice-detail :data="form"></receivable-invoice-detail>
|
||||||
|
<template #footer>
|
||||||
|
<span>开票编号: {{ form.invoiceBillCode }}</span>
|
||||||
|
</template>
|
||||||
|
</ApproveLayout>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-divider content-position="left">流转意见</el-divider>
|
||||||
|
<div class="process-container">
|
||||||
|
<el-timeline>
|
||||||
|
<el-timeline-item v-for="(log, index) in approveLogs" :key="index" :timestamp="log.approveTime" placement="top">
|
||||||
|
<el-card>
|
||||||
|
<h4>{{ log.approveOpinion }}</h4>
|
||||||
|
<p><b>操作人:</b> {{ log.approveUserName }} </p>
|
||||||
|
<p><b>审批状态:</b> <el-tag size="small">{{ getStatusText(log.approveStatus) }}</el-tag></p>
|
||||||
|
</el-card>
|
||||||
|
</el-timeline-item>
|
||||||
|
</el-timeline>
|
||||||
|
<div v-if="!approveLogs || approveLogs.length === 0">暂无流转过程数据。</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="detailDialogVisible = false">关 闭</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { listInvoiceApproved, getInvoiceDetail } from "@/api/finance/invoice";
|
||||||
|
import { listCompletedFlows } from "@/api/flow";
|
||||||
|
import ReceivableInvoiceDetail from "../components/ReceivableInvoiceDetail";
|
||||||
|
import ApproveLayout from "@/views/approve/ApproveLayout";
|
||||||
|
import { exportElementToPDF } from "@/views/approve/finance/pdfUtils";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "ReceivableInvoiceRefundApproved",
|
||||||
|
components: { ReceivableInvoiceDetail, ApproveLayout },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: true,
|
||||||
|
showSearch: true,
|
||||||
|
total: 0,
|
||||||
|
invoiceList: [],
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
invoiceBillCode: null,
|
||||||
|
partnerName: null,
|
||||||
|
projectName: null,
|
||||||
|
processKey: 'finance_invoice_refound',
|
||||||
|
},
|
||||||
|
dateRange: [],
|
||||||
|
detailDialogVisible: false,
|
||||||
|
detailLoading: false,
|
||||||
|
form: {},
|
||||||
|
approveLogs: [],
|
||||||
|
currentInvoiceId: null,
|
||||||
|
pdfExporting: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getList() {
|
||||||
|
this.loading = true;
|
||||||
|
listInvoiceApproved(this.addDateRange(this.queryParams, this.dateRange, 'ApplyTime')).then(response => {
|
||||||
|
this.invoiceList = response.rows;
|
||||||
|
this.total = response.total;
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleQuery() {
|
||||||
|
this.queryParams.pageNum = 1;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
resetQuery() {
|
||||||
|
this.dateRange = [];
|
||||||
|
this.resetForm("queryForm");
|
||||||
|
this.handleQuery();
|
||||||
|
},
|
||||||
|
handleView(row) {
|
||||||
|
this.form = {};
|
||||||
|
this.approveLogs = [];
|
||||||
|
this.currentInvoiceId = row.id;
|
||||||
|
this.detailLoading = true;
|
||||||
|
this.detailDialogVisible = true;
|
||||||
|
|
||||||
|
getInvoiceDetail(this.currentInvoiceId).then(response => {
|
||||||
|
this.form = response.data;
|
||||||
|
this.loadApproveHistory(this.form.invoiceBillCode);
|
||||||
|
this.detailLoading = false;
|
||||||
|
}).catch(() => {
|
||||||
|
this.detailLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
loadApproveHistory(businessKey) {
|
||||||
|
if (businessKey) {
|
||||||
|
listCompletedFlows({ businessKey: businessKey }).then(response => {
|
||||||
|
this.approveLogs = response.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getStatusText(status) {
|
||||||
|
const map = { '1': '提交审批', '2': '驳回', '3': '批准' };
|
||||||
|
return map[status] || '提交审批';
|
||||||
|
},
|
||||||
|
async exportPDF() {
|
||||||
|
this.pdfExporting = true;
|
||||||
|
try {
|
||||||
|
const element = this.$refs.approveLayout.$el;
|
||||||
|
const fileName = `开票单-${this.form.invoiceBillCode || ''}.pdf`;
|
||||||
|
await exportElementToPDF(element, fileName);
|
||||||
|
this.$modal.msgSuccess('PDF导出成功');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('PDF导出失败:', error);
|
||||||
|
this.$modal.msgError('PDF导出失败,请稍后重试');
|
||||||
|
} finally {
|
||||||
|
this.pdfExporting = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.process-container {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 导出PDF时的特殊样式 */
|
||||||
|
.approve-container.exporting-pdf ::v-deep .el-button--primary,
|
||||||
|
.approve-container.exporting-pdf ::v-deep .el-button--text {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.approve-container.exporting-pdf ::v-deep .el-input__inner,
|
||||||
|
.approve-container.exporting-pdf ::v-deep .el-textarea__inner {
|
||||||
|
border: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
resize: none !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
.approve-container.exporting-pdf ::v-deep .el-input__suffix {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
<template>
|
||||||
|
<div class="invoice-detail">
|
||||||
|
<el-descriptions title="开票单信息" :column="3" border>
|
||||||
|
<el-descriptions-item label="销售-开票单编号">{{ data.invoiceBillCode }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item :span="2" label="进货商">{{ data.partnerName }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="含税总价(元)">
|
||||||
|
<span :style="data.totalPriceWithTax < 0 ? 'color: red' : ''">{{ data.totalPriceWithTax }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="未税总价(元)">
|
||||||
|
<span :style="data.totalPriceWithoutTax < 0 ? 'color: red' : ''">{{ data.totalPriceWithoutTax }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="税额(元)">
|
||||||
|
<span :style="data.taxAmount < 0 ? 'color: red' : ''">{{ data.taxAmount }}</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<!-- <el-descriptions-item label="银行账号">{{ data.buyerBankAccount }}</el-descriptions-item>-->
|
||||||
|
<!-- <el-descriptions-item label="账户名称">{{ data.buyerName }}</el-descriptions-item>-->
|
||||||
|
<!-- <el-descriptions-item label="银行开户行">{{ data.buyerBank }}</el-descriptions-item>-->
|
||||||
|
<!-- <el-descriptions-item label="银行行号">{{ data.bankNumber }}</el-descriptions-item> -->
|
||||||
|
</el-descriptions>
|
||||||
|
|
||||||
|
<div class="section" style="margin-top: 20px;">
|
||||||
|
<div class="el-descriptions__title">发票信息</div>
|
||||||
|
<invoice-info-view :data="data" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section" style="margin-top: 20px;" v-show="data.detailDTOList && data.detailDTOList.length>0">
|
||||||
|
<div class="el-descriptions__title">应收单列表</div>
|
||||||
|
<el-table :data="data.detailDTOList" border style="width: 100%; margin-top: 10px;">
|
||||||
|
<el-table-column type="index" label="序号" width="50" align="center"></el-table-column>
|
||||||
|
<el-table-column prop="receivableBillCode" label="销售-应收单编号" align="center"></el-table-column>
|
||||||
|
<el-table-column prop="projectName" label="项目名称" align="center"></el-table-column>
|
||||||
|
<el-table-column prop="productType" label="产品类型" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<dict-tag :options="dict.type.product_type" :value="scope.row.productType"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="totalPriceWithTax" label="含税总价" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span :style="scope.row.totalPriceWithTax < 0 ? 'color: red' : ''">{{ scope.row.totalPriceWithTax }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="receiptAmount" label="本次开票金额" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span :style="scope.row.receiptAmount < 0 ? 'color: red' : ''">{{ scope.row.receiptAmount }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section" style="margin-top: 20px;" v-if="excelList && excelList.length > 0">
|
||||||
|
<div class="el-descriptions__title">附件信息</div>
|
||||||
|
<el-table :data="excelList" border style="width: 100%; margin-top: 10px;">
|
||||||
|
<el-table-column prop="fileName" label="附件名称" align="center"></el-table-column>
|
||||||
|
<el-table-column prop="createUserName" label="上传信息" align="center"></el-table-column>
|
||||||
|
<el-table-column prop="createTime" label="生成时间" align="center"></el-table-column>
|
||||||
|
<el-table-column label="操作" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-download" @click="handleDownload(scope.row)">下载</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section" style="margin-top: 20px;" v-if="attachments && attachments.length > 0">
|
||||||
|
<div class="el-descriptions__title">附件信息</div>
|
||||||
|
<el-table :data="attachments" border style="width: 100%; margin-top: 10px;">
|
||||||
|
<el-table-column prop="fileName" label="附件名称" align="center"></el-table-column>
|
||||||
|
<el-table-column prop="createUserName" label="上传人" align="center"></el-table-column>
|
||||||
|
<el-table-column prop="createTime" label="上传时间" align="center"></el-table-column>
|
||||||
|
<el-table-column label="操作" align="center">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-view" @click="handlePreview(scope.row)">预览</el-button>
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-download" @click="handleDownload(scope.row)">下载</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-dialog :visible.sync="pdfPreviewVisible" width="80%" append-to-body top="5vh" title="PDF预览">
|
||||||
|
<iframe :src="currentPdfUrl" width="100%" height="600px" frameborder="0"></iframe>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog :visible.sync="imagePreviewVisible" width="60%" append-to-body top="5vh" title="图片预览">
|
||||||
|
<img :src="currentImageUrl" style="width: 100%;" />
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getInvoiceAttachments } from "@/api/finance/invoice";
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import InvoiceInfoView from '@/views/finance/invoice/components/InvoiceInfoView';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "ReceivableInvoiceDetail",
|
||||||
|
components: { InvoiceInfoView },
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dicts: ['product_type'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
attachments: [],
|
||||||
|
excelList: [],
|
||||||
|
pdfPreviewVisible: false,
|
||||||
|
currentPdfUrl: '',
|
||||||
|
imagePreviewVisible: false,
|
||||||
|
currentImageUrl: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
data: {
|
||||||
|
handler(val) {
|
||||||
|
if (val && val.updateTime) {
|
||||||
|
this.excelList = [{
|
||||||
|
fileName: '电子发票--购买方公司信息.xlsx',
|
||||||
|
createUserName: '系统生成',
|
||||||
|
createTime: val.updateTime,
|
||||||
|
isSystemGenerated: true
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true,
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
isPdf(filePath) {
|
||||||
|
return filePath && filePath.toLowerCase().endsWith('.pdf');
|
||||||
|
},
|
||||||
|
getImageUrl(resource) {
|
||||||
|
return process.env.VUE_APP_BASE_API + "/common/download/resource?resource=" + resource;
|
||||||
|
},
|
||||||
|
handlePreview(row) {
|
||||||
|
if (this.isPdf(row.filePath)) {
|
||||||
|
request({
|
||||||
|
url: '/common/download/resource',
|
||||||
|
method: 'get',
|
||||||
|
params: { resource: row.filePath },
|
||||||
|
responseType: 'blob'
|
||||||
|
}).then(res => {
|
||||||
|
const blob = new Blob([res.data], { type: 'application/pdf' });
|
||||||
|
this.currentPdfUrl = URL.createObjectURL(blob);
|
||||||
|
this.pdfPreviewVisible = true;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.currentImageUrl = this.getImageUrl(row.filePath);
|
||||||
|
this.imagePreviewVisible = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleDownload(row) {
|
||||||
|
if (row.isSystemGenerated) {
|
||||||
|
request({
|
||||||
|
url: '/finance/invoice/export/' + this.data.invoiceBillCode,
|
||||||
|
method: 'get'
|
||||||
|
}).then(res => {
|
||||||
|
window.location.href = process.env.VUE_APP_BASE_API + "/common/download?fileName=" + encodeURIComponent(res.msg) + "&delete=true";
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = this.getImageUrl(row.filePath);
|
||||||
|
link.download = row.fileName || 'attachment';
|
||||||
|
link.style.display = 'none';
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.invoice-detail {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,302 @@
|
||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="120px">
|
||||||
|
<el-form-item label="开票编号" prop="invoiceBillCode">
|
||||||
|
<el-input v-model="queryParams.invoiceBillCode" placeholder="请输入开票编号" clearable @keyup.enter.native="handleQuery"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="进货商" prop="partnerName">
|
||||||
|
<el-input v-model="queryParams.partnerName" placeholder="请输入进货商" clearable @keyup.enter.native="handleQuery"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="项目名称" prop="projectName">
|
||||||
|
<el-input v-model="queryParams.projectName" placeholder="请输入项目名称" clearable @keyup.enter.native="handleQuery"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="提交日期">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange"
|
||||||
|
style="width: 240px"
|
||||||
|
value-format="yyyy-MM-dd HH:mm:ss"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="-"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
size="mini"
|
||||||
|
@click="toApproved()"
|
||||||
|
>审批历史</el-button>
|
||||||
|
</el-col>
|
||||||
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-table v-loading="loading" :data="invoiceList">
|
||||||
|
<el-table-column label="序号" type="index" width="50" align="center" />
|
||||||
|
<el-table-column label="开票编号" align="center" prop="invoiceBillCode" />
|
||||||
|
<el-table-column label="进货商" align="center" prop="partnerName" />
|
||||||
|
<el-table-column label="金额" align="center" prop="totalPriceWithTax">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span :style="scope.row.totalPriceWithTax < 0 ? 'color: red' : ''">{{ scope.row.totalPriceWithTax }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="提交日期" align="center" prop="applyTime" width="180">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ parseTime(scope.row.applyTime, '{y}-{m}-{d}') }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="审批节点" align="center" prop="approveNode" />
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="200">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleApprove(scope.row)">审批</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"/>
|
||||||
|
|
||||||
|
<!-- 审批详情主对话框 -->
|
||||||
|
<el-dialog title="开票单审批" :visible.sync="detailDialogVisible" width="80%" append-to-body>
|
||||||
|
<div v-loading="detailLoading" style="max-height: 70vh; overflow-y: auto; padding: 20px;">
|
||||||
|
<div style="display: flex;flex-direction: row-reverse; margin-bottom: 10px;">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
icon="el-icon-download"
|
||||||
|
@click="exportPDF"
|
||||||
|
:loading="pdfExporting"
|
||||||
|
>导出PDF</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="approve-container" :class="{ 'exporting-pdf': pdfExporting }">
|
||||||
|
<ApproveLayout ref="approveLayout" title="开票单详情">
|
||||||
|
<receivable-invoice-detail :data="form"></receivable-invoice-detail>
|
||||||
|
<template #footer>
|
||||||
|
<span>{{ form.invoiceBillCode }}</span>
|
||||||
|
</template>
|
||||||
|
</ApproveLayout>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-divider content-position="left">流转意见</el-divider>
|
||||||
|
<div class="process-container">
|
||||||
|
<el-timeline>
|
||||||
|
<el-timeline-item v-for="(log, index) in approveLogs" :key="index" :timestamp="log.approveTime" placement="top">
|
||||||
|
<el-card>
|
||||||
|
<h4>{{ log.approveOpinion }}</h4>
|
||||||
|
<p><b>操作人:</b> {{ log.approveUserName }} </p>
|
||||||
|
<p><b>审批状态:</b> <el-tag size="small">{{ getStatusText(log.approveStatus) }}</el-tag></p>
|
||||||
|
</el-card>
|
||||||
|
</el-timeline-item>
|
||||||
|
</el-timeline>
|
||||||
|
<div v-if="!approveLogs || approveLogs.length === 0">暂无流转过程数据。</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="openOpinionDialog('approve')">同意</el-button>
|
||||||
|
<el-button type="danger" @click="openOpinionDialog('reject')">驳回</el-button>
|
||||||
|
<el-button @click="detailDialogVisible = false">取 消</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 审批意见对话框 -->
|
||||||
|
<el-dialog :title="confirmDialogTitle" :visible.sync="opinionDialogVisible" width="30%" append-to-body>
|
||||||
|
<el-form ref="opinionForm" :model="opinionForm" :rules="opinionRules" label-width="100px">
|
||||||
|
<el-form-item label="审批意见" prop="approveOpinion">
|
||||||
|
<el-input v-model="opinionForm.approveOpinion" type="textarea" :rows="4" placeholder="请输入审批意见"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<span slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="opinionDialogVisible = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="showConfirmDialog()">确 定</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { listInvoiceApprove, getInvoiceDetail } from "@/api/finance/invoice";
|
||||||
|
import { approveTask, listCompletedFlows } from "@/api/flow";
|
||||||
|
import ReceivableInvoiceDetail from "./components/ReceivableInvoiceDetail";
|
||||||
|
import ApproveLayout from "@/views/approve/ApproveLayout";
|
||||||
|
import { exportElementToPDF } from "@/views/approve/finance/pdfUtils";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "ReceivableInvoiceRefundApprove",
|
||||||
|
components: { ReceivableInvoiceDetail, ApproveLayout },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: true,
|
||||||
|
showSearch: true,
|
||||||
|
total: 0,
|
||||||
|
invoiceList: [],
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
invoiceBillCode: null,
|
||||||
|
partnerName: null,
|
||||||
|
projectName: null,
|
||||||
|
processKey: 'finance_invoice_refound',
|
||||||
|
},
|
||||||
|
dateRange: [],
|
||||||
|
detailDialogVisible: false,
|
||||||
|
detailLoading: false,
|
||||||
|
form: {},
|
||||||
|
approveLogs: [],
|
||||||
|
opinionDialogVisible: false,
|
||||||
|
confirmDialogTitle: '',
|
||||||
|
currentApproveType: '',
|
||||||
|
opinionForm: {
|
||||||
|
approveOpinion: ''
|
||||||
|
},
|
||||||
|
opinionRules: {
|
||||||
|
approveOpinion: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
|
||||||
|
},
|
||||||
|
processKey: 'finance_invoice_refound',
|
||||||
|
taskId: null,
|
||||||
|
currentInvoiceId: null,
|
||||||
|
pdfExporting: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getList() {
|
||||||
|
this.loading = true;
|
||||||
|
listInvoiceApprove(this.addDateRange(this.queryParams, this.dateRange, 'ApplyTime')).then(response => {
|
||||||
|
this.invoiceList = response.rows;
|
||||||
|
this.total = response.total;
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleQuery() {
|
||||||
|
this.queryParams.pageNum = 1;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
resetQuery() {
|
||||||
|
this.dateRange = [];
|
||||||
|
this.resetForm("queryForm");
|
||||||
|
this.handleQuery();
|
||||||
|
},
|
||||||
|
toApproved() {
|
||||||
|
this.$router.push('/approve/receivableInvoiceRefundLog')
|
||||||
|
},
|
||||||
|
handleApprove(row) {
|
||||||
|
this.resetDetailForm();
|
||||||
|
this.currentInvoiceId = row.id;
|
||||||
|
this.taskId = row.taskId;
|
||||||
|
this.detailLoading = true;
|
||||||
|
this.detailDialogVisible = true;
|
||||||
|
|
||||||
|
getInvoiceDetail(this.currentInvoiceId).then(response => {
|
||||||
|
this.form = response.data;
|
||||||
|
this.loadApproveHistory(this.form.invoiceBillCode);
|
||||||
|
this.detailLoading = false;
|
||||||
|
}).catch(() => {
|
||||||
|
this.detailLoading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
resetDetailForm() {
|
||||||
|
this.form = {};
|
||||||
|
this.approveLogs = [];
|
||||||
|
this.opinionForm.approveOpinion = '';
|
||||||
|
},
|
||||||
|
loadApproveHistory(businessKey) {
|
||||||
|
if (businessKey) {
|
||||||
|
let keys = [];
|
||||||
|
if(this.processKey) keys.push(this.processKey);
|
||||||
|
|
||||||
|
listCompletedFlows({ businessKey: businessKey, processKeyList: keys }).then(response => {
|
||||||
|
this.approveLogs = response.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
openOpinionDialog(type) {
|
||||||
|
this.currentApproveType = type;
|
||||||
|
this.confirmDialogTitle = type === 'approve' ? '同意审批' : '驳回审批';
|
||||||
|
this.opinionDialogVisible = true;
|
||||||
|
this.opinionForm.approveOpinion = '';
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if(this.$refs.opinionForm) this.$refs.opinionForm.clearValidate();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
showConfirmDialog() {
|
||||||
|
this.$refs.opinionForm.validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
this.opinionDialogVisible = false;
|
||||||
|
this.submitApproval();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
submitApproval() {
|
||||||
|
const approveBtn = this.currentApproveType === 'approve' ? 1 : 0;
|
||||||
|
const params = {
|
||||||
|
businessKey: this.form.invoiceBillCode,
|
||||||
|
processKey: this.processKey,
|
||||||
|
taskId: this.taskId,
|
||||||
|
variables: {
|
||||||
|
comment: this.opinionForm.approveOpinion,
|
||||||
|
approveBtn: approveBtn
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
approveTask(params).then(() => {
|
||||||
|
this.$modal.msgSuccess(this.confirmDialogTitle + "成功");
|
||||||
|
this.detailDialogVisible = false;
|
||||||
|
this.getList();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getStatusText(status) {
|
||||||
|
if (!status) {
|
||||||
|
return '提交审批'
|
||||||
|
}
|
||||||
|
const map = { '1': '提交审批', '2': '驳回', '3': '批准' };
|
||||||
|
return map[status] || '提交审批';
|
||||||
|
},
|
||||||
|
async exportPDF() {
|
||||||
|
this.pdfExporting = true;
|
||||||
|
try {
|
||||||
|
const element = this.$refs.approveLayout.$el;
|
||||||
|
const fileName = `开票单-${this.form.invoiceBillCode || ''}.pdf`;
|
||||||
|
await exportElementToPDF(element, fileName);
|
||||||
|
this.$modal.msgSuccess('PDF导出成功');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('PDF导出失败:', error);
|
||||||
|
this.$modal.msgError('PDF导出失败,请稍后重试');
|
||||||
|
} finally {
|
||||||
|
this.pdfExporting = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.process-container {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 导出PDF时的特殊样式 */
|
||||||
|
.approve-container.exporting-pdf ::v-deep .el-button--primary,
|
||||||
|
.approve-container.exporting-pdf ::v-deep .el-button--text {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.approve-container.exporting-pdf ::v-deep .el-input__inner,
|
||||||
|
.approve-container.exporting-pdf ::v-deep .el-textarea__inner {
|
||||||
|
border: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
resize: none !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
.approve-container.exporting-pdf ::v-deep .el-input__suffix {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -110,7 +110,7 @@
|
||||||
<el-table-column label="数量" prop="quantity" align="center" width="80">
|
<el-table-column label="数量" prop="quantity" align="center" width="80">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-input v-model="scope.row.quantity" size="mini" class="no-border-input"
|
<el-input v-model="scope.row.quantity" size="mini" class="no-border-input"
|
||||||
oninput="value=value.replace(/[^\d.]/g,'')"
|
oninput="value=value.replace(/[^\d.-]/g,'')"
|
||||||
@input="calculateAmount(scope.row)"/>
|
@input="calculateAmount(scope.row)"/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
@ -185,7 +185,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {getInvoiceProducts, applyInvoice} from "@/api/finance/invoice";
|
import {getInvoiceProducts, applyInvoice, applyRefund} from "@/api/finance/invoice";
|
||||||
import { listCompanyInfo } from "@/api/system/companyInfo";
|
import { listCompanyInfo } from "@/api/system/companyInfo";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -199,6 +199,10 @@ export default {
|
||||||
rowData: {
|
rowData: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({})
|
default: () => ({})
|
||||||
|
},
|
||||||
|
isRedRush: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -217,6 +221,7 @@ export default {
|
||||||
sellerBankAccount: undefined,
|
sellerBankAccount: undefined,
|
||||||
remark: undefined,
|
remark: undefined,
|
||||||
invoiceBillCode: this.rowData.invoiceBillCode,
|
invoiceBillCode: this.rowData.invoiceBillCode,
|
||||||
|
id: this.rowData.id,
|
||||||
detailItemList: [
|
detailItemList: [
|
||||||
{
|
{
|
||||||
projectName: '',
|
projectName: '',
|
||||||
|
|
@ -246,8 +251,8 @@ export default {
|
||||||
let total = 0;
|
let total = 0;
|
||||||
this.form.detailItemList.forEach(item => {
|
this.form.detailItemList.forEach(item => {
|
||||||
const amount = parseFloat(item.amount) || 0;
|
const amount = parseFloat(item.amount) || 0;
|
||||||
const tax = parseFloat(item.taxAmount) || 0;
|
// const tax = parseFloat(item.taxAmount) || 0;
|
||||||
total += (amount + tax);
|
total += amount ;
|
||||||
});
|
});
|
||||||
return total.toFixed(2);
|
return total.toFixed(2);
|
||||||
},
|
},
|
||||||
|
|
@ -309,6 +314,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.form.invoiceBillCode = this.rowData.invoiceBillCode;
|
this.form.invoiceBillCode = this.rowData.invoiceBillCode;
|
||||||
|
this.form.id = this.rowData.id;
|
||||||
|
|
||||||
this.updateRemark();
|
this.updateRemark();
|
||||||
|
|
||||||
|
|
@ -316,6 +322,16 @@ export default {
|
||||||
getInvoiceProducts(this.rowData.invoiceBillCode).then(response => {
|
getInvoiceProducts(this.rowData.invoiceBillCode).then(response => {
|
||||||
if (response.data && response.data.length > 0) {
|
if (response.data && response.data.length > 0) {
|
||||||
this.form.detailItemList = response.data.map(item => {
|
this.form.detailItemList = response.data.map(item => {
|
||||||
|
let quantity = item.quantity;
|
||||||
|
let amount = item.allPrice;
|
||||||
|
let taxAmount = item.taxAmount;
|
||||||
|
|
||||||
|
if (this.isRedRush) {
|
||||||
|
quantity = -Math.abs(quantity);
|
||||||
|
amount = -Math.abs(amount);
|
||||||
|
taxAmount = -Math.abs(taxAmount);
|
||||||
|
}
|
||||||
|
|
||||||
const row = {
|
const row = {
|
||||||
projectName: item.projectName,
|
projectName: item.projectName,
|
||||||
id: item.id,
|
id: item.id,
|
||||||
|
|
@ -324,11 +340,11 @@ export default {
|
||||||
productModel: item.productModel, // Mapping projectCode to productModel as requested
|
productModel: item.productModel, // Mapping projectCode to productModel as requested
|
||||||
productName: item.productName, // Mapping projectCode to productModel as requested
|
productName: item.productName, // Mapping projectCode to productModel as requested
|
||||||
unit: item.unit || '',
|
unit: item.unit || '',
|
||||||
quantity: item.quantity,
|
quantity: quantity,
|
||||||
unitPrice: item.price, // Mapping price to unitPrice
|
unitPrice: item.price, // Mapping price to unitPrice
|
||||||
taxRate: item.taxRate,
|
taxRate: item.taxRate,
|
||||||
amount: item.allPrice,
|
amount: amount,
|
||||||
taxAmount: item.taxAmount
|
taxAmount: taxAmount
|
||||||
};
|
};
|
||||||
// Calculate initial amounts
|
// Calculate initial amounts
|
||||||
// this.calculateAmount(row);
|
// this.calculateAmount(row);
|
||||||
|
|
@ -430,8 +446,7 @@ export default {
|
||||||
}
|
}
|
||||||
for (let i = 0; i < this.form.detailItemList.length; i++) {
|
for (let i = 0; i < this.form.detailItemList.length; i++) {
|
||||||
const item = this.form.detailItemList[i];
|
const item = this.form.detailItemList[i];
|
||||||
|
if (!item.productName || !item.productModel || isNaN(item.quantity) || !item.unit || !item.unitPrice || !item.amount || !item.taxAmount || !item.taxRate) {
|
||||||
if (!item.productName || !item.productModel || (item.quantity??false) || !item.unit || !item.unitPrice || !item.amount || !item.taxAmount || !item.taxRate) {
|
|
||||||
this.$modal.msgError(`表格第 ${i + 1} 行数据不完整,请填写所有必填字段`);
|
this.$modal.msgError(`表格第 ${i + 1} 行数据不完整,请填写所有必填字段`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -440,8 +455,9 @@ export default {
|
||||||
item.allPrice=item.amount;
|
item.allPrice=item.amount;
|
||||||
}
|
}
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
applyInvoice(this.form).then(response => {
|
const apiCall = this.isRedRush ? applyRefund : applyInvoice;
|
||||||
this.$modal.msgSuccess("申请提交成功");
|
apiCall(this.form).then(response => {
|
||||||
|
this.$modal.msgSuccess(this.isRedRush ? "申请红冲成功" : "申请提交成功");
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.$emit("update:visible", false);
|
this.$emit("update:visible", false);
|
||||||
this.$emit("submit", this.form);
|
this.$emit("submit", this.form);
|
||||||
|
|
@ -464,11 +480,16 @@ export default {
|
||||||
let decimalNum;
|
let decimalNum;
|
||||||
let chineseStr = '';
|
let chineseStr = '';
|
||||||
let parts;
|
let parts;
|
||||||
|
let prefix = '';
|
||||||
|
|
||||||
if (money === '') {
|
if (money === '') {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
money = parseFloat(money);
|
money = parseFloat(money);
|
||||||
|
if (money < 0) {
|
||||||
|
prefix = '(负数)';
|
||||||
|
money = Math.abs(money);
|
||||||
|
}
|
||||||
if (money >= 999999999999) {
|
if (money >= 999999999999) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
@ -526,7 +547,7 @@ export default {
|
||||||
} else if (decimalNum === '') {
|
} else if (decimalNum === '') {
|
||||||
chineseStr += cnInteger;
|
chineseStr += cnInteger;
|
||||||
}
|
}
|
||||||
return chineseStr;
|
return prefix + chineseStr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,12 @@ export default {
|
||||||
if (money >= 999999999999) return '';
|
if (money >= 999999999999) return '';
|
||||||
if (money === 0) return cnNums[0] + cnIntLast + cnInteger;
|
if (money === 0) return cnNums[0] + cnIntLast + cnInteger;
|
||||||
|
|
||||||
|
let prefix = "";
|
||||||
|
if (money < 0) {
|
||||||
|
prefix = "(负数)";
|
||||||
|
money = Math.abs(money);
|
||||||
|
}
|
||||||
|
|
||||||
money = money.toString();
|
money = money.toString();
|
||||||
if (money.indexOf('.') === -1) {
|
if (money.indexOf('.') === -1) {
|
||||||
integerNum = money;
|
integerNum = money;
|
||||||
|
|
@ -201,7 +207,7 @@ export default {
|
||||||
|
|
||||||
if (chineseStr === '') chineseStr += cnNums[0] + cnIntLast + cnInteger;
|
if (chineseStr === '') chineseStr += cnNums[0] + cnIntLast + cnInteger;
|
||||||
else if (decimalNum === '') chineseStr += cnInteger;
|
else if (decimalNum === '') chineseStr += cnInteger;
|
||||||
return chineseStr;
|
return prefix + chineseStr;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,9 @@
|
||||||
@keyup.enter.native="handleQuery"
|
@keyup.enter.native="handleQuery"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="票据类型" prop="invoiceBillType">
|
<el-form-item label="票据类型" prop="invoiceType">
|
||||||
<el-select v-model="queryParams.invoiceBillType" placeholder="请选择收票单类型" clearable>
|
<el-select v-model="queryParams.invoiceType" placeholder="票据类型" clearable>
|
||||||
<el-option v-for="dict in dict.type.invoice_bill_type" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
|
<el-option v-for="dict in dict.type.finance_invoice_type" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="审批状态" prop="approveStatus">
|
<el-form-item label="审批状态" prop="approveStatus">
|
||||||
|
|
@ -198,7 +198,7 @@
|
||||||
size="mini"
|
size="mini"
|
||||||
type="text"
|
type="text"
|
||||||
icon="el-icon-refresh-left"
|
icon="el-icon-refresh-left"
|
||||||
v-show="scope.row.approveStatus === '2' && scope.row.invoiceStatus === '1'"
|
v-show="scope.row.approveStatus === '2' && scope.row.invoiceStatus === '2'"
|
||||||
@click="handleRedRush(scope.row)"
|
@click="handleRedRush(scope.row)"
|
||||||
>申请红冲</el-button>
|
>申请红冲</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
|
|
@ -227,7 +227,7 @@
|
||||||
<!-- 收票附件弹窗 -->
|
<!-- 收票附件弹窗 -->
|
||||||
<invoice-dialog :visible.sync="receiptOpen" :invoice-data="currentRow" :dicts="dict.type"></invoice-dialog>
|
<invoice-dialog :visible.sync="receiptOpen" :invoice-data="currentRow" :dicts="dict.type"></invoice-dialog>
|
||||||
<!-- 申请开票弹窗 -->
|
<!-- 申请开票弹窗 -->
|
||||||
<apply-invoice :visible.sync="applyOpen" :row-data="currentRow" @submit="getList"></apply-invoice>
|
<apply-invoice :visible.sync="applyOpen" :row-data="currentRow" :is-red-rush="isRedRush" @submit="getList"></apply-invoice>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -248,7 +248,7 @@ export default {
|
||||||
InvoiceDialog,
|
InvoiceDialog,
|
||||||
ApplyInvoice
|
ApplyInvoice
|
||||||
},
|
},
|
||||||
dicts:['invoice_bill_type','approve_status','invoice_bill_status'],
|
dicts:['invoice_bill_type','approve_status','invoice_bill_status','finance_invoice_type'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// 遮罩层
|
// 遮罩层
|
||||||
|
|
@ -266,6 +266,7 @@ export default {
|
||||||
projectCode: null,
|
projectCode: null,
|
||||||
projectName: null,
|
projectName: null,
|
||||||
invoiceBillCode: null,
|
invoiceBillCode: null,
|
||||||
|
invoiceType: null,
|
||||||
partnerName: null,
|
partnerName: null,
|
||||||
receivableBillCode: null,
|
receivableBillCode: null,
|
||||||
invoiceBillType: null,
|
invoiceBillType: null,
|
||||||
|
|
@ -284,6 +285,8 @@ export default {
|
||||||
addOpen: false,
|
addOpen: false,
|
||||||
// 申请开票弹窗
|
// 申请开票弹窗
|
||||||
applyOpen: false,
|
applyOpen: false,
|
||||||
|
// 是否红冲
|
||||||
|
isRedRush: false,
|
||||||
// 收票附件弹窗
|
// 收票附件弹窗
|
||||||
receiptOpen: false,
|
receiptOpen: false,
|
||||||
currentRow: {}
|
currentRow: {}
|
||||||
|
|
@ -350,17 +353,15 @@ export default {
|
||||||
},
|
},
|
||||||
/** 申请开票按钮操作 */
|
/** 申请开票按钮操作 */
|
||||||
handleApplyInvoice(row) {
|
handleApplyInvoice(row) {
|
||||||
|
this.isRedRush = false;
|
||||||
this.currentRow = row;
|
this.currentRow = row;
|
||||||
this.applyOpen = true;
|
this.applyOpen = true;
|
||||||
},
|
},
|
||||||
/** 红冲按钮操作 */
|
/** 红冲按钮操作 */
|
||||||
handleRedRush(row) {
|
handleRedRush(row) {
|
||||||
this.$modal.confirm('是否确认收票单编号为"' + row.invoiceBillCode + '"的数据项进行红冲,并提交财务审批?').then(function() {
|
this.isRedRush = true;
|
||||||
return redRush(row.id);
|
this.currentRow = row;
|
||||||
}).then(() => {
|
this.applyOpen = true;
|
||||||
this.getList();
|
|
||||||
this.$modal.msgSuccess("申请红冲成功");
|
|
||||||
}).catch(() => {});
|
|
||||||
},
|
},
|
||||||
handleReturn(row) {
|
handleReturn(row) {
|
||||||
this.$modal.confirm('是否确认退回收票单编号为"' + row.invoiceBillCode + '"的数据项?').then(function() {
|
this.$modal.confirm('是否确认退回收票单编号为"' + row.invoiceBillCode + '"的数据项?').then(function() {
|
||||||
|
|
|
||||||
|
|
@ -182,11 +182,11 @@ public class OmsInvoiceBillController extends BaseController
|
||||||
/**
|
/**
|
||||||
* 申请红冲
|
* 申请红冲
|
||||||
*/
|
*/
|
||||||
@GetMapping("/applyRefund/{id}")
|
@PostMapping("/applyRefund")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public AjaxResult applyRefund(@PathVariable("id") Long id) {
|
public AjaxResult applyRefund(@RequestBody OmsInvoiceBill omsInvoiceBill) {
|
||||||
try {
|
try {
|
||||||
return omsInvoiceBillService.applyRefund(id);
|
return omsInvoiceBillService.applyRefund(omsInvoiceBill);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("申请红冲失败", e);
|
logger.error("申请红冲失败", e);
|
||||||
return AjaxResult.error("操作失败:" + e.getMessage());
|
return AjaxResult.error("操作失败:" + e.getMessage());
|
||||||
|
|
@ -242,4 +242,9 @@ public class OmsInvoiceBillController extends BaseController
|
||||||
public AjaxResult listProduct(@PathVariable("code") String code) {
|
public AjaxResult listProduct(@PathVariable("code") String code) {
|
||||||
return AjaxResult.success(omsInvoiceBillService.listProduct(code));
|
return AjaxResult.success(omsInvoiceBillService.listProduct(code));
|
||||||
}
|
}
|
||||||
|
@GetMapping("/export/{code}")
|
||||||
|
@ResponseBody
|
||||||
|
public AjaxResult exportItem(@PathVariable("code") String code) {
|
||||||
|
return omsInvoiceBillService.exportItem(code);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
package com.ruoyi.sip.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.ruoyi.common.annotation.Excel;
|
||||||
|
import com.ruoyi.common.core.domain.BaseEntity;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品库存对象 oms_inventory_delivery
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
* @date 2025-08-12
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ToString
|
||||||
|
public class InvoiceDetailItemExcelDto extends BaseEntity
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private String index;
|
||||||
|
|
||||||
|
private String buyerName;
|
||||||
|
private String buyerCreditCode;
|
||||||
|
private String buyerBank;
|
||||||
|
private String buyerBankAccount;
|
||||||
|
/**
|
||||||
|
* 产品名称
|
||||||
|
*/
|
||||||
|
private String productName;
|
||||||
|
/**
|
||||||
|
* 产品型号
|
||||||
|
*/
|
||||||
|
private String productModel;
|
||||||
|
private String unit;
|
||||||
|
private Long quantity;
|
||||||
|
/**
|
||||||
|
* 单价
|
||||||
|
*/
|
||||||
|
private BigDecimal price;
|
||||||
|
/**
|
||||||
|
* 总价
|
||||||
|
*/
|
||||||
|
private BigDecimal allPrice;
|
||||||
|
/**
|
||||||
|
* 税额
|
||||||
|
*/
|
||||||
|
private BigDecimal taxAmount;
|
||||||
|
/**
|
||||||
|
* 税率
|
||||||
|
*/
|
||||||
|
private BigDecimal taxRate;
|
||||||
|
private String invoiceType;
|
||||||
|
private String remark;
|
||||||
|
private String buyerAddress;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.ruoyi.sip.mapper;
|
package com.ruoyi.sip.mapper;
|
||||||
|
|
||||||
import com.ruoyi.sip.domain.OmsReceivableInvoiceDetailItem;
|
import com.ruoyi.sip.domain.OmsReceivableInvoiceDetailItem;
|
||||||
|
import com.ruoyi.sip.dto.InvoiceDetailItemExcelDto;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
@ -49,4 +50,6 @@ public interface OmsReceivableInvoiceDetailItemMapper {
|
||||||
int insertBatch(List<OmsReceivableInvoiceDetailItem> omsReceivableInvoiceDetailItems);
|
int insertBatch(List<OmsReceivableInvoiceDetailItem> omsReceivableInvoiceDetailItems);
|
||||||
|
|
||||||
void updateBatch(List<OmsReceivableInvoiceDetailItem> updateList);
|
void updateBatch(List<OmsReceivableInvoiceDetailItem> updateList);
|
||||||
|
|
||||||
|
List<InvoiceDetailItemExcelDto> exportItem(String code);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ public interface IOmsInvoiceBillService
|
||||||
* @param id 开票单ID
|
* @param id 开票单ID
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public AjaxResult applyRefund(Long id);
|
public AjaxResult applyRefund(OmsInvoiceBill omsInvoiceBill);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退回开票单
|
* 退回开票单
|
||||||
|
|
@ -122,4 +122,5 @@ public interface IOmsInvoiceBillService
|
||||||
|
|
||||||
void returnTicketWriteOff(List<String> collect, List<OmsReceivableInvoiceDetail> omsReceivableInvoiceDetails);
|
void returnTicketWriteOff(List<String> collect, List<OmsReceivableInvoiceDetail> omsReceivableInvoiceDetails);
|
||||||
|
|
||||||
|
AjaxResult exportItem(String code);
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.ruoyi.sip.service;
|
package com.ruoyi.sip.service;
|
||||||
|
|
||||||
import com.ruoyi.sip.domain.OmsReceivableInvoiceDetailItem;
|
import com.ruoyi.sip.domain.OmsReceivableInvoiceDetailItem;
|
||||||
|
import com.ruoyi.sip.dto.InvoiceDetailItemExcelDto;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
@ -43,6 +44,7 @@ public interface IOmsReceivableInvoiceDetailItemService {
|
||||||
*/
|
*/
|
||||||
int batchRemove(Long[] ids);
|
int batchRemove(Long[] ids);
|
||||||
|
|
||||||
|
List<InvoiceDetailItemExcelDto> exportItem(String code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,26 +3,35 @@ package com.ruoyi.sip.service.impl;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.date.DatePattern;
|
import cn.hutool.core.date.DatePattern;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import com.alibaba.excel.EasyExcel;
|
||||||
|
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
|
||||||
|
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
|
||||||
import com.ruoyi.common.config.RuoYiConfig;
|
import com.ruoyi.common.config.RuoYiConfig;
|
||||||
import com.ruoyi.common.config.flow.ProcessConfig;
|
import com.ruoyi.common.config.flow.ProcessConfig;
|
||||||
import com.ruoyi.common.enums.ApproveStatusEnum;
|
import com.ruoyi.common.enums.ApproveStatusEnum;
|
||||||
import com.ruoyi.common.utils.DateUtils;
|
import com.ruoyi.common.utils.DateUtils;
|
||||||
|
import com.ruoyi.common.utils.DictUtils;
|
||||||
import com.ruoyi.common.utils.ShiroUtils;
|
import com.ruoyi.common.utils.ShiroUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
|
||||||
import com.ruoyi.common.utils.file.FileUploadUtils;
|
import com.ruoyi.common.utils.file.FileUploadUtils;
|
||||||
|
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||||
import com.ruoyi.sip.domain.*;
|
import com.ruoyi.sip.domain.*;
|
||||||
import com.ruoyi.sip.domain.dto.InvoiceProductDto;
|
import com.ruoyi.sip.domain.dto.InvoiceProductDto;
|
||||||
import com.ruoyi.sip.domain.dto.ReceiptDetailDTO;
|
import com.ruoyi.sip.domain.dto.ReceiptDetailDTO;
|
||||||
|
import com.ruoyi.sip.dto.InvoiceDetailItemExcelDto;
|
||||||
import com.ruoyi.sip.dto.WriteOffInvoiceRequestDto;
|
import com.ruoyi.sip.dto.WriteOffInvoiceRequestDto;
|
||||||
|
import com.ruoyi.sip.dto.inventory.InventoryDeliveryDetailExcelDto;
|
||||||
import com.ruoyi.sip.flowable.domain.Todo;
|
import com.ruoyi.sip.flowable.domain.Todo;
|
||||||
import com.ruoyi.sip.service.*;
|
import com.ruoyi.sip.service.*;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.flowable.engine.runtime.ProcessInstance;
|
import org.flowable.engine.runtime.ProcessInstance;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
@ -46,6 +55,8 @@ import com.ruoyi.sip.flowable.service.TodoService;
|
||||||
* @date 2025-12-22
|
* @date 2025-12-22
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@Slf4j
|
||||||
public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCommonTemplate
|
public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCommonTemplate
|
||||||
{
|
{
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|
@ -228,7 +239,8 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
|
||||||
|
|
||||||
}
|
}
|
||||||
existBill.setActualInvoiceTime(DateUtils.getNowDate());
|
existBill.setActualInvoiceTime(DateUtils.getNowDate());
|
||||||
existBill.setInvoiceStatus(OmsInvoiceBill.InvoiceStatusEnum.INVOICE.getCode());
|
existBill.setInvoiceStatus(existBill.getInvoiceBillType().equals(OmsInvoiceBill.InvoiceBillTypeEnum.FROM_RECEIVABLE.getCode())?
|
||||||
|
OmsInvoiceBill.InvoiceStatusEnum.INVOICE.getCode():OmsInvoiceBill.InvoiceStatusEnum.RED_RUSH.getCode());
|
||||||
existBill.setInvoicePriceWithTax(bill.getInvoicePriceWithTax());
|
existBill.setInvoicePriceWithTax(bill.getInvoicePriceWithTax());
|
||||||
existBill.setInvoicePriceWithoutTax(bill.getInvoicePriceWithoutTax());
|
existBill.setInvoicePriceWithoutTax(bill.getInvoicePriceWithoutTax());
|
||||||
existBill.setInvoiceType(bill.getInvoiceType());
|
existBill.setInvoiceType(bill.getInvoiceType());
|
||||||
|
|
@ -299,8 +311,8 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public AjaxResult applyRefund(Long id) {
|
public AjaxResult applyRefund(OmsInvoiceBill omsInvoiceBill) {
|
||||||
OmsInvoiceBill originalBill = selectOmsInvoiceBillById(id);
|
OmsInvoiceBill originalBill = selectOmsInvoiceBillById(omsInvoiceBill.getId());
|
||||||
if (originalBill == null) {
|
if (originalBill == null) {
|
||||||
return AjaxResult.error("开票单不存在");
|
return AjaxResult.error("开票单不存在");
|
||||||
}
|
}
|
||||||
|
|
@ -328,9 +340,9 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
|
||||||
refundBill.setInvoicePriceWithTax(originalBill.getInvoicePriceWithTax().negate());
|
refundBill.setInvoicePriceWithTax(originalBill.getInvoicePriceWithTax().negate());
|
||||||
refundBill.setInvoicePriceWithoutTax(originalBill.getInvoicePriceWithoutTax().negate());
|
refundBill.setInvoicePriceWithoutTax(originalBill.getInvoicePriceWithoutTax().negate());
|
||||||
refundBill.setTaxRate(originalBill.getTaxRate());
|
refundBill.setTaxRate(originalBill.getTaxRate());
|
||||||
refundBill.setApproveStatus(ApproveStatusEnum.WAIT_COMMIT.getCode());
|
refundBill.setApproveStatus(ApproveStatusEnum.WAIT_APPROVE.getCode());
|
||||||
refundBill.setInvoiceBillType(OmsInvoiceBill.InvoiceBillTypeEnum.RED_RUSH.getCode());
|
refundBill.setInvoiceBillType(OmsInvoiceBill.InvoiceBillTypeEnum.RED_RUSH.getCode());
|
||||||
refundBill.setInvoiceStatus(OmsInvoiceBill.InvoiceStatusEnum.INVOICE.getCode());
|
refundBill.setInvoiceStatus(OmsInvoiceBill.InvoiceStatusEnum.WAIT_RED_RUSH.getCode());
|
||||||
refundBill.setRefundStatus(OmsInvoiceBill.RefundStatusEnum.REFUNDED.getCode());
|
refundBill.setRefundStatus(OmsInvoiceBill.RefundStatusEnum.REFUNDED.getCode());
|
||||||
|
|
||||||
refundBill.setBuyerName(originalBill.getBuyerName());
|
refundBill.setBuyerName(originalBill.getBuyerName());
|
||||||
|
|
@ -352,11 +364,22 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
|
||||||
|
|
||||||
// 更新原单据的红冲状态
|
// 更新原单据的红冲状态
|
||||||
originalBill.setRefundStatus(OmsInvoiceBill.RefundStatusEnum.REFUNDED.getCode());
|
originalBill.setRefundStatus(OmsInvoiceBill.RefundStatusEnum.REFUNDED.getCode());
|
||||||
|
originalBill.setUpdateTime(DateUtils.getNowDate());
|
||||||
updateOmsInvoiceBill(originalBill);
|
updateOmsInvoiceBill(originalBill);
|
||||||
|
|
||||||
//创建开票明细
|
//创建开票明细
|
||||||
detailService.applyRefund(originalBill.getInvoiceBillCode(), refundBill.getInvoiceBillCode());
|
detailService.applyRefund(originalBill.getInvoiceBillCode(), refundBill.getInvoiceBillCode());
|
||||||
|
for (OmsReceivableInvoiceDetailItem omsReceivableInvoiceDetailItem : omsInvoiceBill.getDetailItemList()) {
|
||||||
|
omsReceivableInvoiceDetailItem.setId(null);
|
||||||
|
omsReceivableInvoiceDetailItem.setInvoiceBillCode(refundBill.getInvoiceBillCode());
|
||||||
|
}
|
||||||
|
detailItemService.saveBatch(omsInvoiceBill.getDetailItemList());
|
||||||
|
todoService.startProcessDeleteBefore(refundBill.getInvoiceBillCode(), refundBill.getInvoiceBillCode()
|
||||||
|
, new HashMap<String, Object>() {{
|
||||||
|
put("applyUserName", ShiroUtils.getSysUser().getUserName());
|
||||||
|
put("applyUser", ShiroUtils.getUserId());
|
||||||
|
}}
|
||||||
|
, processConfig.getDefinition().getFinanceInvoiceRefound());
|
||||||
|
|
||||||
return AjaxResult.success("红冲申请已提交");
|
return AjaxResult.success("红冲申请已提交");
|
||||||
}
|
}
|
||||||
|
|
@ -586,6 +609,96 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AjaxResult exportItem(String code) {
|
||||||
|
try {
|
||||||
|
// 获取项目信息列表
|
||||||
|
List<InvoiceDetailItemExcelDto> list = detailItemService.exportItem(code);
|
||||||
|
|
||||||
|
|
||||||
|
// 构建 Excel 表头和数据
|
||||||
|
List<List<String>> header = buildExcelHeader();
|
||||||
|
List<List<String>> data = buildExcelData(list);
|
||||||
|
|
||||||
|
// 导出 Excel 文件
|
||||||
|
return AjaxResult.success(writeExcelToFile(header, data));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("导出项目信息失败", e);
|
||||||
|
throw new ServiceException("导出项目信息失败,请稍后重试");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<List<String>> buildExcelData(List<InvoiceDetailItemExcelDto> list) {
|
||||||
|
List<List<String>> dataList = new ArrayList<>();
|
||||||
|
AtomicInteger integer=new AtomicInteger(1);
|
||||||
|
BigDecimal reduce = list.stream().map(InvoiceDetailItemExcelDto::getAllPrice).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
for (InvoiceDetailItemExcelDto item : list) {
|
||||||
|
List<String> row = new ArrayList<>();
|
||||||
|
row.add(String.valueOf(integer.getAndIncrement()));
|
||||||
|
row.add(item.getBuyerName());
|
||||||
|
row.add(item.getBuyerCreditCode());
|
||||||
|
row.add(item.getBuyerAddress());
|
||||||
|
row.add("开户行:"+item.getBuyerBank()+"\n"+"账号:"+item.getBuyerBankAccount());
|
||||||
|
row.add("");
|
||||||
|
row.add(item.getProductName());
|
||||||
|
row.add(item.getProductModel());
|
||||||
|
row.add(item.getUnit());
|
||||||
|
row.add(String.valueOf(item.getQuantity()));
|
||||||
|
row.add(String.valueOf(item.getPrice()));
|
||||||
|
row.add(String.valueOf(item.getAllPrice()));
|
||||||
|
row.add(String.valueOf(item.getTaxRate()));
|
||||||
|
row.add(String.valueOf(reduce));
|
||||||
|
row.add(DictUtils.getDictLabel("finance_invoice_type",item.getInvoiceType()));
|
||||||
|
row.add(item.getRemark());
|
||||||
|
dataList.add(row);
|
||||||
|
}
|
||||||
|
return dataList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<List<String>> buildExcelHeader() {
|
||||||
|
|
||||||
|
List<List<String>> headerList = new ArrayList<>();
|
||||||
|
headerList.add(Collections.singletonList("序号"));
|
||||||
|
headerList.add(Collections.singletonList("购方名称"));
|
||||||
|
headerList.add(Collections.singletonList("购方税号"));
|
||||||
|
headerList.add(Collections.singletonList("购方地址电话"));
|
||||||
|
headerList.add(Collections.singletonList("购方银行帐号"));
|
||||||
|
headerList.add(Collections.singletonList("税收编码"));
|
||||||
|
headerList.add(Collections.singletonList("产品名称"));
|
||||||
|
headerList.add(Collections.singletonList("规格"));
|
||||||
|
headerList.add(Collections.singletonList("计量单位"));
|
||||||
|
headerList.add(Collections.singletonList("数量"));
|
||||||
|
headerList.add(Collections.singletonList("单价(含税)"));
|
||||||
|
headerList.add(Collections.singletonList("金额(含税)"));
|
||||||
|
headerList.add(Collections.singletonList("税率"));
|
||||||
|
headerList.add(Collections.singletonList("合计金额(含税)"));
|
||||||
|
headerList.add(Collections.singletonList("票据类型"));
|
||||||
|
headerList.add(Collections.singletonList("备注"));
|
||||||
|
return headerList;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String writeExcelToFile(List<List<String>> header, List<List<String>> data) {
|
||||||
|
ExcelUtil<ProjectInfo> util = new ExcelUtil<>(ProjectInfo.class);
|
||||||
|
String fileName = util.encodingFilename("电子发票-购买方公司信息");
|
||||||
|
String filePath = util.getAbsoluteFile(fileName);
|
||||||
|
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
|
||||||
|
contentWriteCellStyle.setWrapped(true);
|
||||||
|
// 创建工作簿并写入数据
|
||||||
|
EasyExcel.write(filePath).head(header)
|
||||||
|
.sheet("发票信息")
|
||||||
|
// 注册自定义列宽策略
|
||||||
|
.registerWriteHandler(new ProjectInfoServiceImpl.CustomColumnWidthStyleStrategy())
|
||||||
|
// 注册自动换行
|
||||||
|
.registerWriteHandler(new HorizontalCellStyleStrategy(null, contentWriteCellStyle))
|
||||||
|
.doWrite(data);
|
||||||
|
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object todoDetail(String businessKey, String processKey, String todoId) {
|
public Object todoDetail(String businessKey, String processKey, String todoId) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,18 @@
|
||||||
package com.ruoyi.sip.service.impl;
|
package com.ruoyi.sip.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import com.ruoyi.common.utils.ShiroUtils;
|
||||||
|
import com.ruoyi.sip.domain.OmsReceivableInvoiceDetail;
|
||||||
import com.ruoyi.sip.domain.OmsReceivableInvoiceDetailItem;
|
import com.ruoyi.sip.domain.OmsReceivableInvoiceDetailItem;
|
||||||
|
import com.ruoyi.sip.dto.InvoiceDetailItemExcelDto;
|
||||||
import com.ruoyi.sip.mapper.OmsReceivableInvoiceDetailItemMapper;
|
import com.ruoyi.sip.mapper.OmsReceivableInvoiceDetailItemMapper;
|
||||||
import com.ruoyi.sip.service.IOmsReceivableInvoiceDetailItemService;
|
import com.ruoyi.sip.service.IOmsReceivableInvoiceDetailItemService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
@ -78,6 +84,11 @@ public class OmsReceivableInvoiceDetailItemServiceImpl implements IOmsReceivable
|
||||||
return omsReceivableInvoiceDetailItemMapper.batchRemove(ids);
|
return omsReceivableInvoiceDetailItemMapper.batchRemove(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<InvoiceDetailItemExcelDto> exportItem(String code) {
|
||||||
|
return omsReceivableInvoiceDetailItemMapper.exportItem(code);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -678,7 +678,7 @@ public class ProjectInfoServiceImpl implements IProjectInfoService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 自定义列宽策略类
|
// 自定义列宽策略类
|
||||||
private static class CustomColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {
|
public static class CustomColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,31 @@
|
||||||
FROM oms_receivable_invoice_detail_item
|
FROM oms_receivable_invoice_detail_item
|
||||||
WHERE id = #{id}
|
WHERE id = #{id}
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
|
</select>
|
||||||
|
<select id="exportItem" resultType="com.ruoyi.sip.dto.InvoiceDetailItemExcelDto">
|
||||||
|
|
||||||
|
SELECT t1.id,
|
||||||
|
t1. invoice_bill_code,
|
||||||
|
t1. project_name,
|
||||||
|
t1. order_code,
|
||||||
|
t1. product_code,
|
||||||
|
t1.product_name,
|
||||||
|
t1. product_model,
|
||||||
|
t1. quantity,
|
||||||
|
t1. price,
|
||||||
|
t1. unit,
|
||||||
|
t1.all_price,
|
||||||
|
t1.tax_amount,
|
||||||
|
t1.tax_rate,
|
||||||
|
t2.buyer_bank,
|
||||||
|
t2.buyer_name,t2.buyer_credit_code,t2.buyer_bank_account,t2.invoice_type,t3.address as buyer_address,t2.remark
|
||||||
|
FROM oms_receivable_invoice_detail_item t1
|
||||||
|
left join oms_invoice_bill t2 ON t1.invoice_bill_code=t2.invoice_bill_code
|
||||||
|
left join partner_info t3 on t2.partner_code=t3.partner_code
|
||||||
|
where t1.invoice_bill_code=#{code}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -560,7 +560,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
seller_bank_account = #{sellerBankAccount},
|
seller_bank_account = #{sellerBankAccount},
|
||||||
approve_status=#{approveStatus},
|
approve_status=#{approveStatus},
|
||||||
invoice_type=#{invoiceType},
|
invoice_type=#{invoiceType},
|
||||||
remark=#{remark}
|
remark=#{remark},
|
||||||
|
update_time=#{updateTime}
|
||||||
where invoice_bill_code = #{invoiceBillCode}
|
where invoice_bill_code = #{invoiceBillCode}
|
||||||
|
|
||||||
</update>
|
</update>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue