Compare commits

...

10 Commits

Author SHA1 Message Date
chenhao a9142c0e1b feat(finance): 添加付款退款功能并优化应付单界面
- 在付款管理页面增加退款按钮及申请退款功能
- 新增退款状态枚举及相关的业务逻辑处理
- 优化应付单列表展示,移除部分冗余字段显示
- 调整付款明细服务,支持批量插入和退款明细生成
- 修改付款计划查询逻辑,增强数据准确性
- 完善退款接口,支持通过ID申请退款操作
2025-12-10 18:46:24 +08:00
chenhao d3c4776bab feat(finance): 增强付款单功能及附件管理
- 将付款时间相关字段格式从日期调整为日期时间格式
- 在详情页和列表页使用dict-tag展示支付方式、付款状态和审批状态
- 新增回执单下载功能和相关UI组件
- 增加收票计划Tab页支持
- 添加发起付款和回执单弹窗界面及相关逻辑
- 实现附件上传与管理服务,包括财务附件实体和接口定义
- 更新付款单和应付明细实体结构以支持附件关联
- 优化前端组件导入和数据处理逻辑
- 修复并增强多个API接口功能,如applyPayment、uploadReceipt等
- 补充Mapper XML配置和Service实现逻辑
- 调整后端实体类属性以匹配新的业务需求
- 增加对附件信息的查询与绑定处理逻辑
- 引入新的枚举类型用于区分不同类型的关联单据
- 前端增加对新接口调用的支持以及表单交互优化
2025-12-09 20:51:15 +08:00
chenhao a1ea52a934 feat(finance): 新增付款单功能并优化应付单详情展示
- 新增付款单新增表单组件,支持付款单类型、制造商、付款时间等字段录入
- 优化应付单编辑表单,将弹窗改为抽屉展示,增强用户体验
- 应付单详情页增加付款明细表格展示及统计功能
- 调整付款单生成逻辑,支持从应付单直接发起付款操作
- 完善应付单状态显示,明确展示未生成、部分生成、全部生成状态
- 后端增加应付单查询接口及付款明细关联查询功能
- 优化付款单退回按钮显示条件,仅在审批通过状态下可操作
- 重构合并付款弹窗,调整默认付款单类型及展示逻辑
2025-12-09 16:35:45 +08:00
chenhao 05865dc2ef feat(finance): 新增付款单管理功能
- 新增付款单详情抽屉组件,展示付款单及应付单详细信息
- 新增付款单列表页面,支持多条件筛选和分页查询
- 新增财务管理路由模块,包含付款单子菜单
- 优化应付单日期格式化逻辑,统一使用HH:mm:ss格式
- 实现合并付款单并发起支付功能,支持批量处理应付单
- 新增付款明细实体类及相关Mapper、Service实现
- 完善应付单查询条件,增加预计付款时间范围查询
- 调整付款计划相关类包结构,统一移至sip.domain包下
2025-12-09 09:11:32 +08:00
chenhao 30d551fe59 Merge branch 'refs/heads/master' into dev_1.0.0 2025-12-09 09:10:37 +08:00
chenhao 333b5e1a8e fix(finance): 优化付款计划选择逻辑并修正计算方式
- 移除重复的付款计划验证逻辑
- 修正订单当前付款比例的计算方法,使用含税总价替代未付金额
- 新增 handleChooseConfirm 方法处理付款计划的选择确认逻辑
- 在 PaymentPlan 组件中支持传入选中的付款计划,并初始化表格选中状态
- 更新 MergePaymentDialog 中对 PaymentPlanSelector 组件的引用及事件绑定
- 调整付款比例计算条件,允许未付金额为零的情况
2025-12-05 16:35:11 +08:00
chenhao 94348aebc4 feat(finance): 新增采购应付单管理功能
- 新增采购应付单列表页面,支持多条件筛选和分页查询
- 实现应付单详情弹窗,展示应付单基本信息和状态
- 添加合并付款单功能,支持多应付单合并发起付款
- 实现付款计划选择器,可为每个应付单配置付款计划
- 新增应付单修改和删除功能
- 添加数据字典支持,用于展示产品类型、付款状态等枚举值
- 实现应付单导出功能
- 新增后端付款计划相关接口和实体类
- 添加付款计划Mapper接口及实现
- 实现付款计划服务层接口及业务逻辑
2025-12-05 14:18:54 +08:00
chenhao 1d842d3bf2 Merge branch 'refs/heads/master' into dev_1.0.0 2025-12-05 14:09:36 +08:00
chenhao 1bdc88cd7c Merge branch 'refs/heads/master' into dev_1.0.0
# Conflicts:
#	oms_web/oms_vue/src/utils/ruoyi.js
2025-12-04 17:46:58 +08:00
chenhao 1a4f64865a feat(sip): 新增库存出库价同步及应付单生成功能
- 新增 InventoryInfo.listByDeliveryId 方法以支持按出库单查询库存信息
- 在 InventoryDeliveryServiceImpl 中实现保存出库信息时同步更新出库价
- 实现出库时自动生成应付单逻辑,包括税率配置读取与金额计算
- 增加 selectOutPriceByCode 查询用于获取项目产品的价格信息
- 扩展 VendorInfo 支持付款类型枚举,区分入库付款与出库付款
- 修改 OmsPayableBill 实体类,增加项目编码、名称等字段并优化结构
- 优化应付单 Controller 接口,支持更灵活的查询条件
- 重构应付单 Mapper XML 文件,增强关联查询与筛选功能
- 在应付单 Service 层新增事务控制与默认付款计划创建逻辑
- 移除前端精确货币舍入工具函数,改用 decimal.js 进行高精度运算
- 注册全局计算工具至 Vue 实例,替换原有金额计算方式提升准确性
2025-12-04 10:53:27 +08:00
60 changed files with 4975 additions and 223 deletions

View File

