feat(finance): 增强付款单功能及附件管理

- 将付款时间相关字段格式从日期调整为日期时间格式
- 在详情页和列表页使用dict-tag展示支付方式、付款状态和审批状态
- 新增回执单下载功能和相关UI组件
- 增加收票计划Tab页支持
- 添加发起付款和回执单弹窗界面及相关逻辑
- 实现附件上传与管理服务,包括财务附件实体和接口定义
- 更新付款单和应付明细实体结构以支持附件关联
- 优化前端组件导入和数据处理逻辑
- 修复并增强多个API接口功能,如applyPayment、uploadReceipt等
- 补充Mapper XML配置和Service实现逻辑
- 调整后端实体类属性以匹配新的业务需求
- 增加对附件信息的查询与绑定处理逻辑
- 引入新的枚举类型用于区分不同类型的关联单据
- 前端增加对新接口调用的支持以及表单交互优化
dev_1.0.0
chenhao 2025-12-09 20:51:15 +08:00
parent a1ea52a934
commit d3c4776bab
23 changed files with 1336 additions and 217 deletions

View File

@ -42,3 +42,20 @@ export function mergeAndInitiatePayment(data) {
data: data
})
}
// [PLACEHOLDER] 查询收票计划列表 - Endpoint to be confirmed by user
export function getReceivingTicketPlan(payableBillId) {
return request({
url: `/finance/payable/ticket-plan/${payableBillId}`,
method: 'get'
})
}
// [PLACEHOLDER] 更新收票计划 - Endpoint to be confirmed by user
export function updateReceivingTicketPlan(payableBillId, data) {
return request({
url: `/finance/payable/ticket-plan/${payableBillId}`,
method: 'post',
data: data
})
}

View File

