feat(finance): 新增收票审批功能模块

- 新增收票待审批与已审批列表查询接口
- 实现收票审批与驳回流程处理逻辑
- 添加收票单详情查看及附件预览下载功能
- 配置收票审批相关路由与页面组件
- 完善收票单据明细展示与数据字典支持
- 优化附件查询SQL关联创建人姓名字段
- 修复流程定义中财务票据退款键名拼写错误
- 调整付款单据查询逻辑以适配指定流程KEY筛选
- 更新实体类增加审批相关字段支持动态查询
- 补充Vue页面样式与交互细节提升用户体验
dev_1.0.0
chenhao 2025-12-16 15:45:14 +08:00
parent 56d79e96b6
commit 7c46ae5db4
18 changed files with 801 additions and 19 deletions

View File

@ -0,0 +1,36 @@
import request from '@/utils/request'
// 查询收票待审批列表
export function listInvoiceReceiptApprove(query) {
return request({
url: '/finance/ticket/approve/list',
method: 'post',
data: query
})
}
// 查询收票已审批列表
export function listInvoiceReceiptApproved(query) {
return request({
url: '/finance/ticket/approved/list',
method: 'post',
data: query
})
}
// 查询收票详情
export function getInvoiceReceipt(id) {
return request({
url: '/finance/ticket/' + id,
method: 'get'
})
}
// 查询收票附件
export function getInvoiceReceiptAttachments(id,params) {
return request({
url: '/finance/ticket/attachment/' + id,
method: 'get',
params
})
}

View File

