You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
412 lines
22 KiB
C#
412 lines
22 KiB
C#
using Dapper;
|
|
using Estsh.Core.Base;
|
|
using Estsh.Core.Dapper;
|
|
using Estsh.Core.Wms.IRepositories;
|
|
using Estsh.Core.Model.Result;
|
|
using Estsh.Core.Repositories;
|
|
using System.Collections;
|
|
using System.Data;
|
|
using System.Text;
|
|
using System.Security.Cryptography;
|
|
using System.Text.Json;
|
|
using Estsh.Core.Models;
|
|
using Newtonsoft.Json.Linq;
|
|
using Estsh.Core.Model.EnumUtil;
|
|
using Estsh.Core.Util;
|
|
|
|
namespace Estsh.Core.Wms.Repositories
|
|
{
|
|
public class NcConcessionRepository : BaseRepository<BaseEntity>, INcConcessionRepository
|
|
{
|
|
public NcConcessionRepository(DapperDbContext _dapperDbContext) : base(_dapperDbContext)
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取库位信息
|
|
/// </summary>
|
|
/// <param name="locateName"></param>
|
|
/// <returns></returns>
|
|
public SysLocate GetLocateInfo(string locateName)
|
|
{
|
|
using (IDbConnection dbConn = dapperDbContext.GetDbConnection())
|
|
{
|
|
dbConn.Open();
|
|
string result = string.Empty;
|
|
|
|
StringBuilder sql = new StringBuilder(1024);
|
|
sql.Append("SELECT a.*,b.erp_warehouse FROM dbo.sys_locate a (nolock) ");
|
|
sql.Append("JOIN dbo.sys_zone b (nolock) ON a.zone_id = b.zone_id ");
|
|
sql.Append("WHERE locate_name = @locateName ");
|
|
|
|
DynamicParameters parameters = new DynamicParameters();
|
|
parameters.Add("@locateName", locateName);
|
|
|
|
return dbConn.QueryFirstOrDefault<SysLocate>(sql.ToString(), parameters);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取库位对应的物料信息
|
|
/// </summary>
|
|
/// <param name="locateName"></param>
|
|
/// <returns></returns>
|
|
public SysLocatePart GetLocatePartInfo(string locateName)
|
|
{
|
|
using (IDbConnection dbConn = dapperDbContext.GetDbConnection())
|
|
{
|
|
dbConn.Open();
|
|
string result = string.Empty;
|
|
|
|
StringBuilder sql = new StringBuilder(1024);
|
|
sql.Append("SELECT * FROM dbo.sys_locate_part (nolock) WHERE locate_name = @locateName ");
|
|
DynamicParameters parameters = new DynamicParameters();
|
|
parameters.Add("@locateName", locateName);
|
|
|
|
//List<SysStock> dt = dbConn.Query<SysStock>(sql.ToString(), parameters).ToList();
|
|
return dbConn.QueryFirstOrDefault<SysLocatePart>(sql.ToString(), parameters);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 处理扫描的箱条码
|
|
/// </summary>
|
|
/// <param name="cartonInfo"></param>
|
|
/// <param name="moveDetail"></param>
|
|
/// <param name="moveSn"></param>
|
|
/// <returns></returns>
|
|
public bool DoCarton(SysStock cartonInfo, SysLocate locateInfo, WmsMoveDetail moveDetail, WmsMoveSn? moveSn, string loginId)
|
|
{
|
|
List<string> sqlStrings = new List<string>();
|
|
List<DynamicParameters> parameterList = new List<DynamicParameters>();
|
|
|
|
//更改条码表状态
|
|
StringBuilder updateSql = new StringBuilder(1024);
|
|
updateSql.Append("UPDATE sys_stock ");
|
|
updateSql.Append("SET status = @status, ");
|
|
updateSql.Append(" locate_id = @locateId, ");
|
|
updateSql.Append(" locate_name = @locateName, ");
|
|
updateSql.Append(" zone_id = @zoneId, ");
|
|
updateSql.Append(" zone_name = @zoneName, ");
|
|
updateSql.Append(" warehouse_id = @warehouseId, ");
|
|
updateSql.Append(" warehouse_name = @warehouseName, ");
|
|
updateSql.Append(" erp_warehouse = @erpWarehouse, ");
|
|
updateSql.Append(" update_userid = @updateUserid, ");
|
|
updateSql.Append(" update_time = @updateTime ");
|
|
updateSql.Append("WHERE carton_no = @cartonNo ");
|
|
|
|
DynamicParameters updateParameters = new DynamicParameters();
|
|
updateParameters.Add("@cartonNo", cartonInfo.CartonNo);
|
|
updateParameters.Add("@status", WmsEnumUtil.StockStatus.INSTOCKED);
|
|
updateParameters.Add("@locateId", locateInfo.LocateId);
|
|
updateParameters.Add("@locateName", locateInfo.LocateName);
|
|
updateParameters.Add("@zoneId", locateInfo.ZoneId);
|
|
updateParameters.Add("@zoneName", locateInfo.ZoneName);
|
|
updateParameters.Add("@warehouseId", locateInfo.WarehouseId);
|
|
updateParameters.Add("@warehouseName", locateInfo.WarehouseName);
|
|
updateParameters.Add("@erpWarehouse", locateInfo.ErpWarehouse);
|
|
updateParameters.Add("@updateUserid", loginId);
|
|
updateParameters.Add("@updateTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
|
|
|
|
sqlStrings.Add(updateSql.ToString());
|
|
parameterList.Add(updateParameters);
|
|
|
|
//更新单据主表--处理中
|
|
updateSql.Remove(0, updateSql.Length);
|
|
updateSql.Append("UPDATE dbo.wms_move_header ");
|
|
updateSql.Append("SET order_status = @orderStatus, ");
|
|
updateSql.Append(" update_userid = @updateUserid, ");
|
|
updateSql.Append(" update_time = @updateTime ");
|
|
updateSql.Append("WHERE order_no = @orderNo ");
|
|
updateSql.Append(" AND order_status < @orderStatus2 ");
|
|
|
|
updateParameters = new DynamicParameters();
|
|
updateParameters.Add("@orderStatus", WmsEnumUtil.MoveOrderStatus.PROCESSING);
|
|
updateParameters.Add("@updateUserid", loginId);
|
|
updateParameters.Add("@updateTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
|
|
updateParameters.Add("@orderNo", moveDetail.OrderNo);
|
|
updateParameters.Add("@orderStatus2", WmsEnumUtil.MoveOrderStatus.PROCESSING);
|
|
|
|
sqlStrings.Add(updateSql.ToString());
|
|
parameterList.Add(updateParameters);
|
|
|
|
bool isDetailComplate = cartonInfo.Qty + moveDetail.PickQty >= moveDetail.Qty;
|
|
|
|
//更新单据明细表--处理中或完成
|
|
updateSql.Remove(0, updateSql.Length);
|
|
updateSql.Append("UPDATE dbo.wms_move_detail ");
|
|
updateSql.Append("SET pick_qty = pick_qty + @qty, ");
|
|
updateSql.Append(" item_status = @itemStatus, ");
|
|
|
|
updateSql.Append(" dest_warehouse_id = @destWarehouseId, ");
|
|
updateSql.Append(" dest_warehouse_name = @destWarehouseName, ");
|
|
updateSql.Append(" dest_zone_id = @destZoneId, ");
|
|
updateSql.Append(" dest_zone_name = @destZoneName, ");
|
|
updateSql.Append(" dest_erp_warehouse = @destErpWarehouse, ");
|
|
|
|
updateSql.Append(" update_userid = @updateUserid, ");
|
|
updateSql.Append(" update_time = @updateTime ");
|
|
updateSql.Append("WHERE order_no = @orderNo ");
|
|
updateSql.Append(" AND part_id = @partId ");
|
|
|
|
updateParameters = new DynamicParameters();
|
|
updateParameters.Add("@orderNo", moveDetail.OrderNo);
|
|
updateParameters.Add("@partId", moveDetail.PartId);
|
|
updateParameters.Add("@qty", cartonInfo.Qty);
|
|
if (isDetailComplate)
|
|
{
|
|
updateParameters.Add("@itemStatus", WmsEnumUtil.MoveOrderDetailStatus.COMPLETED);
|
|
}
|
|
else
|
|
{
|
|
updateParameters.Add("@itemStatus", WmsEnumUtil.MoveOrderDetailStatus.BATCHING);
|
|
}
|
|
updateParameters.Add("@destWarehouseId", locateInfo.WarehouseId);
|
|
updateParameters.Add("@destWarehouseName", locateInfo.WarehouseName);
|
|
updateParameters.Add("@destZoneId", locateInfo.ZoneId);
|
|
updateParameters.Add("@destZoneName", locateInfo.ZoneName);
|
|
updateParameters.Add("@destErpWarehouse", locateInfo.ErpWarehouse);
|
|
|
|
updateParameters.Add("@updateUserid", loginId);
|
|
updateParameters.Add("@updateTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
|
|
|
|
sqlStrings.Add(updateSql.ToString());
|
|
parameterList.Add(updateParameters);
|
|
|
|
if (moveSn == null)
|
|
{
|
|
//插入单据条码表
|
|
updateSql.Remove(0, updateSql.Length);
|
|
updateSql.Append("INSERT INTO dbo.wms_move_sn ");
|
|
updateSql.Append("( ");
|
|
updateSql.Append(" order_no,item_no,part_id,part_no,part_spec, ");
|
|
updateSql.Append(" carton_no,qty,unit,status,factory_id,factory_code,enabled, ");
|
|
updateSql.Append(" create_userid,create_time,update_userid,update_time,guid ");
|
|
updateSql.Append(") ");
|
|
updateSql.Append("VALUES ");
|
|
updateSql.Append("( @orderNo,@itemNo,@partId,@partNo,@partSpec, ");
|
|
updateSql.Append(" @cartonNo,@qty,@unit,@status,@factoryId,@factoryCode,@enabled, ");
|
|
updateSql.Append(" @createUserid,@createTime,@updateUserid,@updateTime,@guid ");
|
|
updateSql.Append(" ) ");
|
|
|
|
updateParameters = new DynamicParameters();
|
|
updateParameters.Add("@orderNo", moveDetail.OrderNo);
|
|
updateParameters.Add("@itemNo", moveDetail.ItemNo);
|
|
updateParameters.Add("@partId", moveDetail.PartId);
|
|
updateParameters.Add("@partNo", moveDetail.PartNo);
|
|
updateParameters.Add("@partSpec", moveDetail.PartSpec);
|
|
updateParameters.Add("@cartonNo", cartonInfo.CartonNo);
|
|
updateParameters.Add("@qty", cartonInfo.Qty);
|
|
updateParameters.Add("@unit", cartonInfo.Unit);
|
|
updateParameters.Add("@status", (int)WmsEnumUtil.MoveOrderSnStatus.PROCESSED);
|
|
updateParameters.Add("@factoryId", moveDetail.FactoryId);
|
|
updateParameters.Add("@factoryCode", moveDetail.FactoryCode);
|
|
updateParameters.Add("@enabled", WmsEnumUtil.Enabled.Y.ToString());
|
|
updateParameters.Add("@createUserid", loginId);
|
|
updateParameters.Add("@createTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
|
|
updateParameters.Add("@updateUserid", loginId);
|
|
updateParameters.Add("@updateTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
|
|
updateParameters.Add("@guid", Guid.NewGuid());
|
|
|
|
sqlStrings.Add(updateSql.ToString());
|
|
parameterList.Add(updateParameters);
|
|
}
|
|
else
|
|
{
|
|
//更新单据条码表
|
|
updateSql.Remove(0, updateSql.Length);
|
|
updateSql.Append("UPDATE dbo.wms_move_sn ");
|
|
updateSql.Append("SET status = @status, ");
|
|
updateSql.Append(" update_userid = @updateUserid, ");
|
|
updateSql.Append(" update_time = @updateTime ");
|
|
updateSql.Append("WHERE order_no = @orderNo ");
|
|
updateSql.Append(" AND carton_no = @cartonNo ");
|
|
|
|
updateParameters = new DynamicParameters();
|
|
updateParameters.Add("@orderNo", moveDetail.OrderNo);
|
|
updateParameters.Add("@cartonNo", cartonInfo.CartonNo);
|
|
updateParameters.Add("@status", (int)WmsEnumUtil.MoveOrderSnStatus.PROCESSED);
|
|
updateParameters.Add("@updateUserid", loginId);
|
|
updateParameters.Add("@updateTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
|
|
|
|
sqlStrings.Add(updateSql.ToString());
|
|
parameterList.Add(updateParameters);
|
|
}
|
|
|
|
//新增 sys_stock_trans 事务表
|
|
updateSql.Remove(0, updateSql.Length);
|
|
updateSql.Append("INSERT INTO [dbo].[sys_stock_trans] ");
|
|
updateSql.Append("( ");
|
|
updateSql.Append(" [trans_code],[carton_no],[part_id],[part_no],[part_spec],[src_locate_id],[src_locate_name],[dest_locate_id], ");
|
|
updateSql.Append(" [dest_locate_name],[old_qty],[new_qty],[trans_qty],[old_status],[new_status],[old_qms_status],[new_qms_status],[unit], ");
|
|
updateSql.Append(" [factory_id],[factory_code],[src_erp_warehouse],[dest_erp_warehouse],[src_warehouse_id],[src_warehouse_name], ");
|
|
updateSql.Append(" [dest_warehouse_id],[dest_warehouse_name],[src_zone_id],[src_zone_name],[dest_zone_id],[dest_zone_name],[enabled], ");
|
|
updateSql.Append(" [update_userid],[update_time], [create_userid],[create_time],[guid],ref_order_no ");
|
|
updateSql.Append(") ");
|
|
updateSql.Append("VALUES ");
|
|
updateSql.Append("(@trans_code, @carton_no, @part_id, @part_no, @part_spec, @src_locate_id, @src_locate_name, @dest_locate_id, ");
|
|
updateSql.Append(" @dest_locate_name, @old_qty, @new_qty, @trans_qty, @old_status, @new_status, @old_qms_status, @new_qms_status, @unit, ");
|
|
updateSql.Append(" @factory_id, @factory_code, @src_erp_warehouse, @dest_erp_warehouse, @src_warehouse_id, @src_warehouse_name, ");
|
|
updateSql.Append(" @dest_warehouse_id, @dest_warehouse_name, @src_zone_id, @src_zone_name, @dest_zone_id, @dest_zone_name, @enabled, ");
|
|
updateSql.Append(" @update_userid, @update_time, @create_userid, @create_time, @guid,@ref_order_no) ");
|
|
|
|
|
|
updateParameters = new DynamicParameters();
|
|
updateParameters.Add("@trans_code", (int)WmsEnumUtil.TransType.NC_CONCESSION);
|
|
updateParameters.Add("@carton_no", cartonInfo.CartonNo);
|
|
updateParameters.Add("@part_id", cartonInfo.PartId);
|
|
updateParameters.Add("@part_no", cartonInfo.PartNo);
|
|
updateParameters.Add("@part_spec", cartonInfo.PartSpec);
|
|
updateParameters.Add("@src_locate_id", cartonInfo.LocateId);
|
|
updateParameters.Add("@src_locate_name", cartonInfo.LocateName);
|
|
updateParameters.Add("@dest_locate_id", locateInfo.LocateId);
|
|
updateParameters.Add("@dest_locate_name", locateInfo.LocateName);
|
|
updateParameters.Add("@old_qty", cartonInfo.Qty);
|
|
updateParameters.Add("@new_qty", cartonInfo.Qty);
|
|
updateParameters.Add("@trans_qty", cartonInfo.Qty);
|
|
updateParameters.Add("@old_status", cartonInfo.Status);
|
|
updateParameters.Add("@new_status", (int)WmsEnumUtil.StockStatus.INSTOCKED);
|
|
updateParameters.Add("@old_qms_status", "N");
|
|
updateParameters.Add("@new_qms_status", "N");
|
|
updateParameters.Add("@unit", cartonInfo.Unit);
|
|
updateParameters.Add("@factory_id", cartonInfo.FactoryId);
|
|
updateParameters.Add("@factory_code", cartonInfo.FactoryCode);
|
|
updateParameters.Add("@src_erp_warehouse", cartonInfo.ErpWarehouse);
|
|
updateParameters.Add("@dest_erp_warehouse", locateInfo.ErpWarehouse);
|
|
updateParameters.Add("@src_warehouse_id", cartonInfo.WarehouseId);
|
|
updateParameters.Add("@src_warehouse_name", cartonInfo.WarehouseName);
|
|
updateParameters.Add("@dest_warehouse_id", locateInfo.WarehouseId);
|
|
updateParameters.Add("@dest_warehouse_name", locateInfo.WarehouseName);
|
|
updateParameters.Add("@src_zone_id", cartonInfo.ZoneId);
|
|
updateParameters.Add("@src_zone_name", cartonInfo.ZoneName);
|
|
updateParameters.Add("@dest_zone_id", locateInfo.ZoneId);
|
|
updateParameters.Add("@dest_zone_name", locateInfo.ZoneName);
|
|
updateParameters.Add("@enabled", cartonInfo.Enabled);
|
|
updateParameters.Add("@update_userid", loginId);
|
|
updateParameters.Add("@update_time", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
|
|
updateParameters.Add("@create_userid", loginId);
|
|
updateParameters.Add("@create_time", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
|
|
updateParameters.Add("@guid", Guid.NewGuid());
|
|
updateParameters.Add("@ref_order_no", moveDetail.OrderNo);
|
|
|
|
sqlStrings.Add(updateSql.ToString());
|
|
parameterList.Add(updateParameters);
|
|
|
|
return this.ExecuteTransaction(sqlStrings, parameterList);
|
|
|
|
}
|
|
|
|
//获取完成信息提交数据
|
|
public List<WmsMoveDetail> GetFinishMoveDetailByOrderNo(string orderNo)
|
|
{
|
|
using (IDbConnection dbConn = dapperDbContext.GetDbConnection())
|
|
{
|
|
dbConn.Open();
|
|
StringBuilder SqlStringBuilder = new StringBuilder(1024);
|
|
SqlStringBuilder.Append("SELECT SUM(CONVERT(INT, c.pick_qty)) pick_qty,c.part_no,src_erp_warehouse,dest_erp_warehouse,plan_date,plan_time,a.factory_code,a.order_no,c.item_no FROM dbo.wms_move_header a (nolock) ");
|
|
SqlStringBuilder.Append("LEFT JOIN dbo.wms_move_detail c (nolock) ON a.order_no=c.order_no ");
|
|
SqlStringBuilder.Append(" WHERE a.order_no = '" + orderNo + "' and a.enabled='Y' group by c.part_no,src_erp_warehouse,dest_erp_warehouse,plan_date,plan_time,a.factory_code,a.order_no,c.item_no");
|
|
|
|
List<WmsMoveDetail> wmsMoves = dbConn.Query<WmsMoveDetail>(SqlStringBuilder.ToString()).ToList();
|
|
return wmsMoves;
|
|
}
|
|
}
|
|
|
|
//获取零件号信息
|
|
public SysPart GetPartNOInfoByPartNo(string partNo)
|
|
{
|
|
using (IDbConnection dbConn = dapperDbContext.GetDbConnection())
|
|
{
|
|
dbConn.Open();
|
|
StringBuilder SqlStringBuilder = new StringBuilder(1024);
|
|
SqlStringBuilder.Append(" SELECT * from sys_part (nolock) where part_no='" + partNo + "' ");
|
|
SysPart sysParts = dbConn.QueryFirstOrDefault<SysPart>(SqlStringBuilder.ToString());
|
|
return sysParts;
|
|
}
|
|
}
|
|
|
|
//把结果添加到接口表
|
|
public bool InsertInterfaceByNCConcession(string orderNo)
|
|
{
|
|
using (IDbConnection dbConn = dapperDbContext.GetDbConnection())
|
|
{
|
|
dbConn.Open();
|
|
List<string> sqlStrings = new List<string>();
|
|
List<DynamicParameters> parameterList = new List<DynamicParameters>();
|
|
|
|
List<WmsMoveDetail> wmsMoves = GetFinishMoveDetailByOrderNo(orderNo);
|
|
if (wmsMoves.Count > 0)
|
|
{
|
|
StringBuilder SqlStringBuilder = new StringBuilder(1024);
|
|
SqlStringBuilder.Append("INSERT INTO dbo.WMS_MOVR(ZINSTNO,ZEILE,WERKS,LGORT,UMLGO,MATNR,ERFMG ");
|
|
SqlStringBuilder.Append(" ,ERFME,ACTION,ZPOST,ZTIME,SID,RECTIM,SYNFLG ");
|
|
SqlStringBuilder.Append(" ,GUID) ");
|
|
SqlStringBuilder.Append(" VALUES(@ZINSTNO,@ZEILE,@WERKS,@LGORT,@UMLGO,@MATNR,@ERFMG,@ERFME ");
|
|
SqlStringBuilder.Append(" ,@ACTION,@ZPOST,@ZTIME,@SID,@RECTIM,@SYNFLG ");
|
|
SqlStringBuilder.Append(" ,@GUID) ");
|
|
|
|
string sid = Guid.NewGuid().ToString().Replace("-", "");
|
|
for (int i = 0; i < wmsMoves.Count; i++)
|
|
{
|
|
SysPart sysPart = GetPartNOInfoByPartNo(wmsMoves[i].PartNo);
|
|
sqlStrings.Add(SqlStringBuilder.ToString());
|
|
DynamicParameters parameters = new DynamicParameters();
|
|
parameters.Add("@ZINSTNO", wmsMoves[i].OrderNo);//盘点凭证号
|
|
parameters.Add("@ZEILE", wmsMoves[i].ItemNo);//行号
|
|
parameters.Add("@WERKS", wmsMoves[i].FactoryCode);//工厂
|
|
parameters.Add("@LGORT", wmsMoves[i].SrcErpWarehouse);//发出库存地点
|
|
parameters.Add("@UMLGO", wmsMoves[i].DestErpWarehouse);//接收库存地点
|
|
parameters.Add("@MATNR", wmsMoves[i].PartNo);//物料编码
|
|
parameters.Add("@ERFMG", wmsMoves[i].PickQty);//转储数量
|
|
if (sysPart == null)
|
|
{
|
|
parameters.Add("@ERFME", "");//计量单位
|
|
}
|
|
else
|
|
{
|
|
parameters.Add("@ERFME", sysPart.Unit);//计量单位
|
|
}
|
|
parameters.Add("@ACTION", "M02"); //M02:NC让步接收
|
|
parameters.Add("@ZPOST", DateTime.Now.ToString("yyyyMMdd"));//交易日期
|
|
parameters.Add("@ZTIME", DateTime.Now.ToString("HHmmss"));//交易时间
|
|
parameters.Add("@SID", sid);
|
|
parameters.Add("@RECTIM", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
|
|
parameters.Add("@SYNFLG", "N");
|
|
parameters.Add("@GUID", Guid.NewGuid().ToString());
|
|
parameterList.Add(parameters);
|
|
}
|
|
}
|
|
IDbTransaction transaction = dbConn.BeginTransaction();
|
|
try
|
|
{
|
|
bool successCount = true;
|
|
for (int i = 0; i < sqlStrings.Count; i++)
|
|
{
|
|
dbConn.Execute(sqlStrings[i], parameterList[i], transaction);
|
|
}
|
|
//提交事务
|
|
transaction.Commit();
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
//回滚事务
|
|
LogHelper.Error("ExecuteTransaction", ex);
|
|
transaction.Rollback();
|
|
dbConn.Close();
|
|
dbConn.Dispose();
|
|
throw ex;
|
|
}
|
|
finally
|
|
{
|
|
dbConn.Close();
|
|
dbConn.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|