@ -21,6 +21,27 @@ export function getPayment(id) {
})
}
// 查询付款单附件
export function getPaymentAttachments(id, params) {
return request({
url: `/finance/payment/attachment/${id}`,
method: 'get',
params
})
}
// 上传付款单附件
export function uploadPaymentAttachment(data) {
return request({
url: '/finance/payment/uploadReceipt',
method: 'post',
headers: {
'Content-Type': 'multipart/form-data'
},
data: data
});
}
// 退回付款单
export function returnPayment(id) {
return request({
@ -38,3 +59,13 @@ export function addPayment(data) {
needLoading: true
})
}
// 申请付款
export function applyPaymentApi(data) {
return request({
url: '/finance/payment/applyPayment',
method: 'post',
data: data
})
}

View File

@ -100,7 +100,8 @@
<el-table-column prop="paymentBillCode" label="采购付款单编号"></el-table-column>
<el-table-column label="回执单/退款图">
<template slot-scope="scope">
{{ scope.row.receiptAttachmentId || scope.row.refundProofAttachmentId }}
{{ scope.row.finAttachment && scope.row.finAttachment.fileName || '-'}}
<el-button v-show="scope.row.finAttachment" type="primary" size="mini" @click="downloadFile(scope.row.finAttachment)"></el-button>
</template>
</el-table-column>
</el-table>
@ -108,6 +109,9 @@
<el-tab-pane label="付款计划" name="paymentPlan">
<PaymentPlan :isInitEdit=true :payableData="data"/>
</el-tab-pane>
<el-tab-pane label="收票计划" name="receivingTicketPlan">
<ReceivingTicketPlan :isInitEdit=true :payableData="data"/>
</el-tab-pane>
</el-tabs>
</div>
</div>
@ -121,13 +125,15 @@
<script>
import PaymentPlan from './PaymentPlan.vue';
import ReceivingTicketPlan from './ReceivingTicketPlan.vue';
import { getPayable } from "@/api/finance/payable";
export default {
name: "EditForm",
dicts: ['product_type','payment_status','payable_detail_type'],
components: {
PaymentPlan
PaymentPlan,
ReceivingTicketPlan
},
props: {
visible: {
@ -166,6 +172,17 @@ export default {
this.formData = res.data;
});
},
downloadFile(attachment){
if (attachment){
const link = document.createElement('a');
link.href = process.env.VUE_APP_BASE_API + "/common/download/resource?resource=" +attachment.filePath;
link.download = attachment.fileName || 'receipt';
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
},
getSummaries(param) {
const { columns, data } = param;
const sums = [];

View File

@ -19,9 +19,9 @@
<el-form-item label="预计付款时间" prop="paymentTime">
<el-date-picker
v-model="form.paymentTime"
type="date"
type="datetime"
placeholder="选择日期"
value-format="yyyy-MM-dd"
value-format="yyyy-MM-dd HH:mm:ss"
></el-date-picker>
</el-form-item>
<el-form-item label="含税总价" prop="totalPriceWithTax">

View File

@ -47,15 +47,19 @@
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<div class="detail-item">支付方式: {{ detail.paymentMethod || '-'}}</div>
</el-col>
<el-col :span="8">
<div class="detail-item">回执单/退款图: {{ detail.receiptAttachmentId }} /
{{ detail.refundProofAttachmentId }}
<div class="detail-item">支付方式:
<dict-tag :options="dict.type.payment_method" :value="detail.paymentMethod"/>
</div>
</el-col>
<el-col :span="8">
<div class="detail-item">付款状态: {{ detail.paymentStatus }}</div>
<div class="detail-item">回执单/退款图:
<!-- <span onclick="downloadFile(this.detail.finAttachment)">{{detail.finAttachment?.fileName || '-'}}</span>-->
</div>
</el-col>
<el-col :span="8">
<div class="detail-item">付款状态:
<dict-tag :options="dict.type.payment_status" :value="detail.paymentStatus"/>
</div>
</el-col>
</el-row>
<el-row :gutter="20">
@ -85,7 +89,9 @@
<div class="detail-item">审批节点: {{ detail.approveNode|| '-' }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item">审批状态: {{ detail.approveStatus || '-'}}</div>
<div class="detail-item">审批状态:
<dict-tag :options="dict.type.approve_status" :value="detail.approveStatus"/>
</div>
</el-col>
<el-col :span="8">
<div class="detail-item">审批通过时间: {{ detail.approveTime || '-'}}</div>
@ -123,8 +129,19 @@ export default {
default: () => null,
},
},
dicts:['payment_bill_type'],
dicts:['payment_bill_type','approve_status','payment_status','payment_method'],
methods: {
downloadFile(attachment){
if (attachment){
const link = document.createElement('a');
link.href = this.getImageUrl(attachment.filePath);
link.download = attachment.fileName || 'receipt';
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
},
handleClose() {
this.$emit("update:visible", false);
},

View File

@ -0,0 +1,317 @@
<template>
<el-dialog title="回执单" :visible.sync="dialogVisible" width="900px" @close="handleClose">
<div v-if="loading" class="loading-spinner">
<i class="el-icon-loading"></i>
</div>
<div v-else class="receipt-dialog-body">
<div v-if="canUpload" class="upload-section">
<h4>上传新的回执单</h4>
<el-upload
ref="upload"
:http-request="handleUpload"
:before-upload="beforeUpload"
:file-list="fileList"
:auto-upload="false"
:limit="1"
:on-change="handleChange"
:on-remove="handleRemove"
list-type="picture-card"
accept=".pdf,.jpg,.jpeg,.png"
>
<i class="el-icon-plus"></i>
<div slot="tip" class="el-upload__tip">只能上传jpg/png/pdf文件, 且不超过2MB</div>
</el-upload>
<el-input
type="textarea"
:rows="2"
placeholder="请输入备注"
v-model="uploadRemark"
style="margin-bottom: 15px;"
></el-input>
</div>
<el-timeline v-if="attachments.length > 0">
<el-timeline-item
v-for="attachment in attachments"
:key="attachment.id"
:timestamp="parseTime(attachment.createTime, '{y}-{m}-{d} {h}:{i}:{s}')"
placement="top"
>
<el-card>
<div class="receipt-card-content">
<div class="receipt-details">
<div class="detail-item">
<span class="item-label">付款方式</span>
<span class="item-value">
<dict-tag :options="dicts.payment_method" :value="paymentData.paymentMethod"/>
</span>
</div>
<div class="detail-item">
<span class="item-label">回执单</span>
<div class="item-value">
<div class="image-wrapper">
<el-image
v-if="!isPdf(attachment.filePath)"
:src="getImageUrl(attachment.filePath)"
:preview-src-list="previewList"
style="width: 200px; height: 150px;"
fit="contain"
></el-image>
<a v-else :href="getImageUrl(attachment.filePath)" target="_blank" class="pdf-placeholder">
<i class="el-icon-document"></i>
<span>PDF - 点击预览</span>
</a>
<div v-if="attachment.delFlag === '2'" class="void-overlay"></div>
</div>
<el-button
size="mini"
type="primary"
class="download-btn"
icon="el-icon-download"
@click="downloadFile(attachment)"
>下载回执单</el-button>
</div>
</div>
<div class="detail-item">
<span class="item-label">含税总价</span>
<span class="item-value">{{ paymentData.totalPriceWithTax }}</span>
</div>
<div class="detail-item">
<span class="item-label">备注</span>
<span class="item-value">{{ attachment.remark }}</span>
</div>
</div>
</div>
</el-card>
</el-timeline-item>
</el-timeline>
<el-empty v-else description="暂无回执单"></el-empty>
</div>
<span slot="footer" class="dialog-footer">
<el-button v-if="canUpload" type="primary" @click="submitUpload"></el-button>
<el-button @click="dialogVisible = false">关闭</el-button>
</span>
</el-dialog>
</template>
<script>
import { getPaymentAttachments, uploadPaymentAttachment } from "@/api/finance/payment";
export default {
name: "ReceiptDialog",
props: {
visible: {
type: Boolean,
default: false,
},
paymentData: {
type: Object,
default: () => null,
},
dicts: {
type: Object,
default: () => ({})
}
},
data() {
return {
loading: false,
attachments: [],
fileList: [],
uploadRemark: "",
};
},
computed: {
dialogVisible: {
get() {
return this.visible;
},
set(val) {
this.$emit("update:visible", val);
},
},
previewList() {
return this.attachments
.filter(att => !this.isPdf(att.filePath))
.map(att => this.getImageUrl(att.filePath));
},
canUpload() {
if (!this.attachments || this.attachments.length === 0) {
return true;
}
return this.attachments.every(att => att.delFlag === '2');
}
},
watch: {
visible(val) {
if (val && this.paymentData) {
this.fetchAttachments();
}
},
},
methods: {
fetchAttachments() {
if (!this.paymentData.id) return;
this.loading = true;
getPaymentAttachments(this.paymentData.id, { type: 'payment' })
.then(response => {
const data = response.data || [];
data.sort((a, b) => new Date(b.createTime) - new Date(a.createTime));
this.attachments = data;
this.loading = false;
})
.catch(() => {
this.attachments = [];
this.loading = false;
});
},
getImageUrl(resource) {
return process.env.VUE_APP_BASE_API + "/common/download/resource?resource=" + resource;
},
isPdf(filePath) {
return filePath && filePath.toLowerCase().endsWith('.pdf');
},
downloadFile(attachment) {
const link = document.createElement('a');
link.href = this.getImageUrl(attachment.filePath);
link.download = attachment.fileName || 'receipt';
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
},
handleClose() {
this.attachments = [];
this.fileList = [];
this.uploadRemark = "";
},
submitUpload() {
if (this.$refs.upload.uploadFiles.length === 0) {
this.$message.warning("请选择要上传的文件");
return;
}
this.$refs.upload.submit();
},
handleRemove(file, fileList) {
this.fileList = fileList;
},
handleChange(file, fileList) {
this.fileList = fileList.slice(-1);
},
handleUpload(options) {
const formData = new FormData();
formData.append("file", options.file);
formData.append("relatedBillId", this.paymentData.id);
formData.append("remark", this.uploadRemark);
uploadPaymentAttachment(formData)
.then(response => {
this.$message.success("上传成功");
this.fileList = [];
this.uploadRemark = "";
this.fetchAttachments();
})
.catch(error => {
this.$message.error("上传失败");
});
},
beforeUpload(file) {
const isLt2M = file.size / 1024 / 1024 < 2;
const isAcceptedType = ['image/jpeg', 'image/png', 'application/pdf'].includes(file.type);
if (!isAcceptedType) {
this.$message.error('上传文件只能是 JPG/PNG/PDF 格式!');
}
if (!isLt2M) {
this.$message.error('上传文件大小不能超过 2MB!');
}
return isAcceptedType && isLt2M;
},
},
};
</script>
<style scoped>
.receipt-dialog-body {
max-height: 60vh;
overflow-y: auto;
}
.loading-spinner {
text-align: center;
font-size: 24px;
padding: 20px;
}
.receipt-card-content {
display: flex;
}
.receipt-details {
flex-grow: 1;
}
.detail-item {
display: flex;
margin-bottom: 12px;
font-size: 14px;
}
.item-label {
width: 80px;
color: #606266;
text-align: right;
margin-right: 15px;
flex-shrink: 0;
}
.item-value {
color: #303133;
}
.image-wrapper {
position: relative;
width: 200px;
min-height: 150px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #DCDFE6;
border-radius: 4px;
margin-bottom: 10px;
}
.void-overlay {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(-30deg);
color: red;
font-size: 48px;
font-weight: bold;
opacity: 0.7;
pointer-events: none;
}
.download-btn {
display: block;
}
.upload-section {
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid #eee;
}
.pdf-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 200px;
height: 150px;
color: #606266;
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
}
.pdf-placeholder:hover {
border-color: #409EFF;
color: #409EFF;
}
.pdf-placeholder .el-icon-document {
font-size: 48px;
margin-bottom: 5px;
}
</style>

View File

@ -130,10 +130,10 @@
<el-table-column label="付款单编号" align="center" prop="paymentBillCode" />
<el-table-column label="预计付款时间" align="center" prop="paymentTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.paymentTime, '{y}-{m}-{d}') }}</span>
<span>{{ parseTime(scope.row.paymentTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="制造商名称" align="center" prop="vendorCode" />
<el-table-column label="制造商名称" align="center" prop="vendorName" />
<el-table-column label="含税总价" align="center" prop="totalPriceWithTax" />
<el-table-column label="付款单类型" align="center" prop="paymentBillType" >
<template slot-scope="scope">
@ -143,10 +143,14 @@
<el-table-column label="预付单剩余额度" align="center" prop="preResidueAmount" />
<el-table-column label="实际付款时间" align="center" prop="actualPaymentTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.actualPaymentTime, '{y}-{m}-{d}') }}</span>
<span>{{ parseTime(scope.row.actualPaymentTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="支付方式" align="center" prop="paymentMethod" >
<template slot-scope="scope">
<dict-tag :options="dict.type.payment_method" :value="scope.row.paymentMethod"/>
</template>
</el-table-column>
<el-table-column label="支付方式" align="center" prop="paymentMethod" />
<el-table-column label="付款状态" align="center" prop="paymentStatus" >
<template slot-scope="scope">
<dict-tag :options="dict.type.payment_status" :value="scope.row.paymentStatus"/>
@ -159,7 +163,7 @@
</el-table-column>
<el-table-column label="审批通过时间" align="center" prop="approveTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.approveTime, '{y}-{m}-{d}') }}</span>
<span>{{ parseTime(scope.row.approveTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="审批节点" align="center" prop="approveNode" />
@ -171,6 +175,18 @@
icon="el-icon-view"
@click="handleDetail(scope.row)"
>查看详情</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-money"
@click="handleReceipt(scope.row)"
>回执单</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-position"
@click="applyPayment(scope.row)"
>发起付款</el-button>
<el-button
size="mini"
type="text"
@ -194,22 +210,60 @@
<detail-drawer :visible.sync="detailOpen" :detail="detailData"></detail-drawer>
<!-- 新增弹窗 -->
<add-form :visible.sync="addOpen" :dicts="dict.type" @submit="handleAddSubmit"></add-form>
<!-- 回执单弹窗 -->
<receipt-dialog :visible.sync="receiptOpen" :payment-data="currentRow" :dicts="dict.type"></receipt-dialog>
<!-- 付款申请弹窗 -->
<el-dialog title="发起付款" :visible.sync="applyPaymentOpen" width="600px" append-to-body>
<el-form ref="applyPaymentForm" :model="applyPaymentForm" label-width="120px">
<el-form-item label="付款方式" prop="paymentMethod">
<el-select v-model="applyPaymentForm.paymentMethod" placeholder="请选择付款方式">
<el-option
v-for="dict in dict.type.payment_method"
:key="dict.value"
:label="dict.label"
:value="dict.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="账户名称" prop="payName">
<el-input v-model="applyPaymentForm.payName" placeholder="请输入账户名称" />
</el-form-item>
<el-form-item label="银行账号" prop="payBankNumber">
<el-input v-model="applyPaymentForm.payBankNumber" placeholder="请输入银行账号" />
</el-form-item>
<el-form-item label="银行开户行" prop="payBankOpenAddress">
<el-input v-model="applyPaymentForm.payBankOpenAddress" placeholder="请输入银行开户行" />
</el-form-item>
<el-form-item label="银行行号" prop="bankNumber">
<el-input v-model="applyPaymentForm.bankNumber" placeholder="请输入银行行号" />
</el-form-item>
<el-form-item label="含税金额" prop="totalPriceWithTax">
<el-input v-model="applyPaymentForm.totalPriceWithTax" :disabled="true" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="applyPaymentOpen = false"> </el-button>
<el-button type="primary" @click="submitApplyPayment"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listPayment, getPayment, returnPayment, addPayment } from "@/api/finance/payment";
import { listPayment, getPayment, returnPayment, addPayment, applyPaymentApi } from "@/api/finance/payment";
import { addDateRange } from "@/utils/ruoyi";
import DetailDrawer from "./components/DetailDrawer.vue";
import AddForm from "./components/AddForm.vue";
import ReceiptDialog from "./components/ReceiptDialog.vue";
export default {
name: "Payment",
components: {
DetailDrawer,
AddForm
AddForm,
ReceiptDialog
},
dicts:['payment_bill_type','approve_status','payment_status'],
dicts:['payment_bill_type','approve_status','payment_status', 'payment_method'],
data() {
return {
//
@ -244,6 +298,12 @@ export default {
detailData: null,
//
addOpen: false,
//
receiptOpen: false,
currentRow: null,
//
applyPaymentOpen: false,
applyPaymentForm: {},
};
},
created() {
@ -251,7 +311,30 @@ export default {
},
methods: {
addDateRange, // Mixin addDateRange function
/** 查询付款单列表 */
/** 发起付款按钮操作 */
applyPayment(row){
this.applyPaymentForm = {
id: row.id,
paymentMethod: row.paymentMethod,
payName: row.payName,
payBankNumber: row.payBankNumber,
payBankOpenAddress: row.payBankOpenAddress,
bankNumber: row.bankNumber,
totalPriceWithTax: row.totalPriceWithTax
};
this.applyPaymentOpen = true;
},
/** 提交付款申请 */
submitApplyPayment() {
applyPaymentApi(this.applyPaymentForm).then(response => {
this.$modal.msgSuccess("付款申请提交成功");
this.applyPaymentOpen = false;
this.getList();
}).catch(error => {
console.error("付款申请提交失败", error);
this.$modal.msgError("付款申请提交失败");
});
},
getList() {
this.loading = true;
let query = { ...this.queryParams };
@ -300,6 +383,11 @@ export default {
this.detailOpen = true;
});
},
/** 回执单按钮操作 */
handleReceipt(row) {
this.currentRow = row;
this.receiptOpen = true;
},
/** 退回按钮操作 */
handleReturn(row) {
this.$modal.confirm('是否确认退回付款单编号为"' + row.paymentBillCode + '"的数据项?').then(function() {

View File

@ -0,0 +1,26 @@
package com.ruoyi.sip.controller;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.sip.domain.OmsFinAttachment;
import com.ruoyi.sip.service.IOmsFinAttachmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/finance/attachment")
public class OmsFinAttachmentController extends BaseController {
@Autowired
private IOmsFinAttachmentService omsFinAttachmentService;
@GetMapping("/{id}")
@ResponseBody
public OmsFinAttachment getInfo(@PathVariable("id") Long id)
{
return omsFinAttachmentService.selectOmsFinAttachmentById(id);
}
}

View File

@ -1,6 +1,10 @@
package com.ruoyi.sip.controller;
import java.util.Collections;
import java.util.List;
import com.ruoyi.sip.domain.OmsFinAttachment;
import com.ruoyi.sip.service.IOmsFinAttachmentService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@ -14,6 +18,7 @@ import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
import org.springframework.web.multipart.MultipartFile;
/**
* Controller
@ -29,6 +34,8 @@ public class OmsPaymentBillController extends BaseController
@Autowired
private IOmsPaymentBillService omsPaymentBillService;
@Autowired
private IOmsFinAttachmentService omsFinAttachmentService;
@RequiresPermissions("finance:payment:view")
@GetMapping()
@ -147,56 +154,49 @@ public class OmsPaymentBillController extends BaseController
}
// /**
// * 提交申请付款
// */
// @RequiresPermissions("finance:payment:apply")
// @Log(title = "申请付款", businessType = BusinessType.UPDATE)
// @PostMapping("/applyPayment")
// @ResponseBody
// public AjaxResult applyPaymentSave(OmsPaymentBill omsPaymentBill)
// {
// return toAjax(omsPaymentBillService.applyPayment(omsPaymentBill));
// }
/**
*
*/
@RequiresPermissions("finance:payment:apply")
@Log(title = "申请付款", businessType = BusinessType.UPDATE)
@PostMapping("/applyPayment")
@ResponseBody
public AjaxResult applyPaymentSave(@RequestBody OmsPaymentBill omsPaymentBill)
{
return toAjax(omsPaymentBillService.applyPayment(omsPaymentBill));
}
/**
*
*/
@GetMapping("/attachment/{id}")
@ResponseBody
public AjaxResult viewReceipt(@PathVariable("id") Long id, @RequestParam("type") String type)
{
return AjaxResult.success( omsFinAttachmentService.list(Collections.singletonList(id),type));
}
//
// /**
// * 查看回执单页面
// */
// @GetMapping("/viewReceipt/{id}")
// public String viewReceipt(@PathVariable("id") Long id, @RequestParam("type") String type, ModelMap mmap)
// {
// OmsPaymentBill paymentBill = omsPaymentBillService.selectOmsPaymentBillById(id);
// if (paymentBill != null)
// {
// if ("receipt".equals(type) && (paymentBill.getReceiptAttachmentId() != null)) {
// mmap.put("attachment", omsFinAttachmentService.selectOmsFinAttachmentById(paymentBill.getReceiptAttachmentId()));
// } else if ("proof".equals(type) && paymentBill.getRefundProofAttachmentId() != null) {
// mmap.put("attachment", omsFinAttachmentService.selectOmsFinAttachmentById(paymentBill.getRefundProofAttachmentId()));
// }
// }
// mmap.put("paymentBill", paymentBill);
// return prefix + "/viewReceipt";
// }
//
// /**
// * 上传回执单
// */
// @RequiresPermissions("finance:payment:uploadReceipt")
// @Log(title = "上传回执单", businessType = BusinessType.UPDATE)
// @PostMapping("/uploadReceipt")
// @ResponseBody
// public AjaxResult uploadReceipt(@RequestParam("paymentBillId") Long paymentBillId, @RequestParam("file") MultipartFile file)
// {
// try
// {
// return omsPaymentBillService.uploadReceipt(paymentBillId, file);
// }
// catch (Exception e)
// {
// logger.error("上传回执单失败", e);
// return AjaxResult.error("操作失败:" + e.getMessage());
// }
// }
/**
*
*/
@RequiresPermissions("finance:payment:uploadReceipt")
@Log(title = "上传回执单", businessType = BusinessType.UPDATE)
@PostMapping("/uploadReceipt")
@ResponseBody
public AjaxResult uploadReceipt(OmsFinAttachment attachment, @RequestParam("file") MultipartFile file)
{
try
{
attachment.setRelatedBillType(OmsFinAttachment.RelatedBillTypeEnum.PAYMENT.getCode());
return omsPaymentBillService.uploadReceipt(attachment, file);
}
catch (Exception e)
{
logger.error("上传回执单失败", e);
return AjaxResult.error("操作失败:" + e.getMessage());
}
}
//
// /**
// * 申请退款

View File

@ -0,0 +1,73 @@
package com.ruoyi.sip.domain;
import lombok.Data;
import lombok.Getter;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import java.util.List;
/**
* oms_fin_attachment
*
* @author ruoyi
* @date 2025-10-22
*/
@Data
public class OmsFinAttachment extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键ID */
private Long id;
/** 关联单据ID */
@Excel(name = "关联单据ID")
private Long relatedBillId;
private List<Long> relatedBillIdList;
/** 关联单据类型 */
@Excel(name = "关联单据类型")
private String relatedBillType;
/** 原始文件名 */
@Excel(name = "原始文件名")
private String fileName;
/** 文件存储路径 */
@Excel(name = "文件存储路径")
private String filePath;
/** 文件大小(字节) */
@Excel(name = "文件大小", readConverterExp = "字节")
private Long fileSize;
/** 文件MIME类型 */
@Excel(name = "文件MIME类型")
private String fileType;
/** 删除标志0代表存在 2代表删除 */
private String delFlag;
@Getter
public enum RelatedBillTypeEnum {
/** 付款单 */
PAYMENT("payment", "付款单"),
INVOICE("invoice", "收票单"),
;
private final String code;
private final String desc;
RelatedBillTypeEnum(String code, String desc) {
this.code = code;
this.desc = desc;
}
}
}

View File

@ -22,14 +22,12 @@ public class OmsPayablePaymentDetail extends BaseEntity {
private BigDecimal paymentAmount;
private BigDecimal paymentRate;
private String paymentBillCode;
private Long paymentBillId;
private Date actualPaymentTime;
private String paymentStatus;
/** 回执单附件ID */
private Long receiptAttachmentId;
/** 退款图附件ID */
private Long refundProofAttachmentId;
private OmsFinAttachment finAttachment;
@Getter
public enum PayableDetailTypeEnum {

View File

@ -33,8 +33,8 @@ public class OmsPaymentBill extends BaseEntity
private String paymentBillType;
/** 付款时间 */
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@Excel(name = "付款时间", width = 30, dateFormat = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Excel(name = "付款时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date paymentTime;
/** 制造商名称 */
@ -74,8 +74,8 @@ public class OmsPaymentBill extends BaseEntity
private BigDecimal preResidueAmount;
/** 实际付款时间 */
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@Excel(name = "实际付款时间", width = 30, dateFormat = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Excel(name = "实际付款时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date actualPaymentTime;
/** 付款状态 */
@ -91,8 +91,8 @@ public class OmsPaymentBill extends BaseEntity
private String approveNode;
/** 审批时间 */
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@Excel(name = "审批时间", width = 30, dateFormat = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Excel(name = "审批时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date approveTime;
/** 支付方式 */
@ -119,8 +119,7 @@ public class OmsPaymentBill extends BaseEntity
@Excel(name = "银行行号")
private String bankNumber;
/** 回执单附件ID */
private Long receiptAttachmentId;
/** 关联的原始付款单ID */
private Long originalBillId;
@ -128,8 +127,7 @@ public class OmsPaymentBill extends BaseEntity
/** 退款状态 */
private String refundStatus;
/** 退款图附件ID */
private Long refundProofAttachmentId;
@Getter
public enum PaymentBillTypeEnum {

View File

@ -0,0 +1,61 @@
package com.ruoyi.sip.mapper;
import java.util.List;
import com.ruoyi.sip.domain.OmsFinAttachment;
/**
* Mapper
*
* @author ruoyi
* @date 2025-10-22
*/
public interface OmsFinAttachmentMapper
{
/**
*
*
* @param id
* @return
*/
public OmsFinAttachment selectOmsFinAttachmentById(Long id);
/**
*
*
* @param omsFinAttachment
* @return
*/
public List<OmsFinAttachment> selectOmsFinAttachmentList(OmsFinAttachment omsFinAttachment);
/**
*
*
* @param omsFinAttachment
* @return
*/
public int insertOmsFinAttachment(OmsFinAttachment omsFinAttachment);
/**
*
*
* @param omsFinAttachment
* @return
*/
public int updateOmsFinAttachment(OmsFinAttachment omsFinAttachment);
/**
*
*
* @param id
* @return
*/
public int deleteOmsFinAttachmentById(Long id);
/**
*
*
* @param ids
* @return
*/
public int deleteOmsFinAttachmentByIds(Long[] ids);
}

View File

@ -46,6 +46,7 @@ public interface OmsPaymentBillMapper
* @return
*/
public int updateOmsPaymentBill(OmsPaymentBill omsPaymentBill);
public int updateOmsPaymentBillByCode(OmsPaymentBill omsPaymentBill);
/**
*
@ -90,4 +91,6 @@ public interface OmsPaymentBillMapper
void clearRelationPayable(String payableBillCode);
OmsPaymentBill selectOmsPaymentBillByCode(String businessKey);
}

View File

@ -0,0 +1,75 @@
package com.ruoyi.sip.service;
import java.util.List;
import com.ruoyi.sip.domain.OmsFinAttachment;
import org.springframework.web.multipart.MultipartFile;
/**
* Service
*
* @author ruoyi
* @date 2025-10-22
*/
public interface IOmsFinAttachmentService
{
/**
*
*
* @param id
* @return
*/
public OmsFinAttachment selectOmsFinAttachmentById(Long id);
/**
*
*
* @param omsFinAttachment
* @return
*/
public List<OmsFinAttachment> selectOmsFinAttachmentList(OmsFinAttachment omsFinAttachment);
/**
*
*
* @param omsFinAttachment
* @return
*/
public int insertOmsFinAttachment(OmsFinAttachment omsFinAttachment);
/**
*
*
* @param omsFinAttachment
* @return
*/
public int updateOmsFinAttachment(OmsFinAttachment omsFinAttachment);
/**
*
*
* @param ids
* @return
*/
public int deleteOmsFinAttachmentByIds(Long[] ids);
/**
*
*
* @param id
* @return
*/
public int deleteOmsFinAttachmentById(Long id);
/**
*
*
* @param file
* @param invoiceReceiptBillId
* @param type
* @return
* @throws Exception
*/
public OmsFinAttachment uploadAttachment(MultipartFile file, Long invoiceReceiptBillId, OmsFinAttachment.RelatedBillTypeEnum type) throws Exception;
List<OmsFinAttachment> list(List<Long> ids, String type);
}

View File

@ -3,8 +3,10 @@ package com.ruoyi.sip.service;
import java.util.List;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.sip.domain.OmsFinAttachment;
import com.ruoyi.sip.domain.OmsPaymentBill;
import com.ruoyi.sip.domain.dto.PaymentBillDetailDTO;
import org.springframework.web.multipart.MultipartFile;
/**
* Service
@ -66,4 +68,31 @@ public interface IOmsPaymentBillService
AjaxResult returnPaymentBill(Long id);
int applyPayment(OmsPaymentBill omsPaymentBill);
/**
*
*
* @param paymentBillId ID
* @param file
* @param remark
* @return
*/
public AjaxResult uploadReceipt(OmsFinAttachment omsFinAttachment, MultipartFile file) throws Exception;
/**
* 退
*
* @param originalPaymentId ID
* @return
*/
public AjaxResult applyRefund(Long originalPaymentId);
/**
* 退
*
* @param paymentBillId ID
* @param file
* @return
*/
public AjaxResult uploadRefundProof(Long paymentBillId, MultipartFile file) throws Exception;
}

View File

@ -0,0 +1,129 @@
package com.ruoyi.sip.service.impl;
import java.util.Collections;
import java.util.List;
import com.ruoyi.common.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.sip.mapper.OmsFinAttachmentMapper;
import com.ruoyi.sip.domain.OmsFinAttachment;
import com.ruoyi.sip.service.IOmsFinAttachmentService;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.config.RuoYiConfig;
import org.springframework.web.multipart.MultipartFile;
/**
* Service
*
* @author ruoyi
* @date 2025-10-22
*/
@Service
public class OmsFinAttachmentServiceImpl implements IOmsFinAttachmentService
{
@Autowired
private OmsFinAttachmentMapper omsFinAttachmentMapper;
@Override
public OmsFinAttachment uploadAttachment(MultipartFile file, Long relatedBillId, OmsFinAttachment.RelatedBillTypeEnum type) throws Exception
{
// 上传文件路径
String filePath = RuoYiConfig.getUploadPath();
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
OmsFinAttachment attachment = new OmsFinAttachment();
attachment.setFileName(fileName);
attachment.setFilePath(fileName);
attachment.setFileSize(file.getSize());
attachment.setFileType(file.getContentType());
attachment.setRelatedBillType(type.getCode());
attachment.setRelatedBillId(relatedBillId);
attachment.setCreateBy(com.ruoyi.common.utils.ShiroUtils.getLoginName());
this.insertOmsFinAttachment(attachment);
return attachment;
}
@Override
public List<OmsFinAttachment> list(List<Long> ids, String type) {
OmsFinAttachment omsFinAttachment = new OmsFinAttachment();
omsFinAttachment.setRelatedBillIdList(ids);
omsFinAttachment.setRelatedBillType(type);
return omsFinAttachmentMapper.selectOmsFinAttachmentList(omsFinAttachment);
}
/**
*
*
* @param id
* @return
*/
@Override
public OmsFinAttachment selectOmsFinAttachmentById(Long id)
{
return omsFinAttachmentMapper.selectOmsFinAttachmentById(id);
}
/**
*
*
* @param omsFinAttachment
* @return
*/
@Override
public List<OmsFinAttachment> selectOmsFinAttachmentList(OmsFinAttachment omsFinAttachment)
{
return omsFinAttachmentMapper.selectOmsFinAttachmentList(omsFinAttachment);
}
/**
*
*
* @param omsFinAttachment
* @return
*/
@Override
public int insertOmsFinAttachment(OmsFinAttachment omsFinAttachment)
{
omsFinAttachment.setCreateTime(DateUtils.getNowDate());
return omsFinAttachmentMapper.insertOmsFinAttachment(omsFinAttachment);
}
/**
*
*
* @param omsFinAttachment
* @return
*/
@Override
public int updateOmsFinAttachment(OmsFinAttachment omsFinAttachment)
{
omsFinAttachment.setUpdateTime(DateUtils.getNowDate());
return omsFinAttachmentMapper.updateOmsFinAttachment(omsFinAttachment);
}
/**
*
*
* @param ids
* @return
*/
@Override
public int deleteOmsFinAttachmentByIds(Long[] ids)
{
return omsFinAttachmentMapper.deleteOmsFinAttachmentByIds(ids);
}
/**
*
*
* @param id
* @return
*/
@Override
public int deleteOmsFinAttachmentById(Long id)
{
return omsFinAttachmentMapper.deleteOmsFinAttachmentById(id);
}
}

View File

@ -242,6 +242,7 @@ public class OmsPayableBillServiceImpl implements IOmsPayableBillService {
omsPayableBill.setUnpaidAmount(decimal);
return omsPayableBill;
}
}

View File

@ -1,20 +1,27 @@
package com.ruoyi.sip.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.sip.domain.OmsFinAttachment;
import com.ruoyi.sip.domain.OmsPayablePaymentDetail;
import com.ruoyi.sip.mapper.OmsPayablePaymentDetailMapper;
import com.ruoyi.sip.service.IOmsFinAttachmentService;
import com.ruoyi.sip.service.IOmsPayablePaymentDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
public class OmsPayablePaymentDetailServiceImpl implements IOmsPayablePaymentDetailService {
@Autowired
private OmsPayablePaymentDetailMapper omsPayablePaymentDetailMapper;
@Autowired
private IOmsFinAttachmentService finAttachmentService;
@Override
public int insertOmsPayablePaymentDetail(OmsPayablePaymentDetail omsPayablePaymentDetail) {
return omsPayablePaymentDetailMapper.insertOmsPayablePaymentDetail(omsPayablePaymentDetail);
@ -24,7 +31,21 @@ public class OmsPayablePaymentDetailServiceImpl implements IOmsPayablePaymentDet
public List<OmsPayablePaymentDetail> listByPayableBillId(Long payableBillId) {
OmsPayablePaymentDetail omsPayablePaymentDetail = new OmsPayablePaymentDetail();
omsPayablePaymentDetail.setPayableBillId(payableBillId);
return omsPayablePaymentDetailMapper.list(omsPayablePaymentDetail);
List<OmsPayablePaymentDetail> list = omsPayablePaymentDetailMapper.list(omsPayablePaymentDetail);
if (CollUtil.isNotEmpty(list)){
OmsFinAttachment omsFinAttachment = new OmsFinAttachment();
omsFinAttachment.setRelatedBillIdList(list.stream().map(OmsPayablePaymentDetail::getPaymentBillId).distinct().collect(Collectors.toList()));
omsFinAttachment.setRelatedBillType(OmsFinAttachment.RelatedBillTypeEnum.PAYMENT.getCode());
omsFinAttachment.setDelFlag("0");
List<OmsFinAttachment> attachmentList = finAttachmentService.selectOmsFinAttachmentList(omsFinAttachment);
Map<Long, OmsFinAttachment> collect = attachmentList.stream().collect(Collectors.toMap(OmsFinAttachment::getRelatedBillId, Function.identity()));
for (OmsPayablePaymentDetail payablePaymentDetail : list) {
payablePaymentDetail.setFinAttachment(collect.get(payablePaymentDetail.getPaymentBillId()));
}
}
return list;
}
@Override

View File

@ -5,21 +5,27 @@ import java.util.List;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.ApproveStatusEnum;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.sip.domain.OmsPayableBill;
import com.ruoyi.sip.domain.VendorInfo;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.sip.domain.*;
import com.ruoyi.sip.domain.dto.PaymentBillDetailDTO;
import com.ruoyi.sip.flowable.domain.Todo;
import com.ruoyi.sip.flowable.service.TodoCommonTemplate;
import com.ruoyi.sip.service.IOmsFinAttachmentService;
import com.ruoyi.sip.service.IVendorInfoService;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.sip.mapper.OmsPaymentBillMapper;
import com.ruoyi.sip.domain.OmsPaymentBill;
import com.ruoyi.sip.service.IOmsPaymentBillService;
import com.ruoyi.common.core.text.Convert;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
/**
* Service
@ -29,13 +35,15 @@ import org.springframework.transaction.annotation.Transactional;
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class OmsPaymentBillServiceImpl implements IOmsPaymentBillService
public class OmsPaymentBillServiceImpl implements IOmsPaymentBillService , TodoCommonTemplate
{
@Autowired
private OmsPaymentBillMapper omsPaymentBillMapper;
@Autowired
private IVendorInfoService vendorInfoService;
@Autowired
private IOmsFinAttachmentService omsFinAttachmentService;
/**
*
*
@ -183,120 +191,189 @@ public class OmsPaymentBillServiceImpl implements IOmsPaymentBillService
* @param paymentBill
* @return
*/
// @Override
// public int applyPayment(OmsPaymentBill paymentBill) {
// paymentBill.setUpdateTime(DateUtils.getNowDate());
// paymentBill.setUpdateBy(ShiroUtils.getLoginName());
// // todo 开启审批流程
// paymentBill.setApproveStatus(OmsPaymentBill.ApproveStatusEnum.UNDER_APPROVAL.getCode());
// return omsPaymentBillMapper.updateOmsPaymentBill(paymentBill);
// }
@Override
public int applyPayment(OmsPaymentBill paymentBill) {
paymentBill.setUpdateTime(DateUtils.getNowDate());
paymentBill.setUpdateBy(ShiroUtils.getLoginName());
// todo 开启审批流程
paymentBill.setApproveStatus(ApproveStatusEnum.WAIT_APPROVE.getCode());
return omsPaymentBillMapper.updateOmsPaymentBill(paymentBill);
}
// @Override
// public AjaxResult uploadReceipt(Long paymentBillId, MultipartFile file) throws Exception {
// OmsPaymentBill paymentBill = selectOmsPaymentBillById(paymentBillId);
// if (paymentBill == null) {
// return AjaxResult.error("付款单不存在");
@Override
public Object todoDetail(String businessKey, String processKey, String todoId) {
return null;
}
@Override
public Object completedTodoDetail(String businessKey, String processKey, String todoId) {
return null;
}
@Override
public void fillBusinessInfo(List<Todo> todoCompletedList) {
}
private void handleCompanyLeaderApproval(String businessKey) {
OmsPaymentBill existData = omsPaymentBillMapper.selectOmsPaymentBillByCode(businessKey);
OmsPaymentBill omsPaymentBill = new OmsPaymentBill();
omsPaymentBill.setPayableBillCode(businessKey);
omsPaymentBill.setApproveStatus(ApproveStatusEnum.APPROVE_COMPLETE.getCode());
if (existData.getPaymentBillType().equals(OmsPaymentBill.PaymentBillTypeEnum.PRE_PAYMENT.getCode())){
existData.setPreResidueAmount(existData.getTotalPriceWithTax());
}
omsPaymentBill.setApproveTime(DateUtils.getNowDate());
omsPaymentBill.setUpdateTime(DateUtils.getNowDate());
omsPaymentBillMapper.updateOmsPaymentBillByCode(omsPaymentBill);
}
@Override
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();
// 审批驳回处理
if (approveBtn.equals(0)) {
handleRejectOrder( businessKey);
}
// else {
// if ("公司领导".equals(taskName) && approveBtn == 1) {
// handleCompanyLeaderApproval(businessKey);
// }
// }
//
// if (file.isEmpty())
// {
// return AjaxResult.error("上传文件不能为空");
// }
// // 上传文件路径
// String filePath = RuoYiConfig.getUploadPath();
// // 上传并返回新文件名称
// String fileName = FileUploadUtils.upload(filePath, file);
//
// SysUser loginUser = ShiroUtils.getSysUser();
// OmsFinAttachment attachment = new OmsFinAttachment();
// attachment.setRelatedBillId(paymentBillId);
// attachment.setRelatedBillType(OmsFinAttachment.RelatedBillTypeEnum.PAYMENT.getCode());
// attachment.setFileName(file.getOriginalFilename());
// attachment.setFilePath(fileName);
// attachment.setFileSize(file.getSize());
// attachment.setFileType(file.getContentType());
// attachment.setCreateBy(loginUser.getUserId().toString());
// omsFinAttachmentService.insertOmsFinAttachment(attachment);
// paymentBill.setActualPaymentTime(DateUtils.getNowDate());
// paymentBill.setReceiptAttachmentId(attachment.getId());
// paymentBill.setPaymentStatus(OmsPaymentBill.PaymentStatusEnum.PAYMENT.getCode());
// updateOmsPaymentBill(paymentBill);
//
// return AjaxResult.success(attachment);
// }
//
// @Override
// @Transactional
// public AjaxResult applyRefund(Long originalPaymentId) {
// // 1. 验证原始付款单
// OmsPaymentBill originalBill = selectOmsPaymentBillById(originalPaymentId);
// if (originalBill == null) {
// return AjaxResult.error("原始付款单不存在");
// }
// if (!OmsPaymentBill.PaymentStatusEnum.PAYMENT.getCode().equals(originalBill.getPaymentStatus())) {
// return AjaxResult.error("只有已付款的订单才能申请退款");
// }
// if ("REFUND_APPLIED".equals(originalBill.getRefundStatus())) {
// return AjaxResult.error("该付款单已申请过退款,请勿重复操作");
// }
//
// // 2. 创建新的退款单
// OmsPaymentBill refundBill = new OmsPaymentBill();
//
// // 复制属性并取反金额
// refundBill.setTotalPriceWithTax(originalBill.getTotalPriceWithTax().negate());
// refundBill.setTotalPriceWithoutTax(originalBill.getTotalPriceWithoutTax().negate());
// refundBill.setTaxAmount(originalBill.getTaxAmount().negate());
//
// refundBill.setVendorCode(originalBill.getVendorCode());
// refundBill.setOrderCode(originalBill.getOrderCode());
// refundBill.setPayName(originalBill.getPayName());
// refundBill.setPayBankNumber(originalBill.getPayBankNumber());
// refundBill.setPayBankOpenAddress(originalBill.getPayBankOpenAddress());
// refundBill.setBankNumber(originalBill.getBankNumber());
//
// // 设置新属性
// refundBill.setPaymentBillType(OmsPaymentBill.PaymentBillTypeEnum.REFUND.getCode());
// refundBill.setPaymentStatus(OmsPaymentBill.PaymentStatusEnum.WAIT_PAYMENT.getCode());
// refundBill.setApproveStatus(OmsPaymentBill.ApproveStatusEnum.UNDER_APPROVAL.getCode());
// refundBill.setOriginalBillId(originalPaymentId);
// refundBill.setRemark("退款-关联原付款单:" + originalBill.getPaymentBillCode());
//
// insertOmsPaymentBill(refundBill);
//
// // 3. 更新原始付款单状态
// originalBill.setRefundStatus("1");
// updateOmsPaymentBill(originalBill);
//
// return AjaxResult.success("退款申请已提交,新的退款单号为:" + refundBill.getPaymentBillCode());
// }
//
// @Override
// public AjaxResult uploadRefundProof(Long paymentBillId, MultipartFile file) throws Exception {
// OmsPaymentBill paymentBill = selectOmsPaymentBillById(paymentBillId);
// if (paymentBill == null) {
// return AjaxResult.error("付款单不存在");
// }
// if (!OmsPaymentBill.PaymentBillTypeEnum.REFUND.getCode().equals(paymentBill.getPaymentBillType())) {
// return AjaxResult.error("只有退款单才能上传退款图");
// }
//
// if (file.isEmpty())
// {
// return AjaxResult.error("上传文件不能为空");
// }
//
// // 上传文件并创建附件记录
// OmsFinAttachment attachment = omsFinAttachmentService.uploadAttachment(file, paymentBillId, OmsFinAttachment.RelatedBillTypeEnum.PAYMENT);
//
// // 更新付款单
// paymentBill.setRefundProofAttachmentId(attachment.getId());
// // 更新为“已付款”
// paymentBill.setPaymentStatus(OmsPaymentBill.PaymentStatusEnum.PAYMENT.getCode());
// paymentBill.setActualPaymentTime(DateUtils.getNowDate());
// updateOmsPaymentBill(paymentBill);
//
// return AjaxResult.success(attachment);
// }
return TodoCommonTemplate.super.todoApproveCallback(todo);
}
private void handleRejectOrder(String businessKey) {
OmsPaymentBill omsPaymentBill = new OmsPaymentBill();
omsPaymentBill.setPayableBillCode(businessKey);
omsPaymentBill.setApproveStatus(ApproveStatusEnum.APPROVE_REJECT.getCode());
omsPaymentBillMapper.updateOmsPaymentBillByCode(omsPaymentBill);
}
@Override
public boolean multiInstanceApproveCallback(String activityName, ProcessInstance processInstance) {
return TodoCommonTemplate.super.multiInstanceApproveCallback(activityName, processInstance);
}
@Override
public AjaxResult uploadReceipt( OmsFinAttachment attachment , MultipartFile file) throws Exception {
OmsPaymentBill paymentBill = selectOmsPaymentBillById(attachment.getRelatedBillId());
if (paymentBill == null) {
return AjaxResult.error("付款单不存在");
}
if (file.isEmpty())
{
return AjaxResult.error("上传文件不能为空");
}
// 上传文件路径
String filePath = RuoYiConfig.getUploadPath();
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
SysUser loginUser = ShiroUtils.getSysUser();
attachment.setFileName(file.getOriginalFilename());
attachment.setFilePath(fileName);
attachment.setFileSize(file.getSize());
attachment.setFileType(file.getContentType());
attachment.setCreateBy(loginUser.getUserId().toString());
omsFinAttachmentService.insertOmsFinAttachment(attachment);
paymentBill.setActualPaymentTime(DateUtils.getNowDate());
paymentBill.setPaymentStatus(OmsPaymentBill.PaymentStatusEnum.PAYMENT.getCode());
updateOmsPaymentBill(paymentBill);
return AjaxResult.success(attachment);
}
@Override
@Transactional
public AjaxResult applyRefund(Long originalPaymentId) {
// 1. 验证原始付款单
OmsPaymentBill originalBill = selectOmsPaymentBillById(originalPaymentId);
if (originalBill == null) {
return AjaxResult.error("原始付款单不存在");
}
if (!OmsPaymentBill.PaymentStatusEnum.PAYMENT.getCode().equals(originalBill.getPaymentStatus())) {
return AjaxResult.error("只有已付款的订单才能申请退款");
}
if ("REFUND_APPLIED".equals(originalBill.getRefundStatus())) {
return AjaxResult.error("该付款单已申请过退款,请勿重复操作");
}
// 2. 创建新的退款单
OmsPaymentBill refundBill = new OmsPaymentBill();
// 复制属性并取反金额
refundBill.setTotalPriceWithTax(originalBill.getTotalPriceWithTax().negate());
refundBill.setTotalPriceWithoutTax(originalBill.getTotalPriceWithoutTax().negate());
refundBill.setTaxAmount(originalBill.getTaxAmount().negate());
refundBill.setVendorCode(originalBill.getVendorCode());
refundBill.setOrderCode(originalBill.getOrderCode());
refundBill.setPayName(originalBill.getPayName());
refundBill.setPayBankNumber(originalBill.getPayBankNumber());
refundBill.setPayBankOpenAddress(originalBill.getPayBankOpenAddress());
refundBill.setBankNumber(originalBill.getBankNumber());
// 设置新属性
refundBill.setPaymentBillType(OmsPaymentBill.PaymentBillTypeEnum.REFUND.getCode());
refundBill.setPaymentStatus(OmsPaymentBill.PaymentStatusEnum.WAIT_PAYMENT.getCode());
refundBill.setApproveStatus(ApproveStatusEnum.WAIT_COMMIT.getCode());
refundBill.setOriginalBillId(originalPaymentId);
refundBill.setRemark("退款-关联原付款单:" + originalBill.getPaymentBillCode());
insertOmsPaymentBill(refundBill);
// 3. 更新原始付款单状态
originalBill.setRefundStatus("1");
updateOmsPaymentBill(originalBill);
return AjaxResult.success("退款申请已提交,新的退款单号为:" + refundBill.getPaymentBillCode());
}
@Override
public AjaxResult uploadRefundProof(Long paymentBillId, MultipartFile file) throws Exception {
OmsPaymentBill paymentBill = selectOmsPaymentBillById(paymentBillId);
if (paymentBill == null) {
return AjaxResult.error("付款单不存在");
}
if (!OmsPaymentBill.PaymentBillTypeEnum.REFUND.getCode().equals(paymentBill.getPaymentBillType())) {
return AjaxResult.error("只有退款单才能上传退款图");
}
if (file.isEmpty())
{
return AjaxResult.error("上传文件不能为空");
}
// 上传文件并创建附件记录
OmsFinAttachment attachment = omsFinAttachmentService.uploadAttachment(file, paymentBillId, OmsFinAttachment.RelatedBillTypeEnum.PAYMENT);
// 更新付款单
// 更新为“已付款”
paymentBill.setPaymentStatus(OmsPaymentBill.PaymentStatusEnum.PAYMENT.getCode());
paymentBill.setActualPaymentTime(DateUtils.getNowDate());
updateOmsPaymentBill(paymentBill);
return AjaxResult.success(attachment);
}
}

View File

@ -0,0 +1,112 @@
<?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.OmsFinAttachmentMapper">
<resultMap type="OmsFinAttachment" id="OmsFinAttachmentResult">
<result property="id" column="id" />
<result property="relatedBillId" column="related_bill_id" />
<result property="relatedBillType" column="related_bill_type" />
<result property="fileName" column="file_name" />
<result property="filePath" column="file_path" />
<result property="fileSize" column="file_size" />
<result property="fileType" column="file_type" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
<result property="delFlag" column="del_flag" />
</resultMap>
<sql id="selectOmsFinAttachmentVo">
select id, related_bill_id, related_bill_type, file_name, file_path, file_size, file_type, create_by, create_time, update_by, update_time, remark, del_flag from oms_fin_attachment
</sql>
<select id="selectOmsFinAttachmentList" parameterType="OmsFinAttachment" resultMap="OmsFinAttachmentResult">
<include refid="selectOmsFinAttachmentVo"/>
<where>
<if test="relatedBillId != null "> and related_bill_id = #{relatedBillId}</if>
<if test="relatedBillIdList != null and relatedBillIdList.size>0 "> and related_bill_id
in <foreach item="item" index="index" collection="relatedBillIdList" separator="," open="(" close=")">
#{item}
</foreach>
</if>
<if test="relatedBillType != null and relatedBillType != ''"> and related_bill_type = #{relatedBillType}</if>
<if test="fileName != null and fileName != ''"> and file_name like concat('%', #{fileName}, '%')</if>
<if test="filePath != null and filePath != ''"> and file_path = #{filePath}</if>
<if test="fileSize != null "> and file_size = #{fileSize}</if>
<if test="fileType != null and fileType != ''"> and file_type = #{fileType}</if>
<if test="delFlag != null and delFlag != ''"> and del_flag = #{delFlag}</if>
</where>
</select>
<select id="selectOmsFinAttachmentById" parameterType="Long" resultMap="OmsFinAttachmentResult">
<include refid="selectOmsFinAttachmentVo"/>
where id = #{id}
</select>
<insert id="insertOmsFinAttachment" parameterType="OmsFinAttachment" useGeneratedKeys="true" keyProperty="id">
insert into oms_fin_attachment
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="relatedBillId != null">related_bill_id,</if>
<if test="relatedBillType != null and relatedBillType != ''">related_bill_type,</if>
<if test="fileName != null and fileName != ''">file_name,</if>
<if test="filePath != null and filePath != ''">file_path,</if>
<if test="fileSize != null">file_size,</if>
<if test="fileType != null">file_type,</if>
<if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
<if test="updateTime != null">update_time,</if>
<if test="remark != null">remark,</if>
<if test="delFlag != null">del_flag,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="relatedBillId != null">#{relatedBillId},</if>
<if test="relatedBillType != null and relatedBillType != ''">#{relatedBillType},</if>
<if test="fileName != null and fileName != ''">#{fileName},</if>
<if test="filePath != null and filePath != ''">#{filePath},</if>
<if test="fileSize != null">#{fileSize},</if>
<if test="fileType != null">#{fileType},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="remark != null">#{remark},</if>
<if test="delFlag != null">#{delFlag},</if>
</trim>
</insert>
<update id="updateOmsFinAttachment" parameterType="OmsFinAttachment">
update oms_fin_attachment
<trim prefix="SET" suffixOverrides=",">
<if test="relatedBillId != null">related_bill_id = #{relatedBillId},</if>
<if test="relatedBillType != null and relatedBillType != ''">related_bill_type = #{relatedBillType},</if>
<if test="fileName != null and fileName != ''">file_name = #{fileName},</if>
<if test="filePath != null and filePath != ''">file_path = #{filePath},</if>
<if test="fileSize != null">file_size = #{fileSize},</if>
<if test="fileType != null">file_type = #{fileType},</if>
<if test="createBy != null">create_by = #{createBy},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="remark != null">remark = #{remark},</if>
<if test="delFlag != null">del_flag = #{delFlag},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteOmsFinAttachmentById" parameterType="Long">
delete from oms_fin_attachment where id = #{id}
</delete>
<delete id="deleteOmsFinAttachmentByIds" parameterType="String">
delete from oms_fin_attachment where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

View File

@ -47,7 +47,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="list" resultType="com.ruoyi.sip.domain.OmsPayablePaymentDetail">
SELECT
t1.*,t2.payment_bill_code,t2.actual_payment_time,t2.payment_status,t2.refund_proof_attachment_id,t2.receipt_attachment_id
t1.*,t2.payment_bill_code,t2.actual_payment_time,t2.payment_status,t2.id as paymentBillId
FROM
oms_payable_payment_detail t1
LEFT JOIN oms_payment_bill t2 ON t1.payment_bill_code = t2.payment_bill_code

View File

@ -34,8 +34,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="payBankNumber" column="pay_bank_number" />
<result property="payBankOpenAddress" column="pay_bank_open_address" />
<result property="bankNumber" column="bank_number" />
<result property="receiptAttachmentId" column="receipt_attachment_id" />
<result property="refundProofAttachmentId" column="refund_proof_attachment_id" />
<result property="refundStatus" column="refund_status" />
</resultMap>
@ -51,8 +50,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="preResidueAmount" column="pre_residue_amount" />
<result property="actualPaymentTime" column="actual_payment_time" />
<result property="paymentMethod" column="payment_method" />
<result property="receiptAttachmentId" column="receipt_attachment_id" />
<result property="refundProofAttachmentId" column="refund_proof_attachment_id" />
<result property="paymentStatus" column="payment_status" />
<result property="remark" column="remark" />
<result property="createBy" column="create_by" />
@ -104,8 +101,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
pb.pay_bank_number,
pb.pay_bank_open_address,
pb.bank_number,
pb.refund_proof_attachment_id,
pb.receipt_attachment_id,
pb.refund_status,
ovi.vendor_name
from oms_payment_bill pb
@ -174,8 +170,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="payBankNumber != null">pay_bank_number,</if>
<if test="payBankOpenAddress != null">pay_bank_open_address,</if>
<if test="bankNumber != null">bank_number,</if>
<if test="refundProofAttachmentId != null">refund_proof_attachment_id,</if>
<if test="receiptAttachmentId != null">receipt_attachment_id,</if>
<if test="refundStatus != null">refund_status,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
@ -206,8 +200,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="payBankNumber != null">#{payBankNumber},</if>
<if test="payBankOpenAddress != null">#{payBankOpenAddress},</if>
<if test="bankNumber != null">#{bankNumber},</if>
<if test="refundProofAttachmentId != null">#{refundProofAttachmentId},</if>
<if test="receiptAttachmentId != null">#{receiptAttachmentId},</if>
<if test="refundStatus != null">#{refundStatus},</if>
</trim>
</insert>
@ -242,12 +234,45 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="payBankNumber != null">pay_bank_number = #{payBankNumber},</if>
<if test="payBankOpenAddress != null">pay_bank_open_address = #{payBankOpenAddress},</if>
<if test="bankNumber != null">bank_number = #{bankNumber},</if>
<if test="refundProofAttachmentId != null">refund_proof_attachment_id = #{refundProofAttachmentId},</if>
<if test="receiptAttachmentId != null">receipt_attachment_id = #{receiptAttachmentId},</if>
<if test="refundStatus != null">refund_status = #{refundStatus},</if>
</trim>
where id = #{id}
</update>
<update id="updateOmsPaymentBillByCode">
update oms_payment_bill
<trim prefix="SET" suffixOverrides=",">
<if test="paymentBillType != null">payment_bill_type = #{paymentBillType},</if>
<if test="paymentTime != null">payment_time = #{paymentTime},</if>
<if test="vendorCode != null">vendor_code = #{vendorCode},</if>
<if test="orderCode != null">order_code = #{orderCode},</if>
<if test="totalPriceWithTax != null">total_price_with_tax = #{totalPriceWithTax},</if>
<if test="totalPriceWithoutTax != null">total_price_without_tax = #{totalPriceWithoutTax},</if>
<if test="taxAmount != null">tax_amount = #{taxAmount},</if>
<if test="createBy != null">create_by = #{createBy},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="remark != null">remark = #{remark},</if>
<if test="delFlag != null">del_flag = #{delFlag},</if>
<if test="projectCode != null">project_code = #{projectCode},</if>
<if test="projectName != null">project_name = #{projectName},</if>
<if test="preResidueAmount != null">pre_residue_amount = #{preResidueAmount},</if>
<if test="actualPaymentTime != null">actual_payment_time = #{actualPaymentTime},</if>
<if test="paymentStatus != null">payment_status = #{paymentStatus},</if>
<if test="approveStatus != null">approve_status = #{approveStatus},</if>
<if test="approveNode != null">approve_node = #{approveNode},</if>
<if test="approveTime != null">approve_time = #{approveTime},</if>
<if test="paymentMethod != null">payment_method = #{paymentMethod},</if>
<if test="payName != null">pay_name = #{payName},</if>
<if test="payBankNumber != null">pay_bank_number = #{payBankNumber},</if>
<if test="payBankOpenAddress != null">pay_bank_open_address = #{payBankOpenAddress},</if>
<if test="bankNumber != null">bank_number = #{bankNumber},</if>
<if test="refundStatus != null">refund_status = #{refundStatus},</if>
</trim>
where payment_bill_code = #{paymentBillCode}
</update>
<delete id="deleteOmsPaymentBillById" parameterType="Long">
delete from oms_payment_bill where id = #{id}
@ -276,6 +301,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
resultType="com.ruoyi.sip.domain.dto.PaymentBillPayableDetailDTO">
</select>
<select id="selectOmsPaymentBillByCode" resultType="com.ruoyi.sip.domain.OmsPaymentBill">
<include refid="selectOmsPaymentBillVo"/>
where pb.payment_bill_code = #{code}
</select>
</mapper>