feat(finance): 更新开票申请功能和审批流程

- 修改ApplyInvoice.vue中的表单字段映射,将projectName改为productName
- 为表格输入框添加禁用状态,当存在产品编码时不可编辑
- 更新表格列配置,将"产品型号"改为"规格型号",新增"单位"列
- 添加数值输入验证,限制数量字段只能输入数字和小数点
- 修正发票类型默认值从"-"改为"2"
- 将detailList改为detailItemList以保持数据结构一致性
- 在handleSubmit方法中添加表格明细校验逻辑
- 为发票详情页面添加PDF导出功能
- 创建新的开票审批历史页面receivableInvoice/approved/index.vue
- 创建新的开票审批页面receivableInvoice/index.vue,包含审批流程
- 更新发票列表页面的字段标签和查询条件
- 调整日期选择器格式为包含时间的datetimerange
- 隐藏实际收票时间筛选条件并调整列显示
- 更新按钮显示条件,仅在审批状态为0时显示申请开票
- 在InventoryOuter实体类中添加receivableBillCode字段
- 重构库存出库Mapper的查询语句,添加应收单编号关联查询
dev_1.0.1
chenhao 2025-12-29 20:21:28 +08:00
parent 5583bb0f11
commit f992b2b29e
28 changed files with 2049 additions and 167 deletions

View File

@ -5,7 +5,10 @@ import {tansParams} from "@/utils/ruoyi"
export function listInvoice(query) { export function listInvoice(query) {
return request({ return request({
url: '/finance/invoice/list', url: '/finance/invoice/list',
method: 'get', method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
params: query params: query
}) })
} }
@ -90,3 +93,35 @@ export function revokeInvoice(id) {
method: 'delete' method: 'delete'
}) })
} }
// 查询开票审批列表
export function listInvoiceApprove(query) {
return request({
url: '/finance/invoice/approve/list',
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: query
})
}
// 查询已审批开票列表
export function listInvoiceApproved(query) {
return request({
url: '/finance/invoice/approved/list',
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: query
})
}
// 查询开票单详细
export function getInvoiceDetail(id) {
return request({
url: '/finance/invoice/' + id,
method: 'get'
})
}

View File

