Merge remote-tracking branch 'origin/master'

This commit is contained in:
jiang 2025-08-28 19:18:43 +08:00
commit 6de69becb8
17 changed files with 174 additions and 24 deletions

View File

@ -2,12 +2,15 @@ package com.bonus.material.codeCollection.controller;
import com.bonus.common.core.web.controller.BaseController; import com.bonus.common.core.web.controller.BaseController;
import com.bonus.common.core.web.domain.AjaxResult; import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.core.web.page.TableDataInfo;
import com.bonus.common.log.annotation.SysLog; import com.bonus.common.log.annotation.SysLog;
import com.bonus.common.log.enums.OperaType; import com.bonus.common.log.enums.OperaType;
import com.bonus.common.security.utils.SecurityUtils; import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.material.codeCollection.domain.WsMaInfo; import com.bonus.material.codeCollection.domain.WsMaInfo;
import com.bonus.material.codeCollection.service.WsMaInfoService; import com.bonus.material.codeCollection.service.WsMaInfoService;
import com.bonus.material.common.annotation.PreventRepeatSubmit; import com.bonus.material.common.annotation.PreventRepeatSubmit;
import com.bonus.material.ma.domain.Machine;
import com.bonus.material.ma.domain.vo.MachineVo;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -94,4 +97,13 @@ public class WsMaInfoController extends BaseController {
} }
@ApiOperation(value = "查询小工具编码信息列表")
@GetMapping("/getGadgetList")
public TableDataInfo getGadgetList(WsMaInfo info) {
startPage();
List<WsMaInfo> list = service.getGadgetList(info);
return getDataTable(list);
}
} }

View File

@ -1,5 +1,6 @@
package com.bonus.material.codeCollection.domain; package com.bonus.material.codeCollection.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@ -108,4 +109,15 @@ public class WsMaInfo {
* 二维码 * 二维码
*/ */
private String qrCode; private String qrCode;
/**
* 关键字
*/
private String keyWord;
@ApiModelProperty(value = "开始时间")
private String startTime;
@ApiModelProperty(value = "结束时间")
private String endTime;
} }

View File

@ -93,4 +93,11 @@ public interface WsMaInfoMapper {
* @return 条数 * @return 条数
*/ */
int updateCheckTime(WsMaInfo info); int updateCheckTime(WsMaInfo info);
/**
* 获取机具信息
* @param info 查询条件
* @return 机具信息集合
*/
List<WsMaInfo> getGadgetList(WsMaInfo info);
} }

View File

@ -85,4 +85,11 @@ public interface WsMaInfoService {
* @return 条数 * @return 条数
*/ */
AjaxResult updateCheckTime(WsMaInfo info); AjaxResult updateCheckTime(WsMaInfo info);
/**
* 查询小工具编码信息列表
* @param info
* @return
*/
List<WsMaInfo> getGadgetList(WsMaInfo info);
} }

View File

@ -10,6 +10,7 @@ import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -209,4 +210,14 @@ public class WsMaInfoServiceImpl implements WsMaInfoService {
return AjaxResult.error("更新失败"); return AjaxResult.error("更新失败");
} }
} }
@Override
public List<WsMaInfo> getGadgetList(WsMaInfo info) {
try {
return mapper.getGadgetList(info);
} catch (Exception e) {
log.error("查询小工具编码信息列表:", e.getMessage());
return new ArrayList<>();
}
}
} }

View File