@ -0,0 +1,61 @@
import request from '@/utils/request'
// 查询采购应付单列表
export function listPayable(query) {
return request({
url: '/finance/payable/list',
method: 'post',
data: query
})
}
// 查询采购应付单详情
export function getPayable(id) {
return request({
url: '/finance/payable/' + id,
method: 'get'
})
}
// 查询付款计划列表
export function getPaymentPlan(payableBillId) {
return request({
url: `/finance/payable/plan/${payableBillId}`,
method: 'get'
})
}
// 更新付款计划
export function updatePaymentPlan(payableBillId, data) {
return request({
url: `/finance/payable/plan/${payableBillId}`,
method: 'post',
data: data
})
}
// 合并并发起付款
export function mergeAndInitiatePayment(data) {
return request({
url: '/finance/payable/mergeAndInitiatePayment',
method: 'post',
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

@ -0,0 +1,79 @@
import request from '@/utils/request'
import { tansParams } from "@/utils/ruoyi"
// 查询付款单列表
export function listPayment(query) {
return request({
url: '/finance/payment/list',
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: tansParams(query)
})
}
// 查询付款单详细
export function getPayment(id) {
return request({
url: '/finance/payment/' + id,
method: 'get'
})
}
// 查询付款单附件
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({
url: '/finance/payment/returnPayment/' + id,
method: 'delete'
})
}
// 新增付款单
export function addPayment(data) {
return request({
url: '/finance/payment/add',
method: 'post',
data: data,
needLoading: true
})
}
// 申请付款
export function applyPaymentApi(data) {
return request({
url: '/finance/payment/applyPayment',
method: 'post',
data: data
})
}
// 申请退款
export function applyRefund(id) {
return request({
url: '/finance/payment/applyRefund/'+id,
method: 'get'
})
}

View File

@ -142,6 +142,24 @@ export const dynamicRoutes = [
}
]
},
{
path: '/finance',
component: Layout,
redirect: 'noRedirect',
name: 'Finance',
meta: {
title: '财务管理',
icon: 'money'
},
children: [
{
path: 'payment',
component: () => import('@/views/finance/payment/index'),
name: 'Payment',
meta: { title: '付款单', icon: 'form' }
}
]
},
{
path: '/inventory/execution',
component: Layout,

View File

@ -0,0 +1,242 @@
<template>
<el-drawer title="修改采购应付单" :visible.sync="internalVisible" size="70%" @close="handleClose">
<div class="dialog-body">
<!-- Part 1: Details -->
<div>
<el-divider content-position="left">采购-应付单</el-divider>
<div class="details-container">
<el-row :gutter="20">
<el-col :span="8">
<div class="detail-item"><strong>应付单编号:</strong> {{ formData.payableBillCode }}</div>
</el-col>
<el-col :span="16">
<div class="detail-item"><strong>生成时间:</strong> {{ formData.createTime }}</div>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<div class="detail-item"><strong>制造商名称:</strong> {{ formData.vendorName }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item"><strong>项目编号:</strong> {{ formData.projectCode }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item"><strong>项目名称:</strong> {{ formData.projectName }}</div>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<div class="detail-item"><strong>合同编号:</strong> {{ formData.orderCode }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item"><strong>出入库单号:</strong> {{ formData.inventoryCode }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item" style="display: flex"><strong>产品类型:</strong>
<dict-tag :options="dict.type.product_type" :value="formData.productType"/>
</div>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<div class="detail-item"><strong>含税总价:</strong> {{ formData.totalPriceWithTax }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item"><strong>未税总价:</strong> {{ formData.totalPriceWithoutTax }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item"><strong>税额:</strong> {{ formData.taxAmount }}</div>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<div class="detail-item"><strong>未付款金额:</strong> {{ formData.unpaidAmount }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item"><strong>已付款金额:</strong> {{ formData.paidAmount }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item"><strong>付款中金额:</strong> {{ formData.payingAmount }}</div>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<div class="detail-item"><strong>未收票金额:</strong> {{ formData.unInvoicedAmount }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item"><strong>已收票金额:</strong> {{ formData.invoicedAmount }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item"><strong>收票中金额:</strong> {{ formData.invoicingAmount }}</div>
</el-col>
</el-row>
</div>
</div>
<!-- Part 2: Tabs -->
<div style="padding: 20px">
<el-tabs v-model="activeTab">
<el-tab-pane label="明细" name="details">
<el-divider content-position="left">采购付款单</el-divider>
<el-table :data="formData.detailList" style="width: 100%" show-summary :summary-method="getSummaries">
<el-table-column type="index" label="序号" width="50"></el-table-column>
<el-table-column prop="payableDetailType" label="付款通道">
<template slot-scope="scope">
<dict-tag :options="dict.type.payable_detail_type" :value="scope.row.payableDetailType"/>
</template>
</el-table-column>
<el-table-column prop="actualPaymentTime" label="实际付款时间">
<template slot-scope="scope">
{{ scope.row.actualPaymentTime || '-' }}
</template>
</el-table-column>
<el-table-column prop="paymentAmount" label="本次付款金额"></el-table-column>
<el-table-column prop="paymentRate" label="本次付款比例"></el-table-column>
<el-table-column prop="paymentStatus" label="付款状态">
<template slot-scope="scope">
<dict-tag :options="dict.type.payment_status" :value="scope.row.paymentStatus"/>
</template>
</el-table-column>
<el-table-column prop="paymentBillCode" label="采购付款单编号"></el-table-column>
<el-table-column label="回执单/退款图">
<template slot-scope="scope">
{{ 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>
</el-tab-pane>
<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>
<!-- <div slot="footer" class="dialog-footer">-->
<!-- <el-button @click="handleClose"> </el-button>-->
<!-- <el-button type="primary" @click="handleSubmit"> </el-button>-->
<!-- </div>-->
</el-drawer>
</template>
<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,
ReceivingTicketPlan
},
props: {
visible: {
type: Boolean,
default: false
},
data: {
type: Object,
default: () => ({})
}
},
data() {
return {
internalVisible: this.visible, // Local copy of the visible prop
activeTab: 'details',
formData: {}
};
},
watch: {
visible(newVal) {
this.internalVisible = newVal; // Sync prop to local data
if (newVal && this.data.id) {
this.getDetails();
}
},
internalVisible(newVal) {
if (!newVal) {
this.formData = {};
}
this.$emit('update:visible', newVal); // Emit changes to parent
}
},
methods: {
getDetails() {
getPayable(this.data.id).then(res => {
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 = [];
let paymentAmountSum = 0;
if (data && data.length > 0) {
paymentAmountSum = data.reduce((acc, item) => {
const value = Number(item.paymentAmount);
return acc + (isNaN(value) ? 0 : value);
}, 0);
}
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '合计';
} else if (column.property === 'paymentAmount') {
sums[index] = paymentAmountSum.toFixed(2);
} else if (column.property === 'paymentRate') {
if (this.formData.totalPriceWithTax && this.formData.totalPriceWithTax > 0) {
const ratio = this.$calc.div(paymentAmountSum , this.formData.totalPriceWithTax,4);
sums[index] = (ratio * 100).toFixed(2) + '%';
} else {
sums[index] = '0.00%';
}
} else {
sums[index] = '';
}
});
return sums;
},
handleClose() {
this.internalVisible = false; // Close dialog locally
},
handleSubmit() {
this.handleClose();
},
}
};
</script>
<style scoped>.details-container {
border: 1px solid #EBEEF5;
padding: 20px;
border-radius: 4px;
}
.detail-item {
border: 1px solid #EBEEF5;
padding: 10px;
border-radius: 4px;
margin-bottom: 10px;
font-size: 14px;
}
.dialog-body {
overflow-y: auto;
}
</style>

View File

@ -0,0 +1,362 @@
<template>
<el-dialog title="合并发起付款单" :visible.sync="dialogVisible" width="80%" @close="handleClose" append-to-body>
<div class="dialog-body">
<el-form ref="form" :model="form" :inline="true" label-width="120px">
<el-row>
<el-col :span="8">
<el-form-item label="付款单类型" prop="paymentBillType">
<el-select disabled v-model="form.paymentBillType" placeholder="请选择付款单类型" clearable>
<el-option
v-for="dict in dict.type.payment_bill_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="制造商名称">
<el-input v-model="form.vendorName" readonly/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预计付款时间" prop="estimatedPaymentTime">
<el-date-picker
v-model="form.estimatedPaymentTime"
type="date"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="选择日期"
></el-date-picker>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-divider content-position="left">采购应付单表</el-divider>
<el-table :data="payableOrdersWithPlans" border max-height="300px" style="margin-bottom: 20px;">
<el-table-column label="应付单编号" align="center" prop="payableBillCode" width="150"/>
<el-table-column label="预计付款时间" align="center" prop="estimatedPaymentTime" width="180"/>
<el-table-column label="付款计划" align="center" width="100">
<template slot-scope="scope">
<span>{{ scope.row.paymentPlans ? scope.row.paymentPlans.length : 0 }} 条计划</span>
</template>
</el-table-column>
<el-table-column label="项目名称" align="center" prop="projectName" width="150"/>
<el-table-column label="合同编号" align="center" prop="orderCode" width="150"/>
<el-table-column label="出入库单号" align="center" prop="inventoryCode" width="150"/>
<el-table-column label="付款状态" align="center" prop="paymentStatus" width="120">
<template slot-scope="scope">
<dict-tag :options="dict.type.payment_status" :value="scope.row.paymentStatus"/>
</template>
</el-table-column>
<el-table-column label="含税总价" align="center" prop="totalPriceWithTax" width="120"/>
<el-table-column label="未付款金额" align="center" prop="unpaidAmount" width="120"/>
<el-table-column label="本次付款金额" align="center" width="120">
<template slot-scope="scope">
{{ calculateOrderCurrentPaymentAmount(scope.row.id).toFixed(2) }}
</template>
</el-table-column>
<el-table-column label="本次付款比例" align="center" width="120">
<template slot-scope="scope">
{{ calculateOrderCurrentPaymentRate(scope.row.id) }}%
</template>
</el-table-column>
<el-table-column label="已付款金额" align="center" prop="paidAmount" width="120"/>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="100" fixed="right">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleOpenPaymentPlanSelector(scope.row, scope.$index)"
>选择
</el-button>
</template>
</el-table-column>
</el-table>
<div class="total-info">
<span style="margin-left: 20px;">计划付款总金额: <el-tag type="success">{{
totalPlannedAmount.toFixed(2)
}}</el-tag></span>
<span>计划付款比例: <el-tag type="info">{{ this.$calc.div(totalPlannedAmount,totalPayableAmountWithTax,4)*100 }}%</el-tag></span>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="handleCancel"> </el-button>
<el-button type="primary" @click="handleConfirm"> </el-button>
</div>
<el-dialog :title="planTitle" :visible.sync="isPaymentPlanSelectorOpen" width="70%"
@close="isPaymentPlanSelectorOpen=false" append-to-body>
<payment-plan-selector
ref="planSelector"
:payable-data="choosePayable"
:selected-plans="choosePayable.paymentPlans"
@confirm="handlePaymentPlanConfirm"
/>
<div slot="footer" class="dialog-footer">
<el-button @click="isPaymentPlanSelectorOpen=false"> </el-button>
<!-- <el-button type="primary" @click="handleConfirm" > </el-button>-->
<el-button type="primary" @click="handleChooseConfirm"> </el-button>
</div>
</el-dialog>
<!-- 付款计划选择器弹窗 -->
</el-dialog>
</template>
<script>
import PaymentPlan from './PaymentPlan.vue';
import {getPaymentPlan} from "@/api/finance/payable";
export default {
name: "MergePaymentDialog",
components: {PaymentPlanSelector: PaymentPlan},
dicts: ['payment_status','payment_bill_type'], // Add dicts for dict-tag
props: {
visible: {
type: Boolean,
default: false
},
payableOrders: {
type: Array,
default: () => []
}
},
data() {
return {
internalVisible: this.visible,
planTitle: '',
choosePayable: {},
form: {
paymentBillType: 'FROM_PAYABLE', // Default to a type, or make it dynamic
vendorName: '',
estimatedPaymentTime: null,
},
payableOrdersWithPlans: [], // Each order will now have its own paymentPlans array
isPaymentPlanSelectorOpen: false,
currentPayableOrderIndexForPlan: -1, // Index of the order in payableOrdersWithPlans
loadingPaymentPlans: false, // Loading state for fetching payment plans
};
},
computed: {
dialogVisible: {
get() {
return this.internalVisible;
},
set(val) {
this.internalVisible = val;
this.$emit('update:visible', val);
}
},
totalPayableAmountWithTax() {
return this.payableOrdersWithPlans.reduce((sum, order) => sum + (order.totalPriceWithTax || 0), 0);
},
totalPlannedAmount() {
return this.payableOrdersWithPlans.reduce((orderSum, order) => {
const orderPlansTotal = (order.paymentPlans || []).reduce((planSum, plan) => planSum + (plan.planAmount || 0), 0);
return orderSum + orderPlansTotal;
}, 0);
},
},
watch: {
visible(newVal) {
this.internalVisible = newVal;
if (newVal) {
this.initDialogData();
}
},
payableOrders: {
handler(newVal) {
if (this.dialogVisible) {
this.initDialogData();
}
},
deep: true
}
},
methods: {
initDialogData() {
// Initialize form fields
if (this.payableOrders.length > 0) {
const firstVendorName = this.payableOrders[0].vendorName;
const allSameVendor = this.payableOrders.every(order => order.vendorName === firstVendorName);
this.form.vendorName = allSameVendor ? firstVendorName : '多个制造商';
this.form.estimatedPaymentTime = this.payableOrders[0].estimatedPaymentTime || null; // Use first order's estimated time as default
} else {
this.form.vendorName = '';
this.form.estimatedPaymentTime = null;
}
this.form.paymentBillType = 'FROM_PAYABLE'; // Default
// Initialize payableOrdersWithPlans
this.payableOrdersWithPlans = this.payableOrders.map(order => ({
...order,
paymentPlans: order.paymentPlans || [], // Retain existing plans if any, otherwise empty
totalPriceWithTax: order.totalPriceWithTax || 0, // Ensure numeric for calculations
unpaidAmount: order.unpaidAmount || 0,
paidAmount: order.paidAmount || 0, // Ensure numeric for calculations
}));
},
handleClose() {
this.dialogVisible = false;
this.resetForm();
},
handleChooseConfirm() {
if (!this.$refs.planSelector || !this.$refs.planSelector.selectedPlan) {
this.$modal.msgError('无法获取计划选择器组件或其选择的计划');
return;
}
const selectedPlans = this.$refs.planSelector.selectedPlan;
const orderIndex = this.payableOrdersWithPlans.findIndex(o => o.id === this.choosePayable.id);
if (orderIndex === -1) {
this.$modal.msgError('找不到要更新的应付单');
return;
}
const currentOrder = this.payableOrdersWithPlans[orderIndex];
// Ensure the paymentPlans array exists
if (!currentOrder.paymentPlans) {
this.$set(currentOrder, 'paymentPlans', []);
}
// Add new plans, checking for duplicates by plan ID
let addedCount = 0;
selectedPlans.forEach(newPlan => {
const existingPlan = currentOrder.paymentPlans.find(p => p.id === newPlan.id);
if (!existingPlan) {
currentOrder.paymentPlans.push(newPlan);
addedCount++;
}
});
this.isPaymentPlanSelectorOpen = false;
if (addedCount > 0) {
this.$modal.msgSuccess(`成功补充 ${addedCount} 条付款计划`);
} else {
this.$modal.msgWarning('没有新的付款计划被添加');
}
},
handleConfirm() {
// Validate main form fields
if (!this.form.paymentBillType) {
this.$modal.msgError('请选择付款单类型');
return;
}
if (!this.form.estimatedPaymentTime) {
this.$modal.msgError('请选择预计付款时间');
return;
}
// Validate each payable order's payment plans
for (const order of this.payableOrdersWithPlans) {
if (!order.paymentPlans || order.paymentPlans.length === 0) {
this.$modal.msgError(`应付单 ${order.payableBillCode} 至少需要一条付款计划`);
return;
}
for (const plan of order.paymentPlans) {
if (!plan.planPaymentDate) {
this.$modal.msgError(`应付单 ${order.payableBillCode} 的付款计划中预计付款时间不能为空。`);
return;
}
if (plan.planAmount === null || plan.planAmount === undefined || plan.planAmount <= 0) {
this.$modal.msgError(`应付单 ${order.payableBillCode} 的付款计划中预计付款金额必须大于0。`);
return;
}
if (plan.planRate === null || plan.planRate === undefined) {
this.$modal.msgError(`应付单 ${order.payableBillCode} 的付款计划中应付比例不能为空。`);
return;
}
}
}
// Construct the final data to be emitted to the parent
const mergedPaymentData = {
paymentBillType: this.form.paymentBillType,
estimatedPaymentTime: this.form.estimatedPaymentTime,
// Collect all payable orders with their updated payment plans
payableOrders: this.payableOrdersWithPlans.map(order => ({
id: order.id,
payableBillCode: order.payableBillCode,
paymentPlans: order.paymentPlans.map(plan => ({
planPaymentDate: plan.planPaymentDate,
planAmount: plan.planAmount,
planRate: plan.planRate,
remark: plan.remark,
id: plan.id,
})),
})),
totalMergePaymentAmount: this.totalPlannedAmount, // Total amount for the merged bill
};
this.$emit('confirm', mergedPaymentData);
this.dialogVisible = false;
},
handleCancel() {
this.dialogVisible = false;
this.resetForm();
},
resetForm() {
this.form = {
paymentBillType: 'FROM_PAYABLE',
vendorName: '',
estimatedPaymentTime: null,
};
this.payableOrdersWithPlans = [];
this.currentPayableOrderIndexForPlan = -1;
this.loadingPaymentPlans = false;
},
handleOpenPaymentPlanSelector(row, index) {
this.planTitle = `选择付款计划 - ${row.payableBillCode}`;
this.choosePayable = row;
this.currentPayableOrderIndexForPlan = index;
this.isPaymentPlanSelectorOpen = true;
console.log(this.choosePayable.id)
},
handlePaymentPlanConfirm(updatedPlans) {
// Update the payment plans for the specific order
if (this.currentPayableOrderIndexForPlan !== -1) {
this.$set(this.payableOrdersWithPlans[this.currentPayableOrderIndexForPlan], 'paymentPlans', updatedPlans);
}
this.isPaymentPlanSelectorOpen = false;
this.currentPayableOrderIndexForPlan = -1;
},
calculateOrderCurrentPaymentAmount(orderId) {
const order = this.payableOrdersWithPlans.find(o => o.id === orderId);
if (order && order.paymentPlans) {
return order.paymentPlans.reduce((sum, plan) => sum + (plan.planAmount || 0), 0);
}
return 0;
},
calculateOrderCurrentPaymentRate(orderId) {
const order = this.payableOrdersWithPlans.find(o => o.id === orderId);
if (order && order.paymentPlans && order.unpaidAmount >= 0) {
const currentAmount = this.calculateOrderCurrentPaymentAmount(orderId);
return this.$calc.mul(this.$calc.div(currentAmount ,order.totalPriceWithTax,4 ),100);
}
return 0;
},
},
};
</script>
<style scoped>
.dialog-body {
max-height: 70vh;
overflow-y: auto;
padding-right: 10px; /* To prevent scrollbar from overlapping content */
}
.total-info {
margin-top: 20px;
text-align: right;
font-weight: bold;
}
</style>

View File

@ -0,0 +1,306 @@
<template>
<div class="dialog-body">
<el-divider content-position="left">付款计划</el-divider>
<el-button v-if="isEditing" type="primary" size="mini" @click="handleSavePaymentPlan"
style="margin-bottom: 10px;">
保存付款计划
</el-button>
<el-button v-else type="primary" size="mini" @click="isEditing=true"
style="margin-bottom: 10px;">
编辑
</el-button>
<el-table :data="paymentPlans" border @selection-change="selectPlan" ref="paymentPlanTable">
<el-table-column type="selection" width="50" align="center" :selectable="selectableRow"/>
<el-table-column label="序号" type="index" width="50" align="center"></el-table-column>
<el-table-column label="预计付款时间" align="center" width="200">
<template slot-scope="scope">
<el-date-picker v-model="scope.row.planPaymentDate" type="date" style="width: 180px"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="选择日期"
:disabled="!isEditing || isNumberStr(scope.row.detailId)"></el-date-picker>
</template>
</el-table-column>
<el-table-column label="预计付款金额" align="center" width="230">
<template slot-scope="scope">
<el-input-number
v-model="scope.row.planAmount"
:precision="2"
:step="100"
:min="0.01"
:readonly="!scope.row.detailId"
:max="totalPriceWithTax"
@change="handleAmountChange(scope.row)"
:disabled="!isEditing || isNumberStr(scope.row.detailId)"
></el-input-number>
</template>
</el-table-column>
<el-table-column label="应付比例(%)" align="center" width="230">
<template slot-scope="scope">
<el-input-number
v-model="scope.row.planRate"
:precision="2"
:step="1"
:min="0.01"
:max="100"
:readonly="!scope.row.detailId"
@change="handleRateChange(scope.row)"
:disabled="!isEditing || isNumberStr(scope.row.detailId)"
></el-input-number>
</template>
</el-table-column>
<el-table-column label="备注" align="center">
<template slot-scope="scope">
<el-input v-model="scope.row.remark" placeholder="请输入备注"
:disabled="!isEditing || isNumberStr(scope.row.detailId)"></el-input>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="150" fixed="right">
<template slot-scope="scope">
<el-button v-if="isEditing && !isNumberStr(scope.row.detailId)"
size="mini"
type="text"
icon="el-icon-plus"
@click="handleAddPaymentPlanRow"
>增加下行
</el-button>
<el-button v-if="isEditing && !isNumberStr(scope.row.detailId)"
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDeletePaymentPlanRow(scope.$index)"
:disabled="paymentPlans.length === 1 || scope.row.status === 'paid'"
>删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- <div class="total-info">-->
<!-- <span>应付单未付款金额: <el-tag type="info">{{ totalUnpaidAmount.toFixed(2) }}</el-tag></span>-->
<!-- <span style="margin-left: 20px;">计划付款总金额: <el-tag type="success">{{-->
<!-- totalPlannedAmount.toFixed(2)-->
<!-- }}</el-tag></span>-->
<!-- </div>-->
</div>
</template>
<script>
import {getPaymentPlan, updatePaymentPlan} from "@/api/finance/payable";
import {isNumberStr} from "@/utils";
export default {
name: "PaymentPlanSelector",
props: {
payableData: {
type: Object,
default: () => {
}
},
isInitEdit: {
type: Boolean,
default: false
},
selectedPlans: {
type: Array,
default: () => []
}
},
data() {
return {
selectedPlan:[],
isEditing: false,
loading: false,
paymentPlans: [],
};
},
computed: {
title() {
return `选择付款计划 - ${this.payableData.payableBillCode}`;
},
totalPlannedAmount() {
return this.paymentPlans.reduce((sum, plan) => sum + (plan.planAmount || 0), 0);
},
totalUnpaidAmount() {
return this.payableData.unpaidAmount || 0;
},
totalPriceWithTax() {
return this.payableData.totalPriceWithTax || 0;
}
},
watch: {
'payableData.id': {
handler(newVal, oldVal) {
if (newVal) {
this.fetchPaymentPlans(newVal)
}
},
immediate: true
},
isInitEdit: {
handler(newVal) {
if (newVal) {
this.isEditing = newVal
}
},
immediate: true
}
},
methods: {
isNumberStr,
selectableRow(row, index){
return !row.detailId;
},
selectPlan( selection){
this.selectedPlan=selection
},
fetchPaymentPlans(payableId) {
if (this.payableData && payableId) {
getPaymentPlan(payableId).then(response => {
this.paymentPlans = response.data.map(item => ({
...item,
// Add a default status if not present, similar to EditForm.vue
status: item.status || 'pending'
}));
if (this.paymentPlans.length === 0) {
this.initDefaultPaymentPlan();
} else {
this.$nextTick(() => {
this.paymentPlans.forEach(plan => {
const isSelected = this.selectedPlans.some(selected => selected.id === plan.id);
if (isSelected) {
this.$refs.paymentPlanTable.toggleRowSelection(plan, true);
}
});
});
}
})
} else {
this.initDefaultPaymentPlan();
}
},
initDefaultPaymentPlan() {
// Default to a single plan covering the unpaid amount if no initial plans
this.paymentPlans = [{
planPaymentDate: null,
planAmount: this.totalUnpaidAmount,
planRate: 100,
remark: '',
status: 'pending' // Default status
}];
},
handleSavePaymentPlan() {
if (!this.validatePaymentPlans()) {
return;
}
if (!this.validatePaymentPlanTotals()) {
return;
}
for (let i = 0; i < this.paymentPlans.length; i++) {
const plan = this.paymentPlans[i];
if (!plan.planPaymentDate) {
this.$modal.msgError(`${i + 1} 行付款计划的预计付款时间不能为空。`);
return;
}
if (plan.planAmount === null || plan.planAmount === undefined || plan.planAmount === '' || plan.planAmount < 0) {
this.$modal.msgError(`${i + 1} 行付款计划的预计付款金额不能为空。`);
return;
}
if (plan.planRate === null || plan.planRate === undefined || plan.planRate === '') {
this.$modal.msgError(`${i + 1} 行付款计划的应付比例不能为空。`);
return;
}
}
updatePaymentPlan(this.payableData.id, this.paymentPlans).then(() => {
this.$modal.msgSuccess("保存成功");
this.fetchPaymentPlans(this.payableData.id); // Re-fetch using the correct method and ID
});
},
handleAddPaymentPlanRow() {
this.paymentPlans.push({
planPaymentDate: null,
planAmount: 0,
planRate: 0,
remark: '',
status: 'pending' // Default status
});
},
handleDeletePaymentPlanRow(index) {
if (this.paymentPlans.length === 1) {
this.$modal.msgError("至少需要保留一条付款计划。");
return;
}
// Only allow deletion if not 'paid' or status is not set (newly added)
if (this.paymentPlans[index].status === 'paid') {
this.$modal.msgError("已付款的计划不能删除。");
return;
}
this.paymentPlans.splice(index, 1);
},
handleAmountChange(row) {
if (this.totalPriceWithTax === 0) {
row.planRate = 0;
return;
}
row.planRate = this.$calc.mul((this.$calc.div(row.planAmount, this.totalPriceWithTax,4)), 100);
},
handleRateChange(row) {
row.planAmount = this.$calc.div(this.$calc.mul(this.totalPriceWithTax , row.planRate),100);
},
validatePaymentPlanTotals() {
const totalAmount = this.paymentPlans.reduce((sum, plan) => sum + (plan.planAmount || 0), 0);
const totalRate = this.paymentPlans.reduce((sum, plan) => sum + (plan.planRate || 0), 0);
if (totalAmount !== this.totalPriceWithTax) {
this.$modal.msgError(`预计付款金额之和应该等于应付总金额[${this.totalPriceWithTax}]`);
return false;
}
return true;
},
validatePaymentPlans() {
if (this.paymentPlans.length === 0) {
this.$modal.msgError("请至少添加一条付款计划。");
return false;
}
const totalPlannedAmount = this.paymentPlans.reduce((sum, plan) => sum + (plan.planAmount || 0), 0);
for (let i = 0; i < this.paymentPlans.length; i++) {
const plan = this.paymentPlans[i];
if (!plan.planPaymentDate) {
this.$modal.msgError(`${i + 1} 行付款计划的预计付款时间不能为空。`);
return false;
}
if (plan.planAmount === null || plan.planAmount === undefined || plan.planAmount <= 0) {
this.$modal.msgError(`${i + 1} 行付款计划的预计付款金额必须大于0。`);
return false;
}
if (plan.planRate === null || plan.planRate === undefined || plan.planRate === '') {
this.$modal.msgError(`${i + 1} 行付款计划的应付比例不能为空。`);
return false;
}
}
return true;
}
}
};
</script>
<style scoped>
.dialog-body {
max-height: 70vh;
overflow-y: auto;
padding-right: 10px; /* To prevent scrollbar from overlapping content */
}
.total-info {
margin-top: 20px;
text-align: right;
font-weight: bold;
}
</style>

View File

@ -0,0 +1,357 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
<el-form-item label="项目编号" prop="projectCode">
<el-input
v-model="queryParams.projectCode"
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="应付单编号" prop="payableBillCode">
<el-input
v-model="queryParams.payableBillCode"
placeholder="请输入应付单编号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="制造商名称" prop="vendorName">
<el-input
v-model="queryParams.vendorName"
placeholder="请输入制造商名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<!-- <el-form-item label="合同编号" prop="orderCode">-->
<!-- <el-input-->
<!-- v-model="queryParams.orderCode"-->
<!-- placeholder="请输入合同编号"-->
<!-- clearable-->
<!-- @keyup.enter.native="handleQuery"-->
<!-- />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="出入库单号" prop="inventoryCode">-->
<!-- <el-input-->
<!-- v-model="queryParams.inventoryCode"-->
<!-- placeholder="请输入出入库单号"-->
<!-- clearable-->
<!-- @keyup.enter.native="handleQuery"-->
<!-- />-->
<!-- </el-form-item>-->
<el-form-item label="产品类型" prop="productType">
<el-select v-model="queryParams.productType" placeholder="请选择产品类型" clearable>
<el-option
v-for="dict in dict.type.product_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="付款状态" prop="paymentStatus">
<el-select v-model="queryParams.paymentStatus" placeholder="请选择付款状态" clearable>
<el-option
v-for="dict in dict.type.payment_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="收票状态" prop="paymentStatus">
<el-select v-model="queryParams.paymentStatus" placeholder="请选择付款状态" clearable>
<el-option
v-for="dict in dict.type.payment_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</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 label="预计付款时间">
<el-date-picker
v-model="estimatedPaymentDateRange"
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 icon="el-icon-plus" @click="handleMergeAndInitiatePayment" v-hasPermi="['finance:payable:mergePayment']">
合并并发起付款单
</el-button>
</el-col>
<el-col :span="1.5" >
<el-button type="primary" plain icon="el-icon-plus" v-hasPermi="['inventory:inner:add']">
合并并发起收票单
</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="payableList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" />
<el-table-column label="项目编号" align="center" prop="projectCode" width="120" />
<el-table-column label="项目名称" align="center" prop="projectName" width="150" />
<el-table-column label="应付单编号" align="center" prop="payableBillCode" width="150" />
<!-- <el-table-column label="生成时间" align="center" prop="createTime" width="180"/>-->
<el-table-column label="预计付款时间" align="center" prop="estimatedPaymentTime" width="180"/>
<el-table-column label="预计付款金额" align="center" prop="totalPriceWithTax" width="120" />
<el-table-column label="该制造商是否有预付单" align="center" prop="hasAdvancePayment" width="150" />
<!-- <el-table-column label="预付金额" align="center" prop="advancePaymentAmount" width="120" />-->
<el-table-column label="制造商名称" align="center" prop="vendorName" width="150" />
<!-- <el-table-column label="合同编号" align="center" prop="orderCode" width="150" />-->
<!-- <el-table-column label="出入库单号" align="center" prop="inventoryCode" width="150" />-->
<el-table-column label="产品类型" align="center" prop="productType" width="120">
<template slot-scope="scope">
<dict-tag :options="dict.type.product_type" :value="scope.row.productType"/>
</template>
</el-table-column>
<el-table-column label="含税总价" align="center" prop="totalPriceWithTax" width="120" />
<!-- <el-table-column label="未税总价" align="center" prop="totalPriceWithoutTax" width="120" />-->
<!-- <el-table-column label="税额" align="center" prop="taxAmount" width="120" />-->
<!-- <el-table-column label="付款状态" align="center" prop="paymentStatus" width="120">-->
<!-- <template slot-scope="scope">-->
<!-- {{ scope.row.unpaidAmount === scope.row.totalPriceWithTax ? '未生成' : scope.row.unpaidAmount === 0 ? '全部生成' : '部分生成' }}-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column label="生成付款单" align="center" width="120">-->
<!-- <template slot-scope="scope">-->
<!-- {{scope.row.unpaidAmount===scope.row.totalPriceWithTax?'未生成':scope.row.unpaidAmount===0?'全部生成':'部分生成'}}-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column label="收票状态" align="center" prop="invoiceStatus" width="120">-->
<!-- <template slot-scope="scope">-->
<!-- <dict-tag :options="dict.type.invoice_status" :value="scope.row.invoiceStatus"/>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column label="生成收票单" align="center" width="120">-->
<!-- <template slot-scope="scope">-->
<!-- <el-button-->
<!-- size="mini"-->
<!-- type="text"-->
<!-- @click="handleGenerateInvoice(scope.row)"-->
<!-- >生成收票单</el-button>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="未付款金额" align="center" prop="unpaidAmount" width="120" />
<!-- <el-table-column label="付款中金额" align="center" prop="payingAmount" width="120" />-->
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="160" fixed="right">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['finance:payable:edit']"
>查看详情</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-edit"
v-show="scope.row.unpaidAmount!==0"
@click="handleGeneratedPayment(scope.row)"
v-hasPermi="['finance:payable:edit']"
>生成付款单</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['finance:payable:remove']"
>删除</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"
/>
<!-- 修改弹窗 -->
<edit-form :visible.sync="open" :data="selectedRow" />
<!-- 合并付款单弹窗 -->
<merge-payment-dialog :visible.sync="isMergePaymentDialogOpen" :payable-orders="selectedPayableRows" @confirm="confirmMergePayment" />
</div>
</template>
<script>
import { listPayable, mergeAndInitiatePayment } from "@/api/finance/payable";
import EditForm from './components/EditForm.vue';
import MergePaymentDialog from './components/MergePaymentDialog.vue';
export default {
name: "Payable",
components: { EditForm, MergePaymentDialog },
dicts: ['product_type', 'payment_status', 'invoice_status'],
data() {
return {
// (other data properties)
//
open: false,
//
selectedRow: {},
//
loading: true,
//
showSearch: true,
//
total: 0,
//
payableList: [],
//
dateRange: [],
//
estimatedPaymentDateRange: [],
//
queryParams: {
pageNum: 1,
pageSize: 10,
projectCode: null,
projectName: null,
payableBillCode: null,
vendorName: null,
orderCode: null,
inventoryCode: null,
productType: null,
paymentStatus: null,
createTimeStart: null,
createTimeEnd: null,
estimatedPaymentTimeStart: null,
estimatedPaymentTimeEnd: null
},
//
selectedPayableRows: [],
//
isMergePaymentDialogOpen: false
};
},
created() {
this.getList();
},
methods: {
/** 查询采购应付单列表 */
getList() {
this.loading = true;
if (null != this.dateRange && '' != this.dateRange) {
this.queryParams.createTimeStart = this.dateRange[0];
this.queryParams.createTimeEnd = this.dateRange[1];
}
if (null != this.estimatedPaymentDateRange && '' != this.estimatedPaymentDateRange) {
this.queryParams.estimatedPaymentTimeStart = this.estimatedPaymentDateRange[0];
this.queryParams.estimatedPaymentTimeEnd = this.estimatedPaymentDateRange[1];
}
listPayable(this.queryParams).then(response => {
this.payableList = response.rows;
this.total = response.total;
this.loading = false;
});
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = [];
this.estimatedPaymentDateRange = [];
this.resetForm("queryForm");
this.queryParams.createTimeStart=null;
this.queryParams.createTimeEnd=null;
this.queryParams.estimatedPaymentTimeStart=null;
this.queryParams.estimatedPaymentTimeEnd=null;
this.handleQuery();
},
/** 修改按钮操作 */
handleUpdate(row) {
this.selectedRow = row;
this.open = true;
},
/** 删除按钮操作 */
handleDelete(row) {
this.$modal.confirm('是否确认删除采购应付单编号为"' + row.payableBillCode + '"的数据项?').then(function() {
return Promise.resolve();
}).then(() => {
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 生成付款单按钮操作 */
handleGeneratePayment(row) {
console.log("handleGeneratePayment", row);
},
/** 生成收票单按钮操作 */
handleGenerateInvoice(row) {
console.log("handleGenerateInvoice", row);
},
/** 多选框选中数据 */
handleSelectionChange(selection) {
this.selectedPayableRows = selection;
},
handleGeneratedPayment(row) {
this.selectedPayableRows=[row]
this.handleMergeAndInitiatePayment()
},
/** 合并并发起付款单按钮操作 */
handleMergeAndInitiatePayment() {
if (this.selectedPayableRows.length === 0) {
this.$modal.msgWarning("请选择至少一条应付单进行合并操作");
return;
}
let vendorLength = new Set(this.selectedPayableRows.map(item=>item.vendorCode)).size;
if (vendorLength > 1) {
this.$modal.msgWarning("请选择同一家供应商的应付单进行合并操作");
return;
}
this.isMergePaymentDialogOpen = true;
},
/** 确认合并付款单操作 */
confirmMergePayment(paymentData) {
mergeAndInitiatePayment(paymentData).then(() => {
this.$modal.msgSuccess("合并付款单发起成功");
this.isMergePaymentDialogOpen = false;
this.getList(); // Refresh the list
});
}
}
};
</script>

View File

@ -0,0 +1,146 @@
<template>
<el-dialog title="新增付款单" :visible.sync="internalVisible" width="500px" @close="handleClose">
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
<el-form-item label="付款单类型" prop="paymentBillType">
<el-select v-model="form.paymentBillType" disabled placeholder="请选择付款单类型">
<el-option
v-for="dict in dicts.payment_bill_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="制造商名称" prop="vendorCode">
<el-select v-model="form.vendorCode" placeholder="请选择制造商" style="width:100%" >
<el-option v-for="item in vendorOptions" :key="item.vendorCode" :label="item.vendorName" :value="item.vendorCode"></el-option>
</el-select>
</el-form-item>
<el-form-item label="预计付款时间" prop="paymentTime">
<el-date-picker
v-model="form.paymentTime"
type="datetime"
placeholder="选择日期"
value-format="yyyy-MM-dd HH:mm:ss"
></el-date-picker>
</el-form-item>
<el-form-item label="含税总价" prop="totalPriceWithTax">
<el-input-number v-model="form.totalPriceWithTax" @change="handlePriceChange" :precision="2"
:step="1"></el-input-number>
</el-form-item>
<el-form-item label="税率" prop="taxRate">
<el-input-number v-model="form.taxRate" @change="handlePriceChange" :precision="2" :step="0.01"
:max="1"></el-input-number>
</el-form-item>
<el-form-item label="未税总价" prop="totalPriceWithoutTax">
<el-input v-model="form.totalPriceWithoutTax" :disabled="true"/>
</el-form-item>
<el-form-item label="税额" prop="taxAmount">
<el-input v-model="form.taxAmount" :disabled="true"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="handleClose"> </el-button>
<el-button type="primary" @click="handleSubmit"> </el-button>
</div>
</el-dialog>
</template>
<script>
import {listAllVendor} from "@/api/base/vendor";
export default {
name: "AddForm",
props: {
visible: {
type: Boolean,
default: false
},
dicts: {
type: Object,
default: () => ({})
}
},
data() {
return {
internalVisible: this.visible,
vendorOptions: [],
form: {
paymentBillType:'PRE_PAYMENT',
vendorName: null,
paymentTime: null,
totalPriceWithTax: 0,
taxRate: 0.13, // Default tax rate
totalPriceWithoutTax: 0,
taxAmount: 0
},
rules: {
paymentBillType: [{required: true, message: "付款单类型不能为空", trigger: "change"}],
vendorName: [{required: true, message: "制造商名称不能为空", trigger: "blur"}],
paymentTime: [{required: true, message: "预计付款时间不能为空", trigger: "change"}],
totalPriceWithTax: [{required: true, message: "含税总价不能为空", trigger: "blur"}]
}
};
},
watch: {
visible(newVal) {
this.internalVisible = newVal;
if (newVal) {
this.resetForm();
this.getVendorList();
}
},
internalVisible(newVal) {
this.$emit("update:visible", newVal);
}
},
methods: {
/** 获取厂商列表 */
getVendorList() {
return listAllVendor().then(res => {
this.vendorOptions = res.data;
})
},
handlePriceChange() {
const taxed = this.form.totalPriceWithTax || 0;
const rate = this.form.taxRate || 0;
const unTaxed = this.$calc.div(taxed, this.$calc.add(1, rate));
const taxAmount = this.$calc.sub(taxed, unTaxed);
this.form.totalPriceWithoutTax = unTaxed;
this.form.taxAmount = taxAmount;
},
handleClose() {
this.internalVisible = false;
},
handleSubmit() {
this.$refs.form.validate(valid => {
if (valid) {
// Here you would typically emit an event to the parent component
// to handle the form submission, e.g., call an API.
this.form.preResidueAmount=0;
this.$emit("submit", this.form);
}
});
},
resetForm() {
if (this.$refs.form) {
this.$refs.form.resetFields();
}
this.form = {
paymentBillType: 'PRE_PAYMENT',
vendorName: null,
paymentTime: null,
totalPriceWithTax: 0,
taxRate: 0.13,
totalPriceWithoutTax: 0,
taxAmount: 0
};
this.handlePriceChange();
}
}
};
</script>

View File

@ -0,0 +1,185 @@
<template>
<el-drawer
title="付款单详情"
:visible.sync="visible"
direction="rtl"
size="70%"
@close="handleClose"
>
<div class="dialog-body" v-if="detail">
<div class="section">
<el-divider content-position="left">采购-付款单</el-divider>
<div class="details-container">
<el-row :gutter="20">
<el-col :span="8">
<div class="detail-item">采购-付款单编号: {{ detail.paymentBillCode }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item">预计付款时间: {{ detail.paymentTime }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item">制造商名称: {{ detail.vendorName }}</div>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<div class="detail-item">含税总价: {{ detail.totalPriceWithTax }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item">未税总价: {{ detail.totalPriceWithoutTax }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item">税额: {{ detail.taxAmount }}</div>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<div class="detail-item">付款单类型:
<dict-tag :options="dict.type.payment_bill_type" :value="detail.paymentBillType"/>
</div>
</el-col>
<el-col :span="8">
<div class="detail-item">预付单剩余额度: {{ detail.preResidueAmount || '-' }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item">财务付款时间: {{ detail.actualPaymentTime || '-'}}</div>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<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">回执单/退款图:
<!-- <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">
<el-col :span="8">
<div class="detail-item">备注: {{ detail.remark }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item">上传人姓名: {{ detail.createBy }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item">账户名称: {{ detail.payName }}</div>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<div class="detail-item">银行账号: {{ detail.payBankNumber }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item">银行开户行: {{ detail.payBankOpenAddress }}</div>
</el-col>
<el-col :span="8">
<div class="detail-item">银行行号: {{ detail.bankNumber }}</div>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<div class="detail-item">审批节点: {{ detail.approveNode|| '-' }}</div>
</el-col>
<el-col :span="8">
<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>
</el-col>
</el-row>
</div>
</div>
<div class="section">
<el-divider content-position="left">采购-应付单</el-divider>
<el-table :data="detail.payableDetails">
<el-table-column type="index" label="序号" width="50"></el-table-column>
<el-table-column property="projectCode" label="项目编号"></el-table-column>
<el-table-column property="projectName" label="项目名称"></el-table-column>
<el-table-column property="payableBillCode" label="采购应付单编号"></el-table-column>
<el-table-column property="totalPriceWithTax" label="含税总价"></el-table-column>
<el-table-column property="paymentAmount" label="本次付款金额"></el-table-column>
<el-table-column property="paymentRatio" label="本次付款比例"></el-table-column>
</el-table>
</div>
</div>
</el-drawer>
</template>
<script>
export default {
name: "DetailDrawer",
props: {
visible: {
type: Boolean,
default: false,
},
detail: {
type: Object,
default: () => null,
},
},
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);
},
},
};
</script>
<style scoped>
.dialog-body {
max-height: calc(100vh - 50px); /* Adjust based on actual header/footer height */
overflow-y: auto;
padding: 0 20px 20px 20px; /* Adjust padding to match dialog-body style */
}
.details-container {
border: 1px solid #EBEEF5;
padding: 20px;
border-radius: 4px;
}
.detail-item {
display: flex;
border: 1px solid #EBEEF5;
padding: 10px;
border-radius: 4px;
margin-bottom: 10px;
font-size: 14px;
align-items: center;
}
.section {
margin-bottom: 20px;
}
.grid-content {
border-radius: 4px;
min-height: 36px;
line-height: 36px;
}
</style>

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

@ -0,0 +1,419 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
<el-form-item label="项目编号" prop="projectCode">
<el-input
v-model="queryParams.projectCode"
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="付款单编号" prop="paymentBillCode">
<el-input
v-model="queryParams.paymentBillCode"
placeholder="请输入付款单编号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="制造商名称" prop="vendorCode">
<el-input
v-model="queryParams.vendorCode"
placeholder="请输入制造商名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="应付单编号" prop="payableBillCode">
<el-input
v-model="queryParams.payableBillCode"
placeholder="请输入应付单编号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="付款单类型" prop="paymentBillType">
<el-select v-model="queryParams.paymentBillType" placeholder="请选择付款单类型" clearable>
<el-option v-for="dict in dict.type.payment_bill_type" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="支付方式" prop="paymentMethod">
<el-select v-model="queryParams.paymentMethod" placeholder="请选择支付方式" clearable>
<el-option label="方式一" value="1" />
<el-option label="方式二" value="2" />
</el-select>
</el-form-item>
<el-form-item label="审批状态" prop="approveStatus">
<el-select v-model="queryParams.approveStatus" placeholder="请选择审批状态" clearable>
<el-option label="待提交" value="0" />
<el-option label="审批中" value="1" />
<el-option label="已审批" value="2" />
<el-option label="已驳回" value="3" />
</el-select>
</el-form-item>
<el-form-item label="付款状态" prop="paymentStatus">
<el-select v-model="queryParams.paymentStatus" placeholder="请选择付款状态" clearable>
<el-option label="待付款" value="0" />
<el-option label="已付款" value="1" />
</el-select>
</el-form-item>
<el-form-item label="审批节点" prop="approveNode">
<el-input
v-model="queryParams.approveNode"
placeholder="请输入审批节点"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="审批通过时间">
<el-date-picker
v-model="dateRangeApproval"
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 label="预计付款时间">
<el-date-picker
v-model="dateRangeEstimated"
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 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-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
icon="el-icon-plus"
size="mini"
@click="handleAdd"
>新增</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="paymentList">
<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} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<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">
<dict-tag :options="dict.type.payment_bill_type" :value="scope.row.paymentBillType"/>
</template>
</el-table-column>
<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} {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="paymentStatus" >
<template slot-scope="scope">
<dict-tag :options="dict.type.payment_status" :value="scope.row.paymentStatus"/>
</template>
</el-table-column>
<el-table-column label="审批状态" align="center" prop="approveStatus" >
<template slot-scope="scope">
<dict-tag :options="dict.type.approve_status" :value="scope.row.approveStatus"/>
</template>
</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} {h}:{i}:{s}') }}</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">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
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"
icon="el-icon-refresh-left"
v-show="scope.row.approveStatus=='1'"
@click="handleReturn(scope.row)"
>退回</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-refresh-right"
v-if="scope.row.paymentStatus === '2' && scope.row.refundStatus !== 'REFUND_APPLIED' && scope.row.paymentBillType !== 'REFUND'"
@click="handleApplyRefund(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"
/>
<!-- 详情抽屉 -->
<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, applyPaymentApi, applyRefund } 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,
ReceiptDialog
},
dicts:['payment_bill_type','approve_status','payment_status', 'payment_method'],
data() {
return {
//
loading: true,
//
showSearch: true,
//
total: 0,
//
paymentList: [],
//
queryParams: {
pageNum: 1,
pageSize: 10,
projectCode: null,
projectName: null,
paymentBillCode: null,
vendorCode: null,
payableBillCode: null,
paymentBillType: null,
paymentMethod: null,
approveStatus: null,
paymentStatus: null,
approveNode: null,
},
//
dateRangeApproval: [],
dateRangeEstimated: [],
dateRangeActual: [],
//
detailOpen: false,
detailData: null,
//
addOpen: false,
//
receiptOpen: false,
currentRow: null,
//
applyPaymentOpen: false,
applyPaymentForm: {},
};
},
created() {
this.getList();
},
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 };
query = this.addDateRange(query, this.dateRangeApproval, 'ApproveTime');
query = this.addDateRange(query, this.dateRangeEstimated, 'PaymentTime');
query = this.addDateRange(query, this.dateRangeActual, 'ActualPaymentTime');
listPayment(query).then(response => {
this.paymentList = response.rows;
this.total = response.total;
this.loading = false;
});
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.dateRangeApproval = [];
this.dateRangeEstimated = [];
this.dateRangeActual = [];
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.addOpen = true;
},
/** 新增提交 */
handleAddSubmit(form) {
addPayment(form).then(response => {
this.$modal.msgSuccess("新增成功");
this.addOpen = false;
this.getList();
}).catch(error => {
console.error("新增付款单失败", error);
this.$modal.msgError("新增失败");
});
},
/** 详情按钮操作 */
handleDetail(row) {
getPayment(row.id).then(response => {
this.detailData = response.data;
this.detailOpen = true;
});
},
/** 回执单按钮操作 */
handleReceipt(row) {
this.currentRow = row;
this.receiptOpen = true;
},
/** 退回按钮操作 */
handleReturn(row) {
this.$modal.confirm('是否确认退回付款单编号为"' + row.paymentBillCode + '"的数据项?').then(function() {
return returnPayment(row.id);
}).then(() => {
this.getList();
this.$modal.msgSuccess("退回成功");
}).catch(() => {});
},
/** 申请退款按钮操作 */
handleApplyRefund(row) {
this.$modal.confirm('是否确认对付款单编号为"' + row.paymentBillCode + '"的款项申请退款?').then(() => {
return applyRefund(row.id);
}).then(() => {
this.getList();
this.$modal.msgSuccess("申请退款成功");
}).catch(() => {});
}
}
};
</script>

View File

@ -28,7 +28,7 @@
<!-- 操作按钮栏 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['inventory:outer:export']"></el-button>
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['inventory:outer:export']"></el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>

View File

@ -534,15 +534,15 @@ export default {
/** 分配数据权限操作 */
handleDataScope(row) {
this.reset()
const deptTreeSelect = this.getDeptTree(row.roleId)
// const deptTreeSelect = this.getDeptTree(row.roleId)
getRole(row.roleId).then(response => {
this.form = response.data
this.openDataScope = true
this.$nextTick(() => {
deptTreeSelect.then(res => {
this.$refs.dept.setCheckedKeys(res.checkedKeys)
})
})
// this.$nextTick(() => {
// deptTreeSelect.then(res => {
// this.$refs.dept.setCheckedKeys(res.checkedKeys)
// })
// })
})
this.title = "分配数据权限"
},

View File

@ -0,0 +1,72 @@
flowable:
database-schema-update: false
ruoyi:
excelTemplate: /home/application/excelTemplate
profile: /home/application/uploadPath
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
druid:
# 主库数据源
master:
url: jdbc:mysql://121.199.168.157:3306/unis_pms?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowMultiQueries=true
username: root
password: unis@db
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置连接超时时间
connectTimeout: 30000
# 配置网络超时时间
socketTimeout: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: ruoyi
login-password: 123456
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
unis:
order:
# 执行单截止时间
endHour: 96
mail:
enabled: false

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,15 +1,13 @@
package com.ruoyi.sip.controller;
import java.util.List;
import com.ruoyi.sip.domain.OmsPaymentBill;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.sip.domain.OmsPayableBill;
@ -18,6 +16,12 @@ 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 com.ruoyi.sip.service.IOmsPaymentBillService;
import com.ruoyi.sip.service.IOmsInvoiceReceiptBillService;
import com.ruoyi.sip.domain.OmsInvoiceReceiptBill;
import org.springframework.ui.ModelMap;
import com.ruoyi.sip.domain.dto.MergedPaymentDataDto;
/**
* Controller
@ -34,6 +38,12 @@ public class OmsPayableBillController extends BaseController
@Autowired
private IOmsPayableBillService omsPayableBillService;
@Autowired
private IOmsPaymentBillService omsPaymentBillService;
@Autowired
private IOmsInvoiceReceiptBillService omsInvoiceReceiptBillService;
@RequiresPermissions("finance:payable:view")
@GetMapping()
public String payable()
@ -47,7 +57,7 @@ public class OmsPayableBillController extends BaseController
@RequiresPermissions("finance:payable:list")
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(OmsPayableBill omsPayableBill)
public TableDataInfo list(@RequestBody OmsPayableBill omsPayableBill)
{
startPage();
List<OmsPayableBill> list = omsPayableBillService.selectOmsPayableBillList(omsPayableBill);
@ -89,6 +99,14 @@ public class OmsPayableBillController extends BaseController
{
return toAjax(omsPayableBillService.insertOmsPayableBill(omsPayableBill));
}
@RequiresPermissions("finance:payable:query")
@Log(title = "采购应付单", businessType = BusinessType.INSERT)
@GetMapping("/{id}")
@ResponseBody
public AjaxResult query(@PathVariable("id") Long id)
{
return AjaxResult.success(omsPayableBillService.query(id));
}
/**
*
@ -125,4 +143,16 @@ public class OmsPayableBillController extends BaseController
{
return toAjax(omsPayableBillService.deleteOmsPayableBillByIds(ids));
}
/**
*
*/
@RequiresPermissions("finance:payable:mergePayment")
@Log(title = "合并并发起付款单", businessType = BusinessType.INSERT)
@PostMapping("/mergeAndInitiatePayment")
@ResponseBody
public AjaxResult mergeAndInitiatePayment(@RequestBody MergedPaymentDataDto dto)
{
return toAjax(omsPayableBillService.mergeAndInitiatePayment(dto));
}
}

View File

@ -0,0 +1,35 @@
package com.ruoyi.sip.controller;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.sip.domain.OmsPayablePaymentPlan;
import com.ruoyi.sip.service.IOmsPayablePaymentPlanService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/finance/payable/plan")
public class OmsPayablePlanController extends BaseController {
@Autowired
private IOmsPayablePaymentPlanService paymentPlanService;
@GetMapping("/{payableBillId}")
public AjaxResult getPaymentPlan(@PathVariable("payableBillId") Long payableBillId) {
return AjaxResult.success(paymentPlanService.selectOmsPayablePaymentPlanListByPayableBillId(payableBillId));
}
@PostMapping("/{payableBillId}")
public AjaxResult updatePaymentPlan(@PathVariable("payableBillId") Long payableBillId, @RequestBody List<OmsPayablePaymentPlan> paymentPlanList) {
paymentPlanService.updatePaymentPlans(payableBillId, paymentPlanList);
return AjaxResult.success();
}
}

View File

@ -1,15 +1,15 @@
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;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.sip.domain.OmsPaymentBill;
@ -18,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
@ -33,6 +34,8 @@ public class OmsPaymentBillController extends BaseController
@Autowired
private IOmsPaymentBillService omsPaymentBillService;
@Autowired
private IOmsFinAttachmentService omsFinAttachmentService;
@RequiresPermissions("finance:payment:view")
@GetMapping()
@ -71,11 +74,12 @@ public class OmsPaymentBillController extends BaseController
/**
*
*/
@RequiresPermissions("finance:payment:add")
@GetMapping("/add")
public String add()
@RequiresPermissions("finance:payment:query")
@GetMapping("/{id}")
@ResponseBody
public AjaxResult query(@PathVariable("id") Long id)
{
return prefix + "/add";
return AjaxResult.success(omsPaymentBillService.query(id));
}
/**
@ -85,7 +89,7 @@ public class OmsPaymentBillController extends BaseController
@Log(title = "采购付款单", businessType = BusinessType.INSERT)
@PostMapping("/add")
@ResponseBody
public AjaxResult addSave(OmsPaymentBill omsPaymentBill)
public AjaxResult addSave(@RequestBody OmsPaymentBill omsPaymentBill)
{
return toAjax(omsPaymentBillService.insertOmsPaymentBill(omsPaymentBill));
}
@ -125,4 +129,102 @@ public class OmsPaymentBillController extends BaseController
{
return toAjax(omsPaymentBillService.deleteOmsPaymentBillByIds(ids));
}
/**
* 退
*/
@RequiresPermissions("finance:payment:return")
@Log(title = "退回付款单", businessType = BusinessType.UPDATE)
@DeleteMapping("/returnPayment/{id}")
@ResponseBody
public AjaxResult returnPayment(@PathVariable("id") Long id)
{
try {
// 验证付款单ID
if (id == null) {
return AjaxResult.error("付款单ID不能为空");
}
// 调用服务层方法处理退回逻辑
return omsPaymentBillService.returnPaymentBill(id);
} catch (Exception e) {
logger.error("退回付款单失败", e);
return AjaxResult.error("操作失败:" + e.getMessage());
}
}
/**
*
*/
@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));
}
//
/**
*
*/
@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());
}
}
/**
* 退
*/
@GetMapping("/applyRefund/{id}")
@ResponseBody
public AjaxResult applyRefund(@PathVariable("id") Long id) {
try {
return omsPaymentBillService.applyRefund(id);
} catch (Exception e) {
logger.error("申请退款失败", e);
return AjaxResult.error("操作失败:" + e.getMessage());
}
}
//
// /**
// * 上传退款图
// */
// @PostMapping("/uploadRefundProof")
// @ResponseBody
// public AjaxResult uploadRefundProof(@RequestParam("paymentBillId") Long paymentBillId, @RequestParam("file") MultipartFile file) {
// try {
// return omsPaymentBillService.uploadRefundProof(paymentBillId, 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