@ -0,0 +1,151 @@
<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="receiptNo">
<el-input v-model="queryParams.receiptNo" placeholder="请输入收票编号" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="供应商" prop="vendorName">
<el-input v-model="queryParams.vendorName" 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>
<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="invoiceReceiptList">
<el-table-column label="序号" type="index" width="50" align="center" />
<el-table-column label="收票编号" align="center" prop="receiptBillCode" />
<el-table-column label="供应商" align="center" prop="vendorName" />
<el-table-column label="项目名称" align="center" prop="projectName" />
<el-table-column label="金额" align="center" prop="totalPriceWithTax" />
<el-table-column label="登记人" align="center" prop="createUserName" />
<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;">
<ApproveLayout title="收票单详情">
<invoice-receipt-detail :data="form"></invoice-receipt-detail>
<template #footer>
<span>收票编号: {{ form.receiptBillCode }}</span>
</template>
</ApproveLayout>
<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 { listInvoiceReceiptApproved, getInvoiceReceipt } from "@/api/finance/invoiceReceipt";
import { listCompletedFlows } from "@/api/flow";
import InvoiceReceiptDetail from "../components/InvoiceReceiptDetail";
import ApproveLayout from "@/views/approve/ApproveLayout";
export default {
name: "InvoiceReceiptApproved",
components: { InvoiceReceiptDetail, ApproveLayout },
data() {
return {
loading: true,
showSearch: true,
total: 0,
invoiceReceiptList: [],
queryParams: {
pageNum: 1,
pageSize: 10,
receiptNo: null,
vendorName: null,
processKey: 'fianance_ticket',
projectName: null
},
detailDialogVisible: false,
detailLoading: false,
form: {},
approveLogs: [],
currentInvoiceReceiptId: null
};
},
created() {
this.getList();
},
methods: {
getList() {
this.loading = true;
listInvoiceReceiptApproved(this.queryParams).then(response => {
this.invoiceReceiptList = response.rows;
this.total = response.total;
this.loading = false;
});
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
handleView(row) {
this.form = {};
this.approveLogs = [];
this.currentInvoiceReceiptId = row.id;
this.detailLoading = true;
this.detailDialogVisible = true;
getInvoiceReceipt(this.currentInvoiceReceiptId).then(response => {
this.form = response.data;
this.loadApproveHistory(this.form.receiptBillCode);
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] || '提交审批';
}
}
};
</script>
<style scoped>
.process-container {
padding: 10px;
}
</style>

View File

@ -0,0 +1,136 @@
<template>
<div class="invoice-receipt-detail">
<el-descriptions title="收票单信息" :column="3" border>
<el-descriptions-item label="收票单编号">{{ data.ticketBillCode }}</el-descriptions-item>
<el-descriptions-item label="供应商名称">{{ data.vendorName }}</el-descriptions-item>
<el-descriptions-item label="发票类型">
<dict-tag :options="dict.type.finance_invoice_type" :value="data.ticketType"/>
</el-descriptions-item>
<el-descriptions-item label="含税总价">{{ data.totalPriceWithTax }}</el-descriptions-item>
<el-descriptions-item label="未税总价">{{ data.totalPriceWithoutTax }}</el-descriptions-item>
<el-descriptions-item label="税额">{{ data.taxAmount }}</el-descriptions-item>
<el-descriptions-item label="制造商开票时间">{{ data.vendorTicketTime }}</el-descriptions-item>
<el-descriptions-item label="备注" :span="3">{{ data.remark }}</el-descriptions-item>
</el-descriptions>
<div class="section" style="margin-top: 20px;" v-show="data.detailList && data.detailList.length>0">
<div class="el-descriptions__title">发票明细列表</div>
<el-table :data="data.detailList" border style="width: 100%; margin-top: 10px;">
<el-table-column type="index" label="序号" width="50" align="center"></el-table-column>
<el-table-column prop="payableBillCode" 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"></el-table-column>
<el-table-column prop="paymentAmount" label="本次收票金额" align="center"></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 { getInvoiceReceiptAttachments } from "@/api/finance/invoiceReceipt";
import request from '@/utils/request';
export default {
name: "InvoiceReceiptDetail",
props: {
data: {
type: Object,
required: true,
default: () => ({})
}
},
dicts: ['finance_invoice_type', 'product_type'],
data() {
return {
attachments: [],
pdfPreviewVisible: false,
currentPdfUrl: '',
imagePreviewVisible: false,
currentImageUrl: ''
};
},
watch: {
'data.id': {
handler(val) {
if (val) {
this.fetchAttachments(val);
}
},
immediate: true
}
},
methods: {
fetchAttachments(id) {
getInvoiceReceiptAttachments(id,{ type: 'ticket' }).then(response => {
this.attachments = (response.data || []).filter(item => item.delFlag !== '2');
});
},
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) {
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-receipt-detail {
margin-bottom: 20px;
}
</style>

View File

@ -0,0 +1,238 @@
<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="receiptNo">
<el-input v-model="queryParams.receiptNo" placeholder="请输入收票编号" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="供应商" prop="vendorName">
<el-input v-model="queryParams.vendorName" 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>
<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="invoiceReceiptList">
<el-table-column label="序号" type="index" width="50" align="center" />
<el-table-column label="收票编号" align="center" prop="ticketBillCode" />
<el-table-column label="供应商" align="center" prop="vendorName" />
<!-- <el-table-column label="项目名称" align="center" prop="projectName" />-->
<el-table-column label="金额" align="center" prop="totalPriceWithTax" />
<!-- <el-table-column label="登记人" align="center" prop="createUserName" />-->
<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;">
<ApproveLayout title="收票单详情">
<invoice-receipt-detail :data="form"></invoice-receipt-detail>
<template #footer>
<span>收票编号: {{ form.ticketBillCode }}</span>
</template>
</ApproveLayout>
<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 { listInvoiceReceiptApprove, getInvoiceReceipt } from "@/api/finance/invoiceReceipt";
import { approveTask, listCompletedFlows } from "@/api/flow";
import InvoiceReceiptDetail from "./components/InvoiceReceiptDetail";
import ApproveLayout from "@/views/approve/ApproveLayout";
export default {
name: "InvoiceReceiptApprove",
components: { InvoiceReceiptDetail, ApproveLayout },
data() {
return {
loading: true,
showSearch: true,
total: 0,
invoiceReceiptList: [],
queryParams: {
pageNum: 1,
pageSize: 10,
receiptNo: null,
vendorName: null,
processKey: 'fianance_ticket',
projectName: null
},
detailDialogVisible: false,
detailLoading: false,
form: {},
approveLogs: [],
opinionDialogVisible: false,
confirmDialogTitle: '',
currentApproveType: '',
opinionForm: {
approveOpinion: ''
},
opinionRules: {
approveOpinion: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
},
processKey: 'fianance_ticket',
taskId: null,
currentInvoiceReceiptId: null
};
},
created() {
this.getList();
},
methods: {
getList() {
this.loading = true;
listInvoiceReceiptApprove(this.queryParams).then(response => {
this.invoiceReceiptList = response.rows;
this.total = response.total;
this.loading = false;
});
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
toApproved() {
this.$router.push( '/approve/invoiceReceiptLog' )
},
handleApprove(row) {
this.resetDetailForm();
this.currentInvoiceReceiptId = row.id;
this.taskId = row.taskId;
this.detailLoading = true;
this.detailDialogVisible = true;
getInvoiceReceipt(this.currentInvoiceReceiptId).then(response => {
this.form = response.data;
this.loadApproveHistory(this.form.receiptBillCode);
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.ticketBillCode,
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] || '提交审批';
}
}
};
</script>
<style scoped>
.process-container {
padding: 10px;
}
</style>

View File

@ -25,15 +25,40 @@
<el-table-column type="index" label="序号" width="50" align="center"></el-table-column> <el-table-column type="index" label="序号" width="50" align="center"></el-table-column>
<el-table-column prop="payableBillCode" label="采购应付单编号" align="center"></el-table-column> <el-table-column prop="payableBillCode" label="采购应付单编号" align="center"></el-table-column>
<el-table-column prop="projectName" label="项目名称" align="center"></el-table-column> <el-table-column prop="projectName" label="项目名称" align="center"></el-table-column>
<!-- Note: Product Type is requested but not present in reference DetailDrawer.vue. Omitting for safety or need to ask. -->
<el-table-column prop="totalPriceWithTax" label="含税总价" align="center"></el-table-column> <el-table-column prop="totalPriceWithTax" label="含税总价" align="center"></el-table-column>
<el-table-column prop="paymentAmount" label="本次付款金额" align="center"></el-table-column> <el-table-column prop="paymentAmount" label="本次付款金额" align="center"></el-table-column>
</el-table> </el-table>
</div> </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> </div>
</template> </template>
<script> <script>
import { getPaymentAttachments } from "@/api/finance/payment";
import request from '@/utils/request';
export default { export default {
name: "PaymentDetail", name: "PaymentDetail",
props: { props: {
@ -43,7 +68,68 @@ export default {
default: () => ({}) default: () => ({})
} }
}, },
dicts: ['payment_bill_type', 'payment_method'] dicts: ['payment_bill_type', 'payment_method'],
data() {
return {
attachments: [],
pdfPreviewVisible: false,
currentPdfUrl: '',
imagePreviewVisible: false,
currentImageUrl: ''
};
},
watch: {
'data.id': {
handler(val) {
if (val) {
this.fetchAttachments(val);
}
},
immediate: true
}
},
methods: {
fetchAttachments(id) {
getPaymentAttachments(id).then(response => {
// Filter out voided (delFlag == '2')
this.attachments = (response.data || []).filter(item => item.delFlag !== '2');
});
},
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)) {
// PDF Preview logic
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 {
// Image Preview
this.currentImageUrl = this.getImageUrl(row.filePath);
this.imagePreviewVisible = true;
}
},
handleDownload(row) {
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> </script>
@ -51,4 +137,4 @@ export default {
.payment-detail { .payment-detail {
margin-bottom: 20px; margin-bottom: 20px;
} }
</style> </style>

View File

@ -148,6 +148,7 @@ process:
financePayment: finance_payment financePayment: finance_payment
financeRefund: finance_refund financeRefund: finance_refund
fiananceTicket: fianance_ticket fiananceTicket: fianance_ticket
financeTicketRefound: finance_ticket_refound
#业务执行实例bean name ,可以按审批节点配置 业务审批回调方法处理业务逻辑. key 为流程节点主键ID value 要执行的业务方法名称,不配置则默认调用TodoCommonTemplate.todoApproveCallback #业务执行实例bean name ,可以按审批节点配置 业务审批回调方法处理业务逻辑. key 为流程节点主键ID value 要执行的业务方法名称,不配置则默认调用TodoCommonTemplate.todoApproveCallback
instance: instance:
@ -163,6 +164,8 @@ process:
beanName: omsPaymentBillServiceImpl beanName: omsPaymentBillServiceImpl
fiananceTicket: fiananceTicket:
beanName: omsTicketBillServiceImpl beanName: omsTicketBillServiceImpl
financeTicketRefound:
beanName: omsTicketBillServiceImpl
unis: unis:
inventory: inventory:
allAuthRole: 103,101 allAuthRole: 103,101

View File

@ -78,7 +78,7 @@ public class OmsPaymentBillController extends BaseController
List<OmsPaymentBill> list = omsPaymentBillService.listApprove(omsPaymentBill); List<OmsPaymentBill> list = omsPaymentBillService.listApprove(omsPaymentBill);
clearPage(); clearPage();
todoService.fillApproveNode(list, todoService.fillApproveNode(list,
Arrays.asList(processConfig.getDefinition().getFinancePayment(), processConfig.getDefinition().getFinanceRefund()) Collections.singletonList(omsPaymentBill.getProcessKey())
, OmsPaymentBill::getPaymentBillCode, (a, b) -> a.setApproveNode(b.get(a.getPaymentBillCode()))); , OmsPaymentBill::getPaymentBillCode, (a, b) -> a.setApproveNode(b.get(a.getPaymentBillCode())));
return getDataTable(list); return getDataTable(list);
} }
@ -91,7 +91,7 @@ public class OmsPaymentBillController extends BaseController
List<OmsPaymentBill> list = omsPaymentBillService.listApproved(omsPaymentBill); List<OmsPaymentBill> list = omsPaymentBillService.listApproved(omsPaymentBill);
clearPage(); clearPage();
todoService.fillApproveNode(list, todoService.fillApproveNode(list,
Arrays.asList(processConfig.getDefinition().getFinancePayment(), processConfig.getDefinition().getFinanceRefund()) Collections.singletonList(omsPaymentBill.getProcessKey())
, OmsPaymentBill::getPaymentBillCode, (a, b) -> a.setApproveNode(b.get(a.getPaymentBillCode()))); , OmsPaymentBill::getPaymentBillCode, (a, b) -> a.setApproveNode(b.get(a.getPaymentBillCode())));
return getDataTable(list); return getDataTable(list);
} }

View File

@ -1,10 +1,13 @@
package com.ruoyi.sip.controller; package com.ruoyi.sip.controller;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.config.flow.ProcessConfig;
import com.ruoyi.sip.domain.OmsFinAttachment; import com.ruoyi.sip.domain.OmsFinAttachment;
import com.ruoyi.sip.flowable.service.TodoService;
import com.ruoyi.sip.service.IOmsFinAttachmentService; import com.ruoyi.sip.service.IOmsFinAttachmentService;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -33,6 +36,10 @@ public class OmsTicketBillController extends BaseController
private IOmsTicketBillService omsTicketBillService; private IOmsTicketBillService omsTicketBillService;
@Autowired @Autowired
private IOmsFinAttachmentService omsFinAttachmentService; private IOmsFinAttachmentService omsFinAttachmentService;
@Autowired
private TodoService todoService;
@Autowired
private ProcessConfig processConfig;
/** /**
* *
*/ */
@ -42,6 +49,32 @@ private IOmsFinAttachmentService omsFinAttachmentService;
{ {
startPage(); startPage();
List<OmsTicketBill> list = omsTicketBillService.selectOmsTicketBillList(omsTicketBill); List<OmsTicketBill> list = omsTicketBillService.selectOmsTicketBillList(omsTicketBill);
clearPage();
todoService.fillApproveNode(list,
Arrays.asList(processConfig.getDefinition().getFiananceTicket(), processConfig.getDefinition().getFinanceTicketRefound())
, OmsTicketBill::getTicketBillCode, (a, b) -> a.setApproveNode(b.get(a.getTicketBillCode())));
return getDataTable(list);
}
@PostMapping("/approve/list")
public TableDataInfo listApprove(@RequestBody OmsTicketBill omsTicketBill) {
startPage();
List<OmsTicketBill> list = omsTicketBillService.listApprove(omsTicketBill);
clearPage();
todoService.fillApproveNode(list,
Arrays.asList(omsTicketBill.getProcessKey())
, OmsTicketBill::getTicketBillCode, (a, b) -> a.setApproveNode(b.get(a.getTicketBillCode())));
return getDataTable(list);
}
@PostMapping("/approved/list")
public TableDataInfo listApproved(@RequestBody OmsTicketBill omsTicketBill) {
startPage();
List<OmsTicketBill> list = omsTicketBillService.listApproved(omsTicketBill);
clearPage();
todoService.fillApproveNode(list,
Arrays.asList(processConfig.getDefinition().getFiananceTicket(), processConfig.getDefinition().getFinanceTicketRefound())
, OmsTicketBill::getTicketBillCode, (a, b) -> a.setApproveNode(b.get(a.getTicketBillCode())));
return getDataTable(list); return getDataTable(list);
} }

View File

@ -50,6 +50,7 @@ public class OmsFinAttachment extends BaseEntity
/** 删除标志0代表存在 2代表删除 */ /** 删除标志0代表存在 2代表删除 */
private String delFlag; private String delFlag;
private String createByName;
@Getter @Getter
public enum RelatedBillTypeEnum { public enum RelatedBillTypeEnum {

View File

@ -108,7 +108,12 @@ public class OmsTicketBill extends BaseEntity
/** 关联的原始收票单ID */ /** 关联的原始收票单ID */
private Long originalBillId; private Long originalBillId;
private List<PaymentBillPayableDetailDTO> detailList; private List<PaymentBillPayableDetailDTO> detailList;
private Long approveUser;
private Date applyTime;
private Date todoApproveTime;
private String processKey;
private String todoId;
private String taskId;
public BigDecimal getTaxAmount() { public BigDecimal getTaxAmount() {
if (null != totalPriceWithTax && null != totalPriceWithoutTax){ if (null != totalPriceWithTax && null != totalPriceWithoutTax){

View File

@ -18,6 +18,7 @@ public class PaymentBillPayableDetailDTO {
/** 项目名称 */ /** 项目名称 */
private String projectName; private String projectName;
private String productType;
/** 采购应付单编号 */ /** 采购应付单编号 */
private String payableBillCode; private String payableBillCode;

View File

@ -2,6 +2,7 @@ package com.ruoyi.sip.mapper;
import java.util.List; import java.util.List;
import com.ruoyi.sip.domain.OmsTicketBill; import com.ruoyi.sip.domain.OmsTicketBill;
import org.apache.ibatis.annotations.Param;
/** /**
* Mapper * Mapper
@ -63,4 +64,5 @@ public interface OmsTicketBillMapper
void updateOmsTicketBillByCode(OmsTicketBill omsTicketBill); void updateOmsTicketBillByCode(OmsTicketBill omsTicketBill);
List<OmsTicketBill> listApprove(@Param("entity") OmsTicketBill omsTicketBill, @Param("tableName")String buTodo);
} }

View File

@ -67,4 +67,8 @@ public interface IOmsTicketBillService
AjaxResult applyRefund(Long id); AjaxResult applyRefund(Long id);
AjaxResult returnTicket(Long id); AjaxResult returnTicket(Long id);
List<OmsTicketBill> listApprove(OmsTicketBill omsTicketBill);
List<OmsTicketBill> listApproved(OmsTicketBill omsTicketBill);
} }

View File

@ -288,6 +288,18 @@ public class OmsTicketBillServiceImpl implements IOmsTicketBillService, TodoComm
} }
} }
@Override
public List<OmsTicketBill> listApprove(OmsTicketBill omsTicketBill) {
omsTicketBill.setApproveUser(ShiroUtils.getUserId());
return omsTicketBillMapper.listApprove(omsTicketBill, "bu_todo");
}
@Override
public List<OmsTicketBill> listApproved(OmsTicketBill omsTicketBill) {
omsTicketBill.setApproveUser(ShiroUtils.getUserId());
return omsTicketBillMapper.listApprove(omsTicketBill, "bu_todo_completed");
}
@Override @Override
public Object todoDetail(String businessKey, String processKey, String todoId) { public Object todoDetail(String businessKey, String processKey, String todoId) {

View File

@ -21,24 +21,28 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap> </resultMap>
<sql id="selectOmsFinAttachmentVo"> <sql id="selectOmsFinAttachmentVo">
select id, related_bill_id, related_bill_type, file_name, file_path, file_size, file_type, create_by, create_time, update_by, update_time, remark, del_flag from oms_fin_attachment select t1.id, t1.related_bill_id, t1.related_bill_type, t1.file_name, t1.file_path, t1.file_size, t1.file_type,
t1.create_by, t1.create_time, t1.update_by, t1.update_time, t1.remark, t1.del_flag
,t2.user_name as create_by_name
from oms_fin_attachment t1
left join sys_user t2 on t1.create_by=t2.user_id
</sql> </sql>
<select id="selectOmsFinAttachmentList" parameterType="OmsFinAttachment" resultMap="OmsFinAttachmentResult"> <select id="selectOmsFinAttachmentList" parameterType="OmsFinAttachment" resultMap="OmsFinAttachmentResult">
<include refid="selectOmsFinAttachmentVo"/> <include refid="selectOmsFinAttachmentVo"/>
<where> <where>
<if test="relatedBillId != null "> and related_bill_id = #{relatedBillId}</if> <if test="relatedBillId != null "> and t1.related_bill_id = #{relatedBillId}</if>
<if test="relatedBillIdList != null and relatedBillIdList.size>0 "> and related_bill_id <if test="relatedBillIdList != null and relatedBillIdList.size>0 "> and t1.related_bill_id
in <foreach item="item" index="index" collection="relatedBillIdList" separator="," open="(" close=")"> in <foreach item="item" index="index" collection="relatedBillIdList" separator="," open="(" close=")">
#{item} #{item}
</foreach> </foreach>
</if> </if>
<if test="relatedBillType != null and relatedBillType != ''"> and related_bill_type = #{relatedBillType}</if> <if test="relatedBillType != null and relatedBillType != ''"> and t1.related_bill_type = #{relatedBillType}</if>
<if test="fileName != null and fileName != ''"> and file_name like concat('%', #{fileName}, '%')</if> <if test="fileName != null and fileName != ''"> and t1.file_name like concat('%', #{fileName}, '%')</if>
<if test="filePath != null and filePath != ''"> and file_path = #{filePath}</if> <if test="filePath != null and filePath != ''"> and t1.file_path = #{filePath}</if>
<if test="fileSize != null "> and file_size = #{fileSize}</if> <if test="fileSize != null "> and t1.file_size = #{fileSize}</if>
<if test="fileType != null and fileType != ''"> and file_type = #{fileType}</if> <if test="fileType != null and fileType != ''"> and t1.file_type = #{fileType}</if>
<if test="delFlag != null and delFlag != ''"> and del_flag = #{delFlag}</if> <if test="delFlag != null and delFlag != ''"> and t1.del_flag = #{delFlag}</if>
</where> </where>
</select> </select>

View File

@ -342,15 +342,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
pb.bank_number, pb.bank_number,
pb.refund_status, pb.refund_status,
t2.vendor_name t2.vendor_name
,t5.user_name as hz_user_name
,t3.apply_time,t3.process_key,t3.todo_id,t3.task_id ,t3.apply_time,t3.process_key,t3.todo_id,t3.task_id
<if test="'bu_todo_completed'.equals(tableName)"> <if test="'bu_todo_completed'.equals(tableName)">
,t3.approve_time as todo_approve_time ,t3.approve_time as todo_approve_time
</if> </if>
from oms_payment_bill pb from oms_payment_bill pb
left join oms_vendor_info t2 on pb.vendor_code = t2.vendor_code left join oms_vendor_info t2 on pb.vendor_code = t2.vendor_code
left join project_order_info t4 on pb.order_code = t4.order_code
left join sys_user t5 on t5.user_id = t4.duty
inner join ${tableName} t3 on (t3.process_key in (#{entity.processKey}) and t3.approve_user=#{entity.approveUser} and t3.task_name!='商务' and t3.business_key=pb.payment_bill_code) inner join ${tableName} t3 on (t3.process_key in (#{entity.processKey}) and t3.approve_user=#{entity.approveUser} and t3.task_name!='商务' and t3.business_key=pb.payment_bill_code)
<where> <where>
<if test="entity.paymentBillCode != null and entity.paymentBillCode != ''"> and pb.payment_bill_code like concat('%', #{entity.paymentBillCode}, '%')</if> <if test="entity.paymentBillCode != null and entity.paymentBillCode != ''"> and pb.payment_bill_code like concat('%', #{entity.paymentBillCode}, '%')</if>

View File

@ -83,7 +83,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where id = #{id} where id = #{id}
</select> </select>
<select id="listByTickerCode" resultType="com.ruoyi.sip.domain.dto.PaymentBillPayableDetailDTO"> <select id="listByTickerCode" resultType="com.ruoyi.sip.domain.dto.PaymentBillPayableDetailDTO">
select t1.payment_amount, t2.payable_bill_code, t4.project_name, t4.project_code, t2.total_price_with_tax select t1.payment_amount, t2.payable_bill_code,t2.product_type, t4.project_name, t4.project_code, t2.total_price_with_tax
from (SELECT sum(payment_amount) payment_amount, from (SELECT sum(payment_amount) payment_amount,
payable_bill_id payable_bill_id
FROM oms_payable_ticket_detail FROM oms_payable_ticket_detail

View File

@ -406,5 +406,77 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
FROM oms_ticket_bill FROM oms_ticket_bill
WHERE ticket_bill_code LIKE CONCAT(#{codePrefix}, '%') WHERE ticket_bill_code LIKE CONCAT(#{codePrefix}, '%')
</select> </select>
<select id="listApprove" resultType="com.ruoyi.sip.domain.OmsTicketBill">
select t1.id, t1.ticket_bill_code, t1.ticket_type, t1.ticket_bill_type, t1.vendor_ticket_time, t1.ticket_time, t1.vendor_code,
t1.total_price_with_tax, t1.total_price_without_tax, t1.ticket_price_with_tax, t1.ticket_price_without_tax, t1.tax_rate, t1.create_by, t1.create_time, t1.update_by,
t1.update_time, t1.remark, t1.del_flag, t1.actual_ticket_time, t1.ticket_status, t1.approve_status, t1.approve_node, t1.approve_time, t1.refund_status
,t2.vendor_name
,t3.apply_time,t3.process_key,t3.todo_id,t3.task_id
<if test="'bu_todo_completed'.equals(tableName)">
,t3.approve_time as todo_approve_time
</if>
from oms_ticket_bill t1
left join oms_vendor_info t2 on t1.vendor_code=t2.vendor_code
inner join ${tableName} t3 on (t3.process_key in (#{entity.processKey}) and t3.approve_user=#{entity.approveUser} and t3.task_name!='商务' and t3.business_key=t1.ticket_bill_code)
<where>
<if test="entity.ticketBillCode != null and entity.ticketBillCode != ''">
and t1.ticket_bill_code = #{entity.ticketBillCode}
</if>
<if test="entity.ticketType != null and entity.ticketType != ''">
and t1.ticket_type = #{entity.ticketType}
</if>
<if test="entity.ticketBillType != null and entity.ticketBillType != ''">
and t1.ticket_bill_type = #{entity.ticketBillType}
</if>
<if test="entity.vendorCode != null and entity.vendorCode != ''">
and t1.vendor_code = #{entity.vendorCode}
</if>
<if test="entity.totalPriceWithTax != null">
and t1.total_price_with_tax = #{entity.totalPriceWithTax}
</if>
<if test="entity.totalPriceWithoutTax != null">
and t1.total_price_without_tax = #{entity.totalPriceWithoutTax}
</if>
<if test="entity.taxRate != null">
and t1.tax_rate = #{entity.taxRate}
</if>
<if test="entity.createBy != null and entity.createBy != ''">
and t1.create_by = #{entity.createBy}
</if>
<if test="entity.createTime != null">
and t1.create_time = #{entity.createTime}
</if>
<if test="entity.updateBy != null and entity.updateBy != ''">
and t1.update_by = #{entity.updateBy}
</if>
<if test="entity.updateTime != null">
and t1.update_time = #{entity.updateTime}
</if>
<if test="entity.remark != null and entity.remark != ''">
and t1.remark like concat('%', #{entity.remark}, '%')
</if>
<if test="entity.delFlag != null and entity.delFlag != ''">
and t1.del_flag = #{entity.delFlag}
</if>
<if test="entity.actualTicketTime != null">
and t1.actual_ticket_time = #{entity.actualTicketTime}
</if>
<if test="entity.ticketStatus != null and entity.ticketStatus != ''">
and t1.ticket_status = #{entity.ticketStatus}
</if>
<if test="entity.approveStatus != null and entity.approveStatus != ''">
and t1.approve_status = #{entity.approveStatus}
</if>
<if test="entity.approveNode != null and entity.approveNode != ''">
and t1.approve_node = #{entity.approveNode}
</if>
<if test="entity.approveTime != null">
and t1.approve_time = #{entity.approveTime}
</if>
<if test="entity.refundStatus != null and entity.refundStatus != ''">
and t1.refund_status = #{entity.refundStatus}
</if>
</where>
</select>
</mapper> </mapper>