@ -368,7 +368,7 @@ public class MachineServiceImpl implements IMachineService
// 根据maid查询领料任务 // 根据maid查询领料任务
LeaseApplyInfo leaseInfo = machineMapper.getLeaseParentId(machine); LeaseApplyInfo leaseInfo = machineMapper.getLeaseParentId(machine);
if (leaseInfo.getParentId() == null){ if (leaseInfo == null || leaseInfo.getParentId() == null){
baseInfo.setLeaseTime(null); baseInfo.setLeaseTime(null);
baseInfo.setLeaseUnit(null); baseInfo.setLeaseUnit(null);
baseInfo.setLeaseProject(null); baseInfo.setLeaseProject(null);
@ -381,7 +381,7 @@ public class MachineServiceImpl implements IMachineService
// 根据maid查询退料任务 // 根据maid查询退料任务
LeaseApplyInfo leaseInfoBack = machineMapper.getBackParentId(machine); LeaseApplyInfo leaseInfoBack = machineMapper.getBackParentId(machine);
if (leaseInfoBack.getParentId() == null){ if (leaseInfoBack == null || leaseInfoBack.getParentId() == null){
baseInfo.setBackTime(null); baseInfo.setBackTime(null);
baseInfo.setBackUnit(null); baseInfo.setBackUnit(null);
baseInfo.setBackProject(null); baseInfo.setBackProject(null);

View File

@ -173,8 +173,6 @@ public class WarehousingServiceImpl implements WarehousingService {
machIneDto.setNum(dto.getNum()); machIneDto.setNum(dto.getNum());
machIneDto.setIsCode(dto.getIsCode()); machIneDto.setIsCode(dto.getIsCode());
machIneDto.setTypeId(dto.getTypeId()); machIneDto.setTypeId(dto.getTypeId());
machIneDto.setUnitId(dto.getUnitId());
machIneDto.setProId(dto.getProId());
machIneDto.setRemarks(dto.getRemarks()); machIneDto.setRemarks(dto.getRemarks());
res += insertInfo(machIneDto); res += insertInfo(machIneDto);
machIneDto.setInfoId(machIneDto.getId()); machIneDto.setInfoId(machIneDto.getId());

View File

@ -125,4 +125,11 @@ public interface PartArrivedMapper
* @return * @return
*/ */
int updateTaskStatus(@Param("taskId") Long taskId,@Param("status") Integer status); int updateTaskStatus(@Param("taskId") Long taskId,@Param("status") Integer status);
/**
* 修改采购配件主表
* @param partTypeCheckInfo
* @return
*/
int updatePurchaseCheckInfo(PartTypeCheckInfo partTypeCheckInfo);
} }

View File

@ -105,6 +105,7 @@ public class PartArrivedServiceImpl implements IPartArrivedService
@Transactional @Transactional
public AjaxResult insertPartTypeCheckInfo(PartTypeCheckDto partTypeCheckDto) { public AjaxResult insertPartTypeCheckInfo(PartTypeCheckDto partTypeCheckDto) {
partTypeCheckDto.getPartTypeCheckInfo().setCreateTime(DateUtils.getNowDate()); partTypeCheckDto.getPartTypeCheckInfo().setCreateTime(DateUtils.getNowDate());
partTypeCheckDto.getPartTypeCheckInfo().setPurchaseTime(DateUtils.getNowDate());
partTypeCheckDto.getPartTypeCheckInfo().setCreateBy(SecurityUtils.getLoginUser().getSysUser().getNickName()); partTypeCheckDto.getPartTypeCheckInfo().setCreateBy(SecurityUtils.getLoginUser().getSysUser().getNickName());
try { try {
final int thisMonthMaxOrder = partArrivedMapper.getMonthMaxOrderByDate(DateUtils.getCurrentYear(), DateUtils.getCurrentMonth(), TmTaskTypeEnum.TM_TASK_PART_TYPE.getTaskTypeId()); final int thisMonthMaxOrder = partArrivedMapper.getMonthMaxOrderByDate(DateUtils.getCurrentYear(), DateUtils.getCurrentMonth(), TmTaskTypeEnum.TM_TASK_PART_TYPE.getTaskTypeId());
@ -237,17 +238,17 @@ public class PartArrivedServiceImpl implements IPartArrivedService
BigDecimal inputNum = new BigDecimal(0); BigDecimal inputNum = new BigDecimal(0);
BigDecimal purchasePrice = new BigDecimal(0); BigDecimal purchasePrice = new BigDecimal(0);
BigDecimal purchaseTaxPrice = new BigDecimal(0); BigDecimal purchaseTaxPrice = new BigDecimal(0);
String partName = ""; Set<String> partNameSet = new HashSet<>();
for (int j = 0; j < partTypeCheckDetails.size(); j++) { for (int j = 0; j < partTypeCheckDetails.size(); j++) {
purchaseNum = purchaseNum.add(partTypeCheckDetails.get(j).getPurchaseNum()); purchaseNum = purchaseNum.add(partTypeCheckDetails.get(j).getPurchaseNum());
inputNum = inputNum.add(partTypeCheckDetails.get(j).getInputNum()); inputNum = inputNum.add(partTypeCheckDetails.get(j).getInputNum());
purchasePrice = purchasePrice.add(partTypeCheckDetails.get(j).getPurchasePrice().multiply(partTypeCheckDetails.get(j).getPurchaseNum())); purchasePrice = purchasePrice.add(partTypeCheckDetails.get(j).getPurchasePrice().multiply(partTypeCheckDetails.get(j).getPurchaseNum()));
purchaseTaxPrice = purchaseTaxPrice.add(partTypeCheckDetails.get(j).getPurchaseTaxPrice().multiply(partTypeCheckDetails.get(j).getPurchaseNum())); purchaseTaxPrice = purchaseTaxPrice.add(partTypeCheckDetails.get(j).getPurchaseTaxPrice().multiply(partTypeCheckDetails.get(j).getPurchaseNum()));
partName = partName + partTypeCheckDetails.get(j).getMaTypeName(); // 将名称添加到Set中自动去重
if (j < partTypeCheckDetails.size() - 1) { partNameSet.add(partTypeCheckDetails.get(j).getMaTypeName());
partName += ",";
}
} }
// 将Set中的元素用逗号拼接成字符串
String partName = String.join(",", partNameSet);
partTypeCheckInfos.get(i).setInputMaNumber(inputNum); partTypeCheckInfos.get(i).setInputMaNumber(inputNum);
partTypeCheckInfos.get(i).setPurchaseMaNumber(purchaseNum); partTypeCheckInfos.get(i).setPurchaseMaNumber(purchaseNum);
partTypeCheckInfos.get(i).setPurchasePrice(purchasePrice); partTypeCheckInfos.get(i).setPurchasePrice(purchasePrice);
@ -402,6 +403,11 @@ public class PartArrivedServiceImpl implements IPartArrivedService
} }
partArrivedMapper.deletePartTypeCheckDetailsByParentIds(partTypeCheckDto.getPartTypeCheckInfo().getTaskId()); partArrivedMapper.deletePartTypeCheckDetailsByParentIds(partTypeCheckDto.getPartTypeCheckInfo().getTaskId());
if (ids.length > 0) { if (ids.length > 0) {
// 修改采购配件主表
int res = partArrivedMapper.updatePurchaseCheckInfo(partTypeCheckDto.getPartTypeCheckInfo());
if (res == 0) {
throw new ServiceException("修改失败");
}
insertPartTypeCheckDetails(partTypeCheckDto.getPartTypeCheckDetailsList(), partTypeCheckDto.getPartTypeCheckInfo().getTaskId()); insertPartTypeCheckDetails(partTypeCheckDto.getPartTypeCheckDetailsList(), partTypeCheckDto.getPartTypeCheckInfo().getTaskId());
} }
return true; return true;

View File

@ -335,14 +335,14 @@ public class RepairInputDetailsServiceImpl implements IRepairInputDetailsService
*/ */
@Override @Override
public AjaxResult getInfoByQrcode(BmQrcodeInfo bmQrcodeInfo) { public AjaxResult getInfoByQrcode(BmQrcodeInfo bmQrcodeInfo) {
if (bmQrcodeInfo.getQrCode() == null) { if (bmQrcodeInfo.getQrCode() == null && bmQrcodeInfo.getMaCode() == null) {
return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), "二维码code不能为空"); return AjaxResult.error(HttpCodeEnum.FAIL.getCode(), "编码或二维码code不能为空");
} }
List<RepairInputDetails> recordList = repairInputDetailsMapper.getInfoByQrcode(bmQrcodeInfo); List<RepairInputDetails> recordList = repairInputDetailsMapper.getInfoByQrcode(bmQrcodeInfo);
if (CollectionUtil.isNotEmpty(recordList)) { if (CollectionUtil.isNotEmpty(recordList)) {
return AjaxResult.success(recordList); return AjaxResult.success(recordList);
} }
return AjaxResult.error(HttpCodeEnum.SYSTEM_ERROR.getCode(), "二维码处于非修试待入库状态"); return AjaxResult.error(HttpCodeEnum.SYSTEM_ERROR.getCode(), "码处于非修试待入库状态");
} }
/** /**
@ -781,8 +781,11 @@ public class RepairInputDetailsServiceImpl implements IRepairInputDetailsService
//1查询入参设备是否为待入库设备 //1查询入参设备是否为待入库设备
RepairInputDetails inputInfo = new RepairInputDetails(); RepairInputDetails inputInfo = new RepairInputDetails();
if (StringUtils.isNotBlank(inputApplyDetails.getMaCode())) {
inputInfo = checkCodeMachineStatus(inputApplyDetails.getMaCode());
} else {
inputInfo = checkMachineStatus(inputApplyDetails.getQrCode()); inputInfo = checkMachineStatus(inputApplyDetails.getQrCode());
}
if(inputInfo ==null){ if(inputInfo ==null){
throw new ServiceException("设备不是修试后待入库状态"); throw new ServiceException("设备不是修试后待入库状态");
} }
@ -808,6 +811,32 @@ public class RepairInputDetailsServiceImpl implements IRepairInputDetailsService
return result; return result;
} }
/**
* 修饰入库之编码入库
* @param maCode
* @return
*/
private RepairInputDetails checkCodeMachineStatus(String maCode) {
RepairInputDetails inputInfo = new RepairInputDetails();
Machine ma = new Machine();
ma.setMaCode(maCode);
Machine ma2 = machineMapper.selectMachineByQrCode(ma);
long maId = ma2.getMaId();
String status = ma2.getMaStatus();
if("5".equals(status)){
InputApplyDetails inputApplyDetails = new InputApplyDetails();
inputApplyDetails.setMaId(maId);
inputInfo = repairInputDetailsMapper.selectInputInfoByMaId(inputApplyDetails);
}else{
inputInfo = null;
}
return inputInfo;
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public int sanQrBoxInput(RepairInputDetails repairInputDetails) { public int sanQrBoxInput(RepairInputDetails repairInputDetails) {

View File

@ -1349,6 +1349,8 @@ public class RepairServiceImpl implements RepairService {
} }
} }
} }
//修改退料任务的状态以及退料详情里面的状态
int res = taskMapper.updateTaskStatus(String.valueOf(taskId), 1);
// 4. 删除维修明细数据 // 4. 删除维修明细数据
result = repairMapper.deleteByTaskId(taskId); result = repairMapper.deleteByTaskId(taskId);
if (result < 1) { if (result < 1) {

View File

@ -121,6 +121,36 @@
) AS t2 ) AS t2
</select> </select>
<select id="getGadgetList" resultType="com.bonus.material.codeCollection.domain.WsMaInfo">
SELECT id,
ma_name AS maName,
ma_model AS maModel,
ma_code AS maCode,
this_check_time AS thisCheckTime,
next_check_time AS nextCheckTime,
repair_man AS repairMan,
check_man AS checkMan,
phone,
result
FROM ws_ma_info wmi
WHERE is_active = '1'
<if test="keyWord != null and keyWord != ''">
and ( ma_name like concat('%', #{keyWord}, '%') or
ma_model like concat('%', #{keyWord}, '%') or
ma_code like concat('%', #{keyWord}, '%') or
repair_man like concat('%', #{keyWord}, '%') or
check_man like concat('%', #{keyWord}, '%')
)
</if>
<if test="startTime != null and startTime != '' and endTime != null and endTime != ''">
<![CDATA[
and (
DATE_FORMAT( this_check_time, '%Y-%m-%d' ) BETWEEN #{startTime} AND #{endTime} or
DATE_FORMAT( next_check_time, '%Y-%m-%d' ) BETWEEN #{startTime} AND #{endTime}
)
]]>
</if>
</select>
<insert id="insert" parameterType="com.bonus.material.codeCollection.domain.WsMaInfo" useGeneratedKeys="true" <insert id="insert" parameterType="com.bonus.material.codeCollection.domain.WsMaInfo" useGeneratedKeys="true"

View File

@ -622,8 +622,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
FROM FROM
ma_machine mm ma_machine mm
WHERE WHERE
mm.qr_code = #{qrCode} 1 = 1
<if test="qrCode != null and qrCode != ''">
and mm.qr_code = #{qrCode}
</if>
<if test="maCode != null and maCode != ''">
and mm.ma_code LIKE CONCAT('%',#{maCode},'%')
</if>
</select> </select>
<select id="getInfoByQrcode" resultType="com.bonus.material.ma.domain.Machine"> <select id="getInfoByQrcode" resultType="com.bonus.material.ma.domain.Machine">

View File

@ -64,8 +64,8 @@
</if> </if>
</otherwise> </otherwise>
</choose> </choose>
<if test="typeId != null and typeId != ''">type_id,</if> <!-- <if test="typeId != null">type_id,</if>-->
<if test="creator != null and creator != ''">creator,</if> <if test="creator != null">creator,</if>
<if test="code != null and code != ''">code,</if> <if test="code != null and code != ''">code,</if>
<if test="remarks != null and remarks != ''">remarks,</if> <if test="remarks != null and remarks != ''">remarks,</if>
create_time create_time
@ -83,7 +83,7 @@
</if> </if>
</otherwise> </otherwise>
</choose> </choose>
<if test="typeId != null and typeId != ''">#{typeId},</if>
<if test="creator != null and creator != ''">#{creator},</if> <if test="creator != null and creator != ''">#{creator},</if>
<if test="code != null and code != ''">#{code},</if> <if test="code != null and code != ''">#{code},</if>
<if test="remarks != null and remarks != ''">#{remarks},</if> <if test="remarks != null and remarks != ''">#{remarks},</if>

View File

@ -13,6 +13,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
task_id = #{taskId} task_id = #{taskId}
</update> </update>
<update id="updatePurchaseCheckInfo">
update purchase_part_info
<trim prefix="SET" suffixOverrides=",">
<if test="taskId != null">task_id = #{taskId},</if>
<if test="purchaseTime != null">purchase_time = #{purchaseTime},</if>
<if test="arrivalTime != null">arrival_time = #{arrivalTime},</if>
<if test="purchaser != null">purchaser = #{purchaser},</if>
<if test="createBy != null">create_by = #{createBy},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="remark != null">remark = #{remark},</if>
<if test="companyId != null">company_id = #{companyId},</if>
</trim>
where ID = #{id}
</update>
<select id="getTypeTree" resultType="com.bonus.material.part.domain.PartTypeDto"> <select id="getTypeTree" resultType="com.bonus.material.part.domain.PartTypeDto">
select DISTINCT m.pa_id as partId, m.pa_name as partName, m.parent_id as parentId, m.unit_id as unitId, m.unit_name as unitName, m.storage_num as storageNum, select DISTINCT m.pa_id as partId, m.pa_name as partName, m.parent_id as parentId, m.unit_id as unitId, m.unit_name as unitName, m.storage_num as storageNum,
m.rent_price as rentPrice, m.buy_price as buyPrice, m.level,m.del_flag as delFlag,m.remark m.rent_price as rentPrice, m.buy_price as buyPrice, m.level,m.del_flag as delFlag,m.remark
@ -130,7 +147,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectPartTypeCheckDetailsList" resultType="com.bonus.material.part.domain.PartTypeCheckDetails"> <select id="selectPartTypeCheckDetailsList" resultType="com.bonus.material.part.domain.PartTypeCheckDetails">
select part_id as partId, select part_id as partId,
mpt.pa_name as maTypeName, mpt2.pa_name as maTypeName,
purchase_price as purchasePrice, purchase_price as purchasePrice,
purchase_tax_price as purchaseTaxPrice, purchase_tax_price as purchaseTaxPrice,
purchase_num as purchaseNum, purchase_num as purchaseNum,
@ -138,6 +155,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
IFNULL(ppd.input_num, 0) as inputNum IFNULL(ppd.input_num, 0) as inputNum
from purchase_part_details ppd from purchase_part_details ppd
left join ma_part_type mpt on ppd.part_id = mpt.pa_id and mpt.del_flag = 0 left join ma_part_type mpt on ppd.part_id = mpt.pa_id and mpt.del_flag = 0
left join ma_part_type mpt2 on mpt.parent_id = mpt2.pa_id and mpt2.del_flag = 0
where ppd.task_id = #{taskId} where ppd.task_id = #{taskId}
and ppd.del_flag = 0 and ppd.del_flag = 0
</select> </select>

View File

@ -331,7 +331,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
LEFT JOIN repair_apply_details rad ON rad.id = rid.repair_id LEFT JOIN repair_apply_details rad ON rad.id = rid.repair_id
LEFT JOIN tm_task tt1 on rad.task_id = tt1.task_id LEFT JOIN tm_task tt1 on rad.task_id = tt1.task_id
WHERE WHERE
mm.ma_status = '5' and mm.qr_code = #{qrCode} rid.`status` = '0' and mm.ma_status = '5'
<if test="qrCode != null and qrCode != ''">
and mm.qr_code = #{qrCode}
</if>
<if test="maCode != null and maCode != ''">
and mm.ma_code like concat('%',#{maCode},'%')
</if>
</select> </select>
<insert id="batchInsertRepairInputDetails" parameterType="com.bonus.common.biz.domain.repair.RepairInputDetails"> <insert id="batchInsertRepairInputDetails" parameterType="com.bonus.common.biz.domain.repair.RepairInputDetails">
@ -491,7 +497,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectInputInfoByMaId" resultMap="RepairInputDetailsResult"> <select id="selectInputInfoByMaId" resultMap="RepairInputDetailsResult">
select id, task_id, ma_id, type_id, input_num, create_by, create_time, update_by, update_time, remark, company_id from repair_input_details select id, task_id, ma_id, type_id, input_num, create_by, create_time, update_by, update_time, remark, company_id from repair_input_details
where ma_id = #{maId} where status = '0' and ma_id = #{maId}
limit 1 limit 1
</select> </select>

View File

@ -796,8 +796,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
saa.create_time as createTime, saa.create_time as createTime,
SUM(IF(sad.slt_type = '1',sad.money,0)) AS leaseCost, SUM(IF(sad.slt_type = '1',sad.money,0)) AS leaseCost,
SUM(IF(sad.slt_type = '2',sad.money,0)) AS loseCost, SUM(IF(sad.slt_type = '2',sad.money,0)) AS loseCost,
SUM(IF(sad.slt_type = '3',sad.money,0)) AS repairCost, SUM(IF(sad.slt_type = '3' AND sad.is_charge = '1',sad.money,0)) AS repairCost,
SUM(IF(sad.slt_type = '4',sad.money,0)) AS scrapCost, SUM(IF(sad.slt_type = '4' AND sad.is_charge = '1',sad.money,0)) AS scrapCost,
case when saa.status = '1' then '1' when saa.status = '2' then '2' when saa.status = '3' then '3' end as sltStatus case when saa.status = '1' then '1' when saa.status = '2' then '2' when saa.status = '3' then '3' end as sltStatus
FROM FROM
bm_agreement_info bai bm_agreement_info bai