@ -2,6 +2,8 @@ package com.ruoyi.sip.domain;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.*;
import org.apache.commons.lang3.builder.ToStringBuilder;
@ -16,7 +18,6 @@ import com.ruoyi.common.core.domain.BaseEntity;
* @date 2025-10-22
*/
@Data
@Builder
public class OmsPayableBill extends BaseEntity
{
private static final long serialVersionUID = 1L;
@ -27,6 +28,9 @@ public class OmsPayableBill extends BaseEntity
/** 应付单编号 */
@Excel(name = "应付单编号")
private String payableBillCode;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Excel(name = "生成时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/** 预计付款时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@ -36,7 +40,12 @@ public class OmsPayableBill extends BaseEntity
/** 制造商编码 */
@Excel(name = "制造商编码")
private String vendorCode;
@Excel(name = "制造商名称")
private String vendorName;
@Excel(name = "项目编号")
private String projectCode;
@Excel(name = "项目名称")
private String projectName;
/** 合同编号 */
@Excel(name = "合同编号")
private String orderCode;
@ -48,6 +57,8 @@ public class OmsPayableBill extends BaseEntity
/** 产品类型 */
@Excel(name = "产品类型")
private String productType;
/** 产品编码 */
private String productCode;
/** 含税总价 */
@Excel(name = "含税总价")
@ -61,15 +72,25 @@ public class OmsPayableBill extends BaseEntity
@Excel(name = "税额")
private BigDecimal taxAmount;
/** 关联的付款单ID */
@Excel(name = "关联的付款单ID")
private Long paymentBillId;
/** 关联的收票单ID */
@Excel(name = "关联的收票单ID")
private Long invoiceReceiptBillId;
/** 删除标志0代表存在 2代表删除 */
private String delFlag;
private Date createTimeStart;
private Date createTimeEnd;
private Date estimatedPaymentTimeEnd;
private Date estimatedPaymentTimeStart;
private BigDecimal unpaidAmount;
private BigDecimal paidAmount;
private BigDecimal payingAmount;
private List<OmsPayablePaymentDetail> detailList;
}

View File

@ -0,0 +1,50 @@
package com.ruoyi.sip.domain;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.Getter;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@Data
public class OmsPayablePaymentDetail extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long id;
private Long paymentPlanId;
private Long payableBillId;
private List<Long> payableBillIdList;
private String payableDetailType;
private Date paymentTime;
private BigDecimal paymentAmount;
private BigDecimal paymentRate;
private String paymentBillCode;
private Long paymentBillId;
private Date actualPaymentTime;
private String paymentStatus;
/** 回执单附件ID */
private OmsFinAttachment finAttachment;
@Getter
public enum PayableDetailTypeEnum {
/** 待确认 */
APPLY_PAYMENT("1", "申请付款"),
/** 已确认 */
PREPAY_WRITE_OFF("2", "预付核销"),
REFUND("3", "退款"),
;
private final String code;
private final String desc;
PayableDetailTypeEnum(String code, String desc) {
this.code = code;
this.desc = desc;
}
}
}

