调整 合同、运力、基础配置、客商

This commit is contained in:
2026-09-14 23:43:00 +08:00
parent 70e44da789
commit 087d89b31a
33 changed files with 881 additions and 93 deletions
@@ -61,6 +61,10 @@ public class CustomerArchive extends TenantEntity {
@Schema(description = "客商性质")
private String customerNature;
@Schema(description = "是否广西百强:0否,1是")
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private Integer guangxiTop100;
@Schema(description = "统一社会信用代码")
private String unifiedCreditCode;
@@ -101,6 +105,10 @@ public class CustomerArchive extends TenantEntity {
@Schema(description = "经营范围")
private String businessScope;
@Schema(description = "网络货运平台:0否,1是")
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private Integer networkFreightPlatform;
@Schema(description = "营业期限类型")
private String businessTermType;
@@ -0,0 +1,71 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.transport.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
import java.io.Serial;
/**
* 客商发票联系信息实体类
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("blade_customer_invoice_contact")
@Schema(description = "客商发票联系信息")
public class CustomerInvoiceContact extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
@JsonSerialize(using = ToStringSerializer.class)
@Schema(description = "发票信息ID")
private Long invoiceId;
@Schema(description = "联系人")
private String contactName;
@Schema(description = "联系电话")
private String contactPhone;
@Schema(description = "邮箱地址")
private String email;
@Schema(description = "所属部门ID集合")
private String deptIds;
@Schema(description = "所属部门")
private String deptNames;
@Schema(description = "备注")
private String remark;
}
@@ -50,21 +50,15 @@ public class CustomerInvoiceInfo extends TenantEntity {
@Schema(description = "客商ID")
private Long customerId;
@Schema(description = "受票方名")
@Schema(description = "企业全")
private String invoiceTitle;
@Schema(description = "发票类型")
private String invoiceType;
@Schema(description = "纳税人识别号")
private String taxNo;
@Schema(description = "开户行名称")
private String bankName;
@Schema(description = "注册电话")
private String registeredPhone;
@Schema(description = "银行账号")
private String bankAccount;
@@ -77,24 +71,6 @@ public class CustomerInvoiceInfo extends TenantEntity {
@Schema(description = "注册地址详细地址")
private String registeredDetailAddress;
@Schema(description = "邮箱")
private String email;
@Schema(description = "收件人姓名")
private String receiverName;
@Schema(description = "收件人电话")
private String receiverPhone;
@Schema(description = "收件人地址")
private String receiverAddress;
@Schema(description = "收件人地址行政区划")
private String receiverRegionName;
@Schema(description = "收件人详细地址")
private String receiverDetailAddress;
@Schema(description = "是否默认")
private Integer isDefault;
@@ -52,6 +52,11 @@ public class InsuranceOcrTemplate extends TenantEntity {
@Schema(description = "模板名称")
private String name;
/** 车船类型:车辆/船舶。 */
@TableField("vehicle_type")
@Schema(description = "车船类型:车辆/船舶")
private String vehicleType;
/** 字段映射配置JSON。 */
@TableField("mapping_config")
@Schema(description = "字段映射配置JSON")
@@ -0,0 +1,55 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.transport.pojo.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 年检记录有效期统计
*
* @author Chill
*/
@Data
@Schema(description = "年检记录有效期统计")
public class AnnualInspectionRecordExpiryStatVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "全部")
private Long total;
@Schema(description = "30天内")
private Long within30;
@Schema(description = "已过期")
private Long expired;
}
@@ -72,4 +72,18 @@ public class AnnualInspectionRecordVO extends AnnualInspectionRecord {
@Schema(description = "更新人姓名")
private String updateUserName;
@TableField(exist = false)
@Schema(description = "有效期状态:within30-30天内,expired-已过期")
private String expireStatus;
@TableField(exist = false)
@Schema(description = "当天日期")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate today;
@TableField(exist = false)
@Schema(description = "预警截止日期")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate warningDate;
}
@@ -77,4 +77,12 @@ public class CustomerArchiveVO extends CustomerArchive {
@Schema(description = "变更记录")
private List<CustomerChangeRecordVO> changeRecords = new ArrayList<>();
@TableField(exist = false)
@Schema(description = "是否保存变更记录(仅提交时为 true,保存时不记录)")
private Boolean recordChange;
@TableField(exist = false)
@Schema(description = "客商类型:external外部客商,internal内部组织")
private String customerKind;
}
@@ -0,0 +1,45 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.transport.pojo.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.transport.pojo.entity.CustomerInvoiceContact;
import java.io.Serial;
/**
* 客商发票联系信息视图实体类
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "客商发票联系信息")
public class CustomerInvoiceContactVO extends CustomerInvoiceContact {
@Serial
private static final long serialVersionUID = 1L;
}
@@ -22,12 +22,15 @@
*/
package org.springblade.transport.pojo.vo;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.transport.pojo.entity.CustomerInvoiceInfo;
import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
/**
* 客商发票信息视图实体类
@@ -42,4 +45,8 @@ public class CustomerInvoiceInfoVO extends CustomerInvoiceInfo {
@Serial
private static final long serialVersionUID = 1L;
@TableField(exist = false)
@Schema(description = "联系信息")
private List<CustomerInvoiceContactVO> contacts = new ArrayList<>();
}
@@ -136,7 +136,10 @@ public class DictBizServiceImpl extends ServiceImpl<DictBizMapper, DictBiz> impl
@Override
public IPage<DictBizVO> parentList(Map<String, Object> dict, Query query) {
IPage<DictBiz> page = this.page(Condition.getPage(query), Condition.getQueryWrapper(dict, DictBiz.class).lambda().eq(DictBiz::getParentId, CommonConstant.TOP_PARENT_ID).orderByAsc(DictBiz::getSort));
IPage<DictBiz> page = this.page(Condition.getPage(query), Condition.getQueryWrapper(dict, DictBiz.class).lambda()
.eq(DictBiz::getParentId, CommonConstant.TOP_PARENT_ID)
.orderByAsc(DictBiz::getSort)
.orderByDesc(DictBiz::getId));
return DictBizWrapper.build().pageVO(page);
}
@@ -123,7 +123,10 @@ public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements ID
@Override
public IPage<DictVO> parentList(Map<String, Object> dict, Query query) {
IPage<Dict> page = this.page(Condition.getPage(query), Condition.getQueryWrapper(dict, Dict.class).lambda().eq(Dict::getParentId, CommonConstant.TOP_PARENT_ID).orderByAsc(Dict::getSort));
IPage<Dict> page = this.page(Condition.getPage(query), Condition.getQueryWrapper(dict, Dict.class).lambda()
.eq(Dict::getParentId, CommonConstant.TOP_PARENT_ID)
.orderByAsc(Dict::getSort)
.orderByDesc(Dict::getId));
return DictWrapper.build().pageVO(page);
}
@@ -47,6 +47,7 @@ import org.springblade.transport.excel.AnnualInspectionRecordExcel;
import org.springblade.transport.excel.AnnualInspectionRecordExportExcel;
import org.springblade.transport.excel.AnnualInspectionRecordImporter;
import org.springblade.transport.pojo.entity.AnnualInspectionRecord;
import org.springblade.transport.pojo.vo.AnnualInspectionRecordExpiryStatVO;
import org.springblade.transport.pojo.vo.AnnualInspectionRecordVO;
import org.springblade.transport.service.IAnnualInspectionRecordService;
import org.springblade.transport.wrapper.AnnualInspectionRecordWrapper;
@@ -58,6 +59,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
@@ -91,6 +93,7 @@ public class AnnualInspectionRecordController extends BladeController {
@ApiOperationSupport(order = 2)
@Operation(summary = "分页", description = "传入annualInspectionRecord")
public R<IPage<AnnualInspectionRecordVO>> list(AnnualInspectionRecordVO annualInspectionRecord, Query query) {
fillExpiryDate(annualInspectionRecord);
IPage<AnnualInspectionRecordVO> pages = annualInspectionRecordService.selectAnnualInspectionRecordPage(Condition.getPage(normalizeQuery(query)), annualInspectionRecord);
return R.data(pages);
}
@@ -109,8 +112,17 @@ public class AnnualInspectionRecordController extends BladeController {
return R.status(annualInspectionRecordService.deleteLogic(Func.toLongList(ids)));
}
@PostMapping("/import-annual-inspection-record")
@GetMapping("/expiry-stat")
@ApiOperationSupport(order = 5)
@Operation(summary = "有效期统计", description = "传入annualInspectionRecord")
public R<AnnualInspectionRecordExpiryStatVO> expiryStat(AnnualInspectionRecordVO annualInspectionRecord) {
fillExpiryDate(annualInspectionRecord);
annualInspectionRecord.setExpireStatus(null);
return R.data(annualInspectionRecordService.expiryStat(annualInspectionRecord));
}
@PostMapping("/import-annual-inspection-record")
@ApiOperationSupport(order = 6)
@Operation(summary = "导入年检记录", description = "传入excel")
public R importAnnualInspectionRecord(MultipartFile file, HttpServletResponse response) {
List<AnnualInspectionRecordExcel> failureList = annualInspectionRecordService.importAnnualInspectionRecord(ExcelUtil.read(file, AnnualInspectionRecordExcel.class));
@@ -122,17 +134,18 @@ public class AnnualInspectionRecordController extends BladeController {
}
@GetMapping("/export-annual-inspection-record")
@ApiOperationSupport(order = 6)
@ApiOperationSupport(order = 7)
@Operation(summary = "导出年检记录")
public void exportAnnualInspectionRecord(AnnualInspectionRecordVO annualInspectionRecord,
@RequestParam(required = false) String ids,
HttpServletResponse response) {
fillExpiryDate(annualInspectionRecord);
List<AnnualInspectionRecordExportExcel> list = annualInspectionRecordService.exportAnnualInspectionRecord(buildExportQuery(annualInspectionRecord, ids));
ExcelUtil.export(response, "年检记录" + DateUtil.time(), "年检记录表", list, AnnualInspectionRecordExportExcel.class);
}
@GetMapping("/export-template")
@ApiOperationSupport(order = 7)
@ApiOperationSupport(order = 8)
@Operation(summary = "导出模板")
public void exportTemplate(HttpServletResponse response) {
List<AnnualInspectionRecordExcel> list = new ArrayList<>();
@@ -155,6 +168,15 @@ public class AnnualInspectionRecordController extends BladeController {
return query;
}
private void fillExpiryDate(AnnualInspectionRecordVO annualInspectionRecord) {
if (annualInspectionRecord.getToday() == null) {
annualInspectionRecord.setToday(LocalDate.now());
}
if (annualInspectionRecord.getWarningDate() == null) {
annualInspectionRecord.setWarningDate(annualInspectionRecord.getToday().plusDays(30));
}
}
private LambdaQueryWrapper<AnnualInspectionRecord> buildExportQuery(AnnualInspectionRecordVO annualInspectionRecord, String ids) {
LambdaQueryWrapper<AnnualInspectionRecord> queryWrapper = Wrappers.<AnnualInspectionRecord>lambdaQuery()
.eq(AnnualInspectionRecord::getIsDeleted, 0)
@@ -183,6 +205,15 @@ public class AnnualInspectionRecordController extends BladeController {
if (Func.isNotEmpty(annualInspectionRecord.getCreateTimeEnd())) {
queryWrapper.le(AnnualInspectionRecord::getCreateTime, annualInspectionRecord.getCreateTimeEnd());
}
if ("within30".equals(annualInspectionRecord.getExpireStatus())) {
queryWrapper.isNotNull(AnnualInspectionRecord::getValidUntilDate)
.ge(AnnualInspectionRecord::getValidUntilDate, annualInspectionRecord.getToday())
.le(AnnualInspectionRecord::getValidUntilDate, annualInspectionRecord.getWarningDate());
}
if ("expired".equals(annualInspectionRecord.getExpireStatus())) {
queryWrapper.isNotNull(AnnualInspectionRecord::getValidUntilDate)
.lt(AnnualInspectionRecord::getValidUntilDate, annualInspectionRecord.getToday());
}
return queryWrapper;
}
@@ -27,7 +27,9 @@ package org.springblade.transport.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Param;
import org.springblade.transport.pojo.entity.AnnualInspectionRecord;
import org.springblade.transport.pojo.vo.AnnualInspectionRecordExpiryStatVO;
import org.springblade.transport.pojo.vo.AnnualInspectionRecordVO;
import java.util.List;
@@ -46,6 +48,14 @@ public interface AnnualInspectionRecordMapper extends BaseMapper<AnnualInspectio
* @param annualInspectionRecord 查询参数
* @return 年检记录分页
*/
List<AnnualInspectionRecordVO> selectAnnualInspectionRecordPage(IPage<AnnualInspectionRecordVO> page, AnnualInspectionRecordVO annualInspectionRecord);
List<AnnualInspectionRecordVO> selectAnnualInspectionRecordPage(IPage<AnnualInspectionRecordVO> page, @Param("annualInspectionRecord") AnnualInspectionRecordVO annualInspectionRecord);
/**
* 有效期统计
*
* @param annualInspectionRecord 查询参数
* @return 统计结果
*/
AnnualInspectionRecordExpiryStatVO selectExpiryStat(@Param("annualInspectionRecord") AnnualInspectionRecordVO annualInspectionRecord);
}
@@ -26,6 +26,49 @@
<result column="remark" property="remark"/>
</resultMap>
<sql id="ExpiryWithin30Condition">
valid_until_date IS NOT NULL
AND valid_until_date &gt;= #{annualInspectionRecord.today}
AND valid_until_date &lt;= #{annualInspectionRecord.warningDate}
</sql>
<sql id="ExpiryExpiredCondition">
valid_until_date IS NOT NULL
AND valid_until_date &lt; #{annualInspectionRecord.today}
</sql>
<sql id="QueryCondition">
is_deleted = 0
<if test="annualInspectionRecord.createDept != null">
AND create_dept = #{annualInspectionRecord.createDept}
</if>
<if test="annualInspectionRecord.vehicleType != null and annualInspectionRecord.vehicleType != ''">
AND vehicle_type = #{annualInspectionRecord.vehicleType}
</if>
<if test="annualInspectionRecord.vehicleNo != null and annualInspectionRecord.vehicleNo != ''">
<bind name="vehicleNoLike" value="'%' + annualInspectionRecord.vehicleNo + '%'"/>
AND vehicle_no LIKE #{vehicleNoLike}
</if>
<if test="annualInspectionRecord.inspectionAssessmentDateStart != null">
AND inspection_assessment_date &gt;= #{annualInspectionRecord.inspectionAssessmentDateStart}
</if>
<if test="annualInspectionRecord.inspectionAssessmentDateEnd != null">
AND inspection_assessment_date &lt;= #{annualInspectionRecord.inspectionAssessmentDateEnd}
</if>
<if test="annualInspectionRecord.createTimeStart != null">
AND create_time &gt;= #{annualInspectionRecord.createTimeStart}
</if>
<if test="annualInspectionRecord.createTimeEnd != null">
AND create_time &lt;= #{annualInspectionRecord.createTimeEnd}
</if>
<if test="annualInspectionRecord.expireStatus != null and annualInspectionRecord.expireStatus == 'within30'">
AND <include refid="ExpiryWithin30Condition"/>
</if>
<if test="annualInspectionRecord.expireStatus != null and annualInspectionRecord.expireStatus == 'expired'">
AND <include refid="ExpiryExpiredCondition"/>
</if>
</sql>
<select id="selectAnnualInspectionRecordPage" resultMap="annualInspectionRecordResultMap">
SELECT
id,
@@ -52,30 +95,19 @@
FROM
blade_annual_inspection_record
WHERE
is_deleted = 0
<if test="annualInspectionRecord.createDept != null">
AND create_dept = #{annualInspectionRecord.createDept}
</if>
<if test="annualInspectionRecord.vehicleType != null and annualInspectionRecord.vehicleType != ''">
AND vehicle_type = #{annualInspectionRecord.vehicleType}
</if>
<if test="annualInspectionRecord.vehicleNo != null and annualInspectionRecord.vehicleNo != ''">
<bind name="vehicleNoLike" value="'%' + annualInspectionRecord.vehicleNo + '%'"/>
AND vehicle_no LIKE #{vehicleNoLike}
</if>
<if test="annualInspectionRecord.inspectionAssessmentDateStart != null">
AND inspection_assessment_date &gt;= #{annualInspectionRecord.inspectionAssessmentDateStart}
</if>
<if test="annualInspectionRecord.inspectionAssessmentDateEnd != null">
AND inspection_assessment_date &lt;= #{annualInspectionRecord.inspectionAssessmentDateEnd}
</if>
<if test="annualInspectionRecord.createTimeStart != null">
AND create_time &gt;= #{annualInspectionRecord.createTimeStart}
</if>
<if test="annualInspectionRecord.createTimeEnd != null">
AND create_time &lt;= #{annualInspectionRecord.createTimeEnd}
</if>
<include refid="QueryCondition"/>
ORDER BY create_time DESC
</select>
<select id="selectExpiryStat" resultType="org.springblade.transport.pojo.vo.AnnualInspectionRecordExpiryStatVO">
SELECT
COUNT(1) AS total,
SUM(CASE WHEN <include refid="ExpiryWithin30Condition"/> THEN 1 ELSE 0 END) AS within30,
SUM(CASE WHEN <include refid="ExpiryExpiredCondition"/> THEN 1 ELSE 0 END) AS expired
FROM
blade_annual_inspection_record
WHERE
<include refid="QueryCondition"/>
</select>
</mapper>
@@ -16,6 +16,7 @@
<result column="short_name" property="shortName"/>
<result column="full_name" property="fullName"/>
<result column="customer_nature" property="customerNature"/>
<result column="guangxi_top100" property="guangxiTop100"/>
<result column="unified_credit_code" property="unifiedCreditCode"/>
<result column="customer_type" property="customerType"/>
<result column="project_name" property="projectName"/>
@@ -29,6 +30,7 @@
<result column="dept_name" property="deptName"/>
<result column="invoice_tax_rate" property="invoiceTaxRate"/>
<result column="business_scope" property="businessScope"/>
<result column="network_freight_platform" property="networkFreightPlatform"/>
<result column="business_term_type" property="businessTermType"/>
<result column="business_end_date" property="businessEndDate"/>
<result column="registered_capital" property="registeredCapital"/>
@@ -61,6 +63,7 @@
short_name,
full_name,
customer_nature,
guangxi_top100,
unified_credit_code,
customer_type,
project_name,
@@ -74,6 +77,7 @@
dept_name,
invoice_tax_rate,
business_scope,
network_freight_platform,
business_term_type,
business_end_date,
registered_capital,
@@ -0,0 +1,21 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.transport.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springblade.transport.pojo.entity.CustomerInvoiceContact;
/**
* 客商发票联系信息 Mapper 接口
*
* @author Chill
*/
public interface CustomerInvoiceContactMapper extends BaseMapper<CustomerInvoiceContact> {
}
@@ -31,6 +31,7 @@ import org.springblade.core.mp.base.BaseService;
import org.springblade.transport.excel.AnnualInspectionRecordExcel;
import org.springblade.transport.excel.AnnualInspectionRecordExportExcel;
import org.springblade.transport.pojo.entity.AnnualInspectionRecord;
import org.springblade.transport.pojo.vo.AnnualInspectionRecordExpiryStatVO;
import org.springblade.transport.pojo.vo.AnnualInspectionRecordVO;
import java.util.List;
@@ -44,6 +45,8 @@ public interface IAnnualInspectionRecordService extends BaseService<AnnualInspec
IPage<AnnualInspectionRecordVO> selectAnnualInspectionRecordPage(IPage<AnnualInspectionRecordVO> page, AnnualInspectionRecordVO annualInspectionRecord);
AnnualInspectionRecordExpiryStatVO expiryStat(AnnualInspectionRecordVO annualInspectionRecord);
boolean submit(AnnualInspectionRecord annualInspectionRecord);
List<AnnualInspectionRecordExcel> importAnnualInspectionRecord(List<AnnualInspectionRecordExcel> data);
@@ -68,6 +68,7 @@ public interface ICustomerArchiveService extends BaseService<CustomerArchive> {
/**
* 新增或修改客商档案
* <p>仅当 {@code customer.recordChange = true}(前端点「提交」)时写入变更记录;「保存」不落变更记录。</p>
*
* @param customer 客商档案
* @return 是否成功
@@ -36,13 +36,13 @@ import org.springblade.transport.excel.AnnualInspectionRecordExcel;
import org.springblade.transport.excel.AnnualInspectionRecordExportExcel;
import org.springblade.transport.mapper.AnnualInspectionRecordMapper;
import org.springblade.transport.pojo.entity.AnnualInspectionRecord;
import org.springblade.transport.pojo.vo.AnnualInspectionRecordExpiryStatVO;
import org.springblade.transport.pojo.vo.AnnualInspectionRecordVO;
import org.springblade.transport.service.IAnnualInspectionRecordService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -74,6 +74,24 @@ public class AnnualInspectionRecordServiceImpl extends BaseServiceImpl<AnnualIns
return page.setRecords(records);
}
@Override
public AnnualInspectionRecordExpiryStatVO expiryStat(AnnualInspectionRecordVO annualInspectionRecord) {
AnnualInspectionRecordExpiryStatVO stat = baseMapper.selectExpiryStat(annualInspectionRecord);
if (stat == null) {
stat = new AnnualInspectionRecordExpiryStatVO();
}
if (stat.getTotal() == null) {
stat.setTotal(0L);
}
if (stat.getWithin30() == null) {
stat.setWithin30(0L);
}
if (stat.getExpired() == null) {
stat.setExpired(0L);
}
return stat;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean submit(AnnualInspectionRecord annualInspectionRecord) {
@@ -131,6 +149,7 @@ public class AnnualInspectionRecordServiceImpl extends BaseServiceImpl<AnnualIns
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, SHIP.equals(annualInspectionRecord.getVehicleType()) && Func.isEmpty(annualInspectionRecord.getShipInspectionType()), "船舶检验类型不能为空");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(annualInspectionRecord.getPassengerTypeLevel()) && !PASSENGER_TYPE_LEVELS.contains(annualInspectionRecord.getPassengerTypeLevel()), "客车类型及等级不正确");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(annualInspectionRecord.getValidUntilDate()), "有效期截止日不能为空");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(annualInspectionRecord.getInspectionAssessmentDate()), "检测评定日期不能为空");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(annualInspectionRecord.getValidUntilDate()) && Func.isNotEmpty(annualInspectionRecord.getInspectionAssessmentDate()) && !annualInspectionRecord.getValidUntilDate().isAfter(annualInspectionRecord.getInspectionAssessmentDate()), "有效期截止日应大于检测评定日期");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(annualInspectionRecord.getFee()), "费用不能为空");
org.springblade.common.excel.ImportFailureExcelUtil.addLengthValidationError(validationErrors, annualInspectionRecord.getVehicleNo(), VEHICLE_NO_MAX_LENGTH, "车牌号/船号不能超过30字");
@@ -170,9 +189,6 @@ public class AnnualInspectionRecordServiceImpl extends BaseServiceImpl<AnnualIns
annualInspectionRecord.setAssessmentUnit(trimToNull(annualInspectionRecord.getAssessmentUnit()));
annualInspectionRecord.setAttachments(trimToNull(annualInspectionRecord.getAttachments()));
annualInspectionRecord.setRemark(trimToNull(annualInspectionRecord.getRemark()));
if (annualInspectionRecord.getInspectionAssessmentDate() == null) {
annualInspectionRecord.setInspectionAssessmentDate(LocalDate.now());
}
if (VEHICLE.equals(annualInspectionRecord.getVehicleType())) {
annualInspectionRecord.setShipInspectionType(null);
} else {
@@ -203,6 +219,9 @@ public class AnnualInspectionRecordServiceImpl extends BaseServiceImpl<AnnualIns
if (Func.isEmpty(annualInspectionRecord.getValidUntilDate())) {
throw new ServiceException("有效期截止日不能为空");
}
if (Func.isEmpty(annualInspectionRecord.getInspectionAssessmentDate())) {
throw new ServiceException("检测评定日期不能为空");
}
if (!annualInspectionRecord.getValidUntilDate().isAfter(annualInspectionRecord.getInspectionAssessmentDate())) {
throw new ServiceException("有效期截止日应大于检测评定日期");
}
@@ -121,6 +121,16 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
@Override
@Transactional(rollbackFor = Exception.class)
public boolean submit(ContractManage contractManage) {
// 变更驳回后从编辑页提交,应重新进入变更审批,不能走临时合同提交流程。
if (Func.isNotEmpty(contractManage.getId())) {
ContractManage existing = loadExists(contractManage.getId());
if (Objects.equals(existing.getApprovalStatus(), STATUS_CHANGE_REJECTED)) {
if (Func.isEmpty(TransportBusinessSupport.trimToNull(contractManage.getChangeReason()))) {
contractManage.setChangeReason(resolveResubmitChangeReason(existing));
}
return submitChange(contractManage);
}
}
prepare(contractManage);
validateDraft(contractManage);
validateTemporary(contractManage);
@@ -262,6 +272,9 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
}
TransportBusinessSupport.validateRequired(request.getSettlementCurrency(), "请选择结算币种");
String changeReason = TransportBusinessSupport.trimToNull(request.getChangeReason());
if (Func.isEmpty(changeReason) && Objects.equals(source.getApprovalStatus(), STATUS_CHANGE_REJECTED)) {
changeReason = resolveResubmitChangeReason(source);
}
TransportBusinessSupport.validateRequired(changeReason, "请输入变更原因");
TransportBusinessSupport.validateLength(changeReason, 500, "变更原因不能超过500字");
ContractManage candidate = new ContractManage();
@@ -848,7 +861,8 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
private ContractManage loadEditable(Long id) {
ContractManage contractManage = loadExists(id);
if (!List.of(STATUS_DRAFT, STATUS_WITHDRAWN, STATUS_REJECTED).contains(contractManage.getApprovalStatus())) {
if (!List.of(STATUS_DRAFT, STATUS_WITHDRAWN, STATUS_REJECTED, STATUS_CHANGE_REJECTED)
.contains(contractManage.getApprovalStatus())) {
throw new ServiceException("当前状态不允许编辑");
}
if (!canOperateInCurrentScope(contractManage)) {
@@ -857,6 +871,21 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
return contractManage;
}
/**
* 变更驳回后重新提交时,优先沿用最近一次变更原因。
*/
private String resolveResubmitChangeReason(ContractManage contractManage) {
List<Map<String, Object>> records = parseChangeRecords(contractManage.getChangeRecordJson());
for (int index = records.size() - 1; index >= 0; index--) {
String changeReason = TransportBusinessSupport.trimToNull(
records.get(index).get("changeReason") == null ? null : String.valueOf(records.get(index).get("changeReason")));
if (Func.isNotEmpty(changeReason)) {
return changeReason;
}
}
return "重新提交变更";
}
private boolean canResubmitTemporary(ContractManage contractManage) {
String stage = contractManage.getContractStage();
String status = contractManage.getApprovalStatus();
@@ -46,6 +46,7 @@ import org.springblade.transport.mapper.CustomerChangeRecordMapper;
import org.springblade.transport.mapper.CustomerContactMapper;
import org.springblade.transport.mapper.CustomerCreditScoreDetailMapper;
import org.springblade.transport.mapper.CustomerCreditScoreMapper;
import org.springblade.transport.mapper.CustomerInvoiceContactMapper;
import org.springblade.transport.mapper.CustomerInvoiceInfoMapper;
import org.springblade.transport.mapper.CustomerReceiptAccountMapper;
import org.springblade.transport.mapper.UserCustomerScopeMapper;
@@ -59,6 +60,7 @@ import org.springblade.transport.pojo.entity.CustomerChangeRecord;
import org.springblade.transport.pojo.entity.CustomerContact;
import org.springblade.transport.pojo.entity.CustomerCreditScore;
import org.springblade.transport.pojo.entity.CustomerCreditScoreDetail;
import org.springblade.transport.pojo.entity.CustomerInvoiceContact;
import org.springblade.transport.pojo.entity.CustomerInvoiceInfo;
import org.springblade.transport.pojo.entity.CustomerReceiptAccount;
import org.springblade.transport.pojo.vo.CustomerArchiveVO;
@@ -67,6 +69,7 @@ import org.springblade.transport.pojo.vo.CustomerContactVO;
import org.springblade.transport.pojo.vo.CustomerCreditScoreDetailVO;
import org.springblade.transport.pojo.vo.CustomerCreditScoreVO;
import org.springblade.transport.pojo.vo.CreditRatingStandardVO;
import org.springblade.transport.pojo.vo.CustomerInvoiceContactVO;
import org.springblade.transport.pojo.vo.CustomerInvoiceInfoVO;
import org.springblade.transport.pojo.vo.CustomerReceiptAccountVO;
import org.springblade.transport.service.ICustomerArchiveService;
@@ -108,6 +111,7 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
private final CustomerContactMapper contactMapper;
private final CustomerReceiptAccountMapper receiptAccountMapper;
private final CustomerInvoiceInfoMapper invoiceInfoMapper;
private final CustomerInvoiceContactMapper invoiceContactMapper;
private final CustomerCreditScoreMapper creditScoreMapper;
private final CustomerCreditScoreDetailMapper creditScoreDetailMapper;
private final CustomerChangeRecordMapper changeRecordMapper;
@@ -173,7 +177,8 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
if (created && result) {
grantNewCustomerToIncludedUsers(entity);
}
if (result && !created) {
// 仅「提交」写入变更记录;「保存」不落变更记录
if (result && !created && Boolean.TRUE.equals(customer.getRecordChange())) {
addChangeRecord(entity.getId(), "修改客商档案", before, entity, beforeDetail, customer);
}
return result;
@@ -292,6 +297,7 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
customer.setShortName(trimToNull(customer.getShortName()));
customer.setFullName(trimToEmpty(customer.getFullName()));
customer.setCustomerNature(trimToEmpty(customer.getCustomerNature()));
customer.setGuangxiTop100(normalizeYesNoFlag(customer.getGuangxiTop100()));
customer.setUnifiedCreditCode(trimToEmpty(customer.getUnifiedCreditCode()));
customer.setCustomerType(trimToEmpty(customer.getCustomerType()));
customer.setBusinessScope(trimToNull(customer.getBusinessScope()));
@@ -428,7 +434,7 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
deleteDetail(List.of(customerId), false);
insertContacts(customerId, customer.getContacts());
insertReceiptAccounts(customerId, customer.getReceiptAccounts());
insertInvoices(customerId, customer.getInvoices());
insertInvoices(customerId, customer);
if (Func.isNotEmpty(customer.getScores())) {
deleteScores(List.of(customerId));
insertScores(customerId, customer.getScores());
@@ -461,27 +467,111 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
}
}
private void insertInvoices(Long customerId, List<CustomerInvoiceInfoVO> invoices) {
private void insertInvoices(Long customerId, CustomerArchiveVO customer) {
List<CustomerInvoiceInfoVO> invoices = customer.getInvoices();
if (Func.isEmpty(invoices)) {
return;
}
boolean internal = isInternalCustomer(customer);
for (CustomerInvoiceInfoVO invoiceVO : invoices) {
if (Func.isEmpty(invoiceVO.getInvoiceTitle()) && Func.isEmpty(invoiceVO.getTaxNo())) {
continue;
}
if (Func.isEmpty(invoiceVO.getInvoiceType())) {
throw new ServiceException("发票类型不能为空");
if (Func.isEmpty(invoiceVO.getInvoiceTitle())) {
throw new ServiceException("企业全称不能为空");
}
if (!List.of("增值税专用发票", "普通发票").contains(invoiceVO.getInvoiceType())) {
throw new ServiceException("发票类型不合法");
if (Func.isEmpty(invoiceVO.getTaxNo())) {
throw new ServiceException("纳税人识别号不能为空");
}
if (Func.isEmpty(invoiceVO.getBankName())) {
throw new ServiceException("开户行名称不能为空");
}
if (Func.isEmpty(invoiceVO.getBankAccount())) {
throw new ServiceException("银行账号不能为空");
}
if (Func.isEmpty(invoiceVO.getRegisteredRegionName()) && Func.isEmpty(invoiceVO.getRegisteredAddress())) {
throw new ServiceException("注册地址不能为空");
}
if (Func.isEmpty(invoiceVO.getRegisteredDetailAddress())) {
throw new ServiceException("详细地址不能为空");
}
invoiceVO.setRegisteredAddress(buildAddress(invoiceVO.getRegisteredRegionName(), invoiceVO.getRegisteredDetailAddress(), invoiceVO.getRegisteredAddress()));
invoiceVO.setReceiverAddress(buildAddress(invoiceVO.getReceiverRegionName(), invoiceVO.getReceiverDetailAddress(), invoiceVO.getReceiverAddress()));
CustomerInvoiceInfo invoice = Objects.requireNonNull(BeanUtil.copyProperties(invoiceVO, CustomerInvoiceInfo.class));
invoice.setId(IdWorker.getId());
invoice.setCustomerId(customerId);
invoice.setStatus(STATUS_ENABLED);
invoiceInfoMapper.insert(invoice);
insertInvoiceContacts(invoice.getId(), invoiceVO.getContacts(), internal, customer);
}
}
private void insertInvoiceContacts(Long invoiceId, List<CustomerInvoiceContactVO> contacts, boolean internal,
CustomerArchiveVO customer) {
if (Func.isEmpty(contacts)) {
return;
}
for (CustomerInvoiceContactVO contactVO : contacts) {
if (isBlankInvoiceContact(contactVO)) {
continue;
}
if (Func.isEmpty(contactVO.getContactName())) {
throw new ServiceException("发票联系人不能为空");
}
if (Func.isEmpty(contactVO.getContactPhone())) {
throw new ServiceException("发票联系电话不能为空");
}
validateInvoiceContactEmail(contactVO.getEmail());
if (Func.isNotEmpty(contactVO.getRemark()) && contactVO.getRemark().length() > 200) {
throw new ServiceException("发票联系信息备注最多200个字");
}
if (internal && Func.isEmpty(contactVO.getDeptIds()) && Func.isEmpty(contactVO.getDeptNames())) {
throw new ServiceException("内部组织客商必须选择发票联系信息所属部门");
}
if (!internal) {
if (Func.isEmpty(contactVO.getDeptIds())) {
contactVO.setDeptIds(customer.getDeptIds());
}
if (Func.isEmpty(contactVO.getDeptNames())) {
contactVO.setDeptNames(Func.isNotEmpty(customer.getFullName()) ? customer.getFullName() : customer.getDeptName());
}
}
CustomerInvoiceContact contact = Objects.requireNonNull(BeanUtil.copyProperties(contactVO, CustomerInvoiceContact.class));
contact.setId(IdWorker.getId());
contact.setInvoiceId(invoiceId);
contact.setStatus(STATUS_ENABLED);
invoiceContactMapper.insert(contact);
}
}
private boolean isBlankInvoiceContact(CustomerInvoiceContactVO contactVO) {
return Func.isEmpty(contactVO.getContactName())
&& Func.isEmpty(contactVO.getContactPhone())
&& Func.isEmpty(contactVO.getEmail())
&& Func.isEmpty(contactVO.getDeptIds())
&& Func.isEmpty(contactVO.getDeptNames())
&& Func.isEmpty(contactVO.getRemark());
}
private void validateInvoiceContactEmail(String email) {
if (Func.isEmpty(email)) {
return;
}
if (email.length() > 100) {
throw new ServiceException("发票联系邮箱不能超过100个字");
}
if (!email.matches("^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$")) {
throw new ServiceException("发票联系邮箱格式不正确");
}
}
private boolean isInternalCustomer(CustomerArchiveVO customer) {
String customerKind = customer.getCustomerKind();
if (Func.isNotEmpty(customerKind)) {
return "internal".equals(customerKind) || "内部组织".equals(customerKind);
}
return "internal".equals(customer.getCustomerNature()) || "内部组织".equals(customer.getCustomerNature());
}
private void insertScores(Long customerId, List<CustomerCreditScoreVO> scores) {
for (CustomerCreditScoreVO scoreVO : scores) {
if (Func.isEmpty(scoreVO.getQuantificationId()) && Func.isEmpty(scoreVO.getScoreDate())) {
@@ -529,6 +619,15 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
private void deleteDetail(List<Long> customerIds, boolean deleteScores) {
contactMapper.update(null, Wrappers.<CustomerContact>lambdaUpdate().in(CustomerContact::getCustomerId, customerIds).set(CustomerContact::getIsDeleted, 1));
receiptAccountMapper.update(null, Wrappers.<CustomerReceiptAccount>lambdaUpdate().in(CustomerReceiptAccount::getCustomerId, customerIds).set(CustomerReceiptAccount::getIsDeleted, 1));
List<CustomerInvoiceInfo> invoices = invoiceInfoMapper.selectList(Wrappers.<CustomerInvoiceInfo>lambdaQuery()
.in(CustomerInvoiceInfo::getCustomerId, customerIds)
.eq(CustomerInvoiceInfo::getIsDeleted, 0));
if (Func.isNotEmpty(invoices)) {
List<Long> invoiceIds = invoices.stream().map(CustomerInvoiceInfo::getId).toList();
invoiceContactMapper.update(null, Wrappers.<CustomerInvoiceContact>lambdaUpdate()
.in(CustomerInvoiceContact::getInvoiceId, invoiceIds)
.set(CustomerInvoiceContact::getIsDeleted, 1));
}
invoiceInfoMapper.update(null, Wrappers.<CustomerInvoiceInfo>lambdaUpdate().in(CustomerInvoiceInfo::getCustomerId, customerIds).set(CustomerInvoiceInfo::getIsDeleted, 1));
if (deleteScores) {
deleteScores(customerIds);
@@ -565,12 +664,27 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
}
private List<CustomerInvoiceInfoVO> loadInvoices(Long customerId) {
return invoiceInfoMapper.selectList(Wrappers.<CustomerInvoiceInfo>lambdaQuery()
.eq(CustomerInvoiceInfo::getCustomerId, customerId)
.eq(CustomerInvoiceInfo::getIsDeleted, 0)
.orderByDesc(CustomerInvoiceInfo::getIsDefault)
.orderByAsc(CustomerInvoiceInfo::getCreateTime))
.stream().map(invoice -> Objects.requireNonNull(BeanUtil.copyProperties(invoice, CustomerInvoiceInfoVO.class))).toList();
List<CustomerInvoiceInfo> invoices = invoiceInfoMapper.selectList(Wrappers.<CustomerInvoiceInfo>lambdaQuery()
.eq(CustomerInvoiceInfo::getCustomerId, customerId)
.eq(CustomerInvoiceInfo::getIsDeleted, 0)
.orderByDesc(CustomerInvoiceInfo::getIsDefault)
.orderByAsc(CustomerInvoiceInfo::getCreateTime));
if (Func.isEmpty(invoices)) {
return new ArrayList<>();
}
List<Long> invoiceIds = invoices.stream().map(CustomerInvoiceInfo::getId).toList();
Map<Long, List<CustomerInvoiceContactVO>> contactMap = invoiceContactMapper.selectList(Wrappers.<CustomerInvoiceContact>lambdaQuery()
.in(CustomerInvoiceContact::getInvoiceId, invoiceIds)
.eq(CustomerInvoiceContact::getIsDeleted, 0)
.orderByAsc(CustomerInvoiceContact::getCreateTime))
.stream()
.map(contact -> Objects.requireNonNull(BeanUtil.copyProperties(contact, CustomerInvoiceContactVO.class)))
.collect(Collectors.groupingBy(CustomerInvoiceContactVO::getInvoiceId));
return invoices.stream().map(invoice -> {
CustomerInvoiceInfoVO invoiceVO = Objects.requireNonNull(BeanUtil.copyProperties(invoice, CustomerInvoiceInfoVO.class));
invoiceVO.setContacts(contactMap.getOrDefault(invoice.getId(), new ArrayList<>()));
return invoiceVO;
}).toList();
}
private List<CustomerCreditScoreVO> loadScores(Long customerId) {
@@ -621,6 +735,16 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
return value != null && value.compareTo(BigDecimal.ONE.negate()) == 0 ? null : value;
}
private Integer normalizeYesNoFlag(Integer value) {
if (value == null || Objects.equals(value, -1)) {
return null;
}
if (value == 0 || value == 1) {
return value;
}
throw new ServiceException("是否广西百强只能选择是或否");
}
private Object parseScoreAttachments(String value) {
if (Func.isEmpty(value)) {
return new ArrayList<>();
@@ -928,6 +1052,7 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
snapshot.put("客商简称", customer.getShortName());
snapshot.put("客商全称", customer.getFullName());
snapshot.put("客商性质", customer.getCustomerNature());
snapshot.put("是否广西百强", customer.getGuangxiTop100());
snapshot.put("统一社会信用代码", customer.getUnifiedCreditCode());
snapshot.put("客商类型", customer.getCustomerType());
snapshot.put("所属项目", customer.getProjectName());
@@ -55,6 +55,7 @@ public class InsuranceOcrTemplateServiceImpl extends BaseServiceImpl<InsuranceOc
private static final int NAME_MAX_LENGTH = 100;
private static final int MAPPING_VALUE_MAX_LENGTH = 100;
private static final List<String> VEHICLE_TYPES = List.of("车辆", "船舶");
private static final List<String> INSURANCE_FIELD_KEYS = List.of(
"保险类型", "保单号", "开始日期", "结束日期", "保额", "保费", "发票号", "开票日期", "备注"
);
@@ -64,6 +65,7 @@ public class InsuranceOcrTemplateServiceImpl extends BaseServiceImpl<InsuranceOc
LambdaQueryWrapper<InsuranceOcrTemplate> queryWrapper = Wrappers.<InsuranceOcrTemplate>lambdaQuery()
.eq(InsuranceOcrTemplate::getIsDeleted, 0)
.like(StringUtil.isNotBlank(insuranceOcrTemplate.getName()), InsuranceOcrTemplate::getName, insuranceOcrTemplate.getName())
.eq(StringUtil.isNotBlank(insuranceOcrTemplate.getVehicleType()), InsuranceOcrTemplate::getVehicleType, insuranceOcrTemplate.getVehicleType())
.orderByDesc(InsuranceOcrTemplate::getCreateTime);
return InsuranceOcrTemplateWrapper.build().pageVO(page(page, queryWrapper));
}
@@ -79,6 +81,7 @@ public class InsuranceOcrTemplateServiceImpl extends BaseServiceImpl<InsuranceOc
insuranceOcrTemplate.setTenantId(oldTemplate.getTenantId());
}
insuranceOcrTemplate.setName(trimToNull(insuranceOcrTemplate.getName()));
insuranceOcrTemplate.setVehicleType(trimToNull(insuranceOcrTemplate.getVehicleType()));
insuranceOcrTemplate.setMappingConfig(trimToNull(insuranceOcrTemplate.getMappingConfig()));
if (created && insuranceOcrTemplate.getStatus() == null) {
insuranceOcrTemplate.setStatus(1);
@@ -94,6 +97,12 @@ public class InsuranceOcrTemplateServiceImpl extends BaseServiceImpl<InsuranceOc
if (insuranceOcrTemplate.getName().length() > NAME_MAX_LENGTH) {
throw new ServiceException("模板名称不能超过100个字符");
}
if (StringUtil.isBlank(insuranceOcrTemplate.getVehicleType())) {
throw new ServiceException("请选择车船类型");
}
if (!VEHICLE_TYPES.contains(insuranceOcrTemplate.getVehicleType())) {
throw new ServiceException("车船类型仅支持车辆或船舶");
}
Long nameCount = count(Wrappers.<InsuranceOcrTemplate>lambdaQuery()
.eq(InsuranceOcrTemplate::getIsDeleted, 0)
.eq(InsuranceOcrTemplate::getName, insuranceOcrTemplate.getName())
@@ -85,6 +85,7 @@ public class InsuranceRecordServiceImpl extends BaseServiceImpl<InsuranceRecordM
private static final Set<String> INSURANCE_TYPES = Set.of("交强险", "商业险", "承运人责任险", "货运险", "船舶险");
private static final Set<String> SUPPORT_FILE_TYPES = Set.of("jpg", "jpeg", "png", "bmp");
private static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4})[-/.年](\\d{1,2})[-/.月](\\d{1,2})日?");
private static final Pattern POLICY_NO_PATTERN = Pattern.compile("^[a-zA-Z0-9]+$");
private final IBaiduOcrService baiduOcrService;
private final IInsuranceOcrTemplateService insuranceOcrTemplateService;
@@ -157,6 +158,11 @@ public class InsuranceRecordServiceImpl extends BaseServiceImpl<InsuranceRecordM
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(insuranceRecord.getInsuranceType()), "保险类型不能为空");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(insuranceRecord.getInsuranceType()) && !INSURANCE_TYPES.contains(insuranceRecord.getInsuranceType()), "保险类型不正确");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(insuranceRecord.getPolicyNo()), "保单号不能为空");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(
validationErrors,
Func.isNotEmpty(insuranceRecord.getPolicyNo()) && !POLICY_NO_PATTERN.matcher(insuranceRecord.getPolicyNo()).matches(),
"保单号只能输入数字、字母"
);
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(insuranceRecord.getStartDate()), "开始日期不能为空");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(insuranceRecord.getEndDate()), "结束日期不能为空");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(insuranceRecord.getStartDate()) && Func.isNotEmpty(insuranceRecord.getEndDate()) && insuranceRecord.getEndDate().isBefore(insuranceRecord.getStartDate()), "结束日期不能早于开始日期");
@@ -348,6 +354,9 @@ public class InsuranceRecordServiceImpl extends BaseServiceImpl<InsuranceRecordM
if (Func.isEmpty(insuranceRecord.getPolicyNo())) {
throw new ServiceException("保单号不能为空");
}
if (!POLICY_NO_PATTERN.matcher(insuranceRecord.getPolicyNo()).matches()) {
throw new ServiceException("保单号只能输入数字、字母");
}
if (Func.isEmpty(insuranceRecord.getStartDate())) {
throw new ServiceException("开始日期不能为空");
}
@@ -37,6 +37,7 @@ import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.transport.mapper.CustomerArchiveMapper;
import org.springblade.transport.mapper.CustomerContactMapper;
import org.springblade.transport.mapper.CustomerInvoiceContactMapper;
import org.springblade.transport.mapper.CustomerInvoiceInfoMapper;
import org.springblade.transport.mapper.ContractManageMapper;
import org.springblade.transport.mapper.FormalSettlementDetailMapper;
@@ -52,6 +53,7 @@ import org.springblade.transport.pojo.dto.InvoiceApplicationSaveRequest;
import org.springblade.transport.pojo.dto.InvoiceApplicationStatusRequest;
import org.springblade.transport.pojo.entity.CustomerArchive;
import org.springblade.transport.pojo.entity.CustomerContact;
import org.springblade.transport.pojo.entity.CustomerInvoiceContact;
import org.springblade.transport.pojo.entity.CustomerInvoiceInfo;
import org.springblade.transport.pojo.entity.ContractManage;
import org.springblade.transport.pojo.entity.FormalSettlement;
@@ -63,6 +65,8 @@ import org.springblade.transport.pojo.entity.InvoiceApplicationRecord;
import org.springblade.transport.pojo.entity.InvoiceApplicationSettlement;
import org.springblade.transport.pojo.entity.InvoiceApplicationSheet;
import org.springblade.transport.pojo.entity.Waybill;
import org.springblade.transport.pojo.vo.CustomerInvoiceContactVO;
import org.springblade.transport.pojo.vo.CustomerInvoiceInfoVO;
import org.springblade.transport.pojo.vo.InvoiceApplicationSheetVO;
import org.springblade.transport.pojo.vo.InvoiceApplicationVO;
import org.springblade.transport.service.IInvoiceApplicationService;
@@ -75,6 +79,7 @@ import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@@ -111,6 +116,7 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
private final ContractManageMapper contractManageMapper;
private final CustomerArchiveMapper customerArchiveMapper;
private final CustomerInvoiceInfoMapper customerInvoiceInfoMapper;
private final CustomerInvoiceContactMapper customerInvoiceContactMapper;
private final CustomerContactMapper customerContactMapper;
@Override
@@ -267,7 +273,7 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
String customerName = "receivable".equals(first.getSettlementType())
? first.getPayerName() : first.getPayeeName();
CustomerArchive customer = findCustomer(customerName);
List<CustomerInvoiceInfo> invoiceInfos = customer == null ? List.of() : activeInvoiceInfos(customer.getId());
List<CustomerInvoiceInfoVO> invoiceInfos = customer == null ? List.of() : activeInvoiceInfoVOs(customer.getId());
Map<String, Object> result = new LinkedHashMap<>();
result.put("issuerName", first.getPayeeName());
result.put("receiverName", first.getPayerName());
@@ -321,8 +327,8 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
}
CustomerArchive customer = findCustomer(first.getPayerName());
if (customer == null) throw new ServiceException("未找到正式结算单受票方对应的客商档案");
List<CustomerInvoiceInfo> invoiceInfos = activeInvoiceInfos(customer.getId());
CustomerInvoiceInfo invoiceInfo = invoiceInfos.stream()
List<CustomerInvoiceInfoVO> invoiceInfos = activeInvoiceInfoVOs(customer.getId());
CustomerInvoiceInfoVO invoiceInfo = invoiceInfos.stream()
.filter(item -> Objects.equals(item.getId(), request.getReceiverInvoiceInfoId()))
.findFirst().orElseThrow(() -> new ServiceException("请选择受票方有效的开票信息"));
String departmentEmails = normalizeDepartmentEmails(request.getDepartmentEmails(), invoiceInfos);
@@ -655,8 +661,32 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
.orderByAsc(CustomerInvoiceInfo::getCreateTime));
}
private List<String> invoiceInfoEmails(List<CustomerInvoiceInfo> invoiceInfos) {
return invoiceInfos.stream().map(CustomerInvoiceInfo::getEmail).filter(Func::isNotEmpty)
private List<CustomerInvoiceInfoVO> activeInvoiceInfoVOs(Long customerId) {
List<CustomerInvoiceInfo> invoiceInfos = activeInvoiceInfos(customerId);
if (Func.isEmpty(invoiceInfos)) {
return List.of();
}
List<Long> invoiceIds = invoiceInfos.stream().map(CustomerInvoiceInfo::getId).toList();
Map<Long, List<CustomerInvoiceContactVO>> contactMap = customerInvoiceContactMapper.selectList(
Wrappers.<CustomerInvoiceContact>lambdaQuery()
.in(CustomerInvoiceContact::getInvoiceId, invoiceIds)
.eq(CustomerInvoiceContact::getIsDeleted, 0)
.orderByAsc(CustomerInvoiceContact::getCreateTime))
.stream()
.map(contact -> Objects.requireNonNull(BeanUtil.copyProperties(contact, CustomerInvoiceContactVO.class)))
.collect(Collectors.groupingBy(CustomerInvoiceContactVO::getInvoiceId));
return invoiceInfos.stream().map(invoice -> {
CustomerInvoiceInfoVO invoiceVO = Objects.requireNonNull(BeanUtil.copyProperties(invoice, CustomerInvoiceInfoVO.class));
invoiceVO.setContacts(contactMap.getOrDefault(invoice.getId(), new ArrayList<>()));
return invoiceVO;
}).toList();
}
private List<String> invoiceInfoEmails(List<CustomerInvoiceInfoVO> invoiceInfos) {
return invoiceInfos.stream()
.flatMap(invoice -> (invoice.getContacts() == null ? List.<CustomerInvoiceContactVO>of() : invoice.getContacts()).stream())
.map(CustomerInvoiceContactVO::getEmail)
.filter(Func::isNotEmpty)
.flatMap(value -> splitEmails(value).stream())
.collect(Collectors.toMap(email -> email.toLowerCase(Locale.ROOT), Function.identity(),
(first, duplicate) -> first, LinkedHashMap::new)).values().stream().toList();
@@ -708,7 +738,7 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
.likeRight(InvoiceApplication::getApplicationNo, prefix)) + 1);
}
private String normalizeDepartmentEmails(String value, List<CustomerInvoiceInfo> invoiceInfos) {
private String normalizeDepartmentEmails(String value, List<CustomerInvoiceInfoVO> invoiceInfos) {
Map<String, String> configuredEmails = invoiceInfoEmails(invoiceInfos).stream()
.collect(Collectors.toMap(email -> email.toLowerCase(Locale.ROOT), Function.identity(),
(first, duplicate) -> first, LinkedHashMap::new));
@@ -12,7 +12,9 @@ import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.system.cache.DictBizCache;
import org.springblade.system.cache.UserCache;
import org.springblade.system.pojo.entity.DictBiz;
import org.springblade.transport.excel.OtherExpenseRecordExcel;
import org.springblade.transport.excel.OtherExpenseRecordExportExcel;
import org.springblade.transport.mapper.OtherExpenseRecordMapper;
@@ -28,6 +30,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 其他费用记录 服务实现类
@@ -43,7 +46,7 @@ public class OtherExpenseRecordServiceImpl extends BaseServiceImpl<OtherExpenseR
private static final int MONEY_SCALE = 2;
private static final String VEHICLE = "车辆";
private static final String SHIP = "船舶";
private static final Set<String> EXPENSE_TYPES = Set.of("过路费", "停车费", "维修费", "保险费", "年检费", "装卸费", "其他");
private static final String EXPENSE_TYPE_DICT_CODE = "other_fee_category";
@Override
public IPage<OtherExpenseRecordVO> selectOtherExpenseRecordPage(IPage<OtherExpenseRecordVO> page, OtherExpenseRecordVO otherExpenseRecord) {
@@ -103,7 +106,7 @@ public class OtherExpenseRecordServiceImpl extends BaseServiceImpl<OtherExpenseR
List<String> validationErrors = new ArrayList<>();
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(otherExpenseRecord.getExpenseDate()), "费用日期不能为空");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(otherExpenseRecord.getExpenseType()), "费用类型不能为空");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(otherExpenseRecord.getExpenseType()) && !EXPENSE_TYPES.contains(otherExpenseRecord.getExpenseType()), "费用类型不正确");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(otherExpenseRecord.getExpenseType()) && !loadExpenseTypeValues().contains(otherExpenseRecord.getExpenseType()), "费用类型不正确");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(otherExpenseRecord.getVehicleType()), "车船类型不能为空");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isNotEmpty(otherExpenseRecord.getVehicleType()) && !VEHICLE.equals(otherExpenseRecord.getVehicleType()) && !SHIP.equals(otherExpenseRecord.getVehicleType()), "车船类型不正确");
org.springblade.common.excel.ImportFailureExcelUtil.addValidationError(validationErrors, Func.isEmpty(otherExpenseRecord.getVehicleNo()), "车牌号/船号不能为空");
@@ -152,7 +155,7 @@ public class OtherExpenseRecordServiceImpl extends BaseServiceImpl<OtherExpenseR
if (Func.isEmpty(otherExpenseRecord.getExpenseType())) {
throw new ServiceException("费用类型不能为空");
}
if (!EXPENSE_TYPES.contains(otherExpenseRecord.getExpenseType())) {
if (!loadExpenseTypeValues().contains(otherExpenseRecord.getExpenseType())) {
throw new ServiceException("费用类型不正确");
}
if (Func.isEmpty(otherExpenseRecord.getVehicleType())) {
@@ -217,4 +220,17 @@ public class OtherExpenseRecordServiceImpl extends BaseServiceImpl<OtherExpenseR
return trimValue.isEmpty() ? null : trimValue;
}
private Set<String> loadExpenseTypeValues() {
List<DictBiz> expenseTypes = DictBizCache.getList(EXPENSE_TYPE_DICT_CODE);
if (Func.isEmpty(expenseTypes)) {
return Set.of();
}
return expenseTypes.stream()
.map(DictBiz::getDictValue)
.filter(Objects::nonNull)
.map(String::trim)
.filter(Func::isNotEmpty)
.collect(Collectors.toSet());
}
}
@@ -1565,11 +1565,11 @@ public class ReceivablePayableDetailServiceImpl
private BigDecimal calculateRule(Map<String, Object> rule, Waybill waybill) {
String element = stringValue(rule, "billingElement", ""); String type = stringValue(rule, "billingType", "");
BigDecimal base = measure(rule, waybill); BigDecimal unit = decimal(rule.get("unitPrice"));
BigDecimal measuredBase = measure(rule, waybill); BigDecimal unit = decimal(rule.get("unitPrice"));
List<Map<String, Object>> ranges = ranges(rule);
boolean intervalUnitPrice = "区间单价".equals(type);
boolean intervalFlatPrice = type.contains("区间") && type.contains("一口价");
if (!intervalUnitPrice && !intervalFlatPrice) base = applyMinimum(base, rule, waybill);
BigDecimal base = (!intervalUnitPrice && !intervalFlatPrice) ? applyMinimum(measuredBase, rule, waybill) : measuredBase;
if ("固定一口价".equals(type)) return unit.setScale(2, RoundingMode.HALF_UP);
if (ranges.isEmpty() || "固定单价".equals(type)) return base.multiply(unit).setScale(2, RoundingMode.HALF_UP);
if (intervalFlatPrice) return range(ranges, base).map(r -> decimal(r.get("unitPrice")).signum() == 0 ? unit : decimal(r.get("unitPrice"))).orElse(BigDecimal.ZERO).setScale(2, RoundingMode.HALF_UP);
+28 -9
View File
@@ -9,6 +9,7 @@ CREATE TABLE `blade_customer_archive` (
`short_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '客商简称',
`full_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '客商全称',
`customer_nature` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '客商性质',
`guangxi_top100` tinyint NULL DEFAULT NULL COMMENT '是否广西百强:0否,1是',
`unified_credit_code` varchar(18) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '统一社会信用代码',
`customer_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '客商类型',
`project_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '所属项目',
@@ -22,6 +23,7 @@ CREATE TABLE `blade_customer_archive` (
`dept_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '所属组织',
`invoice_tax_rate` decimal(6,2) NULL DEFAULT NULL COMMENT '开票税点',
`business_scope` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '经营范围',
`network_freight_platform` tinyint NULL DEFAULT NULL COMMENT '网络货运平台:0否,1是',
`business_term_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '营业期限类型',
`business_end_date` date NULL DEFAULT NULL COMMENT '营业期限截止日',
`registered_capital` decimal(18,2) NULL DEFAULT NULL COMMENT '注册资金(万元)',
@@ -116,21 +118,13 @@ CREATE TABLE `blade_customer_invoice_info` (
`id` bigint NOT NULL COMMENT '主键',
`tenant_id` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '000000' COMMENT '租户ID',
`customer_id` bigint NOT NULL COMMENT '客商ID',
`invoice_title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '受票方名',
`invoice_type` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '发票类型',
`invoice_title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '企业全',
`tax_no` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '纳税人识别号',
`bank_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '开户行名称',
`registered_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册电话',
`bank_account` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '银行账号',
`registered_address` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册地址',
`registered_region_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册地址行政区划',
`registered_detail_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '注册地址详细地址',
`email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱',
`receiver_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '收件人姓名',
`receiver_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '收件人电话',
`receiver_address` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '收件人地址',
`receiver_region_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '收件人地址行政区划',
`receiver_detail_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '收件人详细地址',
`is_default` int NULL DEFAULT 0 COMMENT '是否默认',
`create_user` bigint NULL DEFAULT NULL COMMENT '创建人',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
@@ -143,6 +137,31 @@ CREATE TABLE `blade_customer_invoice_info` (
KEY `idx_customer_invoice_customer` (`tenant_id`, `customer_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '客商发票信息';
-- ----------------------------
-- Table structure for blade_customer_invoice_contact
-- ----------------------------
DROP TABLE IF EXISTS `blade_customer_invoice_contact`;
CREATE TABLE `blade_customer_invoice_contact` (
`id` bigint NOT NULL COMMENT '主键',
`tenant_id` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '000000' COMMENT '租户ID',
`invoice_id` bigint NOT NULL COMMENT '发票信息ID',
`contact_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系人',
`contact_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系电话',
`email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱地址',
`dept_ids` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '所属部门ID集合',
`dept_names` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '所属部门',
`remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`create_user` bigint NULL DEFAULT NULL COMMENT '创建人',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`update_user` bigint NULL DEFAULT NULL COMMENT '修改人',
`update_time` datetime NULL DEFAULT NULL COMMENT '修改时间',
`status` int NULL DEFAULT 1 COMMENT '状态',
`is_deleted` int NULL DEFAULT 0 COMMENT '是否已删除',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_customer_invoice_contact_invoice` (`tenant_id`, `invoice_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '客商发票联系信息';
-- ----------------------------
-- Table structure for blade_customer_credit_score
-- ----------------------------
@@ -0,0 +1,4 @@
-- 客商档案:新增「是否广西百强」字段(是否,无默认值,未选择时保持 NULL)
ALTER TABLE `blade_customer_archive`
ADD COLUMN `guangxi_top100` tinyint NULL DEFAULT NULL COMMENT '是否广西百强:0否,1是' AFTER `customer_nature`;
@@ -0,0 +1,4 @@
-- 客商档案:新增「网络货运平台」字段(是否,无默认值)
ALTER TABLE `blade_customer_archive`
ADD COLUMN `network_freight_platform` tinyint NULL DEFAULT NULL COMMENT '网络货运平台:0否,1是' AFTER `business_scope`;
@@ -0,0 +1,63 @@
-- 客商发票信息:去掉邮寄信息/发票类型/注册电话,改为维护多个联系信息
CREATE TABLE IF NOT EXISTS `blade_customer_invoice_contact` (
`id` bigint NOT NULL COMMENT '主键',
`tenant_id` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '000000' COMMENT '租户ID',
`invoice_id` bigint NOT NULL COMMENT '发票信息ID',
`contact_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系人',
`contact_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系电话',
`email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱地址',
`dept_ids` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '所属部门ID集合',
`dept_names` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '所属部门',
`remark` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`create_user` bigint NULL DEFAULT NULL COMMENT '创建人',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`update_user` bigint NULL DEFAULT NULL COMMENT '修改人',
`update_time` datetime NULL DEFAULT NULL COMMENT '修改时间',
`status` int NULL DEFAULT 1 COMMENT '状态',
`is_deleted` int NULL DEFAULT 0 COMMENT '是否已删除',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_customer_invoice_contact_invoice` (`tenant_id`, `invoice_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '客商发票联系信息';
INSERT INTO `blade_customer_invoice_contact` (
`id`, `tenant_id`, `invoice_id`, `contact_name`, `contact_phone`, `email`,
`dept_ids`, `dept_names`, `remark`, `create_user`, `create_dept`, `create_time`,
`update_user`, `update_time`, `status`, `is_deleted`
)
SELECT
invoice.`id`,
invoice.`tenant_id`,
invoice.`id`,
invoice.`receiver_name`,
invoice.`receiver_phone`,
invoice.`email`,
NULL,
NULL,
NULL,
invoice.`create_user`,
invoice.`create_dept`,
invoice.`create_time`,
invoice.`update_user`,
invoice.`update_time`,
IFNULL(invoice.`status`, 1),
IFNULL(invoice.`is_deleted`, 0)
FROM `blade_customer_invoice_info` invoice
WHERE (IFNULL(invoice.`receiver_name`, '') <> ''
OR IFNULL(invoice.`receiver_phone`, '') <> ''
OR IFNULL(invoice.`email`, '') <> '')
AND NOT EXISTS (
SELECT 1 FROM `blade_customer_invoice_contact` contact WHERE contact.`id` = invoice.`id`
);
ALTER TABLE `blade_customer_invoice_info`
MODIFY COLUMN `invoice_title` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '企业全称',
DROP COLUMN `invoice_type`,
DROP COLUMN `registered_phone`,
DROP COLUMN `email`,
DROP COLUMN `receiver_name`,
DROP COLUMN `receiver_phone`,
DROP COLUMN `receiver_address`,
DROP COLUMN `receiver_region_name`,
DROP COLUMN `receiver_detail_address`;
@@ -6,6 +6,7 @@ CREATE TABLE `blade_insurance_ocr_template` (
`id` bigint(20) NOT NULL COMMENT '主键',
`tenant_id` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '000000' COMMENT '租户ID',
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '模板名称',
`vehicle_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '车辆' COMMENT '车船类型:车辆/船舶',
`mapping_config` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字段映射配置JSON',
`create_user` bigint(20) DEFAULT NULL COMMENT '创建人',
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
@@ -16,6 +17,7 @@ CREATE TABLE `blade_insurance_ocr_template` (
`is_deleted` int(11) NOT NULL DEFAULT '0' COMMENT '是否已删除',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_insurance_ocr_template_name` (`tenant_id`, `name`) USING BTREE,
KEY `idx_insurance_ocr_template_vehicle_type` (`tenant_id`, `vehicle_type`) USING BTREE,
KEY `idx_insurance_ocr_template_status` (`status`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='保险OCR识别模板';
@@ -0,0 +1,5 @@
-- 保险OCR识别模板:新增车船类型字段
ALTER TABLE `blade_insurance_ocr_template`
ADD COLUMN `vehicle_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '车辆' COMMENT '车船类型:车辆/船舶' AFTER `name`,
ADD KEY `idx_insurance_ocr_template_vehicle_type` (`tenant_id`, `vehicle_type`) USING BTREE;
+157
View File
@@ -0,0 +1,157 @@
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGBUS (0xa) at pc=0x0000000104d364c0, pid=22822, tid=5379
#
# JRE version: OpenJDK Runtime Environment Zulu17.44+15-CA (17.0.8+7) (build 17.0.8+7-LTS)
# Java VM: OpenJDK 64-Bit Server VM Zulu17.44+15-CA (17.0.8+7-LTS, mixed mode, emulated-client, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, bsd-aarch64)
# Problematic frame:
# C [libzip.dylib+0x64c0] newEntry+0x68
#
# No core dump will be written. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# If you would like to submit a bug report, please visit:
# http://www.azul.com/support/
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
--------------- S U M M A R Y ------------
Command Line: -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:54448,suspend=y,server=n -javaagent:/Users/liangxin/Library/Caches/JetBrains/IntelliJIdea2026.1/captureAgent/debugger-agent.jar=file:///var/folders/pk/drq93rk10q733kk02fgp89xh0000gn/T/capture14073385024433055703.props -XX:TieredStopAtLevel=1 -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dmanagement.endpoints.jmx.exposure.include=* -Dkotlinx.coroutines.debug.enable.creation.stack.trace=false -Ddebugger.agent.enable.coroutines=true -Dkotlinx.coroutines.debug.enable.flows.stack.trace=true -Dkotlinx.coroutines.debug.enable.mutable.state.flows.stack.trace=true -Ddebugger.async.stack.trace.for.all.threads=true -Dfile.encoding=UTF-8 org.springblade.admin.AdminApplication
Host: "Mac15,6" arm64, 12 cores, 36G, Darwin 25.6.0, macOS 26.6.2 (25G83)
Time: Mon Sep 14 22:15:03 2026 CST elapsed time: 5.909458 seconds (0d 0h 0m 5s)
--------------- T H R E A D ---------------
Current thread (0x000000013601ac00): JavaThread "main" [_thread_in_native, id=5379, stack(0x000000016b250000,0x000000016b453000)]
Stack: [0x000000016b250000,0x000000016b453000], sp=0x000000016b450260, free space=2048k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [libzip.dylib+0x64c0] newEntry+0x68
C [libzip.dylib+0x6390] ZIP_GetEntry2+0x14c
C [libzip.dylib+0x6d78] ZIP_FindEntry+0x3c
V [libjvm.dylib+0x25a408] ClassPathZipEntry::open_entry(JavaThread*, char const*, int*, bool)+0xb4
V [libjvm.dylib+0x25a53c] ClassPathZipEntry::open_stream(JavaThread*, char const*)+0x20
V [libjvm.dylib+0x25d918] ClassLoader::load_class(Symbol*, bool, JavaThread*)+0x150
V [libjvm.dylib+0x981d60] SystemDictionary::load_instance_class_impl(Symbol*, Handle, JavaThread*)+0x2d0
V [libjvm.dylib+0x98063c] SystemDictionary::load_instance_class(unsigned int, Symbol*, Handle, JavaThread*)+0x30
V [libjvm.dylib+0x97fd48] SystemDictionary::resolve_instance_class_or_null(Symbol*, Handle, Handle, JavaThread*)+0x4dc
V [libjvm.dylib+0x97f334] SystemDictionary::resolve_or_fail(Symbol*, Handle, Handle, bool, JavaThread*)+0x80
V [libjvm.dylib+0x2beb54] ConstantPool::klass_at_impl(constantPoolHandle const&, int, JavaThread*)+0x1e0
V [libjvm.dylib+0x46d6f0] InterpreterRuntime::_new(JavaThread*, ConstantPool*, int)+0x94
j com.intellij.rt.debugger.agent.CaptureStorage.createCapturedStack(Ljava/lang/Throwable;Lcom/intellij/rt/debugger/agent/CaptureStorage$CapturedStack;)Lcom/intellij/rt/debugger/agent/CaptureStorage$CapturedStack;+14
j com.intellij.rt.debugger.agent.CaptureStorage.access$500(Ljava/lang/Throwable;Lcom/intellij/rt/debugger/agent/CaptureStorage$CapturedStack;)Lcom/intellij/rt/debugger/agent/CaptureStorage$CapturedStack;+2
j com.intellij.rt.debugger.agent.CaptureStorage$3.run()V+75
j com.intellij.rt.debugger.agent.OverheadDetector$PerThread.runIfNoOverhead(Ljava/lang/Runnable;)Z+62
j com.intellij.rt.debugger.agent.CaptureStorage.runWithOverheadTrackingAndWithoutThrowableCapture(Lcom/intellij/rt/debugger/agent/CaptureStorage$ThreadLocalContext;Ljava/lang/Runnable;)Z+15
j com.intellij.rt.debugger.agent.CaptureStorage.capture(Ljava/lang/Object;)V+26
j java.util.concurrent.FutureTask.<init>(Ljava/util/concurrent/Callable;)V+5 java.base@17.0.8
j org.springframework.cglib.core.internal.LoadingCache.createEntry(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;+27
j org.springframework.cglib.core.internal.LoadingCache.get(Ljava/lang/Object;)Ljava/lang/Object;+39
j org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(Lorg/springframework/cglib/core/AbstractClassGenerator;Z)Ljava/lang/Object;+11
j org.springframework.cglib.core.AbstractClassGenerator.create(Ljava/lang/Object;)Ljava/lang/Object;+115
j org.springframework.cglib.reflect.FastClass$Generator.create()Lorg/springframework/cglib/reflect/FastClass;+19
j org.springframework.cglib.proxy.MethodProxy.helper(Lorg/springframework/cglib/proxy/MethodProxy$CreateInfo;Ljava/lang/Class;)Lorg/springframework/cglib/reflect/FastClass;+54
j org.springframework.cglib.proxy.MethodProxy.init()V+40
j org.springframework.cglib.proxy.MethodProxy.create(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/springframework/cglib/proxy/MethodProxy;+80
j org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration$BlockingLoadBalancerRetryConfig$$SpringCGLIB$$0.CGLIB$STATICHOOK1()V+112
j org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration$BlockingLoadBalancerRetryConfig$$SpringCGLIB$$0.<clinit>()V+3
v ~StubRoutines::call_stub
V [libjvm.dylib+0x4781f8] JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, JavaThread*)+0x394
V [libjvm.dylib+0x457c84] InstanceKlass::call_class_initializer(JavaThread*)+0x1e8
V [libjvm.dylib+0x456f48] InstanceKlass::initialize_impl(JavaThread*)+0x65c
V [libjvm.dylib+0x51e020] JVM_FindClassFromCaller+0x340
C [libjava.dylib+0x3a6c] Java_java_lang_Class_forName0+0x138
J 1317 java.lang.Class.forName0(Ljava/lang/String;ZLjava/lang/ClassLoader;Ljava/lang/Class;)Ljava/lang/Class; java.base@17.0.8 (0 bytes) @ 0x000000010ed5306c [0x000000010ed52fc0+0x00000000000000ac]
V [libjvm.dylib+0x4715a0] InterpreterRuntime::resolve_from_cache(JavaThread*, Bytecodes::Code)+0x98
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j com.intellij.rt.debugger.agent.CaptureStorage.createCapturedStack(Ljava/lang/Throwable;Lcom/intellij/rt/debugger/agent/CaptureStorage$CapturedStack;)Lcom/intellij/rt/debugger/agent/CaptureStorage$CapturedStack;+14
j com.intellij.rt.debugger.agent.CaptureStorage.access$500(Ljava/lang/Throwable;Lcom/intellij/rt/debugger/agent/CaptureStorage$CapturedStack;)Lcom/intellij/rt/debugger/agent/CaptureStorage$CapturedStack;+2
j com.intellij.rt.debugger.agent.CaptureStorage$3.run()V+75
j com.intellij.rt.debugger.agent.OverheadDetector$PerThread.runIfNoOverhead(Ljava/lang/Runnable;)Z+62
j com.intellij.rt.debugger.agent.CaptureStorage.runWithOverheadTrackingAndWithoutThrowableCapture(Lcom/intellij/rt/debugger/agent/CaptureStorage$ThreadLocalContext;Ljava/lang/Runnable;)Z+15
j com.intellij.rt.debugger.agent.CaptureStorage.capture(Ljava/lang/Object;)V+26
j java.util.concurrent.FutureTask.<init>(Ljava/util/concurrent/Callable;)V+5 java.base@17.0.8
j org.springframework.cglib.core.internal.LoadingCache.createEntry(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;+27
j org.springframework.cglib.core.internal.LoadingCache.get(Ljava/lang/Object;)Ljava/lang/Object;+39
j org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(Lorg/springframework/cglib/core/AbstractClassGenerator;Z)Ljava/lang/Object;+11
j org.springframework.cglib.core.AbstractClassGenerator.create(Ljava/lang/Object;)Ljava/lang/Object;+115
j org.springframework.cglib.reflect.FastClass$Generator.create()Lorg/springframework/cglib/reflect/FastClass;+19
j org.springframework.cglib.proxy.MethodProxy.helper(Lorg/springframework/cglib/proxy/MethodProxy$CreateInfo;Ljava/lang/Class;)Lorg/springframework/cglib/reflect/FastClass;+54
j org.springframework.cglib.proxy.MethodProxy.init()V+40
j org.springframework.cglib.proxy.MethodProxy.create(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/springframework/cglib/proxy/MethodProxy;+80
j org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration$BlockingLoadBalancerRetryConfig$$SpringCGLIB$$0.CGLIB$STATICHOOK1()V+112
j org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration$BlockingLoadBalancerRetryConfig$$SpringCGLIB$$0.<clinit>()V+3
v ~StubRoutines::call_stub
J 1317 java.lang.Class.forName0(Ljava/lang/String;ZLjava/lang/ClassLoader;Ljava/lang/Class;)Ljava/lang/Class; java.base@17.0.8 (0 bytes) @ 0x000000010ed5306c [0x000000010ed52fc0+0x00000000000000ac]
J 1432 c1 java.lang.Class.forName(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class; java.base@17.0.8 (47 bytes) @ 0x000000010ed807c8 [0x000000010ed806c0+0x0000000000000108]
j org.springframework.cglib.core.ReflectUtils.defineClass(Ljava/lang/String;[BLjava/lang/ClassLoader;Ljava/security/ProtectionDomain;Ljava/lang/Class;)Ljava/lang/Class;+460
j org.springframework.cglib.core.AbstractClassGenerator.generate(Lorg/springframework/cglib/core/AbstractClassGenerator$ClassLoaderData;)Ljava/lang/Class;+209
j org.springframework.cglib.proxy.Enhancer.generate(Lorg/springframework/cglib/core/AbstractClassGenerator$ClassLoaderData;)Ljava/lang/Class;+53
j org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.lambda$new$1(Lorg/springframework/cglib/core/AbstractClassGenerator;)Ljava/lang/Object;+2
j org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$$Lambda$857+0x00000070016c9418.apply(Ljava/lang/Object;)Ljava/lang/Object;+8
j org.springframework.cglib.core.internal.LoadingCache.lambda$createEntry$1(Ljava/lang/Object;)Ljava/lang/Object;+5
j org.springframework.cglib.core.internal.LoadingCache$$Lambda$859+0x00000070016c9a98.call()Ljava/lang/Object;+8
j java.util.concurrent.FutureTask.run$$$capture()V+39 java.base@17.0.8
j java.util.concurrent.FutureTask.run()V+5 java.base@17.0.8
j org.springframework.cglib.core.internal.LoadingCache.createEntry(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;+56
j org.springframework.cglib.core.internal.LoadingCache.get(Ljava/lang/Object;)Ljava/lang/Object;+39
j org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(Lorg/springframework/cglib/core/AbstractClassGenerator;Z)Ljava/lang/Object;+11
j org.springframework.cglib.core.AbstractClassGenerator.create(Ljava/lang/Object;)Ljava/lang/Object;+115
j org.springframework.cglib.proxy.Enhancer.createHelper()Ljava/lang/Object;+102
j org.springframework.cglib.proxy.Enhancer.createClass()Ljava/lang/Class;+6
j org.springframework.context.annotation.ConfigurationClassEnhancer.createClass(Lorg/springframework/cglib/proxy/Enhancer;Z)Ljava/lang/Class;+1
j org.springframework.context.annotation.ConfigurationClassEnhancer.enhance(Ljava/lang/Class;Ljava/lang/ClassLoader;)Ljava/lang/Class;+134
j org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(Lorg/springframework/beans/factory/config/ConfigurableListableBeanFactory;)V+418
j org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanFactory(Lorg/springframework/beans/factory/config/ConfigurableListableBeanFactory;)V+78
j org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(Ljava/util/Collection;Lorg/springframework/beans/factory/config/ConfigurableListableBeanFactory;)V+61
j org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(Lorg/springframework/beans/factory/config/ConfigurableListableBeanFactory;Ljava/util/List;)V+521
j org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(Lorg/springframework/beans/factory/config/ConfigurableListableBeanFactory;)V+5
j org.springframework.context.support.AbstractApplicationContext.refresh()V+62
j org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh()V+1
j org.springframework.boot.SpringApplication.refresh(Lorg/springframework/context/ConfigurableApplicationContext;)V+1
j org.springframework.boot.SpringApplication.refreshContext(Lorg/springframework/context/ConfigurableApplicationContext;)V+19
j org.springframework.boot.SpringApplication.run([Ljava/lang/String;)Lorg/springframework/context/ConfigurableApplicationContext;+113
j org.springframework.boot.builder.SpringApplicationBuilder.run([Ljava/lang/String;)Lorg/springframework/context/ConfigurableApplicationContext;+38
j org.springblade.core.launch.BladeApplication.run(Ljava/lang/String;Ljava/lang/Class;[Ljava/lang/String;)Lorg/springframework/context/ConfigurableApplicationContext;+9
j org.springblade.admin.AdminApplication.main([Ljava/lang/String;)V+5
v ~StubRoutines::call_stub
siginfo: si_signo: 10 (SIGBUS), si_code: 1 (BUS_ADRALN), si_addr: 0x0000000104cfe958
Register to memory mapping:
x0=0x0000600001ebc820 points into unknown readable memory: 0x0000000000000000 | 00 00 00 00 00 00 00 00
x1=0x0 is NULL
x2=0xfffffffffffffff0 is an unknown value
x3=0x0000600001ebc830 points into unknown readable memory: 0x0000000000000000 | 00 00 00 00 00 00 00 00
x4=0x0000600001ebc880 points into unknown readable memory: 0x0000000000000000 | 00 00 00 00 00 00 00 00
x5=0x000000009b858ffb is an unknown value
x6=0x000000001ba00000 is an unknown value
x7=0x00000005c0183f80 is an oop: com.intellij.rt.debugger.agent.CaptureStorage$ConcurrentIdentityWeakHashMap$WeakKey
{0x00000005c0183f80} - klass: 'com/intellij/rt/debugger/agent/CaptureStorage$ConcurrentIdentityWeakHashMap$WeakKey'
- ---- fields (total size 4 words):
- private 'referent' 'Ljava/lang/Object;' @12 a 'java/lang/Thread'{0x00000005c0203dc0} (b80407b8)
- volatile 'queue' 'Ljava/lang/ref/ReferenceQueue;' @16 a 'java/lang/ref/ReferenceQueue'{0x00000005c0183ea0} (b80307d4)
- volatile 'next' 'Ljava/lang/ref/Reference;' @20 NULL (0)
- private transient 'discovered' 'Ljava/lang/ref/Reference;' @24 NULL (0)
- private final 'myHash' 'I' @28 897913732 (35851384)
x8=0x0000000104e2693c: getProcessHandle.procHandle+0x971c in /Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home/lib/libjava.dylib at 0x0000000104e00000
x9=0x0000000000128000 is an unknown value
x10=0x0000600001ebc000 points into unknown readable memory: 0x4c2800498af20001 | 01 00 f2 8a 49 00 28 4c
x11=0x0000000000000820 is an unknown value
x12=0x0000000000000050 is an unknown value
x13=0x0000000000000001 is an unknown value
x14=0x00000000ffffff4e is an unknown value
x15=0x00000000000007fb is an unknown value
x16=0x00000001829fd030: __bzero+0 in /usr/lib/system/libsystem_platform.dylib at 0x00000001829fa000
x17=0x00000001f0a754a8 points into unknown readable memory: 0x00000001829fd030 | 30 d0 9f 82 01 00 00 00
x18=0x0 is NULL
x19=0x0000600001ebc820 points into unknown readable memory: 0x0000000000000000 | 00 00 00 00 00 00 00 00
x20=0x0 is NULL
x21=0x0000600000bf4240 points into unknown readable memory: 0x0000600001af00c0 | c0 00 af 01 00 60 00 00
x22=0x0000000104cfe93c points into unknown readable memory: 50 4b 01 02
x23=