收款管理
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
package com.bms.web.controller.ar;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
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.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.bms.ar.domain.ArBalanceWriteoff;
|
||||
import com.bms.ar.domain.ArBill;
|
||||
import com.bms.ar.service.IArBalanceWriteoffService;
|
||||
import com.bms.common.annotation.Log;
|
||||
import com.bms.common.core.controller.BaseController;
|
||||
import com.bms.common.core.domain.AjaxResult;
|
||||
import com.bms.common.core.page.TableDataInfo;
|
||||
import com.bms.common.enums.BusinessType;
|
||||
import com.bms.customer.customermoney.domain.CustomerReceipt;
|
||||
import com.bms.customer.customermoney.service.ICustomerMoneyService;
|
||||
|
||||
/**
|
||||
* 收款管理 Controller(账单管理-收款管理)
|
||||
* <p>
|
||||
* 收款登记/审核/取消与「客户余额-登记收款」复用同一套 Service 逻辑;
|
||||
* 账单核销同样复用余额核销 Service:登记收款时可携带核销计划(审核通过后联动核销),
|
||||
* 本页「账单核销」页签可直接对账单发起核销/反核销。
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-13
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/ar/receipt")
|
||||
public class ArReceiptController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ICustomerMoneyService customerMoneyService;
|
||||
|
||||
@Autowired
|
||||
private IArBalanceWriteoffService balanceWriteoffService;
|
||||
|
||||
/** 收款时间查询/默认范围格式:精确到秒 */
|
||||
private static final DateTimeFormatter DATE_TIME_FORMATTER =
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
/**
|
||||
* 查询收款记录(跨客户)。支持按客户、收款时间(精确到时分秒)等维度查询,未传时间范围时默认查当天。
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ar:receipt:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(CustomerReceipt query)
|
||||
{
|
||||
if (query != null)
|
||||
{
|
||||
Object begin = query.getParams() == null ? null : query.getParams().get("beginTime");
|
||||
Object end = query.getParams() == null ? null : query.getParams().get("endTime");
|
||||
if (begin == null && end == null)
|
||||
{
|
||||
// 默认当天 00:00:00 ~ 23:59:59
|
||||
LocalDate today = LocalDate.now();
|
||||
query.getParams().put("beginTime", today.atStartOfDay().format(DATE_TIME_FORMATTER));
|
||||
query.getParams().put("endTime", today.atTime(23, 59, 59).format(DATE_TIME_FORMATTER));
|
||||
}
|
||||
}
|
||||
startPage();
|
||||
List<CustomerReceipt> list = customerMoneyService.selectReceiptList(query);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取收款单详情(含核销计划与收款附件)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ar:receipt:query')")
|
||||
@GetMapping("/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||
{
|
||||
return success(customerMoneyService.selectReceiptById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 登记收款(必须选择客户;默认待确认,审核通过后入账并执行登记时选择的核销计划)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ar:receipt:add')")
|
||||
@Log(title = "收款管理-登记收款", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody CustomerReceipt receipt)
|
||||
{
|
||||
receipt.setCreateBy(getUsername());
|
||||
return toAjax(customerMoneyService.insertReceipt(receipt));
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核通过收款单:确认后金额计入客户余额,登记时选择的账单一并核销
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ar:receipt:review')")
|
||||
@Log(title = "收款管理-收款审核", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/confirm/{id}")
|
||||
public AjaxResult confirm(@PathVariable("id") Long id)
|
||||
{
|
||||
return toAjax(customerMoneyService.confirmReceipt(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消收款单(仅待确认可取消)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ar:receipt:edit')")
|
||||
@Log(title = "收款管理-取消收款", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/cancel/{id}")
|
||||
public AjaxResult cancel(@PathVariable("id") Long id)
|
||||
{
|
||||
return toAjax(customerMoneyService.cancelReceipt(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询客户可核销账单(已确认/部分核销,未核销额大于0),登记收款选账单与核销页签共用
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ar:receipt:list')")
|
||||
@GetMapping("/bill/unsettled/{customerId}")
|
||||
public AjaxResult unsettledBills(@PathVariable("customerId") Long customerId)
|
||||
{
|
||||
return success(balanceWriteoffService.selectUnsettledBills(customerId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询核销记录(跨客户,支持客户/账单号/状态/核销日期范围)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ar:receipt:list')")
|
||||
@GetMapping("/writeoff/list")
|
||||
public TableDataInfo writeoffList(ArBalanceWriteoff query)
|
||||
{
|
||||
startPage();
|
||||
List<ArBalanceWriteoff> list = balanceWriteoffService.selectWriteoffList(query);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 账单核销(账单核销页签直接核销;与客户余额页核销同一套逻辑)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ar:receipt:writeoff')")
|
||||
@Log(title = "收款管理-账单核销", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/writeoff")
|
||||
public AjaxResult writeoff(@RequestBody ArBalanceWriteoff cmd)
|
||||
{
|
||||
cmd.setCreateBy(getUsername());
|
||||
return success(balanceWriteoffService.writeoff(cmd));
|
||||
}
|
||||
|
||||
/**
|
||||
* 反核销(取消一笔有效核销,账单恢复未核销金额)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ar:receipt:writeoff:cancel')")
|
||||
@Log(title = "收款管理-反核销", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/writeoff/{writeoffId}/cancel")
|
||||
public AjaxResult cancelWriteoff(@PathVariable("writeoffId") Long writeoffId,
|
||||
@RequestBody(required = false) ArBalanceWriteoff body)
|
||||
{
|
||||
balanceWriteoffService.cancelWriteoff(writeoffId, body == null ? null : body.getCancelRemark());
|
||||
return success();
|
||||
}
|
||||
}
|
||||
+6
@@ -51,6 +51,12 @@ public class CustomerReceipt extends BaseEntity
|
||||
/** 客户ID */
|
||||
private Long customerId;
|
||||
|
||||
/** 客户编码(列表关联查询,仅展示) */
|
||||
private String customerCode;
|
||||
|
||||
/** 客户名称(列表关联查询,仅展示) */
|
||||
private String customerName;
|
||||
|
||||
/** 客户账户ID(预留) */
|
||||
private Long accountId;
|
||||
|
||||
|
||||
@@ -83,6 +83,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="currency != null and currency != ''">and w.currency = #{currency}</if>
|
||||
<if test="writeoffNo != null and writeoffNo != ''">and w.writeoff_no like concat('%', #{writeoffNo}, '%')</if>
|
||||
<if test="billNo != null and billNo != ''">and w.bill_no like concat('%', #{billNo}, '%')</if>
|
||||
<if test="receiptId != null">and w.receipt_id = #{receiptId}</if>
|
||||
<if test="params != null and params.beginTime != null and params.beginTime != ''">
|
||||
and date_format(w.writeoff_date,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d')
|
||||
</if>
|
||||
<if test="params != null and params.endTime != null and params.endTime != ''">
|
||||
and date_format(w.writeoff_date,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d')
|
||||
</if>
|
||||
</where>
|
||||
order by w.create_time desc, w.writeoff_id desc
|
||||
</select>
|
||||
|
||||
@@ -236,6 +236,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<id property="id" column="id" />
|
||||
<result property="receiptNo" column="receipt_no" />
|
||||
<result property="customerId" column="customer_id" />
|
||||
<result property="customerCode" column="customer_code" />
|
||||
<result property="customerName" column="customer_name" />
|
||||
<result property="accountId" column="account_id" />
|
||||
<result property="receiptType" column="receipt_type" />
|
||||
<result property="amount" column="amount" />
|
||||
@@ -268,7 +270,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectCustomerReceiptVo">
|
||||
select r.id, r.receipt_no, r.customer_id, r.account_id, r.receipt_type, r.amount, r.allocated_amount,
|
||||
select r.id, r.receipt_no, r.customer_id, c.customer_code, c.customer_name, r.account_id, r.receipt_type,
|
||||
r.amount, r.allocated_amount,
|
||||
r.unallocated_amount, r.currency, r.exchange_rate, r.rate_source, r.rate_source_desc,
|
||||
r.base_amount, r.pay_method, r.bank_account_id, r.bank_account_name,
|
||||
r.bank_account_no, r.bank_name, r.bank_transaction_no,
|
||||
@@ -278,6 +281,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
(select count(1) from ctr_customer_attachment a
|
||||
where a.biz_id = r.id and a.attachment_type = '3' and a.del_flag = '0') as attachment_count
|
||||
from ctr_customer_receipt r
|
||||
left join ctr_customer c on c.customer_id = r.customer_id
|
||||
</sql>
|
||||
|
||||
<select id="selectReceiptList" parameterType="com.bms.customer.customermoney.domain.CustomerReceipt"
|
||||
@@ -286,7 +290,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<where>
|
||||
r.del_flag = '0'
|
||||
<if test="customerId != null"> and r.customer_id = #{customerId}</if>
|
||||
|
||||
<if test="customerCode != null and customerCode != ''"> and c.customer_code like concat('%', #{customerCode}, '%')</if>
|
||||
<if test="customerName != null and customerName != ''"> and c.customer_name like concat('%', #{customerName}, '%')</if>
|
||||
<if test="receiptNo != null and receiptNo != ''"> and r.receipt_no like concat('%', #{receiptNo}, '%')</if>
|
||||
<if test="receiptType != null and receiptType != ''"> and r.receipt_type = #{receiptType}</if>
|
||||
<if test="status != null and status != ''"> and r.status = #{status}</if>
|
||||
@@ -295,11 +300,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="bankTransactionNo != null and bankTransactionNo != ''">
|
||||
and r.bank_transaction_no like concat('%', #{bankTransactionNo}, '%')
|
||||
</if>
|
||||
<!-- 收款时间精确到时分秒:入参为 yyyy-MM-dd HH:mm:ss 直接比较;
|
||||
兼容客户余额页传入的纯日期 yyyy-MM-dd(开始补 00:00:00、结束补 23:59:59) -->
|
||||
<if test="params != null and params.beginTime != null and params.beginTime != ''">
|
||||
and date_format(r.received_at,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d')
|
||||
and r.received_at >= concat(#{params.beginTime},
|
||||
case when char_length(#{params.beginTime}) = 10 then ' 00:00:00' else '' end)
|
||||
</if>
|
||||
<if test="params != null and params.endTime != null and params.endTime != ''">
|
||||
and date_format(r.received_at,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d')
|
||||
and r.received_at <= concat(#{params.endTime},
|
||||
case when char_length(#{params.endTime}) = 10 then ' 23:59:59' else '' end)
|
||||
</if>
|
||||
</where>
|
||||
order by r.received_at desc, r.id desc
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
-- ============================================================
|
||||
-- 账单管理 - 收款管理 菜单及权限
|
||||
-- 日期:2026-10-13
|
||||
-- 说明:
|
||||
-- 1) 在「账单管理」(menu_id=2400) 下新增「收款管理」页面(应收账单 order=1 之后,应收日志 order=3 之前);
|
||||
-- 2) 页面含两个页签:收款记录(跨客户查询/默认当天/勾选汇总收款总额/登记收款/审核/取消/查看)、
|
||||
-- 账单核销(账单查询并直接核销、核销记录查询与反核销;登记收款时同样可携带核销计划,审核后联动核销);
|
||||
-- 3) 收款登记/审核/取消与「客户余额-登记收款」复用同一套后端 Service 逻辑(ctr_customer_receipt);
|
||||
-- 4) 角色授权与「应收账单」(2401) 当前可见角色保持一致(role_id=6040 销售经理);
|
||||
-- 超级管理员(admin)默认拥有全部权限;其他角色可在 系统管理-角色 中勾选「收款管理」。
|
||||
-- ============================================================
|
||||
|
||||
-- 1. 收款管理 页面菜单
|
||||
insert into sys_menu(menu_id, menu_name, parent_id, order_num, path, component, query, route_name,
|
||||
is_frame, is_cache, menu_type, visible, status, perms, icon,
|
||||
create_by, create_time, remark)
|
||||
values (2461, '收款管理', 2400, 2, 'receipt', 'ar/receipt/index', null, 'ArReceipt',
|
||||
1, 0, 'C', '0', '0', 'ar:receipt:list', 'validCode',
|
||||
'admin', sysdate(), '收款记录查询、登记收款与账单核销');
|
||||
|
||||
-- 2. 按钮权限
|
||||
insert into sys_menu(menu_id, menu_name, parent_id, order_num, path, component, query, route_name,
|
||||
is_frame, is_cache, menu_type, visible, status, perms, icon,
|
||||
create_by, create_time, remark)
|
||||
values
|
||||
(2462, '收款查看', 2461, 1, '', null, null, '', 1, 0, 'F', '0', '0', 'ar:receipt:query', '#', 'admin', sysdate(), '收款单详情(含核销计划与凭证)'),
|
||||
(2463, '登记收款', 2461, 2, '', null, null, '', 1, 0, 'F', '0', '0', 'ar:receipt:add', '#', 'admin', sysdate(), '登记客户收款(必选客户,可同时选择核销账单)'),
|
||||
(2464, '收款审核', 2461, 3, '', null, null, '', 1, 0, 'F', '0', '0', 'ar:receipt:review', '#', 'admin', sysdate(), '审核通过收款单,入账并联动核销'),
|
||||
(2465, '取消收款', 2461, 4, '', null, null, '', 1, 0, 'F', '0', '0', 'ar:receipt:edit', '#', 'admin', sysdate(), '取消待确认收款单'),
|
||||
(2466, '账单核销', 2461, 5, '', null, null, '', 1, 0, 'F', '0', '0', 'ar:receipt:writeoff', '#', 'admin', sysdate(), '账单核销页签直接核销应收账单'),
|
||||
(2467, '核销反核销', 2461, 6, '', null, null, '', 1, 0, 'F', '0', '0', 'ar:receipt:writeoff:cancel', '#', 'admin', sysdate(), '反核销账单核销记录');
|
||||
|
||||
-- 3. 授权给拥有「应收账单」菜单的角色(当前为 role_id=6040 销售经理)
|
||||
insert into sys_role_menu(role_id, menu_id)
|
||||
select r.role_id, m.menu_id
|
||||
from sys_role r
|
||||
cross join (
|
||||
select 2461 as menu_id union all select 2462 union all select 2463 union all
|
||||
select 2464 union all select 2465 union all select 2466 union all select 2467
|
||||
) m
|
||||
where r.role_id in (select role_id from sys_role_menu where menu_id = 2401)
|
||||
and not exists (
|
||||
select 1 from sys_role_menu rm where rm.role_id = r.role_id and rm.menu_id = m.menu_id
|
||||
);
|
||||
@@ -0,0 +1,50 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/** 查询收款记录(跨客户,未传收款时间时后端默认当天) */
|
||||
export function listReceipt(query) {
|
||||
return request({ url: '/ar/receipt/list', method: 'get', params: query })
|
||||
}
|
||||
|
||||
/** 收款单详情(含核销计划与凭证附件) */
|
||||
export function getReceipt(id) {
|
||||
return request({ url: '/ar/receipt/' + id, method: 'get' })
|
||||
}
|
||||
|
||||
/** 登记收款(必须选择客户,与客户余额-登记收款同一套逻辑) */
|
||||
export function addReceipt(data) {
|
||||
return request({ url: '/ar/receipt', method: 'post', data })
|
||||
}
|
||||
|
||||
/** 审核通过收款单 */
|
||||
export function confirmReceipt(id) {
|
||||
return request({ url: '/ar/receipt/confirm/' + id, method: 'put' })
|
||||
}
|
||||
|
||||
/** 取消收款单 */
|
||||
export function cancelReceipt(id) {
|
||||
return request({ url: '/ar/receipt/cancel/' + id, method: 'put' })
|
||||
}
|
||||
|
||||
/** 查询客户可核销账单(已确认/部分核销) */
|
||||
export function listUnsettledBill(customerId) {
|
||||
return request({ url: '/ar/receipt/bill/unsettled/' + customerId, method: 'get' })
|
||||
}
|
||||
|
||||
/** 查询核销记录(跨客户) */
|
||||
export function listReceiptWriteoff(query) {
|
||||
return request({ url: '/ar/receipt/writeoff/list', method: 'get', params: query })
|
||||
}
|
||||
|
||||
/** 账单核销(账单核销页签直接核销) */
|
||||
export function receiptWriteoff(data) {
|
||||
return request({ url: '/ar/receipt/writeoff', method: 'post', data })
|
||||
}
|
||||
|
||||
/** 反核销 */
|
||||
export function cancelReceiptWriteoff(writeoffId, cancelRemark) {
|
||||
return request({
|
||||
url: '/ar/receipt/writeoff/' + writeoffId + '/cancel',
|
||||
method: 'put',
|
||||
data: { cancelRemark }
|
||||
})
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user