View File

@ -0,0 +1,28 @@
package com.ruoyi.sip.domain;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
public class OmsPayablePaymentPlan extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 主键 */
private Long id;
/** 应付单ID */
private Long payableBillId;
/** 计划付款时间 */
private Date planPaymentDate;
/** 计划付款金额 */
private BigDecimal planAmount;
/** 计划付款比例 */
private BigDecimal planRate;
private Long detailId;
}

View File

@ -3,6 +3,8 @@ package com.ruoyi.sip.domain;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
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;
@ -14,6 +16,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
* @author ruoyi
* @date 2025-10-22
*/
@Data
public class OmsPaymentBill extends BaseEntity
{
private static final long serialVersionUID = 1L;
@ -30,13 +33,14 @@ 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;
/** 制造商名称 */
@Excel(name = "制造商名称")
private String vendorCode;
private String vendorName;
/** 合同编号 */
@Excel(name = "合同编号")
@ -57,124 +61,128 @@ public class OmsPaymentBill extends BaseEntity
/** 删除标志0代表存在 2代表删除 */
private String delFlag;
public void setId(Long id)
{
this.id = id;
/** 项目编号 */
@Excel(name = "项目编号")
private String projectCode;
/** 项目名称 */
@Excel(name = "项目名称")
private String projectName;
/** 预付单剩余额度 */
@Excel(name = "预付单剩余额度")
private BigDecimal preResidueAmount;
/** 实际付款时间 */
@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;
/** 付款状态 */
@Excel(name = "付款状态")
private String paymentStatus;
/** 审批状态 */
@Excel(name = "审批状态")
private String approveStatus;
/** 审批节点 */
@Excel(name = "审批节点")
private String approveNode;
/** 审批时间 */
@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;
/** 支付方式 */
@Excel(name = "支付方式")
private String paymentMethod;
/** 应付单编号(关联查询字段) */
@Excel(name = "应付单编号")
private String payableBillCode;
/** 账户名称 */
@Excel(name = "账户名称")
private String payName;
/** 银行账号 */
@Excel(name = "银行账号")
private String payBankNumber;
/** 银行开户行 */
@Excel(name = "银行开户行")
private String payBankOpenAddress;
/** 银行行号 */
@Excel(name = "银行行号")
private String bankNumber;
/** 关联的原始付款单ID */
private Long originalBillId;
/** 退款状态 */
private String refundStatus;
@Getter
public enum PaymentBillTypeEnum {
/** 应付单生成 */
FROM_PAYABLE("FROM_PAYABLE", "应付单生成"),
/** 预付单 */
PRE_PAYMENT("PRE_PAYMENT", "预付单"),
/** 退款单 */
REFUND("REFUND", "退款单"),
;
private final String code;
private final String desc;
PaymentBillTypeEnum(String code, String desc) {
this.code = code;
this.desc = desc;
}
}
@Getter
public enum PaymentStatusEnum {
/** 应付单生成 */
REFUNDED("-1", "已退款"),
WAIT_PAYMENT("1", "未付款"),
/** 预付单 */
PAYMENT("2", "已付款"),
;
private final String code;
private final String desc;
PaymentStatusEnum(String code, String desc) {
this.code = code;
this.desc = desc;
}
}
@Getter
public enum RefundStatusEnum {
/** 应付单生成 */
REFUNDED("REFUND_APPLIED", "已申请退款"),
WAIT_REFUNDED("WAIT_REFUNDED", "未退款")
;
private final String code;
private final String desc;
RefundStatusEnum(String code, String desc) {
this.code = code;
this.desc = desc;
}
}
public Long getId()
{
return id;
}
public void setPaymentBillCode(String paymentBillCode)
{
this.paymentBillCode = paymentBillCode;
}
public String getPaymentBillCode()
{
return paymentBillCode;
}
public void setPaymentBillType(String paymentBillType)
{
this.paymentBillType = paymentBillType;
}
public String getPaymentBillType()
{
return paymentBillType;
}
public void setPaymentTime(Date paymentTime)
{
this.paymentTime = paymentTime;
}
public Date getPaymentTime()
{
return paymentTime;
}
public void setVendorCode(String vendorCode)
{
this.vendorCode = vendorCode;
}
public String getVendorCode()
{
return vendorCode;
}
public void setOrderCode(String orderCode)
{
this.orderCode = orderCode;
}
public String getOrderCode()
{
return orderCode;
}
public void setTotalPriceWithTax(BigDecimal totalPriceWithTax)
{
this.totalPriceWithTax = totalPriceWithTax;
}
public BigDecimal getTotalPriceWithTax()
{
return totalPriceWithTax;
}
public void setTotalPriceWithoutTax(BigDecimal totalPriceWithoutTax)
{
this.totalPriceWithoutTax = totalPriceWithoutTax;
}
public BigDecimal getTotalPriceWithoutTax()
{
return totalPriceWithoutTax;
}
public void setTaxAmount(BigDecimal taxAmount)
{
this.taxAmount = taxAmount;
}
public BigDecimal getTaxAmount()
{
return taxAmount;
}
public void setDelFlag(String delFlag)
{
this.delFlag = delFlag;
}
public String getDelFlag()
{
return delFlag;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("paymentBillCode", getPaymentBillCode())
.append("paymentBillType", getPaymentBillType())
.append("paymentTime", getPaymentTime())
.append("vendorCode", getVendorCode())
.append("orderCode", getOrderCode())
.append("totalPriceWithTax", getTotalPriceWithTax())
.append("totalPriceWithoutTax", getTotalPriceWithoutTax())
.append("taxAmount", getTaxAmount())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("remark", getRemark())
.append("delFlag", getDelFlag())
.toString();
}
}

View File

@ -122,4 +122,18 @@ public class VendorInfo extends BaseEntity
}
}
@Getter
public enum PayTypeEnum {
INNER_PAY("0", "入库付款"),
OUTER_PAY("1", "出库付款"),
;
private final String desc;
private final String code;
PayTypeEnum(String code, String desc) {
this.desc = desc;
this.code = code;
}
}
}

