取消关联关系接口

This commit is contained in:
李贵强 2025-03-13 17:14:45 +08:00
parent b8e40c83e1
commit 2358d450f0
4 changed files with 329 additions and 27 deletions

View File

@ -6,24 +6,20 @@ import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.utils.StringUtils;
import kd.bos.form.FormShowParameter;
import kd.bos.form.ShowType;
import kd.bos.form.control.Button;
import kd.bos.form.control.Control;
import kd.bos.form.control.EntryGrid;
import kd.bos.form.control.Toolbar;
import kd.bos.form.control.events.ItemClickEvent;
import kd.bos.form.events.AfterDoOperationEventArgs;
import kd.bos.form.events.BeforeClosedEvent;
import kd.bos.form.operate.FormOperate;
import kd.bos.form.plugin.AbstractFormPlugin;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.servicehelper.user.UserServiceHelper;
import kd.sdk.plugin.Plugin;
import shjh.jhzj7.fi.fi.plugin.form.info.ClaimFieldsInfo;
import shjh.jhzj7.fi.fi.utils.ApiUtils;
import shjh.jhzj7.fi.fi.utils.EsbUtils;
import java.util.*;
/**
@ -491,6 +487,7 @@ public class FeeControlApiPlugin extends AbstractFormPlugin implements Plugin {
for (int selectRow : selectRows) {
DynamicObject dynamicObject = entity.get(selectRow);
PARAM_LIST.add(dynamicObject);
}
this.getView().close();
} else {

View File

@ -14,7 +14,10 @@ import kd.bos.entity.plugin.PreparePropertysEventArgs;
import kd.bos.entity.plugin.args.AfterOperationArgs;
import kd.bos.entity.validate.AbstractValidator;
import kd.bos.entity.validate.ErrorLevel;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.operation.SaveServiceHelper;
import kd.sdk.plugin.Plugin;
import shjh.jhzj7.fi.fi.utils.ApiUtils;
import shjh.jhzj7.fi.fi.utils.EsbUtils;
@ -30,6 +33,9 @@ import java.util.*;
*/
public class LoanPushSapOperation extends AbstractOperationServicePlugIn implements Plugin {
private final static Log logger = LogFactory.getLog(LoanPushSapOperation.class);
/**
* 操作标识
*/
@ -43,9 +49,11 @@ public class LoanPushSapOperation extends AbstractOperationServicePlugIn impleme
@Override
public void onPreparePropertys(PreparePropertysEventArgs e) {
super.onPreparePropertys(e);
//收款类型=预付款退回 and SAP凭证号不为空
e.getFieldKeys().add(PaymentPushSapOperation.PaymentValidator.KEY_RECEIVING_TYPE);
e.getFieldKeys().add(PaymentPushSapOperation.PaymentValidator.KEY_VOUCHER_NUM);
//收款类型=预付款退回 and SAP凭证号不为空 and是否已推送费控=
e.getFieldKeys().add(LoanPushSapOperation.LoanValidator.KEY_RECEIVING_TYPE);
e.getFieldKeys().add(LoanPushSapOperation.LoanValidator.KEY_VOUCHER_NUM);
e.getFieldKeys().add(LoanPushSapOperation.LoanValidator.KEY_BILL_NUMBER);
e.getFieldKeys().add(LoanPushSapOperation.LoanValidator.KEY_IS_PUSH_FI);
}
/**
@ -57,7 +65,7 @@ public class LoanPushSapOperation extends AbstractOperationServicePlugIn impleme
public void onAddValidators(AddValidatorsEventArgs e) {
super.onAddValidators(e);
//添加自定义校验器:收款类型=员工还款 and SAP凭证号不为空
e.addValidator(new PaymentPushSapOperation.PaymentValidator());
e.addValidator(new LoanValidator());
}
@ -78,14 +86,15 @@ public class LoanPushSapOperation extends AbstractOperationServicePlugIn impleme
String interfaceId = "GeneraRepayBill";
HashMap<String, String> responseHead = ApiUtils.buildHead(interfaceId);
HashMap<String, Object> responseBody = this.assembleRequest(interfaceId,billNumber, recBill,message);
try {
String response = ApiUtils.sendPost(responseHead, responseBody, "https://hipint-stg.jahwa.com.cn:6443/gateway/HIP_ReceiveFromFM/1.0/fm/send");
//try {
// String response = ApiUtils.sendPost(responseHead, responseBody, "https://hipint-stg.jahwa.com.cn:6443/gateway/HIP_ReceiveFromFM/1.0/fm/send");
String response="{ \"rootContextID\": \"8as6dfasd6f98as7d6f9a98sd76f\", \"code\": \"0\", \"msg\": \"成功\", \"data\": { \"ID\": \"ab7a4722-656e-4fdf-bcea-3d40d175fa78\", \"BillConfigID\": 2524, \"RequestCode\": \"JKY2025030400002\" } }";
if (!response.isEmpty()) {
this.parseResponse(response, billNumber, responseBody, interfaceId, message);
this.parseResponse(recBill,response, billNumber, responseBody, interfaceId, message);
}
} catch (IOException ex) {
message.append("收款处理【").append(billNumber).append("】:").append(ex.getMessage()).append("\n");
}
//} catch (IOException ex) {
// message.append("收款处理【").append(billNumber).append("】:").append(ex.getMessage()).append("\n");
//}
if (message.length()!=0){
OperateErrorInfo operateErrorInfo = new OperateErrorInfo();
operateErrorInfo.setMessage(String.valueOf(message));
@ -102,7 +111,11 @@ public class LoanPushSapOperation extends AbstractOperationServicePlugIn impleme
/**
* 自定义校验器
*/
static class PaymentValidator extends AbstractValidator {
static class LoanValidator extends AbstractValidator {
/**
* 单据编码
*/
public final static String KEY_BILL_NUMBER = "billno";
/**
* 收款类型字段标识
*/
@ -111,7 +124,10 @@ public class LoanPushSapOperation extends AbstractOperationServicePlugIn impleme
* SAP凭证号字段标识
*/
public final static String KEY_VOUCHER_NUM = "shjh_vouchernum";
/**
* 是否已推送费控
*/
public final static String KEY_IS_PUSH_FI ="shjh_ispushfc";
@Override
public void validate() {
@ -122,19 +138,24 @@ public class LoanPushSapOperation extends AbstractOperationServicePlugIn impleme
for (ExtendedDataEntity dataEntity : dataEntities) {
if (dataEntity != null) {
rowDataModel.setRowContext(dataEntity.getDataEntity());
String billNo = (String) rowDataModel.getValue(KEY_BILL_NUMBER);
DynamicObject type = (DynamicObject) rowDataModel.getValue(KEY_RECEIVING_TYPE);
if (null != type) {
String number = type.getString("number");
if (null != number) {
if (!"109".equals(number)) {
// 校验不通过输出一条错误提示
this.addErrorMessage(dataEntity, "请选择【收款类型】=【员工还款】的单据");
this.addErrorMessage(dataEntity, "" + billNo + "】收款类型不符");
}
}
}
String voucherNumber = (String) rowDataModel.getValue(KEY_VOUCHER_NUM);
if (voucherNumber.isEmpty()) {
this.addErrorMessage(dataEntity, "SAP凭证不能为空");
this.addErrorMessage(dataEntity, "" + billNo + "】SAP凭证不能为空");
}
boolean result = (boolean) rowDataModel.getValue(KEY_IS_PUSH_FI);
if (result) {
this.addErrorMessage(dataEntity, "" + billNo + "】已推送费控,请勿重复推送!");
}
}
}
@ -197,7 +218,7 @@ public class LoanPushSapOperation extends AbstractOperationServicePlugIn impleme
bodyItem.put("FM_JKYRequestCode", entry.getString("shjh_loannum"));
bodyItem.put("FM_JKYBillHeaderID", entry.getString("shjh_billheaderid"));
bodyItem.put("FM_JKYDetailID", entry.getString("shjh_detailid"));
bodyItem.put("FM_RepayAmt", entry.getBigDecimal("shjh_refundedamount"));
bodyItem.put("FM_RepayAmt", entry.getBigDecimal("shjh_repaymentamount"));
body.add(bodyItem);
}
header.put("FM_LoanRequestList", loanRequestList);
@ -222,13 +243,15 @@ public class LoanPushSapOperation extends AbstractOperationServicePlugIn impleme
* @param body 请求体
* @param apiName 接口名
*/
private void parseResponse(String response, String billNumber, HashMap<String, Object> body, String apiName, StringBuilder message) {
private void parseResponse(DynamicObject recBill,String response, String billNumber, HashMap<String, Object> body, String apiName, StringBuilder message) {
JSONObject result = JSONObject.parseObject(response);
if (null != result) {
String formattedBody = JSON.toJSONString(body);
String code = result.getString("code");
switch (code) {
case "0":
JSONObject data = JSONObject.parseObject(result.getString("data"));
this.successProcess(recBill,data,billNumber);
EsbUtils.saveLog("收款处理"+billNumber, apiName, formattedBody, response, true, "ESBPushApi", "推送成功");
break;
case "1":
@ -250,4 +273,18 @@ public class LoanPushSapOperation extends AbstractOperationServicePlugIn impleme
}
}
}
/**
* 反写字段
* @param recBill
* @param data
* @param billNumber
*/
private void successProcess(DynamicObject recBill,JSONObject data,String billNumber){
recBill.set("shjh_ispushfc",true);
recBill.set("shjh_returnid",data.getString("ID"));
recBill.set("shjh_returncode",data.getString("RequestCode"));
SaveServiceHelper.update(recBill);
logger.info(billNumber+"反写是否已推送费控true");
}
}

View File

@ -14,11 +14,13 @@ import kd.bos.entity.plugin.PreparePropertysEventArgs;
import kd.bos.entity.plugin.args.AfterOperationArgs;
import kd.bos.entity.validate.AbstractValidator;
import kd.bos.entity.validate.ErrorLevel;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.operation.SaveServiceHelper;
import kd.sdk.plugin.Plugin;
import shjh.jhzj7.fi.fi.utils.ApiUtils;
import shjh.jhzj7.fi.fi.utils.EsbUtils;
import shjh.jhzj7.fi.fi.utils.SysUtils;
import java.io.IOException;
import java.text.SimpleDateFormat;
@ -31,6 +33,9 @@ import java.util.*;
*/
public class PaymentPushSapOperation extends AbstractOperationServicePlugIn implements Plugin {
private final static Log logger = LogFactory.getLog(PaymentPushSapOperation.class);
/**
* 操作标识
*/
@ -47,6 +52,8 @@ public class PaymentPushSapOperation extends AbstractOperationServicePlugIn impl
//收款类型=预付款退回 and SAP凭证号不为空
e.getFieldKeys().add(PaymentValidator.KEY_RECEIVING_TYPE);
e.getFieldKeys().add(PaymentValidator.KEY_VOUCHER_NUM);
e.getFieldKeys().add(PaymentValidator.KEY_BILL_NUMBER);
e.getFieldKeys().add(PaymentValidator.KEY_IS_PUSH_FI);
}
/**
@ -82,7 +89,7 @@ public class PaymentPushSapOperation extends AbstractOperationServicePlugIn impl
try {
String response = ApiUtils.sendPost(responseHead, responseBody, "https://hipint-stg.jahwa.com.cn:6443/gateway/HIP_ReceiveFromFM/1.0/fm/send");
if (!response.isEmpty()) {
this.parseResponse(response, billNumber, responseBody, interfaceId, message);
this.parseResponse(recBill,response, billNumber, responseBody, interfaceId, message);
}
} catch (IOException ex) {
message.append("收款处理【").append(billNumber).append("】:").append(ex.getMessage()).append("\n");
@ -104,6 +111,10 @@ public class PaymentPushSapOperation extends AbstractOperationServicePlugIn impl
* 自定义校验器
*/
static class PaymentValidator extends AbstractValidator {
/**
* 单据编码
*/
public final static String KEY_BILL_NUMBER = "billno";
/**
* 收款类型字段标识
*/
@ -112,6 +123,11 @@ public class PaymentPushSapOperation extends AbstractOperationServicePlugIn impl
* SAP凭证号字段标识
*/
public final static String KEY_VOUCHER_NUM = "shjh_vouchernum";
/**
* 是否已推送费控
*/
public final static String KEY_IS_PUSH_FI ="shjh_ispushfc";
@Override
@ -123,19 +139,24 @@ public class PaymentPushSapOperation extends AbstractOperationServicePlugIn impl
for (ExtendedDataEntity dataEntity : dataEntities) {
if (dataEntity != null) {
rowDataModel.setRowContext(dataEntity.getDataEntity());
String billNo = (String) rowDataModel.getValue(KEY_BILL_NUMBER);
DynamicObject type = (DynamicObject) rowDataModel.getValue(KEY_RECEIVING_TYPE);
if (null != type) {
String number = type.getString("number");
if (null != number) {
if (!"103".equals(number)) {
// 校验不通过输出一条错误提示
this.addErrorMessage(dataEntity, "请选择【收款类型】=【退预付款】的单据");
this.addErrorMessage(dataEntity, ""+billNo+"】收款类型不符");
}
}
}
String voucherNumber = (String) rowDataModel.getValue(KEY_VOUCHER_NUM);
if (voucherNumber.isEmpty()) {
this.addErrorMessage(dataEntity, "SAP凭证不能为空");
this.addErrorMessage(dataEntity, ""+billNo+"】SAP凭证不能为空");
}
boolean result = (boolean) rowDataModel.getValue(KEY_IS_PUSH_FI);
if (result){
this.addErrorMessage(dataEntity, ""+billNo+"】已推送费控,请勿重复推送!");
}
}
}
@ -223,13 +244,15 @@ public class PaymentPushSapOperation extends AbstractOperationServicePlugIn impl
* @param body 请求体
* @param apiName 接口名
*/
private void parseResponse(String response, String billNumber, HashMap<String, Object> body, String apiName, StringBuilder message) {
private void parseResponse(DynamicObject recBill,String response, String billNumber, HashMap<String, Object> body, String apiName, StringBuilder message) {
JSONObject result = JSONObject.parseObject(response);
if (null != result) {
String formattedBody = JSON.toJSONString(body);
String code = result.getString("code");
switch (code) {
case "0":
JSONObject data = JSONObject.parseObject(result.getString("data"));
this.successProcess(recBill,data,billNumber);
EsbUtils.saveLog("收款处理"+billNumber, apiName, formattedBody, response, true, "ESBPushApi", "推送成功");
break;
case "1":
@ -269,4 +292,18 @@ public class PaymentPushSapOperation extends AbstractOperationServicePlugIn impl
}
return number;
}
/**
* 反写字段
* @param recBill
* @param data
* @param billNumber
*/
private void successProcess(DynamicObject recBill,JSONObject data,String billNumber){
recBill.set("shjh_ispushfc",true);
recBill.set("shjh_returnid",data.getString("ID"));
recBill.set("shjh_returncode",data.getString("RequestCode"));
SaveServiceHelper.update(recBill);
logger.info(billNumber+"反写是否已推送费控true");
}
}

View File

@ -0,0 +1,231 @@
package shjh.jhzj7.fi.fi.plugin.operate;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.utils.StringUtils;
import kd.bos.entity.ExtendedDataEntity;
import kd.bos.entity.formula.RowDataModel;
import kd.bos.entity.operate.result.OperateErrorInfo;
import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
import kd.bos.entity.plugin.AddValidatorsEventArgs;
import kd.bos.entity.plugin.PreparePropertysEventArgs;
import kd.bos.entity.plugin.args.AfterOperationArgs;
import kd.bos.entity.validate.AbstractValidator;
import kd.bos.entity.validate.ErrorLevel;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.operation.SaveServiceHelper;
import kd.sdk.plugin.Plugin;
import shjh.jhzj7.fi.fi.utils.ApiUtils;
import shjh.jhzj7.fi.fi.utils.EsbUtils;
import shjh.jhzj7.fi.fi.utils.SysUtils;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* 单据操作插件
* 智慧财务-冲销接口
* @author LiGuiQiang
*/
public class RebReversalFiOperation extends AbstractOperationServicePlugIn implements Plugin {
private final static Log logger = LogFactory.getLog(RebReversalFiOperation.class);
/**
* 操作标识
*/
private static final String KEY_REVERSAL = "reversal";
/**
* 操作执行前准备加载单据数据之前触发此事件
*
* @remark 插件可以在此事件中指定需要加载的字段
*/
@Override
public void onPreparePropertys(PreparePropertysEventArgs e) {
super.onPreparePropertys(e);
e.getFieldKeys().add(ReversalValidator.KEY_RECEIVING_TYPE);
e.getFieldKeys().add(ReversalValidator.KEY_VOUCHER_NUM);
e.getFieldKeys().add(ReversalValidator.KEY_BILL_NUMBER);
e.getFieldKeys().add(ReversalValidator.KEY_IS_PUSH_FI);
}
/**
* 执行操作校验前触发此事件
*
* @remark 插件可以在此事件调整预置的操作校验器或者增加自定义操作校验器
*/
@Override
public void onAddValidators(AddValidatorsEventArgs e) {
super.onAddValidators(e);
//添加自定义校验器:1.收款类型=预付款退回 or 员工还款 2.已推费控
e.addValidator(new ReversalValidator());
}
/**
* 自定义校验器
*/
static class ReversalValidator extends AbstractValidator {
/**
* 单据编码
*/
public final static String KEY_BILL_NUMBER = "billno";
/**
* 收款类型字段标识
*/
public final static String KEY_RECEIVING_TYPE = "receivingtype";
/**
* SAP凭证号字段标识
*/
public final static String KEY_VOUCHER_NUM = "shjh_vouchernum";
/**
* 是否已推送费控
*/
public final static String KEY_IS_PUSH_FI ="shjh_ispushfc";
@Override
public void validate() {
//取数模型
RowDataModel rowDataModel = new RowDataModel(this.entityKey, this.getValidateContext().getSubEntityType());
ExtendedDataEntity[] dataEntities = this.getDataEntities();
if (dataEntities != null && dataEntities.length >= 1) {
for (ExtendedDataEntity dataEntity : dataEntities) {
if (dataEntity != null) {
rowDataModel.setRowContext(dataEntity.getDataEntity());
String billNo = (String) rowDataModel.getValue(KEY_BILL_NUMBER);
DynamicObject type = (DynamicObject) rowDataModel.getValue(KEY_RECEIVING_TYPE);
if (null != type) {
String number = type.getString("number");
if (null != number) {
if (!"109".equals(number)&&!"103".equals(number)) {
// 校验不通过输出一条错误提示
this.addErrorMessage(dataEntity, "" + billNo + "】收款类型不符!");
}
}
}
boolean result = (boolean) rowDataModel.getValue(KEY_IS_PUSH_FI);
if (!result) {
this.addErrorMessage(dataEntity, "" + billNo + "】未推送费控,无法冲销!");
}
}
}
}
}
}
@Override
public void afterExecuteOperationTransaction(AfterOperationArgs e) {
//TODO:调用SAP预付款单接口
String operationKey = e.getOperationKey();
if (StringUtils.equals(KEY_REVERSAL, operationKey)) {
DynamicObject[] dataEntities = e.getDataEntities();
if (dataEntities != null && dataEntities.length >= 1) {
StringBuilder message = new StringBuilder();
for (DynamicObject dataEntity : dataEntities) {
DynamicObject recBill = BusinessDataServiceHelper.loadSingle(dataEntity.getLong("id"), "cas_recbill");
if (null != recBill) {
//单号
String billNumber = recBill.getString("billno");
String interfaceId = "BillInvalid";
HashMap<String, String> responseHead = ApiUtils.buildHead(interfaceId);
HashMap<String, Object> responseBody = this.assembleRequest(interfaceId,billNumber, recBill,message);
//try {
// String response = ApiUtils.sendPost(responseHead, responseBody, "https://hipint-stg.jahwa.com.cn:6443/gateway/HIP_ReceiveFromFM/1.0/fm/send");
String response="{ \"rootContextID\": \"8as6dfasd6f98as7d6f9a98sd76f\", \"code\": \"0\", \"msg\": \"红冲作废单据处理成功\", \"data\": null }";
if (!response.isEmpty()) {
this.parseResponse(response, billNumber, responseBody, interfaceId, message);
}
//} catch (IOException ex) {
// message.append("收款处理【").append(billNumber).append("】:").append(ex.getMessage()).append("\n");
//}
//错误消息
if (message.length()!=0){
OperateErrorInfo operateErrorInfo = new OperateErrorInfo();
operateErrorInfo.setMessage(String.valueOf(message));
operateErrorInfo.setErrorLevel(ErrorLevel.Error.name());
operateErrorInfo.setPkValue(dataEntity.getPkValue());
this.operationResult.addErrorInfo(operateErrorInfo);
}
}
}
}
}
}
/**
* 请求头组装
* @param billNumber 单据编号
* @param recBill 收款处理
* @return
*/
private HashMap<String, Object> assembleRequest(String interfaceId,String billNumber,DynamicObject recBill,StringBuilder message){
HashMap<String, Object> responseBody = null;
try {
// 生成唯一事务ID
String rootContextId = UUID.randomUUID().toString();
// 获取当前请求时间格式为 yyyy-MM-dd HH:mm:ss.SSS
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String requestTime = sdf.format(new Date());
responseBody = new HashMap<>(5);
responseBody.put("rootContextID", rootContextId);
responseBody.put("requestTime", requestTime);
HashMap<String, Object> data = new HashMap<>(10);
//员工工号(操作人)
data.put("UserCode", SysUtils.getUserNumber());
//单据标识(2:预付款退回,3:员工还款)
data.put("BillType", "109".equals(recBill.getString(ReversalValidator.KEY_RECEIVING_TYPE)) ? 2:3);
//单据编号生成接口返回的RequestCode
data.put("BillCode",recBill.getString("shjh_returncode"));
//单据编号生成接口返回的ID
data.put("BillID",recBill.getString("shjh_returnid"));
responseBody.put("data", data);
} catch (Exception e) {
message.append("收款处理【").append(billNumber).append("】:").append(e.getMessage()).append("\n");
EsbUtils.saveLog(billNumber, interfaceId, null, e.getMessage(), false, "ESBReversalApi", "数据异常");
}
return responseBody;
}
/**
* 日志记录
*
* @param response 响应参数
* @param billNumber 本单单号
* @param body 请求体
* @param apiName 接口名
*/
private void parseResponse(String response, String billNumber, HashMap<String, Object> body, String apiName, StringBuilder message) {
JSONObject result = JSONObject.parseObject(response);
if (null != result) {
String formattedBody = JSON.toJSONString(body);
String code = result.getString("code");
switch (code) {
case "0":
EsbUtils.saveLog("收款处理"+billNumber, apiName, formattedBody, response, true, "ESBReversalApi", "推送成功");
break;
case "1":
EsbUtils.saveLog("收款处理"+billNumber, apiName, formattedBody, response, false, "ESBReversalApi", "服务异常");
message.append("收款处理【").append(billNumber).append("】:").append("服务异常").append("\n");
break;
case "2":
EsbUtils.saveLog("收款处理"+billNumber, apiName, formattedBody, response, false, "ESBReversalApi", "三方服务异常");
message.append("收款处理【").append(billNumber).append("】:").append("三方服务异常").append("\n");
break;
case "3":
EsbUtils.saveLog("收款处理"+billNumber, apiName, formattedBody, response, false, "ESBReversalApi", "业务异常");
message.append("收款处理【").append(billNumber).append("】:").append("业务异常").append("\n");
break;
default:
EsbUtils.saveLog("收款处理"+billNumber, apiName, formattedBody, response, false, "ESBReversalApi", "未知异常");
message.append("收款处理【").append(billNumber).append("】:").append("未知异常").append("\n");
break;
}
}
}
}