@ -119,6 +119,11 @@ export const constantRoutes = [
component: () => import('@/views/approve/finance/receiptRefound/approved/index.vue'), component: () => import('@/views/approve/finance/receiptRefound/approved/index.vue'),
hidden: true hidden: true
}, },
{
path: 'receivableInvoiceLog',
component: () => import('@/views/approve/finance/receivableInvoice/approved/index.vue'),
hidden: true
},
] ]
}, },
{ {

View File

@ -63,6 +63,8 @@
<script> <script>
import request from '@/utils/request'; import request from '@/utils/request';
import {getInvoiceAttachments} from "@/api/finance/invoice";
import {getReceiptAttachments} from "@/api/finance/receipt";
export default { export default {
name: "ReceiptDetail", name: "ReceiptDetail",
@ -84,10 +86,21 @@ export default {
}; };
}, },
watch: { watch: {
'data.id': {
handler(val) {
if (val) {
this.fetchAttachments(val);
}
},
immediate: true
}
}, },
methods: { methods: {
fetchAttachments(id) {
getReceiptAttachments(id,"receipt").then(response => {
this.attachments = (response.data || []).filter(item => item.delFlag !== '2');
});
},
isPdf(filePath) { isPdf(filePath) {
return filePath && filePath.toLowerCase().endsWith('.pdf'); return filePath && filePath.toLowerCase().endsWith('.pdf');
}, },

View File

@ -0,0 +1,211 @@
<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" />
<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: "ReceivableInvoiceApproved",
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_approve',
},
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>

View File

@ -0,0 +1,131 @@
<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="含税总价(元)">{{ 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.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"></el-table-column>
<el-table-column prop="receiptAmount" 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 { 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: [],
pdfPreviewVisible: false,
currentPdfUrl: '',
imagePreviewVisible: false,
currentImageUrl: ''
};
},
watch: {
},
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) {
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>

View File

@ -0,0 +1,298 @@
<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" />
<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: "ReceivableInvoiceApprove",
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_approve',
},
dateRange: [],
detailDialogVisible: false,
detailLoading: false,
form: {},
approveLogs: [],
opinionDialogVisible: false,
confirmDialogTitle: '',
currentApproveType: '',
opinionForm: {
approveOpinion: ''
},
opinionRules: {
approveOpinion: [{ required: true, message: '审批意见不能为空', trigger: 'blur' }],
},
processKey: 'finance_invoice_approve',
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/receivableInvoiceLog')
},
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>

View File

@ -84,57 +84,70 @@
<!-- 3. 表格区域 --> <!-- 3. 表格区域 -->
<div class="items-table-container"> <div class="items-table-container">
<el-table <el-table
:data="form.detailList" :data="form.detailItemList"
border border
height="250"
class="invoice-table" class="invoice-table"
show-summary show-summary
:summary-method="getSummaries" :summary-method="getSummaries"
> >
<el-table-column label="项目名称" prop="projectName" align="center"> <el-table-column label="项目名称" prop="productName" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.projectName" size="mini" placeholder="请输入" class="no-border-input"/> <el-input v-model="scope.row.productName" size="mini" placeholder="请输入" class="no-border-input"
:disabled="!!scope.row.productCode"/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="产品型号" prop="productModel" align="center" width="120"> <el-table-column label="规格型号" prop="productModel" align="center" width="120">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.productModel" size="mini" placeholder="型号" class="no-border-input"/> <el-input v-model="scope.row.productModel" size="mini" placeholder="型号" class="no-border-input"
:disabled="!!scope.row.productCode"/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="单价" prop="unitPrice" align="center" width="100"> <el-table-column label="单位" prop="unit" align="center" width="60">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.unitPrice" size="mini" @input="calculateAmount(scope.row)" <el-input v-model="scope.row.unit" size="mini" placeholder="单位" class="no-border-input"/>
class="no-border-input"/>
</template> </template>
</el-table-column> </el-table-column>
<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" @input="calculateAmount(scope.row)" <el-input v-model="scope.row.quantity" size="mini" class="no-border-input"
class="no-border-input"/> oninput="value=value.replace(/[^\d.]/g,'')"
@input="calculateAmount(scope.row)"/>
</template>
</el-table-column>
<el-table-column label="单价" prop="unitPrice" align="center" width="100">
<template slot-scope="scope">
<el-input v-if="!scope.row.productCode" v-model="scope.row.unitPrice" size="mini" placeholder="单价"
class="no-border-input" @input="calculateAmount(scope.row)"/>
<span v-else>{{ scope.row.unitPrice }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="金额" prop="amount" align="center" width="100"> <el-table-column label="金额" prop="amount" align="center" width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ scope.row.amount }}</span> <el-input v-if="!scope.row.productCode" v-model="scope.row.amount" size="mini" placeholder="金额"
class="no-border-input" @input="calculateTax(scope.row)"/>
<span v-else>{{ scope.row.amount }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="税率%" prop="taxRate" align="center" width="80"> <el-table-column label="税率%" prop="taxRate" align="center" width="80">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.taxRate" size="mini" @input="calculateTax(scope.row)" <el-input v-if="!scope.row.productCode" v-model="scope.row.taxRate" size="mini" placeholder="税率"
class="no-border-input"/> class="no-border-input" @input="calculateTax(scope.row)"/>
<span v-else>{{ scope.row.taxRate }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="税额" prop="taxAmount" align="center" width="100"> <el-table-column label="税额" prop="taxAmount" align="center" width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ scope.row.taxAmount }}</span> <el-input v-if="!scope.row.productCode" v-model="scope.row.taxAmount" size="mini" placeholder="税额"
class="no-border-input"/>
<span v-else>{{ scope.row.taxAmount }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="60" align="center"> <el-table-column label="操作" width="60" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
<i class="el-icon-plus table-icon" @click="addDetailRow" <i class="el-icon-plus table-icon" @click="addDetailRow"
v-if="scope.$index === form.detailList.length - 1"></i> v-if="scope.$index === form.detailItemList.length - 1"></i>
<i class="el-icon-minus table-icon" @click="removeDetailRow(scope.$index)" <i class="el-icon-minus table-icon" @click="removeDetailRow(scope.$index)"
v-if="form.detailList.length > 1" style="margin-left:5px"></i> v-if="form.detailItemList.length > 1" style="margin-left:5px"></i>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -193,7 +206,7 @@ export default {
loading: false, loading: false,
companyOptions: [], companyOptions: [],
form: { form: {
invoiceType: this.rowData.invoiceType || '-', invoiceType: this.rowData.invoiceType || '2',
buyerName: undefined, buyerName: undefined,
buyerCreditCode: undefined, buyerCreditCode: undefined,
buyerBank: undefined, buyerBank: undefined,
@ -204,7 +217,7 @@ export default {
sellerBankAccount: undefined, sellerBankAccount: undefined,
remark: undefined, remark: undefined,
invoiceBillCode: this.rowData.invoiceBillCode, invoiceBillCode: this.rowData.invoiceBillCode,
detailList: [ detailItemList: [
{ {
projectName: '', projectName: '',
productModel: '', productModel: '',
@ -231,7 +244,7 @@ export default {
computed: { computed: {
totalAmountNumber() { totalAmountNumber() {
let total = 0; let total = 0;
this.form.detailList.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 + tax);
@ -263,7 +276,7 @@ export default {
}, },
reset() { reset() {
this.form = { this.form = {
invoiceType: 'ELECTRONIC', invoiceType: '2',
buyerName: undefined, buyerName: undefined,
buyerCreditCode: undefined, buyerCreditCode: undefined,
buyerBank: undefined, buyerBank: undefined,
@ -273,7 +286,7 @@ export default {
sellerBank: undefined, sellerBank: undefined,
sellerBankAccount: undefined, sellerBankAccount: undefined,
remark: undefined, remark: undefined,
detailList: [] detailItemList: []
}; };
this.resetForm("form"); this.resetForm("form");
}, },
@ -302,18 +315,23 @@ export default {
if (this.rowData.invoiceBillCode) { if (this.rowData.invoiceBillCode) {
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.detailList = response.data.map(item => { this.form.detailItemList = response.data.map(item => {
const row = { const row = {
projectName: item.projectName, projectName: item.projectName,
id: item.id,
orderCode: item.orderCode,
productCode: item.productCode,
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
unit: item.unit || '',
quantity: item.quantity, quantity: item.quantity,
unitPrice: item.price, // Mapping price to unitPrice unitPrice: item.price, // Mapping price to unitPrice
taxRate: item.taxRate, taxRate: item.taxRate,
amount: '', amount: item.allPrice,
taxAmount: '' taxAmount: item.taxAmount
}; };
// Calculate initial amounts // Calculate initial amounts
this.calculateAmount(row); // this.calculateAmount(row);
return row; return row;
}); });
} else { } else {
@ -345,7 +363,7 @@ export default {
this.$emit("update:visible", false); this.$emit("update:visible", false);
}, },
addDetailRow() { addDetailRow() {
this.form.detailList.push({ this.form.detailItemList.push({
projectName: '', projectName: '',
productModel: '', productModel: '',
unit: '', unit: '',
@ -357,9 +375,12 @@ export default {
}); });
}, },
removeDetailRow(index) { removeDetailRow(index) {
this.form.detailList.splice(index, 1); this.form.detailItemList.splice(index, 1);
}, },
calculateAmount(row) { calculateAmount(row) {
if (row.productCode){
return
}
if (row.unitPrice && row.quantity) { if (row.unitPrice && row.quantity) {
row.amount = this.$calc.mul(row.unitPrice, row.quantity); row.amount = this.$calc.mul(row.unitPrice, row.quantity);
this.calculateTax(row); this.calculateTax(row);
@ -381,7 +402,7 @@ export default {
if (column.property === 'amount' || column.property === 'taxAmount') { if (column.property === 'amount' || column.property === 'taxAmount') {
const values = data.map(item => Number(item[column.property])); const values = data.map(item => Number(item[column.property]));
if (!values.every(value => isNaN(value))) { if (!values.every(value => isNaN(value))) {
sums[index] = values.reduce((prev, curr) => { const sum = values.reduce((prev, curr) => {
const value = Number(curr); const value = Number(curr);
if (!isNaN(value)) { if (!isNaN(value)) {
return prev + curr; return prev + curr;
@ -389,7 +410,7 @@ export default {
return prev; return prev;
} }
}, 0); }, 0);
sums[index] = sums[index].toFixed(2); sums[index] = '¥' + sum.toFixed(2);
} else { } else {
sums[index] = ''; sums[index] = '';
} }
@ -402,6 +423,22 @@ export default {
handleSubmit() { handleSubmit() {
this.$refs["form"].validate(valid => { this.$refs["form"].validate(valid => {
if (valid) { if (valid) {
//
if (this.form.detailItemList.length === 0) {
this.$modal.msgError("请至少添加一条开票明细");
return;
}
for (let i = 0; i < this.form.detailItemList.length; i++) {
const item = this.form.detailItemList[i];
if (!item.productName || !item.productModel || (item.quantity??false) || !item.unit || !item.unitPrice || !item.amount || !item.taxAmount || !item.taxRate) {
this.$modal.msgError(`表格第 ${i + 1} 行数据不完整,请填写所有必填字段`);
return;
}
item.invoiceBillCode=this.rowData.invoiceBillCode;
item.price=item.unitPrice;
item.allPrice=item.amount;
}
this.loading = true; this.loading = true;
applyInvoice(this.form).then(response => { applyInvoice(this.form).then(response => {
this.$modal.msgSuccess("申请提交成功"); this.$modal.msgSuccess("申请提交成功");
@ -526,7 +563,7 @@ export default {
} }
.invoice-type-select { .invoice-type-select {
width: 150px; width: 160px;
} }
/* Hide select border to blend in */ /* Hide select border to blend in */
@ -741,4 +778,9 @@ export default {
border: none; border: none;
resize: none; resize: none;
} }
.invoice-table ::v-deep .el-table__body-wrapper {
height: 250px;
overflow-y: auto;
}
</style> </style>

View File

@ -342,7 +342,7 @@ export default {
invoicePriceWithTax: '', invoicePriceWithTax: '',
invoicePriceWithoutTax: '', invoicePriceWithoutTax: '',
invoiceAmount: '', invoiceAmount: '',
invoiceType: '', invoiceType: this.invoiceData.invoiceType,
remark: '', remark: '',
file: null file: null
}; };

View File

@ -0,0 +1,387 @@
<template>
<div>
<!-- 1. 顶部发票类型与票号日期 -->
<div class="invoice-header">
<div class="header-center">
<div class="invoice-title">
电子发票
<span class="invoice-type-wrapper">
(<el-select v-model="data.invoiceType" class="invoice-type-select" disabled :popper-append-to-body="false">
<el-option
v-for="dict in dict.type.finance_invoice_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>)
</span>
</div>
<div class="header-decoration-line"></div>
</div>
<div class="header-right">
<div class="meta-row">
<span class="meta-label">发票号码:</span>
<span class="meta-value">{{ '----------' }}</span>
</div>
<div class="meta-row">
<span class="meta-label">开票日期:</span>
<span class="meta-value">{{'----------' }}</span>
</div>
</div>
</div>
<div class="invoice-body-border">
<el-row type="flex" class="info-container">
<!-- 左侧购买方信息 -->
<el-col :span="12" class="info-column left-column">
<div class="column-label">购买方<br>信息</div>
<div class="column-content">
<div class="info-item"><span class="label">名称:</span> {{ data.buyerName }}</div>
<div class="info-item"><span class="label">纳税人识别号:</span> {{ data.buyerCreditCode }}</div>
</div>
</el-col>
<!-- 右侧销售方信息 -->
<el-col :span="12" class="info-column right-column">
<div class="column-label">销售方<br>信息</div>
<div class="column-content">
<div class="info-item"><span class="label">名称:</span> {{ data.sellerName }}</div>
<div class="info-item"><span class="label">纳税人识别号:</span> {{ data.sellerCreditCode }}</div>
</div>
</el-col>
</el-row>
<!-- 表格区域 -->
<div class="items-table-container">
<el-table :data="data.detailItemList" border class="invoice-table" show-summary :summary-method="getSummaries">
<el-table-column label="项目名称" prop="productName" align="center"></el-table-column>
<el-table-column label="规格型号" prop="productModel" align="center" width="120"></el-table-column>
<el-table-column label="单位" prop="unit" align="center" width="60"></el-table-column>
<el-table-column label="数量" prop="quantity" align="center" width="80"></el-table-column>
<el-table-column label="单价" prop="price" align="center" width="100"></el-table-column>
<el-table-column label="金额" prop="allPrice" align="center" width="100"></el-table-column>
<el-table-column label="税率%" prop="taxRate" align="center" width="80"></el-table-column>
<el-table-column label="税额" prop="taxAmount" align="center" width="100"></el-table-column>
</el-table>
</div>
<!-- 价税合计 -->
<div class="total-row">
<div class="total-label">价税合计 (大写)</div>
<div class="total-value-chinese">
<span class="currency-symbol"></span> {{ totalAmountChinese }}
</div>
<div class="total-label-small">(小写)</div>
<div class="total-value-number">
¥{{ totalAmountNumber }}
</div>
</div>
<!-- 备注 -->
<div class="remark-row">
<div class="remark-label">备注</div>
<div class="remark-content">{{ data.remark }}</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "InvoiceInfoView",
dicts: ['finance_invoice_type'],
props: {
data: {
type: Object,
required: true,
default: () => ({})
}
},
computed: {
totalAmountNumber() {
let total = 0;
if (this.data.detailItemList) {
this.data.detailItemList.forEach(item => {
const amount = parseFloat(item.allPrice) || 0;
// const tax = parseFloat(item.taxAmount) || 0;
total += amount ;
});
}
return total.toFixed(2);
},
totalAmountChinese() {
return this.convertCurrency(this.totalAmountNumber);
}
},
methods: {
getSummaries(param) {
const { columns, data } = param;
const sums = [];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '合计';
return;
}
if (column.property === 'allPrice' || column.property === 'taxAmount') {
const values = data.map(item => Number(item[column.property]));
if (!values.every(value => isNaN(value))) {
const sum = values.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return prev + curr;
} else {
return prev;
}
}, 0);
sums[index] = '¥' + sum.toFixed(2);
} else {
sums[index] = '';
}
} else {
sums[index] = '';
}
});
return sums;
},
convertCurrency(money) {
const cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
const cnIntRadice = ['', '拾', '佰', '仟'];
const cnIntUnits = ['', '万', '亿', '兆'];
const cnDecUnits = ['角', '分', '毫', '厘'];
const cnInteger = '整';
const cnIntLast = '元';
let integerNum;
let decimalNum;
let chineseStr = '';
let parts;
if (money === '') return '';
money = parseFloat(money);
if (money >= 999999999999) return '';
if (money === 0) return cnNums[0] + cnIntLast + cnInteger;
money = money.toString();
if (money.indexOf('.') === -1) {
integerNum = money;
decimalNum = '';
} else {
parts = money.split('.');
integerNum = parts[0];
decimalNum = parts[1].substr(0, 4);
}
if (parseInt(integerNum, 10) > 0) {
let zeroCount = 0;
let IntLen = integerNum.length;
for (let i = 0; i < IntLen; i++) {
let n = integerNum.substr(i, 1);
let p = IntLen - i - 1;
let q = p / 4;
let m = p % 4;
if (n === '0') {
zeroCount++;
} else {
if (zeroCount > 0) chineseStr += cnNums[0];
zeroCount = 0;
chineseStr += cnNums[parseInt(n)] + cnIntRadice[m];
}
if (m === 0 && zeroCount < 4) chineseStr += cnIntUnits[q];
}
chineseStr += cnIntLast;
}
if (decimalNum !== '') {
let decLen = decimalNum.length;
for (let i = 0; i < decLen; i++) {
let n = decimalNum.substr(i, 1);
if (n !== '0') chineseStr += cnNums[Number(n)] + cnDecUnits[i];
}
}
if (chineseStr === '') chineseStr += cnNums[0] + cnIntLast + cnInteger;
else if (decimalNum === '') chineseStr += cnInteger;
return chineseStr;
},
}
};
</script>
<style scoped>
.invoice-header {
position: relative;
height: 80px;
display: flex;
justify-content: center;
align-items: flex-start;
margin-bottom: 10px;
}
.header-center {
text-align: center;
padding-top: 5px;
}
.invoice-title {
font-size: 24px;
font-weight: bold;
color: #8B4513;
line-height: 40px;
letter-spacing: 2px;
}
.invoice-type-wrapper {
margin-left: 5px;
font-size: 22px;
font-weight: bold;
color: #8B4513;
}
.header-decoration-line {
height: 2px;
background-color: #8B4513;
width: 380px;
margin: 0 auto;
border-bottom: 1px solid #8B4513;
box-shadow: 0 2px 0 0 #fff, 0 4px 0 0 #8B4513;
}
.header-right {
position: absolute;
right: 0;
top: 10px;
text-align: left;
}
.meta-row {
font-size: 13px;
color: #8B4513;
line-height: 20px;
}
.meta-label {
display: inline-block;
width: 70px;
}
.invoice-body-border {
border: 2px solid #8B4513;
padding: 0;
color: #606266;
}
.info-container {
display: flex;
border-bottom: 1px solid #8B4513;
}
.info-column {
padding: 5px;
display: flex;
align-items: stretch;
}
.left-column {
border-right: 1px solid #8B4513;
}
.column-label {
width: 30px;
padding: 0 5px;
color: #8B4513;
font-size: 14px;
text-align: center;
line-height: 1.4;
border-right: 1px solid #8B4513;
margin-right: 8px;
display: flex;
align-items: center;
justify-content: center;
word-break: break-all;
}
.column-content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
font-size: 13px;
}
.info-item {
margin-bottom: 2px;
color: #8B4513;
}
.info-item .label {
display: inline-block;
width: 100px;
}
.items-table-container {
padding: 0;
border-bottom: 1px solid #8B4513;
}
.invoice-table ::v-deep th {
font-weight: bold;
color: #8B4513;
border-color: #8B4513;
}
.invoice-table ::v-deep td {
border-color: #8B4513;
}
.total-row {
display: flex;
align-items: center;
border-bottom: 1px solid #8B4513;
height: 40px;
padding: 0 10px;
color: #8B4513;
}
.total-label {
width: 120px;
font-size: 13px;
}
.total-value-chinese {
flex: 1;
font-size: 14px;
padding-left: 10px;
}
.currency-symbol {
border: 1px solid #8B4513;
border-radius: 50%;
padding: 1px 4px;
font-size: 12px;
margin-right: 5px;
}
.total-label-small {
width: 60px;
text-align: right;
font-size: 13px;
}
.total-value-number {
width: 150px;
padding-left: 10px;
font-size: 14px;
}
.remark-row {
display: flex;
min-height: 40px;
padding: 10px;
color: #8B4513;
}
.remark-label {
width: 120px;
font-size: 13px;
}
.remark-content {
flex: 1;
font-size: 13px;
}
.invoice-type-select {
width: 160px;
}
/* Hide select border to blend in */
.invoice-type-select ::v-deep .el-input__inner {
border: none;
background: transparent;
font-size: 22px;
font-weight: bold;
color: #8B4513;
padding: 0;
text-align: center;
height: 40px;
line-height: 40px;
}
.invoice-type-select ::v-deep .el-select__caret {
color: #8B4513;
font-weight: bold;
}
</style>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="150px">
<el-form-item label="项目编号" prop="projectCode"> <el-form-item label="项目编号" prop="projectCode">
<el-input <el-input
v-model="queryParams.projectCode" v-model="queryParams.projectCode"
@ -17,23 +17,23 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="票单编号" prop="invoiceBillCode"> <el-form-item label="销售-开票单编号" prop="invoiceBillCode">
<el-input <el-input
v-model="queryParams.invoiceBillCode" v-model="queryParams.invoiceBillCode"
placeholder="请输入票单编号" placeholder="请输入票单编号"
clearable clearable
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="客户名称" prop="customerName"> <el-form-item label="进货商名称" prop="partnerName">
<el-input <el-input
v-model="queryParams.customerName" v-model="queryParams.partnerName"
placeholder="请输入客户名称" placeholder="请输入客户名称"
clearable clearable
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="应收单编号" prop="receivableBillCode"> <el-form-item label="销售-应收单编号" prop="receivableBillCode">
<el-input <el-input
v-model="queryParams.receivableBillCode" v-model="queryParams.receivableBillCode"
placeholder="请输入应收单编号" placeholder="请输入应收单编号"
@ -41,7 +41,7 @@
@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="invoiceBillType">
<el-select v-model="queryParams.invoiceBillType" placeholder="请选择收票单类型" clearable> <el-select v-model="queryParams.invoiceBillType" 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.invoice_bill_type" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select> </el-select>
@ -56,8 +56,8 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="票状态" prop="invoiceStatus"> <el-form-item label="票状态" prop="invoiceStatus">
<el-select v-model="queryParams.invoiceStatus" placeholder="请选择票状态" clearable> <el-select v-model="queryParams.invoiceStatus" placeholder="请选择票状态" clearable>
<el-option <el-option
v-for="dict in dict.type.invoice_status" v-for="dict in dict.type.invoice_status"
:key="dict.value" :key="dict.value"
@ -78,35 +78,35 @@
<el-date-picker <el-date-picker
v-model="dateRangeApproval" v-model="dateRangeApproval"
style="width: 240px" style="width: 240px"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd HH:mm:ss"
type="daterange" type="datetimerange"
range-separator="-" range-separator="-"
start-placeholder="开始日期" start-placeholder="开始日期"
end-placeholder="结束日期" end-placeholder="结束日期"
></el-date-picker> ></el-date-picker>
</el-form-item> </el-form-item>
<el-form-item label="预计票时间"> <el-form-item label="预计票时间">
<el-date-picker <el-date-picker
v-model="dateRangeEstimated" v-model="dateRangeEstimated"
style="width: 240px" style="width: 240px"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd HH:mm:ss"
type="daterange" type="datetimerange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item label="实际收票时间">
<el-date-picker
v-model="dateRangeActual"
style="width: 240px"
value-format="yyyy-MM-dd"
type="daterange"
range-separator="-" range-separator="-"
start-placeholder="开始日期" start-placeholder="开始日期"
end-placeholder="结束日期" end-placeholder="结束日期"
></el-date-picker> ></el-date-picker>
</el-form-item> </el-form-item>
<!-- <el-form-item label="实际收票时间">-->
<!-- <el-date-picker-->
<!-- v-model="dateRangeActual"-->
<!-- 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-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery"></el-button> <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-button icon="el-icon-refresh" size="mini" @click="resetQuery"></el-button>
@ -134,15 +134,16 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="进货商名称" align="center" prop="partnerName" width="300" /> <el-table-column label="进货商名称" align="center" prop="partnerName" width="300" />
<el-table-column label="含税总价" align="center" prop="totalPriceWithTax" width="180" /> <el-table-column label="含税总价(元)" align="center" prop="totalPriceWithTax" width="180" />
<el-table-column label="未税总价" align="center" prop="totalPriceWithoutTax" width="180"/> <el-table-column label="未税总价(元)" align="center" prop="totalPriceWithoutTax" width="180"/>
<el-table-column label="税额" align="center" prop="taxAmount" width="180"> <el-table-column label="发票未税总价(元)" align="center" prop="invoicePriceWithoutTax" width="180"/>
<el-table-column label="税额(元)" align="center" prop="taxAmount" width="180">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ $calc.sub(scope.row.totalPriceWithTax, scope.row.totalPriceWithoutTax) }}</span> <span>{{ $calc.sub(scope.row.totalPriceWithTax, scope.row.totalPriceWithoutTax) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="发票未税总价" align="center" prop="invoicePriceWithoutTax" width="180"/>
<el-table-column label="发票税额" align="center" prop="invoicePriceTax" width="180"> <el-table-column label="发票税额(元)" align="center" prop="invoicePriceTax" width="180">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ $calc.sub(scope.row.totalPriceWithTax, scope.row.invoicePriceWithoutTax) }}</span> <span>{{ $calc.sub(scope.row.totalPriceWithTax, scope.row.invoicePriceWithoutTax) }}</span>
</template> </template>
@ -183,7 +184,7 @@
size="mini" size="mini"
type="text" type="text"
icon="el-icon-s-ticket" icon="el-icon-s-ticket"
v-show="scope.row.invoiceStatus==='1' &&(scope.row.approveStatus==='0'||scope.row.approveStatus==='3')" v-show="scope.row.invoiceStatus==='1' &&(scope.row.approveStatus==='0')"
@click="handleApplyInvoice(scope.row)" @click="handleApplyInvoice(scope.row)"
>申请开票</el-button> >申请开票</el-button>
<el-button <el-button
@ -265,7 +266,7 @@ export default {
projectCode: null, projectCode: null,
projectName: null, projectName: null,
invoiceBillCode: null, invoiceBillCode: null,
customerName: null, partnerName: null,
receivableBillCode: null, receivableBillCode: null,
invoiceBillType: null, invoiceBillType: null,
approveStatus: null, approveStatus: null,

View File

@ -325,7 +325,7 @@ export default {
fetchAttachments() { fetchAttachments() {
if (!this.receiptData.id) return; if (!this.receiptData.id) return;
this.loading = true; this.loading = true;
getReceiptAttachments(this.receiptData.id, { type: 'ticket' }) getReceiptAttachments(this.receiptData.id, { type: 'receipt' })
.then(response => { .then(response => {
const data = response.data || []; const data = response.data || [];
data.sort((a, b) => new Date(b.createTime) - new Date(a.createTime)); data.sort((a, b) => new Date(b.createTime) - new Date(a.createTime));

View File

@ -41,9 +41,9 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="备注" prop="receiveBillType"> <el-form-item label="备注" prop="receiptBillType">
<el-select v-model="queryParams.receiveBillType" placeholder="请选择" clearable> <el-select v-model="queryParams.receiptBillType" placeholder="请选择" clearable>
<el-option v-for="dict in dict.type.receive_bill_type" :key="dict.value" :label="dict.label" :value="dict.value"></el-option> <el-option v-for="dict in dict.type.receipt_bill_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="receiptMethod"> <el-form-item label="支付方式" prop="receiptMethod">
@ -261,9 +261,9 @@ export default {
receiptBillCode: null, receiptBillCode: null,
partnerName: null, partnerName: null,
receivableBillCode: null, receivableBillCode: null,
receiveBillType: null, receiptBillType: null,
approveStatus: null, approveStatus: null,
receiveStatus: null, receiptStatus: null,
approveNode: null, approveNode: null,
}, },
// //

View File

@ -6,6 +6,7 @@ import java.util.List;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.config.flow.ProcessConfig; import com.ruoyi.common.config.flow.ProcessConfig;
import com.ruoyi.common.enums.ApproveStatusEnum;
import com.ruoyi.sip.domain.OmsFinAttachment; import com.ruoyi.sip.domain.OmsFinAttachment;
import com.ruoyi.sip.flowable.service.TodoService; import com.ruoyi.sip.flowable.service.TodoService;
import com.ruoyi.sip.service.IOmsFinAttachmentService; import com.ruoyi.sip.service.IOmsFinAttachmentService;
@ -48,37 +49,40 @@ public class OmsInvoiceBillController extends BaseController
* *
*/ */
@RequiresPermissions("sip:invoiceBill:list") @RequiresPermissions("sip:invoiceBill:list")
@GetMapping("/list") @PostMapping("/list")
public TableDataInfo list(OmsInvoiceBill omsInvoiceBill) public TableDataInfo list(OmsInvoiceBill omsInvoiceBill)
{ {
startPage(); startPage();
List<OmsInvoiceBill> list = omsInvoiceBillService.selectOmsInvoiceBillList(omsInvoiceBill); List<OmsInvoiceBill> list = omsInvoiceBillService.selectOmsInvoiceBillList(omsInvoiceBill);
clearPage(); clearPage();
// todoService.fillApproveNode(list, todoService.fillApproveNode(list,
// Arrays.asList(processConfig.getDefinition().getFiananceInvoice(), processConfig.getDefinition().getFinanceInvoiceRefound()) Arrays.asList(processConfig.getDefinition().getFinanceInvoiceRefound(), processConfig.getDefinition().getFinanceInvoiceApprove())
// , OmsInvoiceBill::getInvoiceBillCode, (a, b) -> a.setApproveNode(b.get(a.getInvoiceBillCode()))); , OmsInvoiceBill::getInvoiceBillCode,
(a, b) -> a.setApproveNode(a.getApproveStatus().equals(ApproveStatusEnum.WAIT_APPROVE.getCode())?b.get(a.getInvoiceBillCode()):"-"));
return getDataTable(list); return getDataTable(list);
} }
@PostMapping("/approve/list") @PostMapping("/approve/list")
public TableDataInfo listApprove(@RequestBody OmsInvoiceBill omsInvoiceBill) { public TableDataInfo listApprove(OmsInvoiceBill omsInvoiceBill) {
startPage(); startPage();
List<OmsInvoiceBill> list = omsInvoiceBillService.listApprove(omsInvoiceBill); List<OmsInvoiceBill> list = omsInvoiceBillService.listApprove(omsInvoiceBill);
clearPage(); clearPage();
// todoService.fillApproveNode(list, todoService.fillApproveNode(list,
// Arrays.asList(omsInvoiceBill.getProcessKey()) Arrays.asList(omsInvoiceBill.getProcessKey())
// , OmsInvoiceBill::getInvoiceBillCode, (a, b) -> a.setApproveNode(b.get(a.getInvoiceBillCode()))); , OmsInvoiceBill::getInvoiceBillCode,
(a, b) -> a.setApproveNode(a.getApproveStatus().equals(ApproveStatusEnum.WAIT_APPROVE.getCode())?b.get(a.getInvoiceBillCode()):"-"));
return getDataTable(list); return getDataTable(list);
} }
@PostMapping("/approved/list") @PostMapping("/approved/list")
public TableDataInfo listApproved(@RequestBody OmsInvoiceBill omsInvoiceBill) { public TableDataInfo listApproved( OmsInvoiceBill omsInvoiceBill) {
startPage(); startPage();
List<OmsInvoiceBill> list = omsInvoiceBillService.listApproved(omsInvoiceBill); List<OmsInvoiceBill> list = omsInvoiceBillService.listApproved(omsInvoiceBill);
clearPage(); clearPage();
// todoService.fillApproveNode(list, todoService.fillApproveNode(list,
// Arrays.asList(processConfig.getDefinition().getFiananceInvoice(), processConfig.getDefinition().getFinanceInvoiceRefound()) Arrays.asList(omsInvoiceBill.getProcessKey())
// , OmsInvoiceBill::getInvoiceBillCode, (a, b) -> a.setApproveNode(b.get(a.getInvoiceBillCode()))); , OmsInvoiceBill::getInvoiceBillCode,
(a, b) -> a.setApproveNode(b.get(a.getInvoiceBillCode())));
return getDataTable(list); return getDataTable(list);
} }
@ -102,7 +106,12 @@ public class OmsInvoiceBillController extends BaseController
@GetMapping(value = "/{id}") @GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id) public AjaxResult getInfo(@PathVariable("id") Long id)
{ {
return AjaxResult.success(omsInvoiceBillService.selectOmsInvoiceBillById(id)); OmsInvoiceBill data = omsInvoiceBillService.selectOmsInvoiceBillById(id);
todoService.fillApproveNode(Collections.singletonList(data),
Arrays.asList(processConfig.getDefinition().getFinanceInvoiceRefound(), processConfig.getDefinition().getFinanceInvoiceApprove())
, OmsInvoiceBill::getInvoiceBillCode,
(a, b) -> a.setApproveNode(a.getApproveStatus().equals(ApproveStatusEnum.WAIT_APPROVE.getCode())?b.get(a.getInvoiceBillCode()):"-"));
return AjaxResult.success(data);
} }
@RequiresPermissions("sip:invoiceBill:query") @RequiresPermissions("sip:invoiceBill:query")
@PostMapping(value = "/apply") @PostMapping(value = "/apply")

View File

@ -86,6 +86,7 @@ public class InventoryOuter extends BaseEntity
// @Excel(name = "发货时间选择(0:立即发货 1:自定义)") // @Excel(name = "发货时间选择(0:立即发货 1:自定义)")
private String deliveryTimeType; private String deliveryTimeType;
private Long warehouseId; private Long warehouseId;
private String receivableBillCode;
private List<InventoryOuterDetail> detailList; private List<InventoryOuterDetail> detailList;

View File

@ -101,6 +101,7 @@ public class OmsInvoiceBill extends BaseEntity
/** 关联的原始开票单ID */ /** 关联的原始开票单ID */
private Long originalBillId; private Long originalBillId;
private String invoiceApplyUser;
private Long approveUser; private Long approveUser;
private Date applyTime; private Date applyTime;
private Date todoApproveTime; private Date todoApproveTime;
@ -118,7 +119,12 @@ public class OmsInvoiceBill extends BaseEntity
private String sellerBankAccount; private String sellerBankAccount;
private String projectCode;
private String projectName;
private List<ReceiptDetailDTO> detailDTOList; private List<ReceiptDetailDTO> detailDTOList;
private List<OmsReceivableInvoiceDetailItem> detailItemList;
public BigDecimal getTaxAmount() { public BigDecimal getTaxAmount() {
if (null != totalPriceWithTax && null != totalPriceWithoutTax){ if (null != totalPriceWithTax && null != totalPriceWithoutTax){
return totalPriceWithTax.subtract(totalPriceWithoutTax); return totalPriceWithTax.subtract(totalPriceWithoutTax);

View File

@ -0,0 +1,74 @@
package com.ruoyi.sip.domain;
import lombok.Data;
import java.math.BigDecimal;
/**
* -(OmsReceivableInvoiceDetailItem)
*
* @author ch
* @since 2025-12-29 17:00:47
*/
@Data
public class OmsReceivableInvoiceDetailItem {
/**
*
*/
private Long id;
/**
*
*/
private String invoiceBillCode;
/**
*
*/
private String projectName;
/**
*
*/
private String orderCode;
private String unit;
/**
*
*/
private String productCode;
/**
*
*/
private String productName;
/**
*
*/
private String productModel;
/**
*
*/
private Long quantity;
/**
*
*/
private BigDecimal price;
/**
*
*/
private BigDecimal allPrice;
/**
*
*/
private BigDecimal taxAmount;
/**
*
*/
private BigDecimal taxRate;
}

View File

@ -1,6 +1,7 @@
package com.ruoyi.sip.domain.dto; package com.ruoyi.sip.domain.dto;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data; import lombok.Data;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -19,16 +20,22 @@ import java.math.BigDecimal;
* 2025/12/22 ch 1.0 Why & What is modified: <> * * 2025/12/22 ch 1.0 Why & What is modified: <> *
*/ */
@Data @Data
public class InvoiceProductDto { public class InvoiceProductDto extends BaseEntity {
private Long id;
private String projectName; private String projectName;
private Long projectId; private Long projectId;
private String productName; private String productName;
private String productCode; private String productCode;
private String orderCode;
private String productModel; private String productModel;
private String productDesc; private String productDesc;
private Long quantity; private Long quantity;
private BigDecimal price; private BigDecimal price;
private BigDecimal allPrice;
private BigDecimal taxAmount;
private BigDecimal taxRate; private BigDecimal taxRate;
private String unit;
private String invoiceBillCode;

View File

@ -450,7 +450,7 @@ public class TodoServiceImpl implements TodoService {
StringBuilder joinQuerySql = new StringBuilder(); StringBuilder joinQuerySql = new StringBuilder();
StringBuilder joinSql = new StringBuilder(); StringBuilder joinSql = new StringBuilder();
if ("bu_todo".equals(tableName)){ if ("bu_todo".equals(tableName)){
joinQuerySql.append( " ,t3.apply_time,t3.process_key,t3.todo_id,t3.task_id"); joinQuerySql.append( " ,flow.apply_time,flow.process_key,flow.todo_id,flow.task_id");
joinSql.append(" inner join ( "); joinSql.append(" inner join ( ");
joinSql.append(" select bt.business_key,bt.apply_time,bt.process_key,bt.todo_id,bt.task_id from bu_todo bt where "); joinSql.append(" select bt.business_key,bt.apply_time,bt.process_key,bt.todo_id,bt.task_id from bu_todo bt where ");
joinSql.append(StrUtil.format(" bt.process_key IN ({})", processKeyList.stream().map(processKey -> "'" + processKey + "'").collect(Collectors.joining(",")))); joinSql.append(StrUtil.format(" bt.process_key IN ({})", processKeyList.stream().map(processKey -> "'" + processKey + "'").collect(Collectors.joining(","))));
@ -460,9 +460,9 @@ public class TodoServiceImpl implements TodoService {
joinSql.append(notInTaskName.stream().map(taskName -> "'" + taskName + "'").collect(Collectors.joining(","))); joinSql.append(notInTaskName.stream().map(taskName -> "'" + taskName + "'").collect(Collectors.joining(",")));
joinSql.append(") "); joinSql.append(") ");
} }
joinSql.append(") t3 on t3.business_key ="); joinSql.append(") flow on flow.business_key =");
}else{ }else{
joinQuerySql.append( " ,t3.apply_time,t3.approve_time as todo_approve_time,t3.process_key "); joinQuerySql.append( " ,flow.apply_time,flow.approve_time as todo_approve_time,flow.process_key ");
joinSql.append(" inner join ( SELECT business_key, max(btc.approve_time) approve_time, max(btc.apply_time) apply_time, max(btc.process_key) process_key FROM bu_todo_completed btc"); joinSql.append(" inner join ( SELECT business_key, max(btc.approve_time) approve_time, max(btc.apply_time) apply_time, max(btc.process_key) process_key FROM bu_todo_completed btc");
joinSql.append(StrUtil.format(" where btc.process_key IN ({})", processKeyList.stream().map(processKey -> "'" + processKey + "'").collect(Collectors.joining(",")))); joinSql.append(StrUtil.format(" where btc.process_key IN ({})", processKeyList.stream().map(processKey -> "'" + processKey + "'").collect(Collectors.joining(","))));
joinSql.append(" AND btc.approve_user = ").append(approveUser).append(" "); joinSql.append(" AND btc.approve_user = ").append(approveUser).append(" ");
@ -471,7 +471,7 @@ public class TodoServiceImpl implements TodoService {
joinSql.append(notInTaskName.stream().map(taskName -> "'" + taskName + "'").collect(Collectors.joining(","))); joinSql.append(notInTaskName.stream().map(taskName -> "'" + taskName + "'").collect(Collectors.joining(",")));
joinSql.append(") "); joinSql.append(") ");
} }
joinSql.append(" GROUP BY business_key) t3 on t3.business_key = "); joinSql.append(" GROUP BY business_key) flow on flow.business_key = ");
} }
joinSql.append(function.get()); joinSql.append(function.get());

View File

@ -1,6 +1,7 @@
package com.ruoyi.sip.mapper; package com.ruoyi.sip.mapper;
import com.ruoyi.sip.domain.OmsInvoiceBill; import com.ruoyi.sip.domain.OmsInvoiceBill;
import com.ruoyi.sip.flowable.domain.FlowRelationDto;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@ -85,7 +86,7 @@ public interface OmsInvoiceBillMapper
*/ */
public int updateOmsInvoiceBillByCode(OmsInvoiceBill omsInvoiceBill); public int updateOmsInvoiceBillByCode(OmsInvoiceBill omsInvoiceBill);
List<OmsInvoiceBill> listApprove(@Param("entity") OmsInvoiceBill omsInvoiceBill, @Param("tableName") String tableName); List<OmsInvoiceBill> listApprove(@Param("entity") OmsInvoiceBill omsInvoiceBill, @Param("flowRelationDto") FlowRelationDto flowRelationDto);
void clearRelationReceivable(String invoiceBillCode); void clearRelationReceivable(String invoiceBillCode);

View File

@ -0,0 +1,52 @@
package com.ruoyi.sip.mapper;
import com.ruoyi.sip.domain.OmsReceivableInvoiceDetailItem;
import java.util.List;
/**
* @Author ch
* @Desc -(OmsReceivableInvoiceDetailItem)访
* @Date 2025-12-29 17:00:47
*/
public interface OmsReceivableInvoiceDetailItemMapper {
/**
*
*
* @param omsReceivableInvoiceDetailItem
* @return
*/
List<OmsReceivableInvoiceDetailItem> queryAll(OmsReceivableInvoiceDetailItem omsReceivableInvoiceDetailItem);
/**
* ID
*/
OmsReceivableInvoiceDetailItem queryById(Long id);
/**
*
*/
int insert(OmsReceivableInvoiceDetailItem omsReceivableInvoiceDetailItem);
/**
*
*/
int update(OmsReceivableInvoiceDetailItem omsReceivableInvoiceDetailItem);
/**
*
*/
int deleteById(Long id);
/**
* id-
*/
int batchRemove(Long[] ids);
int insertBatch(List<OmsReceivableInvoiceDetailItem> omsReceivableInvoiceDetailItems);
void updateBatch(List<OmsReceivableInvoiceDetailItem> updateList);
}

View File

@ -0,0 +1,49 @@
package com.ruoyi.sip.service;
import com.ruoyi.sip.domain.OmsReceivableInvoiceDetailItem;
import java.util.List;
/**
* @Author ch
* @Desc -(OmsReceivableInvoiceDetailItem)
* @Date 2025-12-29 17:00:47
*/
public interface IOmsReceivableInvoiceDetailItemService {
/**
*
*/
List<OmsReceivableInvoiceDetailItem> queryAll(OmsReceivableInvoiceDetailItem omsReceivableInvoiceDetailItem);
/**
* ID
*/
OmsReceivableInvoiceDetailItem queryById(Long id);
/**
*
*/
int insert(OmsReceivableInvoiceDetailItem omsReceivableInvoiceDetailItem);
void saveBatch(List<OmsReceivableInvoiceDetailItem> omsReceivableInvoiceDetailItems);
/**
*
*/
int update(OmsReceivableInvoiceDetailItem omsReceivableInvoiceDetailItem);
/**
*
*/
int deleteById(Long id);
/**
* id-
*/
int batchRemove(Long[] ids);
}

View File

@ -9,6 +9,7 @@ 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.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.ShiroUtils; import com.ruoyi.common.utils.ShiroUtils;
@ -21,6 +22,7 @@ import com.ruoyi.sip.dto.WriteOffInvoiceRequestDto;
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 org.flowable.engine.runtime.ProcessInstance; import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -66,7 +68,11 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
@Lazy @Lazy
private IOmsReceivableInvoiceWriteOffService writeOffService; private IOmsReceivableInvoiceWriteOffService writeOffService;
@Autowired
private IOmsReceivableInvoiceDetailItemService detailItemService;
@Autowired
private ProcessConfig processConfig;
/** /**
* *
@ -81,7 +87,10 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
// 如果需要关联查询其他数据,可以在这里添加 // 如果需要关联查询其他数据,可以在这里添加
List<ReceiptDetailDTO> receiptDetailDTOS = detailService.listReceivableByInvoiceBillCode(omsInvoiceBill.getInvoiceBillCode()); List<ReceiptDetailDTO> receiptDetailDTOS = detailService.listReceivableByInvoiceBillCode(omsInvoiceBill.getInvoiceBillCode());
omsInvoiceBill.setDetailDTOList(receiptDetailDTOS); omsInvoiceBill.setDetailDTOList(receiptDetailDTOS);
OmsReceivableInvoiceDetailItem queryItem = new OmsReceivableInvoiceDetailItem();
queryItem.setInvoiceBillCode(omsInvoiceBill.getInvoiceBillCode());
List<OmsReceivableInvoiceDetailItem> omsReceivableInvoiceDetailItems = detailItemService.queryAll(queryItem);
omsInvoiceBill.setDetailItemList(omsReceivableInvoiceDetailItems);
return omsInvoiceBill; return omsInvoiceBill;
} }
@ -222,7 +231,13 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
@Override @Override
public List<OmsInvoiceBill> listApprove(OmsInvoiceBill omsInvoiceBill) { public List<OmsInvoiceBill> listApprove(OmsInvoiceBill omsInvoiceBill) {
omsInvoiceBill.setApproveUser(ShiroUtils.getUserId()); omsInvoiceBill.setApproveUser(ShiroUtils.getUserId());
return omsInvoiceBillMapper.listApprove(omsInvoiceBill, "bu_todo"); return omsInvoiceBillMapper.listApprove(omsInvoiceBill, todoService.getFlowRelationSql("bu_todo",
Arrays.asList(omsInvoiceBill.getProcessKey()),
ShiroUtils.getUserId(),
Collections.singletonList("商务"),
()->{
return "t1.invoice_bill_code";
}));
} }
/** /**
@ -234,7 +249,13 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
@Override @Override
public List<OmsInvoiceBill> listApproved(OmsInvoiceBill omsInvoiceBill) { public List<OmsInvoiceBill> listApproved(OmsInvoiceBill omsInvoiceBill) {
omsInvoiceBill.setApproveUser(ShiroUtils.getUserId()); omsInvoiceBill.setApproveUser(ShiroUtils.getUserId());
return omsInvoiceBillMapper.listApprove(omsInvoiceBill, "bu_todo_completed"); return omsInvoiceBillMapper.listApprove(omsInvoiceBill, todoService.getFlowRelationSql("bu_todo_completed",
Arrays.asList(omsInvoiceBill.getProcessKey()),
ShiroUtils.getUserId(),
Collections.singletonList("商务"),
()->{
return "t1.invoice_bill_code";
}));
} }
/** /**
@ -353,6 +374,17 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
@Override @Override
public List<InvoiceProductDto> listProduct(String code) { public List<InvoiceProductDto> listProduct(String code) {
OmsReceivableInvoiceDetailItem omsReceivableInvoiceDetailItem = new OmsReceivableInvoiceDetailItem();
omsReceivableInvoiceDetailItem.setInvoiceBillCode(code);
List<OmsReceivableInvoiceDetailItem> omsReceivableInvoiceDetailItems = detailItemService.queryAll(omsReceivableInvoiceDetailItem);
if (CollUtil.isNotEmpty(omsReceivableInvoiceDetailItems)){
return omsReceivableInvoiceDetailItems.stream().map(item -> {
InvoiceProductDto invoiceProductDto = new InvoiceProductDto();
BeanUtils.copyProperties(item, invoiceProductDto);
return invoiceProductDto;
}).collect(Collectors.toList());
}
List<InventoryOuter> inventoryOuters = outerService.listByInvoiceBillCode(code); List<InventoryOuter> inventoryOuters = outerService.listByInvoiceBillCode(code);
if (CollUtil.isEmpty(inventoryOuters)){ if (CollUtil.isEmpty(inventoryOuters)){
return Collections.emptyList(); return Collections.emptyList();
@ -365,11 +397,17 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
Map<Long, Map<String, ProjectProductInfo>> priceMap = projectProductInfos.stream().collect(Collectors.groupingBy(ProjectProductInfo::getProjectId, Map<Long, Map<String, ProjectProductInfo>> priceMap = projectProductInfos.stream().collect(Collectors.groupingBy(ProjectProductInfo::getProjectId,
Collectors.toMap(ProjectProductInfo::getProductBomCode, Function.identity() , (v1, v2) -> v1)) Collectors.toMap(ProjectProductInfo::getProductBomCode, Function.identity() , (v1, v2) -> v1))
); );
List<ReceiptDetailDTO> receiptDetailDTOS = detailService.listReceivableByInvoiceBillCode(code);
Map<String, BigDecimal> detailMap = receiptDetailDTOS.stream().collect(Collectors.toMap(ReceiptDetailDTO::getReceivableBillCode, ReceiptDetailDTO::getReceiptAmount));
return inventoryOuters.stream().map(inventoryOuter -> { return inventoryOuters.stream().map(inventoryOuter -> {
InvoiceProductDto invoiceProductDto = new InvoiceProductDto(); InvoiceProductDto invoiceProductDto = new InvoiceProductDto();
invoiceProductDto.setAllPrice(detailMap.getOrDefault(inventoryOuter.getReceivableBillCode(), BigDecimal.ZERO));
invoiceProductDto.setProductCode(inventoryOuter.getProductCode()); invoiceProductDto.setProductCode(inventoryOuter.getProductCode());
invoiceProductDto.setQuantity(inventoryOuter.getQuantity()); invoiceProductDto.setOrderCode(inventoryOuter.getOrderCode());
invoiceProductDto.setProjectName(inventoryOuter.getProjectName()); invoiceProductDto.setProjectName(inventoryOuter.getProjectName());
invoiceProductDto.setProjectId(inventoryOuter.getProjectId()); invoiceProductDto.setProjectId(inventoryOuter.getProjectId());
Map<String, ProjectProductInfo> productInfoMap = priceMap.get(inventoryOuter.getProjectId()); Map<String, ProjectProductInfo> productInfoMap = priceMap.get(inventoryOuter.getProjectId());
@ -379,10 +417,13 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
invoiceProductDto.setProductModel(productInfo.getModel()); invoiceProductDto.setProductModel(productInfo.getModel());
invoiceProductDto.setProductName(productInfo.getProductName()); invoiceProductDto.setProductName(productInfo.getProductName());
invoiceProductDto.setProductDesc(productInfo.getProductDesc()); invoiceProductDto.setProductDesc(productInfo.getProductDesc());
invoiceProductDto.setPrice(productInfo.getPrice().divide( invoiceProductDto.setPrice(productInfo.getPrice());
BigDecimal allPriceWithoutTax = invoiceProductDto.getAllPrice().divide(
BigDecimal.ONE.add(productInfo.getTaxRate().divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP)) BigDecimal.ONE.add(productInfo.getTaxRate().divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP))
, 2, RoundingMode.HALF_UP)); , 2, RoundingMode.HALF_UP);
invoiceProductDto.setTaxAmount(invoiceProductDto.getAllPrice().subtract(allPriceWithoutTax));
invoiceProductDto.setTaxRate(productInfo.getTaxRate()); invoiceProductDto.setTaxRate(productInfo.getTaxRate());
invoiceProductDto.setQuantity(invoiceProductDto.getAllPrice().divide(invoiceProductDto.getPrice(), 0, RoundingMode.HALF_UP).longValue());
} }
} }
return invoiceProductDto; return invoiceProductDto;
@ -391,8 +432,13 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
@Override @Override
public AjaxResult applyInvoice(OmsInvoiceBill omsInvoiceBill) { public AjaxResult applyInvoice(OmsInvoiceBill omsInvoiceBill) {
// todo 保存detailList detailItemService.saveBatch(omsInvoiceBill.getDetailItemList());
//todo 开启审批流程 todoService.startProcessDeleteBefore(omsInvoiceBill.getInvoiceBillCode(), omsInvoiceBill.getInvoiceBillCode()
, new HashMap<String, Object>() {{
put("applyUserName", ShiroUtils.getSysUser().getUserName());
put("applyUser", ShiroUtils.getUserId());
}}
, processConfig.getDefinition().getFinanceInvoiceApprove());
omsInvoiceBill.setApproveStatus(ApproveStatusEnum.WAIT_APPROVE.getCode()); omsInvoiceBill.setApproveStatus(ApproveStatusEnum.WAIT_APPROVE.getCode());
omsInvoiceBillMapper.applyInvoice(omsInvoiceBill); omsInvoiceBillMapper.applyInvoice(omsInvoiceBill);
return AjaxResult.success(); return AjaxResult.success();
@ -535,6 +581,38 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
@Override @Override
public boolean todoApproveCallback(Todo todo) { public boolean todoApproveCallback(Todo todo) {
if (CollUtil.isEmpty(todo.getVariables())) {
return TodoCommonTemplate.super.todoApproveCallback(todo);
}
Integer approveBtn = (Integer) todo.getVariables().get("approveBtn");
if (approveBtn == null) {
return TodoCommonTemplate.super.todoApproveCallback(todo);
}
String taskName = todo.getTaskName();
String businessKey = todo.getBusinessKey();
OmsInvoiceBill invoiceBill = selectOmsInvoiceBillByCode(businessKey);
OmsInvoiceBill updateBill = new OmsInvoiceBill();
updateBill.setId(invoiceBill.getId());
if (approveBtn==0){
//驳回
updateBill.setApproveStatus(ApproveStatusEnum.APPROVE_REJECT.getCode());
updateOmsInvoiceBill(updateBill);
}else{
//通过
if (todo.getProcessKey().equals(processConfig.getDefinition().getFinanceInvoiceApprove()) && taskName.startsWith("财务")){
updateBill.setApproveStatus(ApproveStatusEnum.APPROVE_COMPLETE.getCode());
updateBill.setApproveTime(new Date());
updateOmsInvoiceBill(updateBill);
} else if(todo.getProcessKey().equals(processConfig.getDefinition().getFinanceInvoiceRefound()) && taskName.startsWith("财务")){
updateBill.setApproveStatus(ApproveStatusEnum.APPROVE_COMPLETE.getCode());
updateBill.setApproveTime(new Date());
updateOmsInvoiceBill(updateBill);
}
}
return TodoCommonTemplate.super.todoApproveCallback(todo); return TodoCommonTemplate.super.todoApproveCallback(todo);
} }
@ -542,30 +620,5 @@ public class OmsInvoiceBillServiceImpl implements IOmsInvoiceBillService, TodoCo
public boolean multiInstanceApproveCallback(String activityName, ProcessInstance processInstance) { public boolean multiInstanceApproveCallback(String activityName, ProcessInstance processInstance) {
return TodoCommonTemplate.super.multiInstanceApproveCallback(activityName, processInstance); return TodoCommonTemplate.super.multiInstanceApproveCallback(activityName, processInstance);
} }
// @Override
// public String getBusinessKey() {
// return "invoiceBillCode";
// }
//
// @Override
// public void reject(String businessKey) {
// OmsInvoiceBill omsInvoiceBill = new OmsInvoiceBill();
// omsInvoiceBill.setInvoiceBillCode(businessKey);
// omsInvoiceBill.setApproveStatus(ApproveStatusEnum.APPROVE_REJECT.getCode());
// omsInvoiceBillMapper.updateOmsInvoiceBillByCode(omsInvoiceBill);
// }
//
// @Override
// public void approve(String businessKey) {
// OmsInvoiceBill omsInvoiceBill = new OmsInvoiceBill();
// omsInvoiceBill.setInvoiceBillCode(businessKey);
// omsInvoiceBill.setApproveStatus(ApproveStatusEnum.APPROVE_COMPLETE.getCode());
// omsInvoiceBill.setInvoiceStatus(OmsInvoiceBill.InvoiceStatusEnum.INVOICE.getCode());
// omsInvoiceBill.setApproveTime(DateUtils.getNowDate());
// omsInvoiceBillMapper.updateOmsInvoiceBillByCode(omsInvoiceBill);
//
// OmsInvoiceBill existBill = selectOmsInvoiceBillByCode(businessKey);
// // 如果需要更新关联的应收单状态,可以在这里添加逻辑
// // omsReceivableBillService.updateInvoiceAmount(existBill.getReceivableBillCode(), existBill.getTotalPriceWithTax());
// }
} }

View File

@ -0,0 +1,84 @@
package com.ruoyi.sip.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.sip.domain.OmsReceivableInvoiceDetailItem;
import com.ruoyi.sip.mapper.OmsReceivableInvoiceDetailItemMapper;
import com.ruoyi.sip.service.IOmsReceivableInvoiceDetailItemService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Author ch
* @Desc -(OmsReceivableInvoiceDetailItem)
* @Date 2025-12-29 17:00:47
*/
@Service
public class OmsReceivableInvoiceDetailItemServiceImpl implements IOmsReceivableInvoiceDetailItemService {
@Resource
private OmsReceivableInvoiceDetailItemMapper omsReceivableInvoiceDetailItemMapper;
/**
*
*
* @param omsReceivableInvoiceDetailItem
* @return
*/
@Override
public List<OmsReceivableInvoiceDetailItem> queryAll(OmsReceivableInvoiceDetailItem omsReceivableInvoiceDetailItem) {
List<OmsReceivableInvoiceDetailItem> dataList = omsReceivableInvoiceDetailItemMapper.queryAll(omsReceivableInvoiceDetailItem);
return dataList;
}
@Override
public OmsReceivableInvoiceDetailItem queryById(Long id) {
return omsReceivableInvoiceDetailItemMapper.queryById(id);
}
@Override
public int insert(OmsReceivableInvoiceDetailItem omsReceivableInvoiceDetailItem) {
return omsReceivableInvoiceDetailItemMapper.insert(omsReceivableInvoiceDetailItem);
}
@Override
public void saveBatch(List<OmsReceivableInvoiceDetailItem> omsReceivableInvoiceDetailItems) {
List<OmsReceivableInvoiceDetailItem> addList = omsReceivableInvoiceDetailItems.stream().filter(item -> item.getId() == null).collect(Collectors.toList());
if (CollUtil.isNotEmpty(addList)){
omsReceivableInvoiceDetailItemMapper.insertBatch(omsReceivableInvoiceDetailItems);
}
List<OmsReceivableInvoiceDetailItem> updateList = omsReceivableInvoiceDetailItems.stream().filter(item -> item.getId() != null).collect(Collectors.toList());
if (CollUtil.isNotEmpty(updateList)){
omsReceivableInvoiceDetailItemMapper.updateBatch(updateList);
}
}
@Override
public int update(OmsReceivableInvoiceDetailItem omsReceivableInvoiceDetailItem) {
return omsReceivableInvoiceDetailItemMapper.update(omsReceivableInvoiceDetailItem);
}
@Override
public int deleteById(Long id) {
return omsReceivableInvoiceDetailItemMapper.deleteById(id);
}
/**
* id-
*/
@Override
public int batchRemove(Long[] ids) {
return omsReceivableInvoiceDetailItemMapper.batchRemove(ids);
}
}

View File

@ -59,8 +59,8 @@
</if> </if>
<if test="projectCode != null and projectCode != ''"> <if test="projectCode != null and projectCode != ''">
and t1.receipt_bill_code in ( and t1.receipt_bill_code in (
select t1.receipt_bill_code from oms_payable_ticket_detail t1 select t1.receipt_bill_code from oms_receivable_receipt_detail t1
inner join oms_payable_bill t2 on t1.payable_bill_id=t2.id inner join oms_receivable_bill t2 on t1.receivable_bill_id=t2.id
inner join project_order_info t3 on t2.order_code=t3.order_code inner join project_order_info t3 on t2.order_code=t3.order_code
inner join project_info t4 on t3.project_id=t4.id inner join project_info t4 on t3.project_id=t4.id
where t4.project_code = #{projectCode} where t4.project_code = #{projectCode}
@ -68,15 +68,15 @@
</if> </if>
<if test="projectName != null and projectName != ''"> <if test="projectName != null and projectName != ''">
and t1.receipt_bill_code in ( and t1.receipt_bill_code in (
select t1.receipt_bill_code from oms_payable_ticket_detail t1 select t1.receipt_bill_code from oms_receivable_receipt_detail t1
inner join oms_payable_bill t2 on t1.payable_bill_id=t2.id inner join oms_receivable_bill t2 on t1.receivable_bill_id=t2.id
inner join project_order_info t3 on t2.order_code=t3.order_code inner join project_order_info t3 on t2.order_code=t3.order_code
inner join project_info t4 on t3.project_id=t4.id inner join project_info t4 on t3.project_id=t4.id
where t4.project_name like concat('%',#{projectName},'%') where t4.project_name like concat('%',#{projectName},'%')
) )
</if> </if>
<if test="receivableBillCode != null and receivableBillCode != ''"> <if test="receivableBillCode != null and receivableBillCode != ''">
t1.receipt_bill_code in ( and t1.receipt_bill_code in (
select receipt_bill_code from oms_receivable_receipt_detail orrd select receipt_bill_code from oms_receivable_receipt_detail orrd
left join oms_receivable_bill orb on orrd.receivable_bill_id=orb.ID left join oms_receivable_bill orb on orrd.receivable_bill_id=orb.ID
where orb.receivable_bill_code=#{receivableBillCode} where orb.receivable_bill_code=#{receivableBillCode}
@ -154,7 +154,7 @@
and t1.receipt_bill_code in and t1.receipt_bill_code in
( (
select business_key from bu_todo where approve_user_name like concat('%', #{approveNode}, '%') and process_key in ( select business_key from bu_todo where approve_user_name like concat('%', #{approveNode}, '%') and process_key in (
'finance_ticket_refound','fianance_ticket') 'finance_receipt_approve','finance_receipt_refound')
) )
</if> </if>
<if test="approveTime != null"> <if test="approveTime != null">
@ -271,8 +271,8 @@
</if> </if>
<if test="entity.projectCode != null and entity.projectCode != ''"> <if test="entity.projectCode != null and entity.projectCode != ''">
and t1.receipt_bill_code in ( and t1.receipt_bill_code in (
select t1.receipt_bill_code from oms_payable_ticket_detail t1 select t1.receipt_bill_code from oms_receivable_receipt_detail t1
inner join oms_payable_bill t2 on t1.payable_bill_id=t2.id inner join oms_receivable_bill t2 on t1.receivable_bill_id=t2.id
inner join project_order_info t3 on t2.order_code=t3.order_code inner join project_order_info t3 on t2.order_code=t3.order_code
inner join project_info t4 on t3.project_id=t4.id inner join project_info t4 on t3.project_id=t4.id
where t4.project_code = #{entity.projectCode} where t4.project_code = #{entity.projectCode}
@ -280,8 +280,8 @@
</if> </if>
<if test="entity.projectName != null and entity.projectName != ''"> <if test="entity.projectName != null and entity.projectName != ''">
and t1.receipt_bill_code in ( and t1.receipt_bill_code in (
select t1.receipt_bill_code from oms_payable_ticket_detail t1 select t1.receipt_bill_code from oms_receivable_receipt_detail t1
inner join oms_payable_bill t2 on t1.payable_bill_id=t2.id inner join oms_receivable_bill t2 on t1.receivable_bill_id=t2.id
inner join project_order_info t3 on t2.order_code=t3.order_code inner join project_order_info t3 on t2.order_code=t3.order_code
inner join project_info t4 on t3.project_id=t4.id inner join project_info t4 on t3.project_id=t4.id
where t4.project_name like concat('%',#{entity.projectName},'%') where t4.project_name like concat('%',#{entity.projectName},'%')
@ -332,13 +332,13 @@
<if test="(entity.params.beginApplyTime != null and entity.params.beginApplyTime != '') or (entity.params.endApplyTime != null and entity.params.endApplyTime!='')"> <if test="(entity.params.beginApplyTime != null and entity.params.beginApplyTime != '') or (entity.params.endApplyTime != null and entity.params.endApplyTime!='')">
<choose> <choose>
<when test="(entity.params.beginApplyTime != null and entity.params.beginApplyTime != '') and (entity.params.endApplyTime != null and entity.params.endApplyTime!='')"> <when test="(entity.params.beginApplyTime != null and entity.params.beginApplyTime != '') and (entity.params.endApplyTime != null and entity.params.endApplyTime!='')">
and t3.apply_time between #{entity.params.beginApplyTime} and #{entity.params.endApplyTime} and flow.apply_time between #{entity.params.beginApplyTime} and #{entity.params.endApplyTime}
</when> </when>
<when test="(entity.params.beginApplyTime != null and entity.params.beginApplyTime != '')"> <when test="(entity.params.beginApplyTime != null and entity.params.beginApplyTime != '')">
and t3.apply_time <![CDATA[ >= ]]> #{entity.params.beginApplyTime} and flow.apply_time <![CDATA[ >= ]]> #{entity.params.beginApplyTime}
</when> </when>
<when test="(entity.params.endApplyTime != null and entity.params.endApplyTime!='')"> <when test="(entity.params.endApplyTime != null and entity.params.endApplyTime!='')">
and t3.apply_time <![CDATA[ <= ]]> #{entity.params.endApplyTime} and flow.apply_time <![CDATA[ <= ]]> #{entity.params.endApplyTime}
</when> </when>
</choose> </choose>

View File

@ -0,0 +1,302 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.sip.mapper.OmsReceivableInvoiceDetailItemMapper">
<resultMap type="com.ruoyi.sip.domain.OmsReceivableInvoiceDetailItem" id="OmsReceivableInvoiceDetailItemMap">
<result property="id" column="id"/>
<result property="invoiceBillCode" column="invoice_bill_code"/>
<result property="projectName" column="project_name"/>
<result property="orderCode" column="order_code"/>
<result property="productCode" column="product_code"/>
<result property="productName" column="product_name"/>
<result property="productModel" column="product_model"/>
<result property="quantity" column="quantity"/>
<result property="price" column="price"/>
<result property="allPrice" column="all_price"/>
<result property="taxAmount" column="tax_amount"/>
<result property="taxRate" column="tax_rate"/>
</resultMap>
<!-- 基本字段 -->
<sql id="Base_Column_List">
id, invoice_bill_code, project_name, order_code, product_code, product_name, product_model, quantity, price, all_price, tax_amount, tax_rate,unit
</sql>
<!--通过实体作为筛选条件查询-->
<select id="queryAll" resultMap="OmsReceivableInvoiceDetailItemMap">
select
<include refid="Base_Column_List"/>
from oms_receivable_invoice_detail_item
<where>
<if test="id != null">
and id = #{id}
</if>
<if test="invoiceBillCode != null">
and invoice_bill_code = #{invoiceBillCode}
</if>
<if test="projectName != null and projectName != ''">
and project_name = #{projectName}
</if>
<if test="orderCode != null and orderCode != ''">
and order_code = #{orderCode}
</if>
<if test="productCode != null and productCode != ''">
and product_code = #{productCode}
</if>
<if test="productName != null and productName != ''">
and product_name = #{productName}
</if>
<if test="productModel != null and productModel != ''">
and product_model = #{productModel}
</if>
<if test="quantity != null">
and quantity = #{quantity}
</if>
<if test="price != null">
and price = #{price}
</if>
<if test="allPrice != null">
and all_price = #{allPrice}
</if>
<if test="taxAmount != null">
and tax_amount = #{taxAmount}
</if>
<if test="taxRate != null">
and tax_rate = #{taxRate}
</if>
</where>
</select>
<!--根据ID查详情-->
<select id="queryById" parameterType="Integer" resultMap="OmsReceivableInvoiceDetailItemMap">
SELECT id,
invoice_bill_code,
project_name,
order_code,
product_code,
product_name,
product_model,
quantity,
price,
all_price,
tax_amount,
tax_rate
FROM oms_receivable_invoice_detail_item
WHERE id = #{id}
LIMIT 1
</select>
<!--新增所有列-->
<insert id="insert" keyProperty="id" useGeneratedKeys="true">
INSERT INTO oms_receivable_invoice_detail_item
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="invoiceBillCode != null">
invoice_bill_code,
</if>
<if test="projectName != null and projectName != ''">
project_name,
</if>
<if test="orderCode != null and orderCode != ''">
order_code,
</if>
<if test="productCode != null and productCode != ''">
product_code,
</if>
<if test="productName != null and productName != ''">
product_name,
</if>
<if test="productModel != null and productModel != ''">
product_model,
</if>
<if test="quantity != null">
quantity,
</if>
<if test="price != null">
price,
</if>
<if test="allPrice != null">
all_price,
</if>
<if test="taxAmount != null">
tax_amount,
</if>
<if test="taxRate != null">
tax_rate,
</if>
<if test="unit != null">
unit,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="invoiceBillCode != null">
#{invoiceBillCode},
</if>
<if test="projectName != null and projectName != ''">
#{projectName},
</if>
<if test="orderCode != null and orderCode != ''">
#{orderCode},
</if>
<if test="productCode != null and productCode != ''">
#{productCode},
</if>
<if test="productName != null and productName != ''">
#{productName},
</if>
<if test="productModel != null and productModel != ''">
#{productModel},
</if>
<if test="quantity != null">
#{quantity},
</if>
<if test="price != null">
#{price},
</if>
<if test="allPrice != null">
#{allPrice},
</if>
<if test="taxAmount != null">
#{taxAmount},
</if>
<if test="taxRate != null">
#{taxRate},
</if>
<if test="unit != null">
#{unit},
</if>
</trim>
</insert>
<insert id="insertBatch">
INSERT INTO oms_receivable_invoice_detail_item
(
invoice_bill_code,project_name,order_code,product_code,product_name,product_model
,quantity,price,all_price,tax_amount,tax_rate,unit)
values <foreach collection="list" item="item" separator=",">
(
#{item.invoiceBillCode},
#{item.projectName},
#{item.orderCode},
#{item.productCode},
#{item.productName},
#{item.productModel},
#{item.quantity},
#{item.price},
#{item.allPrice},
#{item.taxAmount},
#{item.taxRate},
#{item.unit}
)
</foreach>
</insert>
<!--通过主键修改数据-->
<update id="update">
UPDATE oms_receivable_invoice_detail_item
<trim prefix="SET" suffixOverrides=",">
<if test="invoiceBillCode != null">
invoice_bill_code = #{invoiceBillCode},
</if>
<if test="projectName != null and projectName != ''">
project_name = #{projectName},
</if>
<if test="orderCode != null and orderCode != ''">
order_code = #{orderCode},
</if>
<if test="productCode != null and productCode != ''">
product_code = #{productCode},
</if>
<if test="productName != null and productName != ''">
product_name = #{productName},
</if>
<if test="productModel != null and productModel != ''">
product_model = #{productModel},
</if>
<if test="quantity != null">
quantity = #{quantity},
</if>
<if test="price != null">
price = #{price},
</if>
<if test="allPrice != null">
all_price = #{allPrice},
</if>
<if test="taxAmount != null">
tax_amount = #{taxAmount},
</if>
<if test="taxRate != null">
tax_rate = #{taxRate},
</if>
<if test="unit != null">
unit = #{unit},
</if>
</trim>
WHERE id = #{id}
</update>
<update id="updateBatch">
<foreach collection="list" separator=";" item="item">
UPDATE oms_receivable_invoice_detail_item
<trim prefix="SET" suffixOverrides=",">
<if test="item.invoiceBillCode != null">
invoice_bill_code = #{item.invoiceBillCode},
</if>
<if test="item.projectName != null and item.projectName != ''">
project_name = #{item.projectName},
</if>
<if test="item.orderCode != null and item.orderCode != ''">
order_code = #{item.orderCode},
</if>
<if test="item.productCode != null and item.productCode != ''">
product_code = #{item.productCode},
</if>
<if test="item.productName != null and item.productName != ''">
product_name = #{item.productName},
</if>
<if test="item.productModel != null and item.productModel != ''">
product_model = #{item.productModel},
</if>
<if test="item.quantity != null">
quantity = #{item.quantity},
</if>
<if test="item.price != null">
price = #{item.price},
</if>
<if test="item.allPrice != null">
all_price = #{item.allPrice},
</if>
<if test="item.taxAmount != null">
tax_amount = #{item.taxAmount},
</if>
<if test="item.taxRate != null">
tax_rate = #{item.taxRate},
</if>
<if test="item.unit != null">
unit = #{item.unit},
</if>
</trim>
WHERE id = #{item.id}
</foreach>
</update>
<!--通过主键删除-->
<delete id="deleteById">
DELETE
FROM oms_receivable_invoice_detail_item
WHERE id = #{id}
</delete>
<!--通过id批量删除-->
<delete id="batchRemove">
delete from oms_receivable_invoice_detail_item where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

View File

@ -166,12 +166,39 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select> </select>
<select id="listByInvoiceBillCode" resultType="com.ruoyi.sip.domain.InventoryOuter"> <select id="listByInvoiceBillCode" resultType="com.ruoyi.sip.domain.InventoryOuter">
<include refid="selectInventoryOuterRelationVo"/> select t1.id,
t1.outer_code,
t1.product_code,
t1.quantity,
t1.outer_status,
t1.order_code,
t1.contact_person,
t1.contact_phone,
t1.contact_address,
t1.delivery_time,
t1.delivery_time_type,
t1.create_by,
t1.update_by,
t1.create_time,
t1.update_time,
t1.delivery_status,
t2.model,
t3.id as order_id,
t3.project_id,
t5.user_name as createByName,
t4.project_code,
t4.project_name,
b.receivable_bill_code
from oms_inventory_outer t1
left join product_info t2 on t1.product_code = t2.product_code
left join project_order_info t3 on t1.order_code = t3.order_code
left join project_info t4 on t4.id = t3.project_id
left join sys_user t5 on t1.create_by = t5.user_id
JOIN oms_receivable_bill b JOIN oms_receivable_bill b
ON t1.outer_code = b.inventory_code ON t1.outer_code = b.inventory_code
JOIN oms_receivable_invoice_detail d JOIN oms_receivable_invoice_detail d
ON d.receivable_bill_id = b.id ON d.receivable_bill_id = b.id
WHERE d.invoice_bill_code =#{code}; WHERE d.invoice_bill_code =#{code}
</select> </select>
<insert id="insertInventoryOuter" parameterType="InventoryOuter" useGeneratedKeys="true" keyProperty="id"> <insert id="insertInventoryOuter" parameterType="InventoryOuter" useGeneratedKeys="true" keyProperty="id">

View File

@ -30,6 +30,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="approveTime" column="approve_time" /> <result property="approveTime" column="approve_time" />
<result property="refundStatus" column="refund_status" /> <result property="refundStatus" column="refund_status" />
<result property="originalBillId" column="original_bill_id" /> <result property="originalBillId" column="original_bill_id" />
<result property="invoiceApplyUser" column="invoice_apply_user" />
<result property="buyerName" column="buyer_name" /> <result property="buyerName" column="buyer_name" />
<result property="buyerCreditCode" column="buyer_credit_code" /> <result property="buyerCreditCode" column="buyer_credit_code" />
<result property="buyerBank" column="buyer_bank" /> <result property="buyerBank" column="buyer_bank" />
@ -41,34 +42,62 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap> </resultMap>
<sql id="selectOmsInvoiceBillVo"> <sql id="selectOmsInvoiceBillVo">
select id, invoice_bill_code, invoice_type, invoice_bill_type, select t1.id, t1.invoice_bill_code, t1.invoice_type, t1.invoice_bill_type,
invoice_time, partner_code,partner_name, total_price_with_tax, total_price_without_tax,invoice_price_with_tax,invoice_price_without_tax, t1.invoice_time, t1.partner_code,t1.partner_name, t1.total_price_with_tax, t1.total_price_without_tax,t1.invoice_price_with_tax,t1.invoice_price_without_tax,
tax_rate, create_by, create_time, update_by, update_time, t1.tax_rate, t1.create_by, t1.create_time, t1.update_by, t1.update_time,
remark, del_flag, actual_invoice_time, invoice_status, t1.remark, t1.del_flag, t1.actual_invoice_time, t1.invoice_status,
approve_status, approve_time, refund_status t1.approve_status, t1.approve_time, t1.refund_status
, original_bill_id, buyer_name, buyer_credit_code, buyer_bank, buyer_bank_account, , t1.original_bill_id, t1.invoice_apply_user, t1.buyer_name, t1.buyer_credit_code, t1.buyer_bank, t1.buyer_bank_account,
seller_name, seller_credit_code, seller_bank, seller_bank_account t1.seller_name, t1.seller_credit_code, t1.seller_bank, t1.seller_bank_account
from oms_invoice_bill from oms_invoice_bill t1
</sql> </sql>
<select id="selectOmsInvoiceBillList" parameterType="com.ruoyi.sip.domain.OmsInvoiceBill" resultMap="OmsInvoiceBillResult"> <select id="selectOmsInvoiceBillList" parameterType="com.ruoyi.sip.domain.OmsInvoiceBill" resultMap="OmsInvoiceBillResult">
<include refid="selectOmsInvoiceBillVo"/> <include refid="selectOmsInvoiceBillVo"/>
<where> <where>
<if test="invoiceBillCode != null and invoiceBillCode != ''"> <if test="invoiceBillCode != null and invoiceBillCode != ''">
and invoice_bill_code = #{invoiceBillCode} and t1.invoice_bill_code = #{invoiceBillCode}
</if>
<if test="receivableBillCode != null and receivableBillCode != ''">
and t1.invoice_bill_code in (
select invoice_bill_code from oms_receivable_invoice_detail orrd
left join oms_receivable_bill orb on orrd.receivable_bill_id=orb.id
where orb.receivable_bill_code=#{receivableBillCode}
)
</if>
<if test="projectCode != null and projectCode != ''">
and t1.invoice_bill_code in (
select t1.invoice_bill_code from oms_receivable_invoice_detail t1
inner join oms_receivable_bill t2 on t1.receivable_bill_id=t2.id
inner join project_order_info t3 on t2.order_code=t3.order_code
inner join project_info t4 on t3.project_id=t4.id
where t4.project_code = #{projectCode}
)
</if>
<if test="projectName != null and projectName != ''">
and t1.invoice_bill_code in (
select t1.invoice_bill_code from oms_receivable_invoice_detail t1
inner join oms_receivable_bill t2 on t1.receivable_bill_id=t2.id
inner join project_order_info t3 on t2.order_code=t3.order_code
inner join project_info t4 on t3.project_id=t4.id
where t4.project_name like concat('%',#{projectName},'%')
)
</if> </if>
<if test="invoiceType != null and invoiceType != ''"> <if test="invoiceType != null and invoiceType != ''">
and invoice_type = #{invoiceType} and t1.invoice_type = #{invoiceType}
</if> </if>
<if test="invoiceBillType != null and invoiceBillType != ''"> <if test="invoiceBillType != null and invoiceBillType != ''">
and invoice_bill_type = #{invoiceBillType} and t1.invoice_bill_type = #{invoiceBillType}
</if> </if>
<if test="invoiceTime != null "> <if test="invoiceTime != null ">
and invoice_time = #{invoiceTime} and invoice_time = #{invoiceTime}
</if> </if>
<if test="partnerCode != null and partnerCode != ''"> <if test="partnerCode != null and partnerCode != ''">
and partner_code = #{partnerCode} and t1.partner_code = #{partnerCode}
</if>
<if test="partnerName != null and partnerName != ''">
and t1.partner_name = #{partnerName}
</if> </if>
<if test="totalPriceWithTax != null "> <if test="totalPriceWithTax != null ">
and total_price_with_tax = #{totalPriceWithTax} and total_price_with_tax = #{totalPriceWithTax}
@ -101,13 +130,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
and actual_invoice_time = #{actualInvoiceTime} and actual_invoice_time = #{actualInvoiceTime}
</if> </if>
<if test="invoiceStatus != null and invoiceStatus != ''"> <if test="invoiceStatus != null and invoiceStatus != ''">
and invoice_status = #{invoiceStatus} and t1.invoice_status = #{invoiceStatus}
</if> </if>
<if test="approveStatus != null and approveStatus != ''"> <if test="approveStatus != null and approveStatus != ''">
and approve_status = #{approveStatus} and t1.approve_status = #{approveStatus}
</if> </if>
<if test="approveNode != null and approveNode != ''"> <if test="approveNode != null and approveNode != ''">
and approve_node = #{approveNode} and t1.invoice_bill_code in
(
select business_key from bu_todo where approve_user_name like concat('%', #{approveNode}, '%') and process_key in (
'finance_invoice_approve','finance_invoice_refound')
)
</if> </if>
<if test="approveTime != null "> <if test="approveTime != null ">
and approve_time = #{approveTime} and approve_time = #{approveTime}
@ -142,6 +175,34 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="sellerBankAccount != null and sellerBankAccount != ''"> <if test="sellerBankAccount != null and sellerBankAccount != ''">
and seller_bank_account = #{sellerBankAccount} and seller_bank_account = #{sellerBankAccount}
</if> </if>
<if test="(params.beginApproveTime != null and params.beginApproveTime != '') or (params.endApproveTime != null and params.endApproveTime!='')">
<choose>
<when test="(params.beginApproveTime != null and params.beginApproveTime != '') and (params.endApproveTime != null and params.endApproveTime!='')">
and t1.approve_time between #{params.beginApproveTime} and #{params.endApproveTime}
</when>
<when test="(params.beginApproveTime != null and params.beginApproveTime != '')">
and t1.approve_time <![CDATA[ >= ]]> #{params.beginApproveTime}
</when>
<when test="(params.endApproveTime != null and params.endApproveTime!='')">
and t1.approve_time <![CDATA[ <= ]]> #{params.endApproveTime}
</when>
</choose>
</if>
<if test="(params.beginInvoiceTime != null and params.beginInvoiceTime != '') or (params.endInvoiceTime != null and params.endInvoiceTime!='')">
<choose>
<when test="(params.beginInvoiceTime != null and params.beginInvoiceTime != '') and (params.endInvoiceTime != null and params.endInvoiceTime!='')">
and t1.invoice_time between #{params.beginInvoiceTime} and #{params.endInvoiceTime}
</when>
<when test="(params.beginInvoiceTime != null and params.beginInvoiceTime != '')">
and t1.invoice_time <![CDATA[ >= ]]> #{params.beginInvoiceTime}
</when>
<when test="(params.endInvoiceTime != null and params.endInvoiceTime!='')">
and t1.invoice_time <![CDATA[ <= ]]> #{params.endInvoiceTime}
</when>
</choose>
</if>
</where> </where>
</select> </select>
@ -250,6 +311,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="sellerBankAccount != null and sellerBankAccount != ''"> <if test="sellerBankAccount != null and sellerBankAccount != ''">
seller_bank_account, seller_bank_account,
</if> </if>
<if test="invoiceApplyUser != null and invoiceApplyUser != ''">
invoice_apply_user,
</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="invoiceBillCode != null and invoiceBillCode != ''"> <if test="invoiceBillCode != null and invoiceBillCode != ''">
@ -349,6 +413,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="sellerBankAccount != null and sellerBankAccount != ''"> <if test="sellerBankAccount != null and sellerBankAccount != ''">
#{sellerBankAccount}, #{sellerBankAccount},
</if> </if>
<if test="invoiceApplyUser != null and invoiceApplyUser != ''">
#{invoiceApplyUser},
</if>
</trim> </trim>
</insert> </insert>
@ -450,6 +517,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="sellerBankAccount != null and sellerBankAccount != ''"> <if test="sellerBankAccount != null and sellerBankAccount != ''">
seller_bank_account = #{sellerBankAccount}, seller_bank_account = #{sellerBankAccount},
</if> </if>
<if test="invoiceApplyUser != null and invoiceApplyUser != ''">
invoice_apply_user = #{invoiceApplyUser},
</if>
</trim> </trim>
where id = #{id} where id = #{id}
</update> </update>
@ -488,7 +558,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
seller_credit_code = #{sellerCreditCode}, seller_credit_code = #{sellerCreditCode},
seller_bank = #{sellerBank}, seller_bank = #{sellerBank},
seller_bank_account = #{sellerBankAccount}, seller_bank_account = #{sellerBankAccount},
approve_status=#{approveStatus} approve_status=#{approveStatus},
invoice_type=#{invoiceType},
remark=#{remark}
where invoice_bill_code = #{invoiceBillCode} where invoice_bill_code = #{invoiceBillCode}
</update> </update>
@ -527,17 +599,39 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete> </delete>
<select id="listApprove" resultType="com.ruoyi.sip.domain.OmsInvoiceBill"> <select id="listApprove" resultType="com.ruoyi.sip.domain.OmsInvoiceBill">
select t1.* from oms_invoice_bill t1 select t1.*
left join ${tablename} t2 on t1.invoice_bill_code = t2.business_key ${flowRelationDto.querySql}
from oms_invoice_bill t1
${flowRelationDto.joinSql}
where 1=1 where 1=1
<if test="omsInvoiceBill.invoiceBillCode != null and omsInvoiceBill.invoiceBillCode != ''"> <if test="entity.invoiceBillCode != null and entity.invoiceBillCode != ''">
and t1.invoice_bill_code = #{omsInvoiceBill.invoiceBillCode} and t1.invoice_bill_code = #{entity.invoiceBillCode}
</if> </if>
<if test="omsInvoiceBill.partnerCode != null and omsInvoiceBill.partnerCode != ''"> <if test="entity.partnerName != null and entity.partnerName != ''">
and t1.partner_code = #{omsInvoiceBill.partnerCode} and t1.partner_name like concat('%',#{entity.partnerName},'%')
</if> </if>
<if test="omsInvoiceBill.approveUser != null"> <if test="entity.projectName != null and entity.projectName != ''">
and t2.assignee_user_id = #{omsInvoiceBill.approveUser} and t1.invoice_bill_code in (
select t1.receipt_bill_code from oms_receivable_invoice_detail t1
inner join oms_receivable_bill t2 on t1.receivable_bill_id=t2.id
inner join project_order_info t3 on t2.order_code=t3.order_code
inner join project_info t4 on t3.project_id=t4.id
where t4.project_name like concat('%',#{entity.projectName},'%')
)
</if>
<if test="(entity.params.beginApplyTime != null and entity.params.beginApplyTime != '') or (entity.params.endApplyTime != null and entity.params.endApplyTime!='')">
<choose>
<when test="(entity.params.beginApplyTime != null and entity.params.beginApplyTime != '') and (entity.params.endApplyTime != null and entity.params.endApplyTime!='')">
and flow.apply_time between #{entity.params.beginApplyTime} and #{entity.params.endApplyTime}
</when>
<when test="(entity.params.beginApplyTime != null and entity.params.beginApplyTime != '')">
and flow.apply_time <![CDATA[ >= ]]> #{entity.params.beginApplyTime}
</when>
<when test="(entity.params.endApplyTime != null and entity.params.endApplyTime!='')">
and flow.apply_time <![CDATA[ <= ]]> #{entity.params.endApplyTime}
</when>
</choose>
</if> </if>
order by t1.create_time desc order by t1.create_time desc
</select> </select>

View File

@ -93,7 +93,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
order by create_time desc order by create_time desc
</select> </select>
<select id="listReceivableByInvoiceBillCode" resultType="com.ruoyi.sip.domain.dto.ReceiptDetailDTO"> <select id="listReceivableByInvoiceBillCode" resultType="com.ruoyi.sip.domain.dto.ReceiptDetailDTO">
select t1.receipt_amount, t2.receivable_bill_code, t4.project_name, t4.project_code, t2.total_price_with_tax select t1.receipt_amount, t2.receivable_bill_code, t4.project_name, t4.project_code, t2.total_price_with_tax,t2.product_type
from (SELECT sum(invoice_amount) receipt_amount, from (SELECT sum(invoice_amount) receipt_amount,
receivable_bill_id receivable_bill_id
FROM oms_receivable_invoice_detail FROM oms_receivable_invoice_detail