View File

@ -0,0 +1,17 @@
package com.ruoyi.sip.domain.dto;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@Data
public class MergedPaymentDataDto {
private String paymentBillType;
private Date estimatedPaymentTime;
private List<PayableOrderDto> payableOrders;
private BigDecimal totalMergePaymentAmount;
}

View File

@ -0,0 +1,15 @@
package com.ruoyi.sip.domain.dto;
import com.ruoyi.sip.domain.OmsPayablePaymentPlan;
import lombok.Data;
import java.util.List;
@Data
public class PayableOrderDto {
private Long id;
private String payableBillCode;
private List<OmsPayablePaymentPlan> paymentPlans;
}

View File

@ -0,0 +1,24 @@
package com.ruoyi.sip.domain.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.sip.domain.OmsPaymentBill;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* DTO
*
* @author ruoyi
* @date 2024-12-08
*/
@Data
public class PaymentBillDetailDTO extends OmsPaymentBill {
/** 关联的应付单明细列表 */
private List<PaymentBillPayableDetailDTO> payableDetails;
}

View File

@ -0,0 +1,33 @@
package com.ruoyi.sip.domain.dto;
import lombok.Data;
import java.math.BigDecimal;
/**
* DTO
*
* @author ruoyi
* @date 2024-12-08
*/
@Data
public class PaymentBillPayableDetailDTO {
/** 项目编号 */
private String projectCode;
/** 项目名称 */
private String projectName;
/** 采购应付单编号 */
private String payableBillCode;
/** 应付单含税总价 */
private BigDecimal totalPriceWithTax;
/** 本次付款金额 */
private BigDecimal paymentAmount;
/** 本次付款比例 */
private BigDecimal paymentRate;
}

View File

@ -0,0 +1,44 @@
package com.ruoyi.sip.domain.dto;
import java.math.BigDecimal;
import java.util.Date;
public class PaymentPlanDto {
private Date planPaymentDate;
private BigDecimal planAmount;
private BigDecimal planRate;
private String remark;
// Getters and Setters
public Date getPlanPaymentDate() {
return planPaymentDate;
}
public void setPlanPaymentDate(Date planPaymentDate) {
this.planPaymentDate = planPaymentDate;
}
public BigDecimal getPlanAmount() {
return planAmount;
}
public void setPlanAmount(BigDecimal planAmount) {
this.planAmount = planAmount;
}
public BigDecimal getPlanRate() {
return planRate;
}
public void setPlanRate(BigDecimal planRate) {
this.planRate = planRate;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
}

View File

@ -76,4 +76,5 @@ public interface InventoryInfoMapper
List<InventoryInfo> listByProductSnList(List<String> productSnList);
List<InventoryInfo> listByDeliveryId(Long id);
}

View File

@ -1,5 +1,6 @@
package com.ruoyi.sip.mapper;
import java.math.BigDecimal;
import java.util.List;
import com.ruoyi.sip.domain.InventoryOuter;
import com.ruoyi.sip.domain.VendorInfo;
@ -66,4 +67,6 @@ public interface InventoryOuterMapper
int countByOrderCode(String orderCode);
String selectVendorById(Long id);
BigDecimal selectOutPriceByCode(String outerCode);
}

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

@ -0,0 +1,14 @@
package com.ruoyi.sip.mapper;
import com.ruoyi.sip.domain.OmsPayablePaymentDetail;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface OmsPayablePaymentDetailMapper {
public int insertOmsPayablePaymentDetail(OmsPayablePaymentDetail omsPayablePaymentDetail);
List<OmsPayablePaymentDetail> list(OmsPayablePaymentDetail omsPayablePaymentDetail);
void insertBatch(List<OmsPayablePaymentDetail> addList);
}

View File

@ -0,0 +1,62 @@
package com.ruoyi.sip.mapper;
import java.util.List;
import com.ruoyi.sip.domain.OmsPayablePaymentPlan;
public interface OmsPayablePaymentPlanMapper {
/**
* ID
*
* @param payableBillId ID
* @return
*/
public List<OmsPayablePaymentPlan> selectOmsPayablePaymentPlanListByPayableBillId(Long payableBillId);
/**
*
*
* @param omsPayablePaymentPlan
* @return
*/
public int insertOmsPayablePaymentPlan(OmsPayablePaymentPlan omsPayablePaymentPlan);
/**
*
*
* @param omsPayablePaymentPlan
* @return
*/
public int updateOmsPayablePaymentPlan(OmsPayablePaymentPlan omsPayablePaymentPlan);
/**
*
*
* @param omsPayablePaymentPlanList
* @return
*/
public int batchOmsPayablePaymentPlan(List<OmsPayablePaymentPlan> omsPayablePaymentPlanList);
/**
* ID
*
* @param payableBillId ID
* @return
*/
public int deleteOmsPayablePaymentPlanByPayableBillId(Long payableBillId);
/**
* ID
*
* @param id ID
* @return
*/
public int deleteOmsPayablePaymentPlanById(Long id);
/**
* IDID
*
* @param payableBillId ID
* @return ID
*/
public List<Long> selectOmsPayablePaymentPlanIdsByPayableBillId(Long payableBillId);
}

View File

@ -1,7 +1,11 @@
package com.ruoyi.sip.mapper;
import java.util.List;
import com.ruoyi.sip.domain.OmsPayableBill;
import com.ruoyi.sip.domain.OmsPaymentBill;
import com.ruoyi.sip.domain.dto.PaymentBillDetailDTO;
import com.ruoyi.sip.domain.dto.PaymentBillPayableDetailDTO;
/**
* Mapper
@ -42,6 +46,7 @@ public interface OmsPaymentBillMapper
* @return
*/
public int updateOmsPaymentBill(OmsPaymentBill omsPaymentBill);
public int updateOmsPaymentBillByCode(OmsPaymentBill omsPaymentBill);
/**
*
@ -58,4 +63,34 @@ public interface OmsPaymentBillMapper
* @return
*/
public int deleteOmsPaymentBillByIds(String[] ids);
/**
*
*
* @param prefix
* @return
*/
public int selectMaxCodeByPrefix(String prefix);
/**
*
*
* @param id
* @return
*/
public PaymentBillDetailDTO selectPaymentBillDetail(Long id);
/**
*
*
* @param paymentBillId
* @return
*/
public List<PaymentBillPayableDetailDTO> selectPaymentBillPayableDetails(Long paymentBillId);
void clearRelationPayable(String payableBillCode);
OmsPaymentBill selectOmsPaymentBillByCode(String businessKey);
}

View File

@ -60,4 +60,6 @@ public interface VendorInfoMapper
* @return
*/
public int deleteVendorInfoByVendorIds(String[] vendorIds);
VendorInfo selectVendorInfoByVendorCode(String vendorCode);
}

View File

@ -85,4 +85,6 @@ public interface IInventoryInfoService
void deleteInventoryInfoByInnerIds(String[] idArray);
void recallByOrderCode(List<String> orderCode);
List<InventoryInfo> listByDeliveryId(Long id);
}

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,6 +3,8 @@ package com.ruoyi.sip.service;
import java.util.List;
import com.ruoyi.sip.domain.OmsPayableBill;
import com.ruoyi.sip.domain.dto.MergedPaymentDataDto;
/**
* Service
*
@ -58,4 +60,14 @@ public interface IOmsPayableBillService
* @return
*/
public int deleteOmsPayableBillById(Long id);
/**
*
*
* @param dto
* @return
*/
public int mergeAndInitiatePayment(MergedPaymentDataDto dto);
OmsPayableBill query(Long id);
}

View File

@ -0,0 +1,14 @@
package com.ruoyi.sip.service;
import com.ruoyi.sip.domain.OmsPayablePaymentDetail;
import java.util.List;
public interface IOmsPayablePaymentDetailService {
public int insertOmsPayablePaymentDetail(OmsPayablePaymentDetail omsPayablePaymentDetail);
public List<OmsPayablePaymentDetail> listByPayableBillId(Long payableBillId);
public List<OmsPayablePaymentDetail> listByPayableBillIdList(List<Long> payableBillId);
void applyRefund(String payableBillCode, String payableBillCode1);
}

View File

@ -0,0 +1,22 @@
package com.ruoyi.sip.service;
import java.util.List;
import com.ruoyi.sip.domain.OmsPayablePaymentPlan;
public interface IOmsPayablePaymentPlanService {
/**
* ID
*
* @param payableBillId ID
* @return
*/
public List<OmsPayablePaymentPlan> selectOmsPayablePaymentPlanListByPayableBillId(Long payableBillId);
/**
*
*
* @param payableBillId ID
* @param paymentPlanList
*/
public void updatePaymentPlans(Long payableBillId, List<OmsPayablePaymentPlan> paymentPlanList);
}

View File

@ -1,7 +1,12 @@
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
@ -58,4 +63,36 @@ public interface IOmsPaymentBillService
* @return
*/
public int deleteOmsPaymentBillById(Long id);
PaymentBillDetailDTO query(Long id);
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

