Merge branch 'test' of http://git.lionquexpress.com/wuweihua/BMS into test
This commit is contained in:
@@ -27,8 +27,7 @@ import com.bms.customer.customermoney.service.ICustomerMoneyService;
|
||||
* 收款管理 Controller(账单管理-收款管理)
|
||||
* <p>
|
||||
* 收款登记/审核/取消与「客户余额-登记收款」复用同一套 Service 逻辑;
|
||||
* 账单核销同样复用余额核销 Service:登记收款时可携带核销计划(审核通过后联动核销),
|
||||
* 本页「账单核销」页签可直接对账单发起核销/反核销。
|
||||
* 收款审核只将款项计入客户余额;账单核销由本页「账单核销」页签单独执行。
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-13
|
||||
@@ -82,7 +81,7 @@ public class ArReceiptController extends BaseController
|
||||
}
|
||||
|
||||
/**
|
||||
* 登记收款(必须选择客户;默认待确认,审核通过后入账并执行登记时选择的核销计划)
|
||||
* 登记收款(必须选择客户;默认待确认,审核通过后将款项计入客户余额)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ar:receipt:add')")
|
||||
@Log(title = "收款管理-登记收款", businessType = BusinessType.INSERT)
|
||||
@@ -94,7 +93,7 @@ public class ArReceiptController extends BaseController
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核通过收款单:确认后金额计入客户余额,登记时选择的账单一并核销
|
||||
* 审核通过收款单:确认后仅将收款金额计入客户余额,账单核销由账单核销页单独执行
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ar:receipt:review')")
|
||||
@Log(title = "收款管理-收款审核", businessType = BusinessType.UPDATE)
|
||||
@@ -116,7 +115,7 @@ public class ArReceiptController extends BaseController
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询客户可核销账单(已确认/部分核销,未核销额大于0),登记收款选账单与核销页签共用
|
||||
* 查询客户可核销账单(已确认/部分核销,未核销额大于0),供账单核销页使用
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('ar:receipt:list')")
|
||||
@GetMapping("/bill/unsettled/{customerId}")
|
||||
|
||||
+1
-3
@@ -246,10 +246,8 @@ public class ArBalanceWriteoffServiceImpl implements IArBalanceWriteoffService {
|
||||
String receiptType;
|
||||
if (newAllocated.compareTo(BigDecimal.ZERO) == 0) {
|
||||
receiptType = CustomerReceipt.TYPE_PREPAY;
|
||||
} else if (newAllocated.compareTo(base) >= 0) {
|
||||
receiptType = CustomerReceipt.TYPE_REPAY;
|
||||
} else {
|
||||
receiptType = CustomerReceipt.TYPE_MIXED;
|
||||
receiptType = CustomerReceipt.TYPE_REPAY;
|
||||
}
|
||||
|
||||
CustomerReceipt update = new CustomerReceipt();
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ import com.bms.customer.customermoney.vo.CustomerAccountStatusVO;
|
||||
* <li>收款审核入账/退款:{@link #refundBalance} 加余额</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>注意(核销口径):应收账单的余额核销与反核销(含收款审核联动核销)<b>不调用本接口</b>,
|
||||
* <p>注意(核销口径):应收账单的余额核销与反核销(含历史收款审核联动核销)<b>不调用本接口</b>,
|
||||
* 只更新账单已核销/未核销金额与状态,客户余额与授信额度均不发生变动。</p>
|
||||
*
|
||||
* @author bms
|
||||
|
||||
+3
-5
@@ -30,10 +30,8 @@ public class CustomerReceipt extends BaseEntity
|
||||
|
||||
/** 收款类型:预充值 */
|
||||
public static final String TYPE_PREPAY = "PREPAY";
|
||||
/** 收款类型:还款核销 */
|
||||
/** 收款类型:还款 */
|
||||
public static final String TYPE_REPAY = "REPAY";
|
||||
/** 收款类型:混合 */
|
||||
public static final String TYPE_MIXED = "MIXED";
|
||||
|
||||
/** 汇率来源:系统默认(本币CNY 1:1) */
|
||||
public static final String RATE_SOURCE_SYSTEM = "SYSTEM";
|
||||
@@ -60,7 +58,7 @@ public class CustomerReceipt extends BaseEntity
|
||||
/** 客户账户ID(预留) */
|
||||
private Long accountId;
|
||||
|
||||
/** 收款类型:PREPAY预充值/REPAY还款核销/MIXED混合 */
|
||||
/** 收款类型:PREPAY预充值/REPAY还款 */
|
||||
private String receiptType;
|
||||
|
||||
/** 收款金额 */
|
||||
@@ -131,7 +129,7 @@ public class CustomerReceipt extends BaseEntity
|
||||
/** 收款附件列表(存 ctr_customer_attachment,attachment_type='3',biz_id 关联本单) */
|
||||
private List<BmsCustomerAttachment> attachmentList;
|
||||
|
||||
/** 核销账单计划(登记时选择,审核通过后一并核销) */
|
||||
/** 历史收款单关联的核销计划;新登记收款不再创建计划 */
|
||||
private List<ReceiptWriteoffPlan> writeoffPlans;
|
||||
|
||||
/** 收款附件数量(列表查询统计) */
|
||||
|
||||
+7
-7
@@ -10,9 +10,9 @@ import lombok.EqualsAndHashCode;
|
||||
/**
|
||||
* 收款单核销账单计划 ctr_receipt_writeoff_plan
|
||||
*
|
||||
* <p>登记收款时指定待核销的应收账单(PENDING);收款审核通过后在同一事务内逐张执行核销,
|
||||
* 回写核销单ID并置 EFFECTIVE;待审核收款单被取消则置 CANCELLED;
|
||||
* 已生效的核销单后续在“余额核销”页被反核销则置 REVERSED(核销/反核销均不改动客户余额与额度)。</p>
|
||||
* <p>兼容历史收款单关联的账单核销记录。新收款不再创建联动核销计划;
|
||||
* 历史待审核计划在收款确认或取消时置 CANCELLED;已执行记录保留用于审计,
|
||||
* 已生效核销单在“余额核销”页反核销后置 REVERSED。</p>
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-08
|
||||
@@ -23,13 +23,13 @@ public class ReceiptWriteoffPlan extends BaseEntity
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 状态:待执行(收款单待审核) */
|
||||
/** 状态:历史待审核计划 */
|
||||
public static final String STATUS_PENDING = "PENDING";
|
||||
/** 状态:已核销(收款审核通过并完成账单核销) */
|
||||
/** 状态:已核销(历史收款审核联动完成) */
|
||||
public static final String STATUS_EFFECTIVE = "EFFECTIVE";
|
||||
/** 状态:已作废(待审核收款单被取消,计划未执行) */
|
||||
/** 状态:已作废(收款单取消或确认时清理历史待执行计划) */
|
||||
public static final String STATUS_CANCELLED = "CANCELLED";
|
||||
/** 状态:已反核销(审核联动核销后,核销单在余额核销页被反核销) */
|
||||
/** 状态:已反核销(关联的核销单在余额核销页被反核销) */
|
||||
public static final String STATUS_REVERSED = "REVERSED";
|
||||
|
||||
/** 主键 */
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ public interface CustomerMoneyMapper
|
||||
/** 新增收款单 */
|
||||
int insertReceipt(CustomerReceipt receipt);
|
||||
|
||||
/** 审核通过:PENDING -> CONFIRMED(带状态+乐观锁条件) */
|
||||
/** 审核通过:PENDING -> CONFIRMED,回写未分配金额(带状态+乐观锁条件) */
|
||||
int confirmReceipt(CustomerReceipt receipt);
|
||||
|
||||
/** 取消收款单:PENDING -> CANCELLED */
|
||||
|
||||
+2
-10
@@ -5,25 +5,17 @@ import org.apache.ibatis.annotations.Param;
|
||||
import com.bms.customer.customermoney.domain.ReceiptWriteoffPlan;
|
||||
|
||||
/**
|
||||
* 收款单核销账单计划 Mapper
|
||||
* 历史收款单核销关联 Mapper
|
||||
*
|
||||
* @author bms
|
||||
* @date 2026-10-08
|
||||
*/
|
||||
public interface ReceiptWriteoffPlanMapper
|
||||
{
|
||||
/** 新增一条核销计划 */
|
||||
int insertPlan(ReceiptWriteoffPlan plan);
|
||||
|
||||
/** 按收款单查询全部计划(关联账单展示字段,按计划ID升序) */
|
||||
List<ReceiptWriteoffPlan> selectByReceiptId(@Param("receiptId") Long receiptId);
|
||||
|
||||
/** 执行成功回写:PENDING -> EFFECTIVE,记录核销单ID与核销日期 */
|
||||
int updateEffective(@Param("planId") Long planId,
|
||||
@Param("writeoffId") Long writeoffId,
|
||||
@Param("updateBy") String updateBy);
|
||||
|
||||
/** 收款单取消:其全部 PENDING 计划置 CANCELLED */
|
||||
/** 收款确认或取消:其历史 PENDING 计划置 CANCELLED */
|
||||
int cancelPendingByReceiptId(@Param("receiptId") Long receiptId,
|
||||
@Param("updateBy") String updateBy);
|
||||
|
||||
|
||||
+12
-174
@@ -5,11 +5,8 @@ import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -18,13 +15,8 @@ import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import com.bms.common.exception.ServiceException;
|
||||
import com.bms.common.utils.SecurityUtils;
|
||||
import com.bms.ar.domain.ArBalanceWriteoff;
|
||||
import com.bms.ar.domain.ArBankAccount;
|
||||
import com.bms.ar.domain.ArBill;
|
||||
import com.bms.ar.enums.ArBillStatus;
|
||||
import com.bms.ar.mapper.ArBankAccountMapper;
|
||||
import com.bms.ar.mapper.ArBillMapper;
|
||||
import com.bms.ar.service.IArBalanceWriteoffService;
|
||||
import com.bms.customer.customerinfo.domain.BmsCustomer;
|
||||
import com.bms.customer.customerinfo.domain.BmsCustomerAttachment;
|
||||
import com.bms.customer.customerinfo.mapper.BmsCustomerMapper;
|
||||
@@ -36,7 +28,6 @@ import com.bms.customer.customermoney.domain.CustomerBalanceFlow;
|
||||
import com.bms.customer.customermoney.domain.CustomerCreditApply;
|
||||
import com.bms.customer.customermoney.domain.CustomerCreditFlow;
|
||||
import com.bms.customer.customermoney.domain.CustomerReceipt;
|
||||
import com.bms.customer.customermoney.domain.ReceiptWriteoffPlan;
|
||||
import com.bms.customer.customermoney.mapper.CustomerCreditApplyMapper;
|
||||
import com.bms.customer.customermoney.mapper.CustomerMoneyMapper;
|
||||
import com.bms.customer.customermoney.mapper.ReceiptWriteoffPlanMapper;
|
||||
@@ -89,18 +80,10 @@ public class CustomerMoneyServiceImpl implements ICustomerMoneyService
|
||||
@Autowired
|
||||
private ArBankAccountMapper arBankAccountMapper;
|
||||
|
||||
/** 应收账单:登记收款选择核销账单时校验账单状态/未核销额 */
|
||||
@Autowired
|
||||
private ArBillMapper arBillMapper;
|
||||
|
||||
/** 收款核销计划 */
|
||||
/** 历史收款核销计划:仅用于查询及处理旧计划 */
|
||||
@Autowired
|
||||
private ReceiptWriteoffPlanMapper receiptWriteoffPlanMapper;
|
||||
|
||||
/** 余额核销:收款审核通过事务内逐张核销账单 */
|
||||
@Autowired
|
||||
private IArBalanceWriteoffService balanceWriteoffService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<CustomerAccount> selectAccountList(Long customerId)
|
||||
@@ -157,7 +140,7 @@ public class CustomerMoneyServiceImpl implements ICustomerMoneyService
|
||||
{
|
||||
throw new ServiceException("收款金额必须大于0");
|
||||
}
|
||||
// 统一金额口径:入口即规范为两位小数,后续本位币、核销合计、余额分配均基于该值计算
|
||||
// 统一金额口径:入口即规范为两位小数,后续本位币金额与客户余额入账均基于该值计算
|
||||
receipt.setAmount(receipt.getAmount().setScale(MONEY_SCALE, RoundingMode.HALF_UP));
|
||||
if (!StringUtils.hasText(receipt.getReceiptType()))
|
||||
{
|
||||
@@ -256,24 +239,12 @@ public class CustomerMoneyServiceImpl implements ICustomerMoneyService
|
||||
BigDecimal baseAmount = receipt.getAmount().multiply(rate).setScale(MONEY_SCALE, RoundingMode.HALF_UP);
|
||||
receipt.setBaseAmount(baseAmount);
|
||||
|
||||
// 核销账单计划校验:当前账单均为人民币(CNY)账单,计划金额即本位币 CNY 金额,
|
||||
// 上限为收款按汇率折算后的本位币金额 baseAmount;核销本身不增减客户余额。
|
||||
List<ReceiptWriteoffPlan> plans = validateWriteoffPlans(receipt);
|
||||
BigDecimal allocatedBase = plans.stream()
|
||||
.map(ReceiptWriteoffPlan::getWriteoffAmount)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
// 全额分配=还款核销,部分分配=混合,不选账单=预充值/保持所选类型(本位币口径比较)
|
||||
if (!plans.isEmpty())
|
||||
{
|
||||
receipt.setReceiptType(allocatedBase.compareTo(baseAmount) == 0
|
||||
? CustomerReceipt.TYPE_REPAY : CustomerReceipt.TYPE_MIXED);
|
||||
}
|
||||
|
||||
receipt.setReceiptNo(generateNo("SK"));
|
||||
receipt.setStatus(CustomerReceipt.STATUS_PENDING);
|
||||
// 核销金额即本位币 CNY,无需再乘汇率
|
||||
receipt.setAllocatedAmount(allocatedBase);
|
||||
receipt.setUnallocatedAmount(baseAmount.subtract(allocatedBase));
|
||||
// 登记收款只记录资金,不接受账单核销计划;新收款先全部作为未分配金额入账。
|
||||
receipt.setAllocatedAmount(BigDecimal.ZERO.setScale(MONEY_SCALE, RoundingMode.UNNECESSARY));
|
||||
receipt.setUnallocatedAmount(baseAmount);
|
||||
receipt.setWriteoffPlans(null);
|
||||
if (!StringUtils.hasText(receipt.getInvoiceStatus()))
|
||||
{
|
||||
receipt.setInvoiceStatus("NONE");
|
||||
@@ -281,146 +252,11 @@ public class CustomerMoneyServiceImpl implements ICustomerMoneyService
|
||||
receipt.setVersion(0);
|
||||
customerMoneyMapper.insertReceipt(receipt);
|
||||
|
||||
// 核销计划落 PENDING,审核通过事务内再逐张执行
|
||||
String operator = receipt.getCreateBy();
|
||||
for (ReceiptWriteoffPlan plan : plans)
|
||||
{
|
||||
plan.setReceiptId(receipt.getId());
|
||||
plan.setStatus(ReceiptWriteoffPlan.STATUS_PENDING);
|
||||
plan.setCreateBy(operator);
|
||||
receiptWriteoffPlanMapper.insertPlan(plan);
|
||||
}
|
||||
|
||||
// 收款附件:复用客户附件表,业务模块挂 customer_receipt,biz_id 关联收款单
|
||||
saveReceiptAttachments(receipt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验登记收款携带的核销账单计划并规范化。
|
||||
* 口径(暂不支持多币种账单):
|
||||
* 账单必须属于当前客户、账单币种为人民币 CNY、状态可核销(已确认/部分核销);
|
||||
* 每张本次核销额(CNY)大于0且不超过账单未核销额;
|
||||
* 合计不超过收款按汇率折算后的本位币金额 baseAmount(CNY)。
|
||||
* 审核时会再次锁账单强校验,防止登记后账单被别处抢先核销。
|
||||
*/
|
||||
private List<ReceiptWriteoffPlan> validateWriteoffPlans(CustomerReceipt receipt)
|
||||
{
|
||||
List<ReceiptWriteoffPlan> raw = receipt.getWriteoffPlans();
|
||||
if (CollectionUtils.isEmpty(raw))
|
||||
{
|
||||
return new ArrayList<>();
|
||||
}
|
||||
BigDecimal baseAmount = receipt.getBaseAmount() != null
|
||||
? receipt.getBaseAmount().setScale(MONEY_SCALE, RoundingMode.HALF_UP)
|
||||
: receipt.getAmount().multiply(receipt.getExchangeRate()).setScale(MONEY_SCALE, RoundingMode.HALF_UP);
|
||||
List<ReceiptWriteoffPlan> plans = new ArrayList<>();
|
||||
Set<Long> billIds = new HashSet<>();
|
||||
BigDecimal total = BigDecimal.ZERO;
|
||||
for (ReceiptWriteoffPlan item : raw)
|
||||
{
|
||||
if (item == null || item.getArBillId() == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
BigDecimal amount = item.getWriteoffAmount();
|
||||
if (amount == null)
|
||||
{
|
||||
throw new ServiceException("请填写每张账单的本次核销金额");
|
||||
}
|
||||
amount = amount.setScale(MONEY_SCALE, RoundingMode.HALF_UP);
|
||||
if (amount.compareTo(BigDecimal.ZERO) <= 0)
|
||||
{
|
||||
throw new ServiceException("核销金额必须大于0");
|
||||
}
|
||||
if (!billIds.add(item.getArBillId()))
|
||||
{
|
||||
throw new ServiceException("同一账单不能重复选择,请合并为一条并填写合计金额");
|
||||
}
|
||||
ArBill bill = arBillMapper.selectArBillById(item.getArBillId());
|
||||
if (bill == null)
|
||||
{
|
||||
throw new ServiceException("所选应收账单不存在,请刷新后重新选择");
|
||||
}
|
||||
if (!receipt.getCustomerId().equals(bill.getCustomerId()))
|
||||
{
|
||||
throw new ServiceException("账单【" + bill.getBillNo() + "】不属于当前客户");
|
||||
}
|
||||
// 现阶段仅支持人民币账单核销;外币账单暂不在此入口处理
|
||||
String billCurrency = StringUtils.hasText(bill.getCurrency())
|
||||
? bill.getCurrency().trim().toUpperCase() : BASE_CURRENCY;
|
||||
if (!BASE_CURRENCY.equals(billCurrency))
|
||||
{
|
||||
throw new ServiceException("账单【" + bill.getBillNo() + "】币种为 " + billCurrency
|
||||
+ ",当前仅支持人民币(CNY)账单核销");
|
||||
}
|
||||
ArBillStatus billStatus = ArBillStatus.of(bill.getStatus());
|
||||
if (billStatus == null || !billStatus.canWriteOff())
|
||||
{
|
||||
throw new ServiceException("账单【" + bill.getBillNo() + "】当前状态不允许核销:"
|
||||
+ (billStatus == null ? bill.getStatus() : billStatus.getLabel()));
|
||||
}
|
||||
BigDecimal unwritten = bill.getUnwrittenAmount() == null
|
||||
? BigDecimal.ZERO : bill.getUnwrittenAmount();
|
||||
if (amount.compareTo(unwritten) > 0)
|
||||
{
|
||||
throw new ServiceException("账单【" + bill.getBillNo() + "】本次核销金额 "
|
||||
+ amount.toPlainString() + " 超过其未核销金额 " + unwritten.toPlainString());
|
||||
}
|
||||
total = total.add(amount);
|
||||
if (total.compareTo(baseAmount) > 0)
|
||||
{
|
||||
throw new ServiceException("核销金额合计 " + total.toPlainString()
|
||||
+ " CNY 超过本收款单折算本位币金额 " + baseAmount.toPlainString() + " CNY");
|
||||
}
|
||||
|
||||
ReceiptWriteoffPlan plan = new ReceiptWriteoffPlan();
|
||||
plan.setArBillId(bill.getArBillId());
|
||||
plan.setBillNo(bill.getBillNo());
|
||||
plan.setCustomerId(bill.getCustomerId());
|
||||
plan.setCurrency(BASE_CURRENCY);
|
||||
plan.setWriteoffAmount(amount);
|
||||
plan.setRemark(StringUtils.hasText(item.getRemark()) ? item.getRemark().trim() : null);
|
||||
plans.add(plan);
|
||||
}
|
||||
return plans;
|
||||
}
|
||||
|
||||
/**
|
||||
* 收款审核通过后执行核销计划:同一事务内逐张锁账单核销,
|
||||
* 任一账单已被别处抢先核销导致超额时,整笔审核回滚(含余额入账),不产生半截数据。
|
||||
*/
|
||||
private void executeReceiptWriteoffPlans(CustomerReceipt receipt, String operator)
|
||||
{
|
||||
List<ReceiptWriteoffPlan> plans = receiptWriteoffPlanMapper.selectByReceiptId(receipt.getId());
|
||||
if (CollectionUtils.isEmpty(plans))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Date writeoffDate = new Date();
|
||||
for (ReceiptWriteoffPlan plan : plans)
|
||||
{
|
||||
if (!ReceiptWriteoffPlan.STATUS_PENDING.equals(plan.getStatus()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ArBalanceWriteoff cmd = new ArBalanceWriteoff();
|
||||
cmd.setArBillId(plan.getArBillId());
|
||||
cmd.setCustomerId(plan.getCustomerId());
|
||||
cmd.setReceiptId(receipt.getId());
|
||||
cmd.setWriteoffAmount(plan.getWriteoffAmount());
|
||||
cmd.setWriteoffDate(writeoffDate);
|
||||
cmd.setRemark("收款单审核联动核销:" + receipt.getReceiptNo());
|
||||
cmd.setCreateBy(operator);
|
||||
// writeoff 内部锁账单行、复核状态与未核销额,冲突时抛异常由外层事务统一回滚
|
||||
ArBalanceWriteoff done = balanceWriteoffService.writeoff(cmd);
|
||||
if (receiptWriteoffPlanMapper.updateEffective(plan.getPlanId(), done.getWriteoffId(), operator) != 1)
|
||||
{
|
||||
throw new ServiceException("收款核销计划状态已变化,请刷新后重试");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造汇率表来源说明:汇率来源(中国银行/央行等)+ 命中路径(正向/反向取倒数/经CNY交叉)。
|
||||
* resolveRate 返回对象的 remark 带 __RATE_PATH__ 前缀标记命中路径。
|
||||
@@ -511,14 +347,16 @@ public class CustomerMoneyServiceImpl implements ICustomerMoneyService
|
||||
receipt.setConfirmedAt(new Date());
|
||||
receipt.setConfirmedBy(userId);
|
||||
receipt.setUpdateBy(username);
|
||||
receipt.setAllocatedAmount(BigDecimal.ZERO.setScale(MONEY_SCALE, RoundingMode.UNNECESSARY));
|
||||
receipt.setUnallocatedAmount(baseAmount.setScale(MONEY_SCALE, RoundingMode.HALF_UP));
|
||||
|
||||
// 旧版本待审核收款可能已有未执行计划;转为取消并恢复为未分配金额,不再联动核销。
|
||||
receiptWriteoffPlanMapper.cancelPendingByReceiptId(id, username);
|
||||
int receiptRows = customerMoneyMapper.confirmReceipt(receipt);
|
||||
if (receiptRows == 0)
|
||||
{
|
||||
throw new ServiceException("收款单状态已变更,请刷新后重试");
|
||||
}
|
||||
|
||||
// 3. 登记时选择的账单在同一事务内一并核销;任一账单核销失败则整笔审核回滚
|
||||
executeReceiptWriteoffPlans(receipt, username);
|
||||
return receiptRows;
|
||||
}
|
||||
|
||||
@@ -537,7 +375,7 @@ public class CustomerMoneyServiceImpl implements ICustomerMoneyService
|
||||
}
|
||||
String operator = SecurityUtils.getUsername();
|
||||
int rows = customerMoneyMapper.cancelReceipt(id, operator);
|
||||
// 尚未执行的核销计划一并作废
|
||||
// 旧版本待确认计划一并作废
|
||||
receiptWriteoffPlanMapper.cancelPendingByReceiptId(id, operator);
|
||||
return rows;
|
||||
}
|
||||
|
||||
+2
-2
@@ -83,8 +83,8 @@ public class CustomerReceiptExportVO implements Serializable
|
||||
private static String receiptTypeLabel(String v)
|
||||
{
|
||||
if ("PREPAY".equals(v)) return "预充值";
|
||||
if ("REPAY".equals(v)) return "还款核销";
|
||||
if ("MIXED".equals(v)) return "混合";
|
||||
if ("REPAY".equals(v)) return "还款";
|
||||
if ("MIXED".equals(v)) return "-";
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
@@ -385,6 +385,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<update id="confirmReceipt" parameterType="com.bms.customer.customermoney.domain.CustomerReceipt">
|
||||
update ctr_customer_receipt
|
||||
set status = 'CONFIRMED',
|
||||
allocated_amount = #{allocatedAmount},
|
||||
unallocated_amount = #{unallocatedAmount},
|
||||
confirmed_at = #{confirmedAt},
|
||||
confirmed_by = #{confirmedBy},
|
||||
version = version + 1,
|
||||
@@ -396,12 +398,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<update id="cancelReceipt">
|
||||
update ctr_customer_receipt
|
||||
set status = 'CANCELLED',
|
||||
allocated_amount = 0.00,
|
||||
unallocated_amount = ifnull(base_amount, amount),
|
||||
update_by = #{updateBy},
|
||||
update_time = now()
|
||||
where id = #{id} and status = 'PENDING' and del_flag = '0'
|
||||
</update>
|
||||
|
||||
<!-- 反核销联动:仅回写分配口径金额与收款类型,客户余额/额度不在此变动 -->
|
||||
<!-- 兼容历史反核销联动:回写分配口径金额与收款类型,客户余额/额度不在此变动 -->
|
||||
<update id="updateReceiptAllocation" parameterType="com.bms.customer.customermoney.domain.CustomerReceipt">
|
||||
update ctr_customer_receipt
|
||||
set allocated_amount = #{allocatedAmount},
|
||||
|
||||
@@ -39,32 +39,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
left join ar_bill b on b.ar_bill_id = p.ar_bill_id
|
||||
</sql>
|
||||
|
||||
<insert id="insertPlan" parameterType="com.bms.customer.customermoney.domain.ReceiptWriteoffPlan"
|
||||
useGeneratedKeys="true" keyProperty="planId">
|
||||
insert into ctr_receipt_writeoff_plan (
|
||||
receipt_id, ar_bill_id, bill_no, customer_id, currency, writeoff_amount,
|
||||
status, writeoff_id, remark, create_by, create_time, del_flag
|
||||
) values (
|
||||
#{receiptId}, #{arBillId}, #{billNo}, #{customerId}, #{currency}, #{writeoffAmount},
|
||||
#{status}, #{writeoffId}, #{remark}, #{createBy}, sysdate(), '0'
|
||||
)
|
||||
</insert>
|
||||
|
||||
<select id="selectByReceiptId" resultMap="ReceiptWriteoffPlanResult">
|
||||
<include refid="selectColumns"/>
|
||||
where p.receipt_id = #{receiptId} and p.del_flag = '0'
|
||||
order by p.plan_id asc
|
||||
</select>
|
||||
|
||||
<update id="updateEffective">
|
||||
update ctr_receipt_writeoff_plan
|
||||
set status = 'EFFECTIVE',
|
||||
writeoff_id = #{writeoffId},
|
||||
update_by = #{updateBy},
|
||||
update_time = sysdate()
|
||||
where plan_id = #{planId} and status = 'PENDING' and del_flag = '0'
|
||||
</update>
|
||||
|
||||
<update id="cancelPendingByReceiptId">
|
||||
update ctr_receipt_writeoff_plan
|
||||
set status = 'CANCELLED',
|
||||
|
||||
@@ -659,7 +659,7 @@ CREATE TABLE `ctr_customer_receipt` (
|
||||
`receipt_no` varchar(64) NOT NULL COMMENT '收款单号',
|
||||
`customer_id` bigint(20) NOT NULL COMMENT '客户ID',
|
||||
`account_id` bigint(20) DEFAULT NULL COMMENT '客户账户ID',
|
||||
`receipt_type` varchar(32) NOT NULL DEFAULT 'PREPAY' COMMENT '收款类型:PREPAY预充值/REPAY还款核销/MIXED混合',
|
||||
`receipt_type` varchar(32) NOT NULL DEFAULT 'PREPAY' COMMENT '收款类型:PREPAY预充值/REPAY还款',
|
||||
`amount` decimal(18,2) NOT NULL COMMENT '收款金额',
|
||||
`allocated_amount` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '已核销金额',
|
||||
`unallocated_amount` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '待核销金额',
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
<el-button v-if="row.status === AR_BILL_STATUS.DRAFT" link type="success" v-hasPermi="['ar:bill:confirm']" @click="confirmBill(row)">确认</el-button>
|
||||
<el-button v-if="row.status === AR_BILL_STATUS.DRAFT || row.status === AR_BILL_STATUS.CONFIRMED" link type="warning" v-hasPermi="['ar:bill:void']" @click="voidBill(row)">作废</el-button>
|
||||
<el-button v-if="row.status !== AR_BILL_STATUS.DRAFT && row.status !== AR_BILL_STATUS.VOID" link type="primary" v-hasPermi="['ar:bill:export']" @click="exportBill(row)">导出明细</el-button>
|
||||
<el-button v-if="canGoWriteoff(row)" link type="primary" v-hasPermi="['customer:bill:writeoff']" @click="goWriteoff(row)">去核销</el-button>
|
||||
<el-button v-if="canGoWriteoff(row)" link type="primary" v-hasPermi="['customer:bill:writeoff']" @click="goWriteoff(row)">核销</el-button>
|
||||
<el-button v-if="canGoReverseWriteoff(row)" link type="warning" v-hasPermi="['customer:bill:writeoff:cancel']" @click="goReverseWriteoff(row)">反核销</el-button>
|
||||
</template>
|
||||
</basic-table>
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
<el-table-column label="收款类型" align="center" prop="receiptType" width="95">
|
||||
<template #default="scope">
|
||||
<el-tag :type="receiptTypeTag(scope.row.receiptType)" size="small">
|
||||
{{ formatOption(receiptTypeOptions, scope.row.receiptType) }}
|
||||
{{ formatReceiptType(scope.row.receiptType) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -295,7 +295,6 @@
|
||||
v-model="receiptDialog.form.customerId"
|
||||
placeholder="请选择客户(必选)"
|
||||
:page-size="1000"
|
||||
@change="handleReceiptCustomerChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -382,51 +381,6 @@
|
||||
<el-input v-model="receiptDialog.form.remark" type="textarea" :rows="2" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="核销账单">
|
||||
<div class="receipt-wo-toolbar">
|
||||
<el-button type="primary" plain icon="Plus" @click="openBillPicker">选择账单核销</el-button>
|
||||
<span class="receipt-wo-summary">
|
||||
本次核销合计:<b class="money-out">{{ formatMoney(receiptWriteoffTotal) }} CNY</b>
|
||||
,收款折算本位币:<b>{{ formatMoney(receiptBaseCny) }} CNY</b>
|
||||
</span>
|
||||
</div>
|
||||
<el-table :data="receiptDialog.form.writeoffPlans" border size="small" max-height="220">
|
||||
<el-table-column label="账单号" prop="billNo" align="center" width="170" show-overflow-tooltip />
|
||||
<el-table-column label="账单名称" prop="billName" align="center" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column label="未核销金额" align="center" width="120">
|
||||
<template #default="scope">{{ formatMoney(scope.row.unwrittenAmount) }} {{ scope.row.currency }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="本次核销金额(CNY)" align="center" width="160">
|
||||
<template #default="scope">
|
||||
<el-input-number
|
||||
v-model="scope.row.writeoffAmount"
|
||||
:min="0"
|
||||
:max="Number(scope.row.unwrittenAmount)"
|
||||
:precision="2"
|
||||
:step="1"
|
||||
:controls="false"
|
||||
size="small"
|
||||
style="width: 130px;"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="70">
|
||||
<template #default="scope">
|
||||
<el-button link type="danger" icon="Delete" @click="removeReceiptBill(scope.$index)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<span style="color: var(--el-text-color-secondary);">不选账单则整笔计入客户余额,可在“账单核销”页手工核销</span>
|
||||
</template>
|
||||
</el-table>
|
||||
<div class="upload-tip">
|
||||
当前仅支持<strong>人民币(CNY)账单</strong>核销;所选账单在收款单<strong>审核通过</strong>后一并核销,
|
||||
核销合计不能超过收款金额按汇率折算的本位币金额({{ formatMoney(receiptBaseCny) }} CNY);
|
||||
<strong>核销不扣减客户余额</strong>,正常计入客户余额。
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="收款凭证">
|
||||
<el-upload
|
||||
@@ -468,49 +422,6 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- ====================== 选择核销账单弹窗 ====================== -->
|
||||
<el-dialog title="选择待核销账单" v-model="billPicker.visible" width="860px" append-to-body>
|
||||
<el-alert type="info" :closable="false" class="writeoff-summary">
|
||||
当前仅支持人民币(CNY)账单核销,以下为状态已确认/部分核销的 CNY 账单;
|
||||
已选 {{ billPicker.selected.length }} 张,合计未核销
|
||||
<b class="money-out">{{ formatMoney(billPickerSelectedTotal) }} CNY</b>,
|
||||
本收款单折算可核销上限 <b>{{ formatMoney(receiptBaseCny) }} CNY</b>
|
||||
</el-alert>
|
||||
<el-table
|
||||
ref="billPickerTableRef"
|
||||
:data="billPicker.rows"
|
||||
border
|
||||
size="small"
|
||||
max-height="380"
|
||||
row-key="arBillId"
|
||||
v-loading="billPicker.loading"
|
||||
@selection-change="onPickerSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="42" align="center" reserve-selection />
|
||||
<el-table-column label="账单号" prop="billNo" align="center" width="160" show-overflow-tooltip />
|
||||
<el-table-column label="账单名称" prop="billName" align="center" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column label="账单日期" prop="billDate" align="center" width="105">
|
||||
<template #default="scope">{{ formatDate(scope.row.billDate) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="应收金额" align="center" width="110">
|
||||
<template #default="scope">{{ formatMoney(scope.row.totalAmount) }} {{ scope.row.currency }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已核销" align="center" width="100">
|
||||
<template #default="scope"><span class="money-in">{{ formatMoney(scope.row.writtenOffAmount) }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="未核销" align="center" width="100">
|
||||
<template #default="scope"><span class="money-out">{{ formatMoney(scope.row.unwrittenAmount) }}</span></template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<el-empty description="该客户暂无可核销账单" :image-size="70" />
|
||||
</template>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="confirmBillPicker">确 定({{ billPicker.selected.length }})</el-button>
|
||||
<el-button @click="billPicker.visible = false">取 消</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- ====================== 收款单详情弹窗 ====================== -->
|
||||
<el-dialog title="收款单详情" v-model="viewDialog.visible" width="720px" append-to-body>
|
||||
<el-descriptions :column="2" border v-if="viewDialog.data" size="small">
|
||||
@@ -521,7 +432,7 @@
|
||||
<el-descriptions-item label="客户">{{ viewDialog.data.customerName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="收款时间">{{ formatDateTime(viewDialog.data.receivedAt) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="收款类型">
|
||||
<el-tag :type="receiptTypeTag(viewDialog.data.receiptType)">{{ formatOption(receiptTypeOptions, viewDialog.data.receiptType) }}</el-tag>
|
||||
<el-tag :type="receiptTypeTag(viewDialog.data.receiptType)">{{ formatReceiptType(viewDialog.data.receiptType) }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="原币金额">
|
||||
<span class="money-in">{{ viewDialog.data.currency }} {{ formatMoney(viewDialog.data.amount) }}</span>
|
||||
@@ -676,7 +587,7 @@ import axios from 'axios'
|
||||
import { saveAs } from 'file-saver'
|
||||
import {
|
||||
listReceipt, getReceipt, addReceipt, confirmReceipt, cancelReceipt,
|
||||
listUnsettledBill, listReceiptWriteoff, receiptWriteoff, cancelReceiptWriteoff
|
||||
listReceiptWriteoff, receiptWriteoff, cancelReceiptWriteoff
|
||||
} from '@/api/ar/receipt'
|
||||
import { listArBill } from '@/api/ar/bill'
|
||||
import { convertToBase } from '@/api/data/exchangeRate'
|
||||
@@ -695,8 +606,7 @@ const activeTab = ref('receipt')
|
||||
/* ================= 枚举与格式化 ================= */
|
||||
const receiptTypeOptions = [
|
||||
{ value: 'PREPAY', label: '预充值' },
|
||||
{ value: 'REPAY', label: '还款核销' },
|
||||
{ value: 'MIXED', label: '混合' }
|
||||
{ value: 'REPAY', label: '还款' }
|
||||
]
|
||||
const receiptStatusOptions = [
|
||||
{ value: 'PENDING', label: '待确认' },
|
||||
@@ -724,8 +634,11 @@ function formatOption(options, value) {
|
||||
const opt = options.find(o => String(o.value) === String(value))
|
||||
return opt ? opt.label : value
|
||||
}
|
||||
function formatReceiptType(value) {
|
||||
return value === 'MIXED' ? '-' : formatOption(receiptTypeOptions, value)
|
||||
}
|
||||
function receiptTypeTag(v) {
|
||||
return { PREPAY: '', REPAY: 'warning', MIXED: 'info' }[v] || 'info'
|
||||
return { PREPAY: '', REPAY: 'warning' }[v] || 'info'
|
||||
}
|
||||
function receiptStatusTag(v) {
|
||||
return { PENDING: 'warning', CONFIRMED: 'success', CANCELLED: 'danger' }[v] || 'info'
|
||||
@@ -860,15 +773,11 @@ function resetReceiptQuery() {
|
||||
|
||||
/** 审核通过 */
|
||||
function handleConfirmReceipt(row) {
|
||||
proxy.$modal.confirm(`是否确认审核通过收款单「${row.receiptNo}」?审核通过后金额计入客户余额,登记时选择的账单将一并核销。`).then(() => {
|
||||
proxy.$modal.confirm(`是否确认审核通过收款单「${row.receiptNo}」?`).then(() => {
|
||||
return confirmReceipt(row.id)
|
||||
}).then(() => {
|
||||
proxy.$modal.msgSuccess('审核通过,余额与账单核销已更新')
|
||||
proxy.$modal.msgSuccess('审核通过,收款已计入客户余额')
|
||||
getReceiptList()
|
||||
if (writeoffLoaded) {
|
||||
getBillList()
|
||||
getWriteoffList()
|
||||
}
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
@@ -908,8 +817,7 @@ function resetReceiptForm() {
|
||||
bankAccountNo: '',
|
||||
bankTransactionNo: '',
|
||||
remark: '',
|
||||
attachmentList: [],
|
||||
writeoffPlans: []
|
||||
attachmentList: []
|
||||
}
|
||||
proxy.resetForm('receiptFormRef')
|
||||
}
|
||||
@@ -919,14 +827,6 @@ function handleAddReceipt() {
|
||||
receiptDialog.visible = true
|
||||
}
|
||||
|
||||
/** 切换客户:核销账单归属于客户,已选账单需清空重选 */
|
||||
function handleReceiptCustomerChange() {
|
||||
const plans = receiptDialog.form.writeoffPlans || []
|
||||
if (plans.length) {
|
||||
plans.splice(0, plans.length)
|
||||
}
|
||||
}
|
||||
|
||||
const rateEdited = ref(false)
|
||||
const rateSourceInfo = ref({ source: '', ratePath: '' })
|
||||
|
||||
@@ -978,22 +878,6 @@ watch(() => receiptDialog.form.receivedAt, () => {
|
||||
}
|
||||
})
|
||||
|
||||
/* ============ 选择核销账单 ============ */
|
||||
const billPickerTableRef = ref(null)
|
||||
const billPicker = reactive({ visible: false, loading: false, rows: [], selected: [] })
|
||||
|
||||
const receiptBaseCny = computed(() => {
|
||||
const amt = Number(receiptDialog.form.amount) || 0
|
||||
const rate = Number(receiptDialog.form.exchangeRate) || 0
|
||||
return Math.round(amt * rate * 100) / 100
|
||||
})
|
||||
const receiptWriteoffTotal = computed(() => {
|
||||
return (receiptDialog.form.writeoffPlans || []).reduce((s, r) => s + (Number(r.writeoffAmount) || 0), 0)
|
||||
})
|
||||
const billPickerSelectedTotal = computed(() => {
|
||||
return billPicker.selected.reduce((s, r) => s + (Number(r.unwrittenAmount) || 0), 0)
|
||||
})
|
||||
|
||||
const RECEIPT_PLAN_STATUS_MAP = {
|
||||
PENDING: { label: '待核销', type: 'warning' },
|
||||
EFFECTIVE: { label: '已核销', type: 'success' },
|
||||
@@ -1007,84 +891,6 @@ function receiptPlanStatusTag(s) {
|
||||
return RECEIPT_PLAN_STATUS_MAP[s]?.type || 'info'
|
||||
}
|
||||
|
||||
function openBillPicker() {
|
||||
const customerId = receiptDialog.form.customerId
|
||||
if (!customerId) {
|
||||
proxy.$modal.msgError('请先选择客户')
|
||||
return
|
||||
}
|
||||
billPicker.visible = true
|
||||
billPicker.loading = true
|
||||
billPicker.rows = []
|
||||
billPicker.selected = []
|
||||
listUnsettledBill(customerId).then(res => {
|
||||
billPicker.rows = (res.data || []).filter(r => (r.currency || 'CNY') === 'CNY')
|
||||
nextTick(() => {
|
||||
billPickerTableRef.value?.clearSelection()
|
||||
const chosen = receiptDialog.form.writeoffPlans || []
|
||||
billPicker.rows.forEach(r => {
|
||||
if (chosen.some(p => p.arBillId === r.arBillId)) {
|
||||
billPickerTableRef.value?.toggleRowSelection(r, true)
|
||||
}
|
||||
})
|
||||
})
|
||||
}).finally(() => {
|
||||
billPicker.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
function onPickerSelectionChange(rows) {
|
||||
billPicker.selected = rows || []
|
||||
}
|
||||
|
||||
function confirmBillPicker() {
|
||||
const oldMap = new Map((receiptDialog.form.writeoffPlans || []).map(p => [p.arBillId, p]))
|
||||
receiptDialog.form.writeoffPlans = billPicker.selected.map(r => {
|
||||
const existed = oldMap.get(r.arBillId)
|
||||
const unwritten = Number(r.unwrittenAmount) || 0
|
||||
const usedByOthers = (receiptDialog.form.writeoffPlans || [])
|
||||
.filter(p => p.arBillId !== r.arBillId)
|
||||
.reduce((s, p) => s + (Number(p.writeoffAmount) || 0), 0)
|
||||
const remainCny = Math.max(receiptBaseCny.value - usedByOthers, 0)
|
||||
return {
|
||||
arBillId: r.arBillId,
|
||||
billNo: r.billNo,
|
||||
billName: r.billName,
|
||||
currency: 'CNY',
|
||||
unwrittenAmount: unwritten,
|
||||
writeoffAmount: existed ? Number(existed.writeoffAmount) : Math.round(Math.min(unwritten, remainCny) * 100) / 100
|
||||
}
|
||||
})
|
||||
billPicker.visible = false
|
||||
}
|
||||
|
||||
function removeReceiptBill(index) {
|
||||
receiptDialog.form.writeoffPlans.splice(index, 1)
|
||||
}
|
||||
|
||||
function validateReceiptWriteoffPlans() {
|
||||
const cap = receiptBaseCny.value
|
||||
const list = receiptDialog.form.writeoffPlans || []
|
||||
let total = 0
|
||||
for (const p of list) {
|
||||
const amt = Number(p.writeoffAmount)
|
||||
if (!amt || amt <= 0) {
|
||||
proxy.$modal.msgError(`账单【${p.billNo}】本次核销金额必须大于0`)
|
||||
return false
|
||||
}
|
||||
if (amt > Number(p.unwrittenAmount)) {
|
||||
proxy.$modal.msgError(`账单【${p.billNo}】核销金额超过其未核销金额`)
|
||||
return false
|
||||
}
|
||||
total += amt
|
||||
}
|
||||
if (Math.round(total * 100) > Math.round(cap * 100)) {
|
||||
proxy.$modal.msgError(`核销金额合计 ${total.toFixed(2)} CNY 超过收款折算本位币金额 ${cap.toFixed(2)} CNY`)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function submitReceipt() {
|
||||
receiptFormRef.value.validate(valid => {
|
||||
if (!valid) return
|
||||
@@ -1094,7 +900,6 @@ function submitReceipt() {
|
||||
proxy.$modal.msgError(`请录入 ${cur} 对 CNY 的汇率(汇率表未配置时可手工填写)`)
|
||||
return
|
||||
}
|
||||
if (!validateReceiptWriteoffPlans()) return
|
||||
submitLoading.value = true
|
||||
addReceipt(receiptDialog.form).then(() => {
|
||||
proxy.$modal.msgSuccess('登记成功,等待审核')
|
||||
@@ -1393,12 +1198,6 @@ getReceiptList()
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.receipt-wo-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.attach-title {
|
||||
font-weight: 600;
|
||||
margin: 12px 0 8px;
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
<el-tab-pane label="绑定产品" name="product">
|
||||
<div class="pane-toolbar">
|
||||
<product-select v-model="form.productCodes" />
|
||||
<span class="pane-tip">绑定结果以产品代码逗号串存入客户主表 product_codes,产品代码在新旧库间稳定,用于产品对接映射</span>
|
||||
<!-- <span class="pane-tip">绑定结果以产品代码逗号串存入客户主表 product_codes,产品代码在新旧库间稳定,用于产品对接映射</span>-->
|
||||
</div>
|
||||
<el-table :data="boundProducts" border size="small" class="bound-table">
|
||||
<el-table-column label="序号" type="index" width="55" align="center" />
|
||||
@@ -216,7 +216,7 @@
|
||||
<el-button type="primary" plain icon="Plus" size="small" :disabled="isAdd" @click="openPriceSetDialog()">
|
||||
{{ boundPriceSets.length ? '更换套餐' : '绑定套餐' }}
|
||||
</el-button>
|
||||
<span class="pane-tip">绑定后写入客户套餐关系表 prc_customer_price_set,一个客户仅可绑定一个价格套餐,仅「生效中」的套餐可绑定</span>
|
||||
<span class="pane-tip">一个客户仅可绑定一个价格套餐,仅「生效中」的套餐可绑定</span>
|
||||
</div>
|
||||
<el-table :data="boundPriceSets" border size="small" class="bound-table">
|
||||
<el-table-column label="序号" type="index" width="55" align="center" />
|
||||
@@ -258,7 +258,7 @@
|
||||
<el-tab-pane label="公司主体" name="company">
|
||||
<div class="pane-toolbar">
|
||||
<el-button type="primary" plain icon="Plus" size="small" @click="handleAddCompany">新增公司主体</el-button>
|
||||
<span class="pane-tip">点击「绑定客户」后,主表的统一社会信用代码会自动同步为该公司的信用代码</span>
|
||||
<!-- <span class="pane-tip">点击「绑定客户」后,主表的统一社会信用代码会自动同步为该公司的信用代码</span>-->
|
||||
</div>
|
||||
<el-table :data="form.companyList" border size="small">
|
||||
<el-table-column label="序号" type="index" width="55" align="center" />
|
||||
|
||||
+15
-250
@@ -127,7 +127,7 @@
|
||||
</el-table-column>
|
||||
<el-table-column label="收款类型" align="center" prop="receiptType" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="receiptTypeTag(scope.row.receiptType)">{{ formatOption(receiptTypeOptions, scope.row.receiptType) }}</el-tag>
|
||||
<el-tag :type="receiptTypeTag(scope.row.receiptType)">{{ formatReceiptType(scope.row.receiptType) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="原币金额" align="center" width="130">
|
||||
@@ -679,54 +679,6 @@
|
||||
<el-input v-model="receiptDialog.form.remark" type="textarea" :rows="2" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="核销账单">
|
||||
<div class="receipt-wo-toolbar">
|
||||
<el-button type="primary" plain icon="Plus" @click="openBillPicker">选择账单核销</el-button>
|
||||
<span class="receipt-wo-summary">
|
||||
本次核销合计:<b class="money-out">{{ formatMoney(receiptWriteoffTotal) }} CNY</b>
|
||||
,收款折算本位币:<b>{{ formatMoney(receiptBaseCny) }} CNY</b>
|
||||
<!-- ,核销后剩余入账:<b :class="receiptWriteoffRemain < 0 ? 'money-out' : 'money-in'">-->
|
||||
<!-- {{ formatMoney(receiptWriteoffRemain) }} CNY-->
|
||||
<!-- </b>-->
|
||||
</span>
|
||||
</div>
|
||||
<el-table :data="receiptDialog.form.writeoffPlans" border size="small" max-height="220">
|
||||
<el-table-column label="账单号" prop="billNo" align="center" width="170" show-overflow-tooltip />
|
||||
<el-table-column label="账单名称" prop="billName" align="center" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column label="未核销金额" align="center" width="120">
|
||||
<template #default="scope">{{ formatMoney(scope.row.unwrittenAmount) }} {{ scope.row.currency }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="本次核销金额(CNY)" align="center" width="160">
|
||||
<template #default="scope">
|
||||
<el-input-number
|
||||
v-model="scope.row.writeoffAmount"
|
||||
:min="0"
|
||||
:max="Number(scope.row.unwrittenAmount)"
|
||||
:precision="2"
|
||||
:step="1"
|
||||
:controls="false"
|
||||
size="small"
|
||||
style="width: 130px;"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="70">
|
||||
<template #default="scope">
|
||||
<el-button link type="danger" icon="Delete" @click="removeReceiptBill(scope.$index)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<span style="color: var(--el-text-color-secondary);">不选账单则整笔计入客户余额,可在“账单核销”页手工核销</span>
|
||||
</template>
|
||||
</el-table>
|
||||
<div class="upload-tip">
|
||||
当前仅支持<strong>人民币(CNY)账单</strong>核销,账单行金额均按 CNY 填写;
|
||||
所选账单在收款单<strong>审核通过</strong>后一并核销,核销合计不能超过收款金额按汇率折算的本位币金额
|
||||
({{ formatMoney(receiptBaseCny) }} CNY);<strong>核销不扣减客户余额</strong>,正常计入客户余额。
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="收款凭证">
|
||||
<el-upload
|
||||
@@ -778,7 +730,7 @@
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="收款日期">{{ formatDateTime(viewDialog.data.receivedAt) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="收款类型">
|
||||
<el-tag :type="receiptTypeTag(viewDialog.data.receiptType)">{{ formatOption(receiptTypeOptions, viewDialog.data.receiptType) }}</el-tag>
|
||||
<el-tag :type="receiptTypeTag(viewDialog.data.receiptType)">{{ formatReceiptType(viewDialog.data.receiptType) }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="原币金额">
|
||||
<span class="money-in">{{ viewDialog.data.currency }} {{ formatMoney(viewDialog.data.amount) }}</span>
|
||||
@@ -997,60 +949,14 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- ====== 登记收款-选择核销账单弹窗 ====== -->
|
||||
<el-dialog title="选择待核销账单" v-model="billPicker.visible" width="860px" append-to-body>
|
||||
<el-alert type="info" :closable="false" class="writeoff-summary">
|
||||
当前仅支持人民币(CNY)账单核销,以下为状态已确认/部分核销的 CNY 账单;
|
||||
已选 {{ billPicker.selected.length }} 张,合计未核销
|
||||
<b class="money-out">{{ formatMoney(billPickerSelectedTotal) }} CNY</b>,
|
||||
本收款单折算可核销上限 <b>{{ formatMoney(receiptBaseCny) }} CNY</b>
|
||||
</el-alert>
|
||||
<el-table
|
||||
ref="billPickerTableRef"
|
||||
:data="billPicker.rows"
|
||||
border
|
||||
size="small"
|
||||
max-height="380"
|
||||
row-key="arBillId"
|
||||
v-loading="billPicker.loading"
|
||||
@selection-change="onPickerSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="42" align="center" reserve-selection />
|
||||
<el-table-column label="账单号" prop="billNo" align="center" width="160" show-overflow-tooltip />
|
||||
<el-table-column label="账单名称" prop="billName" align="center" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column label="账单日期" prop="billDate" align="center" width="105">
|
||||
<template #default="scope">{{ formatDate(scope.row.billDate) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="应收金额" align="center" width="110">
|
||||
<template #default="scope">{{ formatMoney(scope.row.totalAmount) }} {{ scope.row.currency }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已核销" align="center" width="100">
|
||||
<template #default="scope"><span class="money-in">{{ formatMoney(scope.row.writtenOffAmount) }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="未核销" align="center" width="100">
|
||||
<template #default="scope"><span class="money-out">{{ formatMoney(scope.row.unwrittenAmount) }}</span></template>
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<el-empty description="该币种暂无可核销账单" :image-size="70" />
|
||||
</template>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="confirmBillPicker">确 定({{ billPicker.selected.length }})</el-button>
|
||||
<el-button @click="billPicker.visible = false">取 消</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- ====== 余额核销账单弹窗 ====== -->
|
||||
<el-dialog title="余额核销账单" v-model="woDialog.visible" width="560px" append-to-body v-loading="woDialog.accountLoading">
|
||||
<!-- ====== 账单核销弹窗 ====== -->
|
||||
<el-dialog title="账单核销" v-model="woDialog.visible" width="560px" append-to-body>
|
||||
<el-descriptions :column="1" border size="small" v-if="woDialog.bill">
|
||||
<el-descriptions-item label="账单号">{{ woDialog.bill.billNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="账单名称">{{ woDialog.bill.billName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="账单未核销金额">
|
||||
<span class="money-out">CNY {{ formatMoney(woDialog.bill.unwrittenAmount) }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="账户可用余额">
|
||||
<span class="money-in">CNY {{ formatMoney(currentAccount.balance) }}</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-form :model="woDialog.form" label-width="110px" class="wo-form">
|
||||
<el-form-item label="本次核销金额" required>
|
||||
@@ -1142,8 +1048,7 @@ const customer = ref({})
|
||||
/* ================= 枚举 ================= */
|
||||
const receiptTypeOptions = [
|
||||
{ value: 'PREPAY', label: '预充值' },
|
||||
{ value: 'REPAY', label: '还款核销' },
|
||||
{ value: 'MIXED', label: '混合' }
|
||||
{ value: 'REPAY', label: '还款' }
|
||||
]
|
||||
const receiptStatusOptions = [
|
||||
{ value: 'PENDING', label: '待确认' },
|
||||
@@ -1184,8 +1089,11 @@ function formatOption(options, value) {
|
||||
const opt = options.find(o => String(o.value) === String(value))
|
||||
return opt ? opt.label : value
|
||||
}
|
||||
function formatReceiptType(value) {
|
||||
return value === 'MIXED' ? '-' : formatOption(receiptTypeOptions, value)
|
||||
}
|
||||
function receiptTypeTag(v) {
|
||||
return { PREPAY: '', REPAY: 'warning', MIXED: 'info' }[v] || 'info'
|
||||
return { PREPAY: '', REPAY: 'warning' }[v] || 'info'
|
||||
}
|
||||
function receiptStatusTag(v) {
|
||||
return { PENDING: 'warning', CONFIRMED: 'success', CANCELLED: 'danger' }[v] || 'info'
|
||||
@@ -1517,10 +1425,10 @@ function handleExportCreditFlow() {
|
||||
|
||||
/** 审核通过 */
|
||||
function handleConfirmReceipt(row) {
|
||||
proxy.$modal.confirm(`是否确认审核通过收款单「${row.receiptNo}」?审核通过后金额计入客户余额,登记时选择的账单将一并核销。`).then(() => {
|
||||
proxy.$modal.confirm(`是否确认审核通过收款单「${row.receiptNo}」?`).then(() => {
|
||||
return confirmReceipt(row.id)
|
||||
}).then(() => {
|
||||
proxy.$modal.msgSuccess("审核通过,余额与账单核销已更新")
|
||||
proxy.$modal.msgSuccess("审核通过,收款已计入客户余额")
|
||||
getReceiptList()
|
||||
loadAccounts()
|
||||
loadBillWriteoffData()
|
||||
@@ -1566,8 +1474,7 @@ function resetReceiptForm() {
|
||||
bankAccountNo: '',
|
||||
bankTransactionNo: '',
|
||||
remark: '',
|
||||
attachmentList: [],
|
||||
writeoffPlans: []
|
||||
attachmentList: []
|
||||
}
|
||||
proxy.resetForm('receiptFormRef')
|
||||
}
|
||||
@@ -1609,7 +1516,7 @@ function fetchDefaultRate() {
|
||||
})
|
||||
}
|
||||
|
||||
/** 切换币种:重置手工标记并重新取默认汇率;核销账单固定为CNY,只需按新汇率重算可核销上限,不清空已选 */
|
||||
/** 切换币种:重置手工标记并重新取默认汇率 */
|
||||
function handleCurrencyChange() {
|
||||
rateEdited.value = false
|
||||
rateSourceInfo.value = { source: '', ratePath: '' }
|
||||
@@ -1635,35 +1542,6 @@ watch(() => receiptDialog.form.receivedAt, () => {
|
||||
}
|
||||
})
|
||||
|
||||
/* ============ 登记收款-选择核销账单 ============ */
|
||||
const billPickerTableRef = ref(null)
|
||||
const billPicker = reactive({
|
||||
visible: false,
|
||||
loading: false,
|
||||
rows: [],
|
||||
selected: []
|
||||
})
|
||||
|
||||
/** 收款金额按汇率折算的本位币金额(CNY),即核销合计上限 */
|
||||
const receiptBaseCny = computed(() => {
|
||||
const amt = Number(receiptDialog.form.amount) || 0
|
||||
const rate = Number(receiptDialog.form.exchangeRate) || 0
|
||||
return Math.round(amt * rate * 100) / 100
|
||||
})
|
||||
/** 已分配合计(账单均为CNY,此值即 CNY) */
|
||||
const receiptWriteoffTotal = computed(() => {
|
||||
const list = receiptDialog.form.writeoffPlans || []
|
||||
return list.reduce((s, r) => s + (Number(r.writeoffAmount) || 0), 0)
|
||||
})
|
||||
/** 核销后剩余入账金额(折算CNY - 已分配CNY) */
|
||||
const receiptWriteoffRemain = computed(() => {
|
||||
return Math.round((receiptBaseCny.value - receiptWriteoffTotal.value) * 100) / 100
|
||||
})
|
||||
/** 选择器中勾选账单的未核销额合计(仅提示) */
|
||||
const billPickerSelectedTotal = computed(() => {
|
||||
return billPicker.selected.reduce((s, r) => s + (Number(r.unwrittenAmount) || 0), 0)
|
||||
})
|
||||
|
||||
const RECEIPT_PLAN_STATUS_MAP = {
|
||||
PENDING: { label: '待核销', type: 'warning' },
|
||||
EFFECTIVE: { label: '已核销', type: 'success' },
|
||||
@@ -1677,88 +1555,6 @@ function receiptPlanStatusTag(s) {
|
||||
return RECEIPT_PLAN_STATUS_MAP[s]?.type || 'info'
|
||||
}
|
||||
|
||||
/** 打开账单选择器:只列与收款同币种的未核销账单,并回显已选 */
|
||||
function openBillPicker() {
|
||||
const customerId = route.query.customerId
|
||||
if (!customerId) {
|
||||
proxy.$modal.msgError('缺少客户信息,请重新进入页面')
|
||||
return
|
||||
}
|
||||
billPicker.visible = true
|
||||
billPicker.loading = true
|
||||
billPicker.rows = []
|
||||
billPicker.selected = []
|
||||
listUnsettledBill(customerId).then(res => {
|
||||
// 现阶段只核销人民币账单,与收款币种无关;核销上限为收款折算 CNY
|
||||
billPicker.rows = (res.data || []).filter(r => (r.currency || 'CNY') === 'CNY')
|
||||
nextTick(() => {
|
||||
billPickerTableRef.value?.clearSelection()
|
||||
const chosen = receiptDialog.form.writeoffPlans || []
|
||||
billPicker.rows.forEach(r => {
|
||||
if (chosen.some(p => p.arBillId === r.arBillId)) {
|
||||
billPickerTableRef.value?.toggleRowSelection(r, true)
|
||||
}
|
||||
})
|
||||
})
|
||||
}).finally(() => {
|
||||
billPicker.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
function onPickerSelectionChange(rows) {
|
||||
billPicker.selected = rows || []
|
||||
}
|
||||
|
||||
/** 确认选择:新增行默认核销额=min(账单未核销额CNY, 收款折算CNY剩余可用),保留已填金额 */
|
||||
function confirmBillPicker() {
|
||||
const oldMap = new Map((receiptDialog.form.writeoffPlans || []).map(p => [p.arBillId, p]))
|
||||
receiptDialog.form.writeoffPlans = billPicker.selected.map(r => {
|
||||
const existed = oldMap.get(r.arBillId)
|
||||
const unwritten = Number(r.unwrittenAmount) || 0
|
||||
const usedByOthers = receiptDialog.form.writeoffPlans
|
||||
.filter(p => p.arBillId !== r.arBillId)
|
||||
.reduce((s, p) => s + (Number(p.writeoffAmount) || 0), 0)
|
||||
const remainCny = Math.max(receiptBaseCny.value - usedByOthers, 0)
|
||||
return {
|
||||
arBillId: r.arBillId,
|
||||
billNo: r.billNo,
|
||||
billName: r.billName,
|
||||
currency: 'CNY',
|
||||
unwrittenAmount: unwritten,
|
||||
writeoffAmount: existed ? Number(existed.writeoffAmount) : Math.round(Math.min(unwritten, remainCny) * 100) / 100
|
||||
}
|
||||
})
|
||||
billPicker.visible = false
|
||||
}
|
||||
|
||||
function removeReceiptBill(index) {
|
||||
receiptDialog.form.writeoffPlans.splice(index, 1)
|
||||
}
|
||||
|
||||
/** 提交前校验核销账单(金额口径均为 CNY) */
|
||||
function validateReceiptWriteoffPlans() {
|
||||
const cap = receiptBaseCny.value
|
||||
const list = receiptDialog.form.writeoffPlans || []
|
||||
let total = 0
|
||||
for (const p of list) {
|
||||
const amt = Number(p.writeoffAmount)
|
||||
if (!amt || amt <= 0) {
|
||||
proxy.$modal.msgError(`账单【${p.billNo}】本次核销金额必须大于0`)
|
||||
return false
|
||||
}
|
||||
if (amt > Number(p.unwrittenAmount)) {
|
||||
proxy.$modal.msgError(`账单【${p.billNo}】核销金额超过其未核销金额`)
|
||||
return false
|
||||
}
|
||||
total += amt
|
||||
}
|
||||
if (Math.round(total * 100) > Math.round(cap * 100)) {
|
||||
proxy.$modal.msgError(`核销金额合计 ${total.toFixed(2)} CNY 超过收款折算本位币金额 ${cap.toFixed(2)} CNY`)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function submitReceipt() {
|
||||
receiptFormRef.value.validate(valid => {
|
||||
if (!valid) return
|
||||
@@ -1768,7 +1564,6 @@ function submitReceipt() {
|
||||
proxy.$modal.msgError(`请录入 ${cur} 对 CNY 的汇率(汇率表未配置时可手工填写)`)
|
||||
return
|
||||
}
|
||||
if (!validateReceiptWriteoffPlans()) return
|
||||
submitLoading.value = true
|
||||
addReceipt(receiptDialog.form).then(() => {
|
||||
proxy.$modal.msgSuccess("登记成功,等待审核")
|
||||
@@ -2106,10 +1901,9 @@ function loadBillWriteoffData() {
|
||||
|
||||
/* ---- 核销弹窗 ---- */
|
||||
const woSubmitLoading = ref(false)
|
||||
const woDialog = reactive({ visible: false, bill: null, form: {}, accountLoading: false })
|
||||
let writeoffAccountRequestSerial = 0
|
||||
const woDialog = reactive({ visible: false, bill: null, form: {} })
|
||||
|
||||
async function openWriteoffDialog(row) {
|
||||
function openWriteoffDialog(row) {
|
||||
const customerId = Number(route.query.customerId)
|
||||
if (!customerId) {
|
||||
proxy.$modal.msgError('缺少客户ID,无法发起核销')
|
||||
@@ -2127,27 +1921,9 @@ async function openWriteoffDialog(row) {
|
||||
remark: ''
|
||||
}
|
||||
woDialog.visible = true
|
||||
|
||||
// 仍刷新账户余额供展示,但不再限制核销金额
|
||||
const requestSerial = ++writeoffAccountRequestSerial
|
||||
woDialog.accountLoading = true
|
||||
try {
|
||||
const res = await listAccount(customerId)
|
||||
if (requestSerial !== writeoffAccountRequestSerial) return
|
||||
accountList.value = res.data || []
|
||||
} catch (e) {
|
||||
if (requestSerial !== writeoffAccountRequestSerial) return
|
||||
proxy.$modal.msgError('账户余额刷新失败,请稍后重试')
|
||||
} finally {
|
||||
if (requestSerial === writeoffAccountRequestSerial) woDialog.accountLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
function submitWriteoff() {
|
||||
if (woDialog.accountLoading) {
|
||||
proxy.$modal.msgWarning('正在刷新账户余额,请稍候')
|
||||
return
|
||||
}
|
||||
const bill = woDialog.bill
|
||||
const rawAmount = typeof woDialog.form.writeoffAmount === 'string'
|
||||
? woDialog.form.writeoffAmount.trim()
|
||||
@@ -2487,17 +2263,6 @@ watch(() => route.query.customerId, (newId, oldId) => {
|
||||
.writeoff-summary {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.receipt-wo-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.receipt-wo-summary {
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
}
|
||||
.wo-summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
<el-tab-pane label="绑定渠道" name="channel">
|
||||
<div class="pane-toolbar">
|
||||
<channel-select v-model="form.channelIds" />
|
||||
<span class="pane-tip">绑定结果以渠道编码逗号串存入供应商主表 channel_ids,渠道来源于老系统服务渠道镜像(每日自动同步)</span>
|
||||
<!-- <span class="pane-tip">绑定结果以渠道编码逗号串存入供应商主表 channel_ids,渠道来源于老系统服务渠道镜像(每日自动同步)</span>-->
|
||||
</div>
|
||||
<el-table :data="boundChannels" border size="small" class="bound-table">
|
||||
<el-table-column label="序号" type="index" width="55" align="center" />
|
||||
@@ -217,7 +217,7 @@
|
||||
<el-tab-pane label="公司主体" name="company">
|
||||
<div class="pane-toolbar">
|
||||
<el-button type="primary" plain icon="Plus" size="small" @click="handleAddCompany">新增公司主体</el-button>
|
||||
<span class="pane-tip">点击「绑定供应商」后,主表的统一社会信用代码会自动同步为该公司的信用代码</span>
|
||||
<!-- <span class="pane-tip">点击「绑定供应商」后,主表的统一社会信用代码会自动同步为该公司的信用代码</span>-->
|
||||
</div>
|
||||
<el-table :data="form.companyList" border size="small">
|
||||
<el-table-column label="序号" type="index" width="55" align="center" />
|
||||
|
||||
Reference in New Issue
Block a user