@ -20,6 +20,7 @@ public interface IVendorInfoService
* @return
*/
public VendorInfo selectVendorInfoByVendorId(Long vendorId);
public VendorInfo selectVendorInfoByVendorCode(String vendorCode);
/**
*

View File

@ -1,5 +1,7 @@
package com.ruoyi.sip.service.impl;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
@ -17,6 +19,7 @@ import com.ruoyi.sip.mapper.InventoryOuterMapper;
import com.ruoyi.sip.service.*;
import com.ruoyi.sip.vo.DeliveryInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import com.ruoyi.sip.mapper.InventoryDeliveryMapper;
@ -59,6 +62,8 @@ public class InventoryDeliveryServiceImpl implements IInventoryDeliveryService {
@Autowired
private IOmsPayableBillService payableBillService;
@Value("${oms.inventory.innerTax:1.13}")
private String defaultTax;
/**
*
*
@ -104,6 +109,9 @@ public class InventoryDeliveryServiceImpl implements IInventoryDeliveryService {
if (CollUtil.isEmpty(productSnList) && CollUtil.isEmpty(productSnDataList)) {
throw new ServiceException("发货清单为空,保存失败");
}
//修改数据的时候同步修改出库价
BigDecimal bigDecimal = inventoryOuterMapper.selectOutPriceByCode(inventoryDelivery.getOuterCode());
List<OmsInventoryDeliveryDetail> detailList=new ArrayList<>();
if (CollUtil.isEmpty(productSnDataList)) {
List<InventoryInfo> inventoryInfoList = productSnList.stream().map(item -> {
@ -113,6 +121,7 @@ public class InventoryDeliveryServiceImpl implements IInventoryDeliveryService {
info.setInventoryStatus(InventoryInfo.InventoryStatusEnum.OUTER.getCode());
info.setUpdateBy(currentUserId);
info.setUpdateTime(nowDate);
info.setOuterPrice(bigDecimal);
OmsInventoryDeliveryDetail detail = new OmsInventoryDeliveryDetail();
detail.setProductSn(item);
detailList.add(detail);
@ -126,6 +135,7 @@ public class InventoryDeliveryServiceImpl implements IInventoryDeliveryService {
inventoryInfo.setOuterCode(inventoryDelivery.getOuterCode());
inventoryInfo.setUpdateBy(currentUserId);
inventoryInfo.setUpdateTime(nowDate);
inventoryInfo.setOuterPrice(bigDecimal);
OmsInventoryDeliveryDetail detail = new OmsInventoryDeliveryDetail();
detail.setProductSn(inventoryInfo.getProductSn());
detailList.add(detail);
@ -220,6 +230,44 @@ public class InventoryDeliveryServiceImpl implements IInventoryDeliveryService {
productInfoService.updateCumulativeCount(outerSum, inventoryDelivery.getProductCode());
List<ProductInfo> productInfos = productInfoService.selectProductInfoByCodeList(Collections.singletonList(inventoryOuter.getProductCode()));
if (CollUtil.isEmpty(productInfos)) {
throw new ServiceException("未找到对应产品");
}
ProductInfo productInfo = productInfos.get(0);
//生成应付单 取入库价
VendorInfo vendorInfo = vendorInfoService.selectVendorInfoByVendorCode(productInfo.getVendorCode());
if (vendorInfo != null && VendorInfo.PayTypeEnum.OUTER_PAY.getCode().equals(vendorInfo.getPayType())) {
List<InventoryInfo> inventoryInfos = inventoryInfoService.listByDeliveryId(inventoryDelivery.getId());
//生成过应付单的不用再次生成
inventoryInfos = inventoryInfos.stream().filter(item -> StringUtils.isEmpty(item.getPayableBillCode())).collect(Collectors.toList());
if (CollUtil.isEmpty(inventoryInfos)) {
return;
}
OmsPayableBill payableBill = new OmsPayableBill();
payableBill.setProductCode(inventoryOuter.getProductCode());
payableBill.setEstimatedPaymentTime(DateUtils.addDays(DateUtils.getNowDate(), vendorInfo.getPayConfigDay()));
payableBill.setProductType(productInfo.getType());
payableBill.setVendorCode(productInfo.getVendorCode());
payableBill.setInventoryCode(inventoryDelivery.getOuterCode());
BigDecimal allPrice = inventoryInfos.stream().map(InventoryInfo::getInnerPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
payableBill.setTotalPriceWithTax(allPrice);
payableBill.setTotalPriceWithoutTax(allPrice.divide(new BigDecimal(defaultTax), 2, RoundingMode.HALF_UP));
payableBill.setTaxAmount(allPrice.subtract(payableBill.getTotalPriceWithoutTax()));
payableBill.setProjectCode(inventoryDelivery.getProjectCode());
payableBill.setOrderCode(inventoryDelivery.getOrderCode());
payableBillService.insertOmsPayableBill(payableBill);
List<InventoryInfo> saveList = inventoryInfos.stream().map(item -> {
InventoryInfo inventoryInfo = new InventoryInfo();
inventoryInfo.setProductSn(item.getProductSn());
inventoryInfo.setPayableBillCode(payableBill.getPayableBillCode());
return inventoryInfo;
}).collect(Collectors.toList());
inventoryInfoService.saveBatch(saveList);
}
}
@Override

View File

@ -207,5 +207,10 @@ public class InventoryInfoServiceImpl implements IInventoryInfoService {
inventoryInfoMapper.recallByOrderCode(orderCode);
}
@Override
public List<InventoryInfo> listByDeliveryId(Long id) {
return inventoryInfoMapper.listByDeliveryId(id);
}
}

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

@ -16,6 +16,7 @@ import com.ruoyi.sip.domain.*;
import com.ruoyi.sip.dto.inventory.InventoryInfoExcelDto;
import com.ruoyi.sip.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.ruoyi.sip.mapper.OmsInventoryInnerMapper;
import com.ruoyi.common.core.text.Convert;
@ -50,6 +51,8 @@ public class OmsInventoryInnerServiceImpl implements IOmsInventoryInnerService {
private IOmsPurchaseOrderService purchaseOrderService;
@Autowired
private IOmsPayableBillService payableBillService;
@Value("${oms.inventory.innerTax:1.13}")
private String defaultTax;
/**
*
*
@ -139,24 +142,25 @@ public class OmsInventoryInnerServiceImpl implements IOmsInventoryInnerService {
}
omsInventoryInner.setWarehouseId(warehouseIdList.get(0));
//修改对应的采购订单
purchaseOrderService.innerWarehouse(omsInventoryInner.getItemId(),omsInventoryInner.getQuantity());
//todo 判断制造商是否需要生成应付单
// BigDecimal totalPriceWithTax = inventoryInfoList.stream().map(InventoryInfo::getInnerPrice).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
// //生成应付单
// BigDecimal taxAmount = totalPriceWithTax.multiply(new BigDecimal("0.13")).setScale(2, RoundingMode.HALF_UP);
// OmsPayableBill payableBill = OmsPayableBill.builder()
// .inventoryCode(omsInventoryInner.getInnerCode())
// .vendorCode(omsInventoryInner.getVendorCode())
// .productType(productInfos.get(0).getType())
// .estimatedPaymentTime(DateUtils.addDays(DateUtils.getNowDate(),30))
// .totalPriceWithTax(totalPriceWithTax)
// .taxAmount(taxAmount)
// .totalPriceWithoutTax(totalPriceWithTax.subtract(taxAmount))
// .build();
// payableBillService.insertOmsPayableBill(payableBill);
OmsPayableBill payableBill = new OmsPayableBill();
VendorInfo vendorInfo = vendorInfoService.selectVendorInfoByVendorCode(vendorCode);
if (vendorInfo != null && VendorInfo.PayTypeEnum.INNER_PAY.getCode().equals(vendorInfo.getPayType())) {
BigDecimal reduce = inventoryInfoList.stream().map(InventoryInfo::getInnerPrice).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
//服务金额为单价* 数量 没有具体的详情
BigDecimal totalPriceWithTax =Arrays.asList("11","22").contains(omsInventoryInner.getProductCode())?
reduce.multiply(new BigDecimal(omsInventoryInner.getQuantity())).setScale(2, RoundingMode.HALF_UP)
: reduce;
//生成应付单
payableBill.setInventoryCode(omsInventoryInner.getInnerCode());
payableBill.setVendorCode(omsInventoryInner.getVendorCode());
payableBill.setProductType(productInfos.get(0).getType());
payableBill.setProjectCode(omsInventoryInner.getProductCode());
payableBill.setEstimatedPaymentTime(DateUtils.addDays(DateUtils.getNowDate(), vendorInfo.getPayConfigDay()));
payableBill.setTotalPriceWithTax(totalPriceWithTax);
payableBill.setTotalPriceWithoutTax(totalPriceWithTax.divide(new BigDecimal(defaultTax), 2, RoundingMode.HALF_UP));
payableBill.setTaxAmount(totalPriceWithTax.subtract(payableBill.getTotalPriceWithoutTax()));
payableBillService.insertOmsPayableBill(payableBill);
}
inventoryInfoList.forEach(item->{
item.setInnerCode(omsInventoryInner.getInnerCode());
item.setCreateBy(currentUserId);

View File

@ -1,19 +1,34 @@
package com.ruoyi.sip.service.impl;
import java.text.DateFormat;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import cn.hutool.core.date.DateField;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ShiroUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.sip.mapper.OmsPayableBillMapper;
import com.ruoyi.sip.domain.OmsPayableBill;
import com.ruoyi.sip.service.IOmsPayableBillService;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.enums.ApproveStatusEnum;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.sip.domain.*;
import com.ruoyi.sip.mapper.OmsPayableBillMapper;
import com.ruoyi.sip.service.IOmsPayableBillService;
import com.ruoyi.sip.service.IVendorInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import com.ruoyi.sip.mapper.OmsPayablePaymentPlanMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.sip.domain.dto.MergedPaymentDataDto;
import com.ruoyi.sip.domain.dto.PayableOrderDto;
import com.ruoyi.sip.service.IOmsPaymentBillService;
import com.ruoyi.sip.service.IOmsPayablePaymentDetailService;
/**
* Service
@ -26,6 +41,17 @@ public class OmsPayableBillServiceImpl implements IOmsPayableBillService {
@Autowired
private OmsPayableBillMapper omsPayableBillMapper;
@Autowired
private OmsPayablePaymentPlanMapper omsPayablePaymentPlanMapper;
@Autowired
private IOmsPaymentBillService omsPaymentBillService;
@Autowired
private IOmsPayablePaymentDetailService omsPayablePaymentDetailService;
@Autowired
private IVendorInfoService vendorInfoService;
/**
*
*
@ -45,7 +71,30 @@ public class OmsPayableBillServiceImpl implements IOmsPayableBillService {
*/
@Override
public List<OmsPayableBill> selectOmsPayableBillList(OmsPayableBill omsPayableBill) {
return omsPayableBillMapper.selectOmsPayableBillList(omsPayableBill);
List<OmsPayableBill> omsPayableBills = omsPayableBillMapper.selectOmsPayableBillList(omsPayableBill);
PageUtils.clearPage();
if (CollUtil.isNotEmpty(omsPayableBills)){
List<Long> idList = omsPayableBills.stream().map(OmsPayableBill::getId).distinct().collect(Collectors.toList());
List<OmsPayablePaymentDetail> omsPayablePaymentDetails = omsPayablePaymentDetailService.listByPayableBillIdList(idList);
Map<Long, Map<String, BigDecimal>> planMap = omsPayablePaymentDetails.stream().collect(Collectors.groupingBy(OmsPayablePaymentDetail::getPayableBillId,
Collectors.groupingBy(
item->item.getPaymentStatus()==null?OmsPaymentBill.PaymentStatusEnum.WAIT_PAYMENT.getCode(): item.getPaymentStatus(),
Collectors.reducing(
BigDecimal.ZERO,
detail -> (detail.getPaymentAmount() != null) ? detail.getPaymentAmount() : BigDecimal.ZERO,
BigDecimal::add
))));
omsPayableBills.forEach(bill -> {
bill.setPaidAmount(planMap.getOrDefault(bill.getId(), Collections.emptyMap()).getOrDefault(OmsPaymentBill.PaymentStatusEnum.PAYMENT.getCode(), BigDecimal.ZERO));
bill.setPayingAmount(planMap.getOrDefault(bill.getId(), Collections.emptyMap()).getOrDefault(OmsPaymentBill.PaymentStatusEnum.WAIT_PAYMENT.getCode(), BigDecimal.ZERO));
bill.setUnpaidAmount(bill.getTotalPriceWithTax().subtract(bill.getPaidAmount()).subtract(bill.getPayingAmount()));
});
}
return omsPayableBills;
}
/**
@ -55,12 +104,26 @@ public class OmsPayableBillServiceImpl implements IOmsPayableBillService {
* @return
*/
@Override
@Transactional
public int insertOmsPayableBill(OmsPayableBill omsPayableBill) {
//生成采购应付单编号
omsPayableBill.setPayableBillCode(generatePayableBillCode());
omsPayableBill.setCreateTime(DateUtils.getNowDate());
omsPayableBill.setCreateBy(ShiroUtils.getUserId().toString());
return omsPayableBillMapper.insertOmsPayableBill(omsPayableBill);
int rows = omsPayableBillMapper.insertOmsPayableBill(omsPayableBill);
// 创建默认付款计划
if (rows > 0) {
OmsPayablePaymentPlan defaultPlan = new OmsPayablePaymentPlan();
defaultPlan.setPayableBillId(omsPayableBill.getId());
defaultPlan.setPlanPaymentDate(omsPayableBill.getEstimatedPaymentTime());
defaultPlan.setPlanAmount(omsPayableBill.getTotalPriceWithTax());
defaultPlan.setPlanRate(new java.math.BigDecimal(100));
defaultPlan.setRemark("默认付款计划");
defaultPlan.setCreateBy(ShiroUtils.getLoginName());
omsPayablePaymentPlanMapper.batchOmsPayablePaymentPlan(java.util.Collections.singletonList(defaultPlan));
}
return rows;
}
/**
@ -99,6 +162,10 @@ public class OmsPayableBillServiceImpl implements IOmsPayableBillService {
*/
@Override
public int deleteOmsPayableBillByIds(String ids) {
// Also delete payment plans
for (String id : Convert.toStrArray(ids)) {
omsPayablePaymentPlanMapper.deleteOmsPayablePaymentPlanByPayableBillId(Long.valueOf(id));
}
return omsPayableBillMapper.deleteOmsPayableBillByIds(Convert.toStrArray(ids));
}
@ -109,7 +176,74 @@ public class OmsPayableBillServiceImpl implements IOmsPayableBillService {
* @return
*/
@Override
@Transactional
public int deleteOmsPayableBillById(Long id) {
omsPayablePaymentPlanMapper.deleteOmsPayablePaymentPlanByPayableBillId(id);
return omsPayableBillMapper.deleteOmsPayableBillById(id);
}
@Override
@Transactional
public int mergeAndInitiatePayment(MergedPaymentDataDto dto) {
// 1. 创建付款单
OmsPaymentBill paymentBill = new OmsPaymentBill();
OmsPayableBill firstPayableBill = omsPayableBillMapper.selectOmsPayableBillById(dto.getPayableOrders().get(0).getId());
paymentBill.setPaymentBillType(dto.getPaymentBillType());
paymentBill.setVendorCode(firstPayableBill.getVendorCode());
paymentBill.setPaymentTime(dto.getEstimatedPaymentTime());
paymentBill.setTotalPriceWithTax(dto.getTotalMergePaymentAmount());
paymentBill.setPaymentBillType(OmsPaymentBill.PaymentBillTypeEnum.FROM_PAYABLE.getCode());
omsPaymentBillService.insertOmsPaymentBill(paymentBill);
// 2. 创建付款明细
for (PayableOrderDto payableOrderDto : dto.getPayableOrders()) {
for (OmsPayablePaymentPlan paymentPlanDto : payableOrderDto.getPaymentPlans()) {
OmsPayablePaymentDetail detail = new OmsPayablePaymentDetail();
detail.setPayableBillId(payableOrderDto.getId());
detail.setPaymentPlanId(paymentPlanDto.getId());
detail.setPaymentBillCode(paymentBill.getPaymentBillCode());
detail.setPaymentAmount(paymentPlanDto.getPlanAmount());
detail.setPaymentRate(paymentPlanDto.getPlanRate());
detail.setPaymentTime(paymentPlanDto.getPlanPaymentDate());
detail.setRemark(paymentPlanDto.getRemark());
detail.setCreateBy(ShiroUtils.getLoginName());
detail.setPayableDetailType(OmsPayablePaymentDetail.PayableDetailTypeEnum.APPLY_PAYMENT.getCode());
omsPayablePaymentDetailService.insertOmsPayablePaymentDetail(detail);
}
// 3. 更新应付单状态
// OmsPayableBill payableBill = omsPayableBillMapper.selectOmsPayableBillById(payableOrderDto.getId());
// // 这里可以根据业务逻辑更新状态,例如 "付款中"
// // payableBill.setPaymentStatus("1");
// omsPayableBillMapper.updateOmsPayableBill(payableBill);
}
return 1;
}
@Override
public OmsPayableBill query(Long id) {
OmsPayableBill omsPayableBill = selectOmsPayableBillById(id);
List<OmsPayablePaymentDetail> omsPayablePaymentDetails = omsPayablePaymentDetailService.listByPayableBillId(id);
omsPayableBill.setDetailList(omsPayablePaymentDetails);
Map<String, BigDecimal> decimalMap = omsPayablePaymentDetails.stream()
.collect(Collectors.groupingBy(
item->item.getPaymentStatus()==null?OmsPaymentBill.PaymentStatusEnum.WAIT_PAYMENT.getCode(): item.getPaymentStatus(),
Collectors.reducing(
BigDecimal.ZERO,
detail -> (detail.getPaymentAmount() != null) ? detail.getPaymentAmount() : BigDecimal.ZERO,
BigDecimal::add
)
));
omsPayableBill.setPaidAmount(decimalMap.getOrDefault(OmsPaymentBill.PaymentStatusEnum.PAYMENT.getCode(), BigDecimal.ZERO));
omsPayableBill.setPayingAmount(decimalMap.getOrDefault(OmsPaymentBill.PaymentStatusEnum.WAIT_PAYMENT.getCode(), BigDecimal.ZERO));
BigDecimal decimal = omsPayableBill.getTotalPriceWithTax().subtract(omsPayableBill.getPaidAmount()).subtract(omsPayableBill.getPayingAmount());
omsPayableBill.setUnpaidAmount(decimal);
return omsPayableBill;
}
}

View File

@ -0,0 +1,84 @@
package com.ruoyi.sip.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.common.utils.ShiroUtils;
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.ArrayList;
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);
}
@Override
public List<OmsPayablePaymentDetail> listByPayableBillId(Long payableBillId) {
OmsPayablePaymentDetail omsPayablePaymentDetail = new OmsPayablePaymentDetail();
omsPayablePaymentDetail.setPayableBillId(payableBillId);
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
public List<OmsPayablePaymentDetail> listByPayableBillIdList(List<Long> payableBillId) {
OmsPayablePaymentDetail omsPayablePaymentDetail = new OmsPayablePaymentDetail();
omsPayablePaymentDetail.setPayableBillIdList(payableBillId);
return omsPayablePaymentDetailMapper.list(omsPayablePaymentDetail);
}
@Override
public void applyRefund(String originalCode, String payableBillCode) {
OmsPayablePaymentDetail omsPayablePaymentDetail = new OmsPayablePaymentDetail();
omsPayablePaymentDetail.setPaymentBillCode(originalCode);
List<OmsPayablePaymentDetail> list = omsPayablePaymentDetailMapper.list(omsPayablePaymentDetail);
if (CollUtil.isNotEmpty(list)){
List<OmsPayablePaymentDetail> addList=new ArrayList<>();
for (OmsPayablePaymentDetail payablePaymentDetail : list) {
OmsPayablePaymentDetail temp = new OmsPayablePaymentDetail();
BeanUtil.copyProperties(payablePaymentDetail,temp);
temp.setId(null);
temp.setPayableDetailType(OmsPayablePaymentDetail.PayableDetailTypeEnum.REFUND.getCode());
temp.setPaymentBillCode(payableBillCode);
temp.setCreateBy(ShiroUtils.getUserId().toString());
temp.setPaymentAmount(payablePaymentDetail.getPaymentAmount().negate());
temp.setPaymentRate(payablePaymentDetail.getPaymentRate().negate());
temp.setPaymentBillCode(payableBillCode);
temp.setRemark("退款");
addList.add( temp);
}
omsPayablePaymentDetailMapper.insertBatch(addList);
}
}
}

View File

@ -0,0 +1,77 @@
package com.ruoyi.sip.service.impl;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import cn.hutool.core.collection.CollUtil;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.sip.domain.OmsPayablePaymentDetail;
import com.ruoyi.sip.service.IOmsPayablePaymentDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.sip.mapper.OmsPayablePaymentPlanMapper;
import com.ruoyi.sip.domain.OmsPayablePaymentPlan;
import com.ruoyi.sip.service.IOmsPayablePaymentPlanService;
@Service
public class OmsPayablePaymentPlanServiceImpl implements IOmsPayablePaymentPlanService {
@Autowired
private OmsPayablePaymentPlanMapper omsPayablePaymentPlanMapper;
@Autowired
private IOmsPayablePaymentDetailService omsPayablePaymentDetailService;
@Override
public List<OmsPayablePaymentPlan> selectOmsPayablePaymentPlanListByPayableBillId(Long payableBillId) {
List<OmsPayablePaymentPlan> omsPayablePaymentPlans = omsPayablePaymentPlanMapper.selectOmsPayablePaymentPlanListByPayableBillId(payableBillId);
if (CollUtil.isNotEmpty(omsPayablePaymentPlans)) {
List<OmsPayablePaymentDetail> omsPayablePaymentDetails = omsPayablePaymentDetailService.listByPayableBillIdList(omsPayablePaymentPlans.stream().map(OmsPayablePaymentPlan::getPayableBillId).collect(Collectors.toList()));
Map<Long, OmsPayablePaymentDetail> detailMap = omsPayablePaymentDetails.stream().collect(Collectors.toMap(OmsPayablePaymentDetail::getPaymentPlanId, Function.identity(),
(v1, v2) -> v1.getCreateTime().after(v2.getCreateTime()) ? v1 : v2));
for (OmsPayablePaymentPlan omsPayablePaymentPlan : omsPayablePaymentPlans) {
//找到最新的一条数据 如果不是退款 那么不允许再次勾选
OmsPayablePaymentDetail omsPayablePaymentDetail = detailMap.get(omsPayablePaymentPlan.getId());
if (omsPayablePaymentDetail != null && !OmsPayablePaymentDetail.PayableDetailTypeEnum.REFUND.getCode().equalsIgnoreCase(omsPayablePaymentDetail.getPayableDetailType()))
omsPayablePaymentPlan.setDetailId(omsPayablePaymentDetail.getId());
}
}
return omsPayablePaymentPlans;
}
@Override
@Transactional
public void updatePaymentPlans(Long payableBillId, List<OmsPayablePaymentPlan> paymentPlanList) {
// 获取数据库中现有付款计划的ID
List<Long> existingPlanIds = omsPayablePaymentPlanMapper.selectOmsPayablePaymentPlanIdsByPayableBillId(payableBillId);
Set<Long> existingPlanIdSet = existingPlanIds.stream().collect(Collectors.toSet());
// 用于存放前端传入的有效非新增或已删除的计划ID
Set<Long> incomingPlanIdSet = paymentPlanList.stream()
.filter(plan -> plan.getId() != null)
.map(OmsPayablePaymentPlan::getId)
.collect(Collectors.toSet());
for (OmsPayablePaymentPlan plan : paymentPlanList) {
plan.setPayableBillId(payableBillId);
if (plan.getId() == null) {
// 新增付款计划
plan.setCreateBy(ShiroUtils.getLoginName());
omsPayablePaymentPlanMapper.insertOmsPayablePaymentPlan(plan);
} else if (existingPlanIdSet.contains(plan.getId())) {
// 更新现有付款计划
omsPayablePaymentPlanMapper.updateOmsPayablePaymentPlan(plan);
}
// 如果plan.getId()不为null但不在existingPlanIdSet中说明是前端新添加但带有id的脏数据或者是非法数据这里不处理
}
// 删除数据库中存在但前端未提交的付款计划
existingPlanIdSet.removeAll(incomingPlanIdSet);
for (Long idToDelete : existingPlanIdSet) {
omsPayablePaymentPlanMapper.deleteOmsPayablePaymentPlanById(idToDelete);
}
}
}

View File

@ -1,13 +1,32 @@
package com.ruoyi.sip.service.impl;
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.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.IOmsPayablePaymentDetailService;
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
@ -16,11 +35,18 @@ import com.ruoyi.common.core.text.Convert;
* @date 2025-10-22
*/
@Service
public class OmsPaymentBillServiceImpl implements IOmsPaymentBillService
@Transactional(rollbackFor = Exception.class)
public class OmsPaymentBillServiceImpl implements IOmsPaymentBillService , TodoCommonTemplate
{
@Autowired
private OmsPaymentBillMapper omsPaymentBillMapper;
@Autowired
private IVendorInfoService vendorInfoService;
@Autowired
private IOmsFinAttachmentService omsFinAttachmentService;
@Autowired
private IOmsPayablePaymentDetailService detailService;
/**
*
*
@ -54,10 +80,35 @@ public class OmsPaymentBillServiceImpl implements IOmsPaymentBillService
@Override
public int insertOmsPaymentBill(OmsPaymentBill omsPaymentBill)
{
VendorInfo vendorInfo = vendorInfoService.selectVendorInfoByVendorCode(omsPaymentBill.getVendorCode());
omsPaymentBill.setCreateBy(ShiroUtils.getUserId().toString());
omsPaymentBill.setPayName(vendorInfo.getPayName());
omsPaymentBill.setPayBankNumber(vendorInfo.getPayBankNumber());
omsPaymentBill.setPayBankOpenAddress(vendorInfo.getPayBankOpenAddress());
omsPaymentBill.setBankNumber(vendorInfo.getBankNumber());
omsPaymentBill.setPaymentStatus(OmsPaymentBill.PaymentStatusEnum.WAIT_PAYMENT.getCode());
omsPaymentBill.setApproveStatus(ApproveStatusEnum.WAIT_COMMIT.getCode());
omsPaymentBill.setPaymentBillCode(generatePaymentBillCode());
omsPaymentBill.setCreateTime(DateUtils.getNowDate());
return omsPaymentBillMapper.insertOmsPaymentBill(omsPaymentBill);
}
/**
* FK+YYMMdd+
* @return
*/
private String generatePaymentBillCode() {
String prefix = "FK";
// 查询当天已有的最大序列号
String codePrefix = prefix + DateUtil.format(DateUtil.date(), DatePattern.PURE_DATE_PATTERN);
int maxSequence = omsPaymentBillMapper.selectMaxCodeByPrefix(codePrefix);
// 生成新的序列号
int newSequence = maxSequence + 1;
// 序列号补零到4位
String sequenceStr = String.format("%04d", newSequence);
return codePrefix + sequenceStr;
}
/**
*
*
@ -94,4 +145,246 @@ public class OmsPaymentBillServiceImpl implements IOmsPaymentBillService
{
return omsPaymentBillMapper.deleteOmsPaymentBillById(id);
}
@Override
public PaymentBillDetailDTO query(Long id) {
PaymentBillDetailDTO paymentBillDetailDTO = omsPaymentBillMapper.selectPaymentBillDetail(id);
return paymentBillDetailDTO;
}
@Override
public AjaxResult returnPaymentBill(Long paymentBillId) {
try {
// 1. 验证付款单是否存在
OmsPaymentBill paymentBill = omsPaymentBillMapper.selectOmsPaymentBillById(paymentBillId);
if (paymentBill == null) {
return AjaxResult.error("付款单不存在");
}
// 2. 检查付款单类型只有FROM_PAYABLE类型的付款单才能退回
if (!OmsPaymentBill.PaymentBillTypeEnum.FROM_PAYABLE.getCode().equals(paymentBill.getPaymentBillType())) {
return AjaxResult.error("只有由应付单合并生成的付款单才能执行退回操作");
}
// 3. 清楚关联
omsPaymentBillMapper.clearRelationPayable(paymentBill.getPaymentBillCode());
// 6. 删除付款单记录
int result = omsPaymentBillMapper.deleteOmsPaymentBillById(paymentBillId);
if (result <= 0) {
throw new RuntimeException("删除付款单失败");
}
return AjaxResult.success("付款单退回成功!");
} catch (Exception e) {
throw new RuntimeException("退回付款单操作失败:" + e.getMessage(), e);
}
}
/**
*
*
* @param paymentBill
* @return
*/
@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 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);
// }
// }
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
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 (OmsPaymentBill.RefundStatusEnum.REFUNDED.getCode().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.setPaymentBillCode(generatePaymentBillCode());
// 设置新属性
refundBill.setPaymentBillType(OmsPaymentBill.PaymentBillTypeEnum.REFUND.getCode());
refundBill.setPaymentStatus(OmsPaymentBill.PaymentStatusEnum.WAIT_PAYMENT.getCode());
refundBill.setApproveStatus(ApproveStatusEnum.WAIT_APPROVE.getCode());
refundBill.setOriginalBillId(originalPaymentId);
refundBill.setPaymentTime(null);
refundBill.setPaymentMethod(originalBill.getPaymentMethod());
refundBill.setRemark("退款-关联原付款单:" + originalBill.getPaymentBillCode());
insertOmsPaymentBill(refundBill);
// 3. 更新原始付款单状态
originalBill.setRefundStatus(OmsPaymentBill.RefundStatusEnum.REFUNDED.getCode());
updateOmsPaymentBill(originalBill);
//4 创建付款明细
detailService.applyRefund(originalBill.getPayableBillCode(),refundBill.getPayableBillCode());
//5.todo 开始退款审批流程
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

@ -48,6 +48,11 @@ public class VendorInfoServiceImpl implements IVendorInfoService {
return vendorInfoMapper.selectVendorInfoByVendorId(vendorId);
}
@Override
public VendorInfo selectVendorInfoByVendorCode(String vendorCode) {
return vendorInfoMapper.selectVendorInfoByVendorCode(vendorCode);
}
/**
*
*

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

@ -15,8 +15,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="totalPriceWithTax" column="total_price_with_tax" />
<result property="totalPriceWithoutTax" column="total_price_without_tax" />
<result property="taxAmount" column="tax_amount" />
<result property="paymentBillId" column="payment_bill_id" />
<result property="invoiceReceiptBillId" column="invoice_receipt_bill_id" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
@ -26,29 +24,85 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectOmsPayableBillVo">
select id, payable_bill_code, estimated_payment_time, vendor_code, order_code, inventory_code, product_type, total_price_with_tax, total_price_without_tax, tax_amount, payment_bill_id, invoice_receipt_bill_id, create_by, create_time, update_by, update_time, remark, del_flag from oms_payable_bill
select id, payable_bill_code, estimated_payment_time, vendor_code, order_code, inventory_code, product_type, total_price_with_tax, total_price_without_tax, tax_amount, create_by, create_time, update_by, update_time, remark, del_flag from oms_payable_bill
</sql>
<sql id="selectOmsPayableBillRelationVo">
SELECT
t1.id,
t1.payable_bill_code,
t1.estimated_payment_time,
t1.vendor_code,
t1.order_code,
t1.inventory_code,
t1.product_type,
t1.total_price_with_tax,
t1.total_price_without_tax,
t1.tax_amount,
t1.create_by,
t1.create_time,
t1.update_by,
t1.update_time,
t1.remark,
t1.del_flag ,
t3.project_code,
t3.project_name,
t4.vendor_name
FROM
oms_payable_bill t1
left join project_order_info t2 on t1.order_code=t2.order_code
left join project_info t3 on t2.project_id=t3.id
left join oms_vendor_info t4 on t1.vendor_code=t4.vendor_code
</sql>
<select id="selectOmsPayableBillList" parameterType="OmsPayableBill" resultMap="OmsPayableBillResult">
<include refid="selectOmsPayableBillVo"/>
<include refid="selectOmsPayableBillRelationVo"/>
<where>
<if test="payableBillCode != null and payableBillCode != ''"> and payable_bill_code like concat( #{payableBillCode},'%') </if>
<if test="estimatedPaymentTime != null "> and estimated_payment_time = #{estimatedPaymentTime}</if>
<if test="vendorCode != null and vendorCode != ''"> and vendor_code = #{vendorCode}</if>
<if test="orderCode != null and orderCode != ''"> and order_code like concat( #{orderCode},'%') </if>
<if test="inventoryCode != null and inventoryCode != ''"> and inventory_code like concat( #{inventoryCode},'%') </if>
<if test="productType != null and productType != ''"> and product_type = #{productType}</if>
<if test="totalPriceWithTax != null "> and total_price_with_tax = #{totalPriceWithTax}</if>
<if test="totalPriceWithoutTax != null "> and total_price_without_tax = #{totalPriceWithoutTax}</if>
<if test="taxAmount != null "> and tax_amount = #{taxAmount}</if>
<if test="paymentBillId != null "> and payment_bill_id = #{paymentBillId}</if>
<if test="invoiceReceiptBillId != null "> and invoice_receipt_bill_id = #{invoiceReceiptBillId}</if>
<if test="payableBillCode != null and payableBillCode != ''"> and t1.payable_bill_code like concat( #{payableBillCode},'%') </if>
<if test="estimatedPaymentTime != null "> and t1.estimated_payment_time = #{estimatedPaymentTime}</if>
<if test="vendorCode != null and vendorCode != ''"> and t1.vendor_code = #{vendorCode}</if>
<if test="vendorName != null and vendorName != ''"> and t4.vendor_name = #{vendorName}</if>
<if test="projectCode != null and projectCode != ''"> and t3.project_code = #{projectCode}</if>
<if test="projectName != null and projectName != ''"> and t3.project_name = #{projectName}</if>
<if test="orderCode != null and orderCode != ''"> and t1.order_code like concat( #{orderCode},'%') </if>
<if test="inventoryCode != null and inventoryCode != ''"> and t1.inventory_code like concat( #{inventoryCode},'%') </if>
<if test="productType != null and productType != ''"> and t1.product_type = #{productType}</if>
<if test="totalPriceWithTax != null "> and t1.total_price_with_tax = #{totalPriceWithTax}</if>
<if test="totalPriceWithoutTax != null "> and t1.total_price_without_tax = #{totalPriceWithoutTax}</if>
<if test="taxAmount != null "> and t1.tax_amount = #{taxAmount}</if>
<if test="createTimeStart != null or createTimeEnd != null">
<choose>
<when test="createTimeStart != null and createTimeEnd != null">
and t1.create_time between date_format(#{createTimeStart}, '%Y-%m-%d 00:00:00') and date_format(#{createTimeEnd}, '%Y-%m-%d 23:59:59')
</when>
<when test="createTimeStart != null">
and t1.create_time <![CDATA[ >= ]]> date_format(#{createTimeStart}, '%Y-%m-%d 00:00:00')
</when>
<when test="createTimeEnd != null">
and t1.create_time <![CDATA[ <= ]]> date_format(#{createTimeEnd}, '%Y-%m-%d 23:59:59')
</when>
</choose>
</if>
<if test="estimatedPaymentTimeStart != null or estimatedPaymentTimeEnd != null">
<choose>
<when test="estimatedPaymentTimeStart != null and estimatedPaymentTimeEnd != null">
and t1.estimated_payment_time between date_format(#{estimatedPaymentTimeStart}, '%Y-%m-%d 00:00:00') and date_format(#{estimatedPaymentTimeEnd}, '%Y-%m-%d 23:59:59')
</when>
<when test="estimatedPaymentTimeStart != null">
and t1.estimated_payment_time <![CDATA[ >= ]]> date_format(#{estimatedPaymentTimeStart}, '%Y-%m-%d 00:00:00')
</when>
<when test="estimatedPaymentTimeEnd != null">
and t1.estimated_payment_time <![CDATA[ <= ]]> date_format(#{estimatedPaymentTimeEnd}, '%Y-%m-%d 23:59:59')
</when>
</choose>
</if>
</where>
</select>
<select id="selectOmsPayableBillById" parameterType="Long" resultMap="OmsPayableBillResult">
<include refid="selectOmsPayableBillVo"/>
where id = #{id}
<include refid="selectOmsPayableBillRelationVo"/>
where t1.id = #{id}
</select>
<select id="selectMaxCodeByPrefix" resultType="java.lang.Integer">
select ifnull(max(SUBSTR(payable_bill_code FROM LENGTH(#{prefix}) + 1 FOR 4)), 0)
@ -68,8 +122,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="totalPriceWithTax != null">total_price_with_tax,</if>
<if test="totalPriceWithoutTax != null">total_price_without_tax,</if>
<if test="taxAmount != null">tax_amount,</if>
<if test="paymentBillId != null">payment_bill_id,</if>
<if test="invoiceReceiptBillId != null">invoice_receipt_bill_id,</if>
<if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
@ -87,8 +141,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="totalPriceWithTax != null">#{totalPriceWithTax},</if>
<if test="totalPriceWithoutTax != null">#{totalPriceWithoutTax},</if>
<if test="taxAmount != null">#{taxAmount},</if>
<if test="paymentBillId != null">#{paymentBillId},</if>
<if test="invoiceReceiptBillId != null">#{invoiceReceiptBillId},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
@ -110,8 +164,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<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="paymentBillId != null">payment_bill_id = #{paymentBillId},</if>
<if test="invoiceReceiptBillId != null">invoice_receipt_bill_id = #{invoiceReceiptBillId},</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>

View File

@ -0,0 +1,79 @@
<?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.OmsPayablePaymentDetailMapper">
<resultMap type="OmsPayablePaymentDetail" id="OmsPayablePaymentDetailResult">
<result property="id" column="id" />
<result property="paymentPlanId" column="payment_plan_id" />
<result property="payableBillId" column="payable_bill_id" />
<result property="paymentStatus" column="payment_status" />
<result property="paymentTime" column="payment_time" />
<result property="paymentAmount" column="payment_amount" />
<result property="paymentRate" column="payment_rate" />
<result property="paymentBillCode" column="payment_bill_code" />
<result property="remark" column="remark" />
<result property="createTime" column="create_time" />
<result property="createBy" column="create_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<insert id="insertOmsPayablePaymentDetail" parameterType="OmsPayablePaymentDetail" useGeneratedKeys="true" keyProperty="id">
insert into oms_payable_payment_detail (
<if test="paymentPlanId != null">payment_plan_id,</if>
<if test="payableBillId != null">payable_bill_id,</if>
<if test="paymentTime != null">payment_time,</if>
<if test="paymentAmount != null">payment_amount,</if>
<if test="paymentRate != null">payment_rate,</if>
<if test="paymentBillCode != null and paymentBillCode != ''">payment_bill_code,</if>
<if test="payableDetailType != null and payableDetailType != ''">payable_detail_type,</if>
<if test="remark != null and remark != ''">remark,</if>
create_by,
create_time
) values (
<if test="paymentPlanId != null">#{paymentPlanId},</if>
<if test="payableBillId != null">#{payableBillId},</if>
<if test="paymentTime != null">#{paymentTime},</if>
<if test="paymentAmount != null">#{paymentAmount},</if>
<if test="paymentRate != null">#{paymentRate},</if>
<if test="paymentBillCode != null and paymentBillCode != ''">#{paymentBillCode},</if>
<if test="payableDetailType != null and payableDetailType != ''">#{payableDetailType},</if>
<if test="remark != null and remark != ''">#{remark},</if>
#{createBy},
sysdate()
)
</insert>
<insert id="insertBatch">
insert into oms_payable_payment_detail (
payment_plan_id, payable_bill_id, payment_time, payment_amount, payment_rate,
payment_bill_code, payable_detail_type, remark, create_by, create_time )
values
<foreach item="item" collection="list" separator="," index="">
(#{item.paymentPlanId},#{item.payableBillId},#{item.paymentTime},#{item.paymentAmount},
#{item.paymentRate},#{item.paymentBillCode},#{item.payableDetailType},#{item.remark},
#{item.createBy},
sysdate())
</foreach>
</insert>
<select id="list" resultType="com.ruoyi.sip.domain.OmsPayablePaymentDetail">
SELECT
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
<where>
<if test="payableBillId != null">
and t1.payable_bill_id = #{payableBillId}
</if>
<if test="payableBillIdList != null and payableBillIdList.size>0">
and t1.payable_bill_id in
<foreach item="item" collection="payableBillIdList" separator="," open="(" close=")" index="">
#{item}
</foreach>
</if>
</where>
</select>
</mapper>

View File

@ -20,29 +20,124 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
<result property="delFlag" column="del_flag" />
<result property="projectCode" column="project_code" />
<result property="projectName" column="project_name" />
<result property="preResidueAmount" column="pre_residue_amount" />
<result property="actualPaymentTime" column="actual_payment_time" />
<result property="paymentStatus" column="payment_status" />
<result property="approveStatus" column="approve_status" />
<result property="approveNode" column="approve_node" />
<result property="approveTime" column="approve_time" />
<result property="paymentMethod" column="payment_method" />
<result property="payableBillCode" column="payable_bill_code" />
<result property="payName" column="pay_name" />
<result property="payBankNumber" column="pay_bank_number" />
<result property="payBankOpenAddress" column="pay_bank_open_address" />
<result property="bankNumber" column="bank_number" />
<result property="refundStatus" column="refund_status" />
</resultMap>
<resultMap type="com.ruoyi.sip.domain.dto.PaymentBillDetailDTO" id="PaymentBillDetailResult">
<result property="id" column="id" />
<result property="paymentBillCode" column="payment_bill_code" />
<result property="paymentTime" column="payment_time" />
<result property="vendorCode" column="vendor_code" />
<result property="totalPriceWithTax" column="total_price_with_tax" />
<result property="totalPriceWithoutTax" column="total_price_without_tax" />
<result property="taxAmount" column="tax_amount" />
<result property="paymentBillType" column="payment_bill_type" />
<result property="preResidueAmount" column="pre_residue_amount" />
<result property="actualPaymentTime" column="actual_payment_time" />
<result property="paymentMethod" column="payment_method" />
<result property="paymentStatus" column="payment_status" />
<result property="remark" column="remark" />
<result property="createBy" column="create_by" />
<result property="payName" column="pay_name" />
<result property="payBankNumber" column="pay_bank_number" />
<result property="payBankOpenAddress" column="pay_bank_open_address" />
<result property="bankNumber" column="bank_number" />
<result property="approveNode" column="approve_node" />
<result property="approveStatus" column="approve_status" />
<result property="approveTime" column="approve_time" />
</resultMap>
<resultMap type="com.ruoyi.sip.domain.dto.PaymentBillPayableDetailDTO" id="PaymentBillPayableDetailResult">
<result property="projectCode" column="project_code" />
<result property="projectName" column="project_name" />
<result property="payableBillCode" column="payable_bill_code" />
<result property="totalPriceWithTax" column="total_price_with_tax" />
<result property="paymentAmount" column="payment_amount" />
<result property="paymentRate" column="payment_rate" />
</resultMap>
<sql id="selectOmsPaymentBillVo">
select id, payment_bill_code, payment_bill_type, payment_time, vendor_code, order_code, total_price_with_tax, total_price_without_tax, tax_amount, create_by, create_time, update_by, update_time, remark, del_flag from oms_payment_bill
select
pb.id,
pb.payment_bill_code,
pb.payment_bill_type,
pb.payment_time,
pb.vendor_code,
pb.order_code,
pb.total_price_with_tax,
pb.total_price_without_tax,
pb.tax_amount,
pb.create_by,
pb.create_time,
pb.update_by,
pb.update_time,
pb.remark,
pb.del_flag,
pb.project_code,
pb.project_name,
pb.pre_residue_amount,
pb.actual_payment_time,
pb.payment_status,
pb.approve_status,
pb.approve_node,
pb.approve_time,
pb.payment_method,
pb.pay_name,
pb.pay_bank_number,
pb.pay_bank_open_address,
pb.bank_number,
pb.refund_status,
ovi.vendor_name
from oms_payment_bill pb
left join oms_vendor_info ovi on pb.vendor_code = ovi.vendor_code
</sql>
<select id="selectOmsPaymentBillList" parameterType="OmsPaymentBill" resultMap="OmsPaymentBillResult">
<include refid="selectOmsPaymentBillVo"/>
<where>
<if test="paymentBillCode != null and paymentBillCode != ''"> and payment_bill_code = #{paymentBillCode}</if>
<if test="paymentBillType != null and paymentBillType != ''"> and payment_bill_type = #{paymentBillType}</if>
<if test="paymentTime != null "> and payment_time = #{paymentTime}</if>
<if test="vendorCode != null and vendorCode != ''"> and vendor_code = #{vendorCode}</if>
<if test="orderCode != null and orderCode != ''"> and order_code = #{orderCode}</if>
<if test="totalPriceWithTax != null "> and total_price_with_tax = #{totalPriceWithTax}</if>
<if test="totalPriceWithoutTax != null "> and total_price_without_tax = #{totalPriceWithoutTax}</if>
<if test="taxAmount != null "> and tax_amount = #{taxAmount}</if>
<if test="paymentBillCode != null and paymentBillCode != ''"> and pb.payment_bill_code like concat('%', #{paymentBillCode}, '%')</if>
<if test="paymentBillType != null and paymentBillType != ''"> and pb.payment_bill_type = #{paymentBillType}</if>
<if test="paymentTime != null "> and date_format(pb.payment_time,'%Y-%m-%d') = date_format(#{paymentTime},'%Y-%m-%d')</if>
<if test="vendorCode != null and vendorCode != ''"> and pb.vendor_code like concat('%', #{vendorCode}, '%')</if>
<if test="orderCode != null and orderCode != ''"> and pb.order_code like concat('%', #{orderCode}, '%')</if>
<if test="totalPriceWithTax != null "> and pb.total_price_with_tax = #{totalPriceWithTax}</if>
<if test="totalPriceWithoutTax != null "> and pb.total_price_without_tax = #{totalPriceWithoutTax}</if>
<if test="taxAmount != null "> and pb.tax_amount = #{taxAmount}</if>
<if test="projectCode != null and projectCode != ''"> and pb.project_code like concat('%', #{projectCode}, '%')</if>
<if test="projectName != null and projectName != ''"> and pb.project_name like concat('%', #{projectName}, '%')</if>
<if test="paymentStatus != null and paymentStatus != ''"> and pb.payment_status = #{paymentStatus}</if>
<if test="approveStatus != null and approveStatus != ''"> and pb.approve_status = #{approveStatus}</if>
<if test="approveNode != null and approveNode != ''"> and pb.approve_node = #{approveNode}</if>
<if test="approveTime != null "> and date_format(pb.approve_time,'%Y-%m-%d') = date_format(#{approveTime},'%Y-%m-%d')</if>
<if test="actualPaymentTime != null "> and date_format(pb.actual_payment_time,'%Y-%m-%d') = date_format(#{actualPaymentTime},'%Y-%m-%d')</if>
<if test="paymentMethod != null and paymentMethod != ''"> and pb.payment_method = #{paymentMethod}</if>
<if test="payableBillCode != null and payableBillCode != ''"> and apb.payable_bill_code like concat('%', #{payableBillCode}, '%')</if>
and pb.del_flag = '0'
</where>
group by pb.id
order by pb.create_time desc
</select>
<select id="selectOmsPaymentBillById" parameterType="Long" resultMap="OmsPaymentBillResult">
<include refid="selectOmsPaymentBillVo"/>
where id = #{id}
where pb.id = #{id}
group by pb.id
</select>
<insert id="insertOmsPaymentBill" parameterType="OmsPaymentBill" useGeneratedKeys="true" keyProperty="id">
@ -62,6 +157,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updateTime != null">update_time,</if>
<if test="remark != null">remark,</if>
<if test="delFlag != null">del_flag,</if>
<if test="projectCode != null">project_code,</if>
<if test="projectName != null">project_name,</if>
<if test="preResidueAmount != null">pre_residue_amount,</if>
<if test="actualPaymentTime != null">actual_payment_time,</if>
<if test="paymentStatus != null">payment_status,</if>
<if test="approveStatus != null">approve_status,</if>
<if test="approveNode != null">approve_node,</if>
<if test="approveTime != null">approve_time,</if>
<if test="paymentMethod != null">payment_method,</if>
<if test="payName != null">pay_name,</if>
<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="refundStatus != null">refund_status,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="paymentBillCode != null and paymentBillCode != ''">#{paymentBillCode},</if>
@ -78,6 +187,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updateTime != null">#{updateTime},</if>
<if test="remark != null">#{remark},</if>
<if test="delFlag != null">#{delFlag},</if>
<if test="projectCode != null">#{projectCode},</if>
<if test="projectName != null">#{projectName},</if>
<if test="preResidueAmount != null">#{preResidueAmount},</if>
<if test="actualPaymentTime != null">#{actualPaymentTime},</if>
<if test="paymentStatus != null">#{paymentStatus},</if>
<if test="approveStatus != null">#{approveStatus},</if>
<if test="approveNode != null">#{approveNode},</if>
<if test="approveTime != null">#{approveTime},</if>
<if test="paymentMethod != null">#{paymentMethod},</if>
<if test="payName != null">#{payName},</if>
<if test="payBankNumber != null">#{payBankNumber},</if>
<if test="payBankOpenAddress != null">#{payBankOpenAddress},</if>
<if test="bankNumber != null">#{bankNumber},</if>
<if test="refundStatus != null">#{refundStatus},</if>
</trim>
</insert>
@ -98,9 +221,58 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<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 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}
@ -112,5 +284,27 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{id}
</foreach>
</delete>
<delete id="clearRelationPayable">
delete from oms_payable_payment_detail where payment_bill_code=#{code}
</delete>
<select id="selectMaxCodeByPrefix" parameterType="String" resultType="Integer">
SELECT IFNULL(MAX(CAST(SUBSTRING(payment_bill_code, LENGTH(#{prefix}) + 1) AS SIGNED)), 0)
FROM oms_payment_bill
WHERE payment_bill_code LIKE CONCAT(#{prefix}, '%')
</select>
<select id="selectPaymentBillDetail" resultType="com.ruoyi.sip.domain.dto.PaymentBillDetailDTO">
<include refid="selectOmsPaymentBillVo"/>
where pb.id = #{id}
</select>
<select id="selectPaymentBillPayableDetails"
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>

View File

@ -94,6 +94,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{item}
</foreach>
</select>
<select id="listByDeliveryId" resultType="com.ruoyi.sip.domain.InventoryInfo">
<include refid="selectInventoryInfoVo"/>
where t1.product_sn in (
select product_sn from oms_inventory_delivery_detail where delivery_id = #{id}
)
</select>
<insert id="insertInventoryInfo" parameterType="InventoryInfo" useGeneratedKeys="true" keyProperty="id">

View File

@ -154,6 +154,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select product_code from oms_inventory_outer where id=8)
</select>
<select id="selectOutPriceByCode" resultType="java.math.BigDecimal">
SELECT t3.price
FROM oms_inventory_outer t2
INNER JOIN project_order_info t4 ON t2.order_code = t4.order_code
INNER JOIN project_product_info t3
ON (t2.product_code = t3.product_bom_code AND t3.project_id = t4.project_id)
where t2.outer_code = #{outerCode}
</select>
<insert id="insertInventoryOuter" parameterType="InventoryOuter" useGeneratedKeys="true" keyProperty="id">
insert into oms_inventory_outer

View File

@ -0,0 +1,91 @@
<?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.OmsPayablePaymentPlanMapper">
<resultMap type="OmsPayablePaymentPlan" id="OmsPayablePaymentPlanResult">
<result property="id" column="id" />
<result property="payableBillId" column="payable_bill_id" />
<result property="planPaymentDate" column="plan_payment_date" />
<result property="planAmount" column="plan_amount" />
<result property="planRate" column="plan_rate" />
<result property="remark" column="remark" />
<result property="createTime" column="create_time" />
<result property="createBy" column="create_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectOmsPayablePaymentPlanVo">
select id, payable_bill_id, plan_payment_date, plan_amount, plan_rate, remark, create_time, create_by, update_time from oms_payable_payment_plan
</sql>
<select id="selectOmsPayablePaymentPlanListByPayableBillId" parameterType="Long" resultMap="OmsPayablePaymentPlanResult">
SELECT
t1.id,
t1.payable_bill_id,
t1.plan_payment_date,
t1.plan_amount,
t1.plan_rate,
t1.remark,
t1.create_time,
t1.create_by,
t1.update_time
FROM
oms_payable_payment_plan t1
where t1.payable_bill_id = #{payableBillId}
order by t1.plan_payment_date
</select>
<select id="selectOmsPayablePaymentPlanIdsByPayableBillId" parameterType="Long" resultType="Long">
select id from oms_payable_payment_plan where payable_bill_id = #{payableBillId}
</select>
<insert id="insertOmsPayablePaymentPlan" parameterType="OmsPayablePaymentPlan" useGeneratedKeys="true" keyProperty="id">
insert into oms_payable_payment_plan(
<if test="payableBillId != null">payable_bill_id,</if>
<if test="planPaymentDate != null">plan_payment_date,</if>
<if test="planAmount != null">plan_amount,</if>
<if test="planRate != null">plan_rate,</if>
<if test="remark != null and remark != ''">remark,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
create_time
)values(
<if test="payableBillId != null">#{payableBillId},</if>
<if test="planPaymentDate != null">#{planPaymentDate},</if>
<if test="planAmount != null">#{planAmount},</if>
<if test="planRate != null">#{planRate},</if>
<if test="remark != null and remark != ''">#{remark},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
sysdate()
)
</insert>
<update id="updateOmsPayablePaymentPlan" parameterType="OmsPayablePaymentPlan">
update oms_payable_payment_plan
<trim prefix="SET" suffixOverrides=",">
<if test="planPaymentDate != null">plan_payment_date = #{planPaymentDate},</if>
<if test="planAmount != null">plan_amount = #{planAmount},</if>
<if test="planRate != null">plan_rate = #{planRate},</if>
<if test="remark != null and remark != ''">remark = #{remark},</if>
update_time = sysdate()
</trim>
where id = #{id}
</update>
<delete id="deleteOmsPayablePaymentPlanById" parameterType="Long">
delete from oms_payable_payment_plan where id = #{id}
</delete>
<delete id="deleteOmsPayablePaymentPlanByPayableBillId" parameterType="Long">
delete from oms_payable_payment_plan where payable_bill_id = #{payableBillId}
</delete>
<insert id="batchOmsPayablePaymentPlan">
insert into oms_payable_payment_plan( payable_bill_id, plan_payment_date, plan_amount, plan_rate, remark, create_by, create_time) values
<foreach item="item" index="index" collection="list" separator=",">
( #{item.payableBillId}, #{item.planPaymentDate}, #{item.planAmount}, #{item.planRate}, #{item.remark}, #{item.createBy}, sysdate())
</foreach>
</insert>
</mapper>

View File

@ -59,6 +59,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectVendorInfoVo"/>
where t1.vendor_id = #{vendorId}
</select>
<select id="selectVendorInfoByVendorCode" resultType="com.ruoyi.sip.domain.VendorInfo">
<include refid="selectVendorInfoVo"/>
where t1.vendor_code = #{vendorCode}
</select>
<insert id="insertVendorInfo" parameterType="VendorInfo">
insert into oms_vendor_info