@ -88,7 +88,7 @@ namespace DSWeb.MvcShipping.Controllers
# endregion
#region 引入 EXCEL
#region 运价管理 运价维护 导入excel 引入 EXCEL
[HttpPost]
public ContentResult onImportClick ( )
{
@ -170,216 +170,242 @@ namespace DSWeb.MvcShipping.Controllers
if ( table . Rows . Count > 0 )
if ( table . Rows . Count > 0 )
{
iheadList = table . Rows . Count ; //执行条数
#region 获取动态 集装箱列名
List < XiaLaKuangModel > ctnList = MsCrmPriceCarrierDAL . GetCtn ( ) ;
string sXG = "" ;
string sDG = "" ;
string sCG = "" ;
string sXKD = "" ;
string sDKD = "" ;
string sXKJ = "" ;
string sDKJ = "" ;
string sXGBJ = "" ;
string sDGBJ = "" ;
string sCGBJ = "" ;
string sXKDBJ = "" ;
string sDKDBJ = "" ;
string sXKJBJ = "" ;
string sDKJBJ = "" ;
foreach ( var enumValue in ctnList )
{
iheadList = table . Rows . Count ; //执行条数
#region 获取动态 集装箱列名
List < XiaLaKuangModel > ctnList = MsCrmPriceCarrierDAL . GetCtn ( ) ;
string sXG = "" ;
string sDG = "" ;
string sCG = "" ;
string sXD = "" ;
string sCD = "" ;
string sXGBJ = "" ;
string sDGBJ = "" ;
string sCGBJ = "" ;
string sXDBJ = "" ;
string sCDBJ = "" ;
foreach ( var enumValue in ctnList )
if ( enumValue . NAME . ToString ( ) . Trim ( ) = = "小柜" )
{
if ( enumValue . NAME . ToString ( ) . Trim ( ) = = "小柜" )
{
sXG = enumValue . VALUE . ToString ( ) . Trim ( ) + "0" ;
sXGBJ = enumValue . VALUE . ToString ( ) . Trim ( ) + "2" ;
}
else if ( enumValue . NAME . ToString ( ) . Trim ( ) = = "大柜" )
{
sDG = enumValue . VALUE . ToString ( ) . Trim ( ) + "0" ;
sDGBJ = enumValue . VALUE . ToString ( ) . Trim ( ) + "2" ;
}
else if ( enumValue . NAME . ToString ( ) . Trim ( ) = = "超高" )
{
sCG = enumValue . VALUE . ToString ( ) . Trim ( ) + "0" ;
sCGBJ = enumValue . VALUE . ToString ( ) . Trim ( ) + "2" ;
}
else if ( enumValue . NAME . ToString ( ) . Trim ( ) = = "小冻" )
{
sXD = enumValue . VALUE . ToString ( ) . Trim ( ) + "0" ;
sXDBJ = enumValue . VALUE . ToString ( ) . Trim ( ) + "2" ;
}
else if ( enumValue . NAME . ToString ( ) . Trim ( ) = = "超冻" )
{
sCD = enumValue . VALUE . ToString ( ) . Trim ( ) + "0" ;
sCDBJ = enumValue . VALUE . ToString ( ) . Trim ( ) + "2" ;
}
sXG = enumValue . VALUE . ToString ( ) . Trim ( ) + "0" ;
sXGBJ = enumValue . VALUE . ToString ( ) . Trim ( ) + "2" ;
}
else if ( enumValue . NAME . ToString ( ) . Trim ( ) = = "大柜" )
{
sDG = enumValue . VALUE . ToString ( ) . Trim ( ) + "0" ;
sDGBJ = enumValue . VALUE . ToString ( ) . Trim ( ) + "2" ;
}
else if ( enumValue . NAME . ToString ( ) . Trim ( ) = = "超高" )
{
sCG = enumValue . VALUE . ToString ( ) . Trim ( ) + "0" ;
sCGBJ = enumValue . VALUE . ToString ( ) . Trim ( ) + "2" ;
}
else if ( enumValue . NAME . ToString ( ) . Trim ( ) = = "小开顶" )
{
sXKD = enumValue . VALUE . ToString ( ) . Trim ( ) + "0" ;
sXKDBJ = enumValue . VALUE . ToString ( ) . Trim ( ) + "2" ;
}
else if ( enumValue . NAME . ToString ( ) . Trim ( ) = = "大开顶" )
{
sDKD = enumValue . VALUE . ToString ( ) . Trim ( ) + "0" ;
sDKDBJ = enumValue . VALUE . ToString ( ) . Trim ( ) + "2" ;
}
else if ( enumValue . NAME . ToString ( ) . Trim ( ) = = "小框架" )
{
sXKJ = enumValue . VALUE . ToString ( ) . Trim ( ) + "0" ;
sXKJBJ = enumValue . VALUE . ToString ( ) . Trim ( ) + "2" ;
}
else if ( enumValue . NAME . ToString ( ) . Trim ( ) = = "大框架" )
{
sDKJ = enumValue . VALUE . ToString ( ) . Trim ( ) + "0" ;
sDKJBJ = enumValue . VALUE . ToString ( ) . Trim ( ) + "2" ;
}
}
# endregion
# endregion
#region 获取动态 费用列名
List < XiaLaKuangModel > feeList = MsCrmPriceCarrierDAL . GetFeeName ( ) ;
string sFJF = "" ;
foreach ( var enumValue in feeList )
#region 获取动态 费用列名
List < XiaLaKuangModel > feeList = MsCrmPriceCarrierDAL . GetFeeName ( ) ;
string sFJF = "" ;
foreach ( var enumValue in feeList )
{
if ( enumValue . NAME . ToString ( ) . Trim ( ) = = "附加费" )
{
if ( enumValue . NAME . ToString ( ) . Trim ( ) = = "附加费" )
{
sFJF = enumValue . VALUE . ToString ( ) . Trim ( ) ;
}
sFJF = enumValue . VALUE . ToString ( ) . Trim ( ) ;
}
# endregion
/ /
string sGID = "" ;
sError = "" ;
for ( int i = 0 ; i < table . Rows . Count ; i + + )
{
bool isAdd = false ;
}
# endregion
/ /
string sGID = "" ;
sError = "" ;
for ( int i = 0 ; i < table . Rows . Count ; i + + )
{
bool isAdd = false ;
#region 获取是否有重复数据
string condition = "[LANE]='" + table . Rows [ i ] [ "航线" ] . ToString ( ) + "' and [PODLOAD]='" + table . Rows [ i ] [ "装货港" ] . ToString ( ) + "' and [PORTDISCHARGEID]='" + table . Rows [ i ] [ "卸货港" ] . ToString ( ) + "' and [PORTDISCHARGE]='" + table . Rows [ i ] [ "卸货港中文" ] . ToString ( ) + "' and [CARRIER]='" + table . Rows [ i ] [ "船公司" ] . ToString ( ) + "' and [VIA]='" + table . Rows [ i ] [ "中转港" ] . ToString ( ) + "' and [ETD]='" + table . Rows [ i ] [ "船期" ] . ToString ( ) + "' and [TT]='" + table . Rows [ i ] [ "航程" ] . ToString ( ) + "' and [EFFECTIVEDATE]='" + table . Rows [ i ] [ "开始日期" ] . ToString ( ) + "' and [VALIDDATE]='" + table . Rows [ i ] [ "结束日期" ] . ToString ( ) + "' and [COMMODITY]='" + table . Rows [ i ] [ "特殊商品" ] . ToString ( ) + "'" ;
List < MsCrmPriceCarrier > dataList = MsCrmPriceCarrierDAL . GetDataList ( condition , 0 , 1000 , Convert . ToString ( Session [ "USERID" ] ) , Convert . ToString ( Session [ "SHOWNAME" ] ) , Convert . ToString ( Session [ "COMPANYID" ] ) , null ) ;
# endregion
#region 获取是否有重复数据
string condition = "[LANE]='" + table . Rows [ i ] [ "航线" ] . ToString ( ) + "' and [PODLOAD]='" + table . Rows [ i ] [ "装货港" ] . ToString ( ) + "' and [PORTDISCHARGEID]='" + table . Rows [ i ] [ "卸货港" ] . ToString ( ) + "' and [PORTDISCHARGE]='" + table . Rows [ i ] [ "卸货港中文" ] . ToString ( ) + "' and [CARRIER]='" + table . Rows [ i ] [ "船公司" ] . ToString ( ) + "' and [VIA]='" + table . Rows [ i ] [ "中转港" ] . ToString ( ) + "' and [ETD]='" + table . Rows [ i ] [ "船期" ] . ToString ( ) + "' and [TT]='" + table . Rows [ i ] [ "航程" ] . ToString ( ) + "' and [EFFECTIVEDATE]='" + table . Rows [ i ] [ "开始日期" ] . ToString ( ) + "' and [VALIDDATE]='" + table . Rows [ i ] [ "结束日期" ] . ToString ( ) + "' and [COMMODITY]='" + table . Rows [ i ] [ "特殊商品" ] . ToString ( ) + "'" ;
List < MsCrmPriceCarrier > dataList = MsCrmPriceCarrierDAL . GetDataList ( condition , 0 , 1000 , Convert . ToString ( Session [ "USERID" ] ) , Convert . ToString ( Session [ "SHOWNAME" ] ) , Convert . ToString ( Session [ "COMPANYID" ] ) , null ) ;
# endregion
if ( dataList ! = null ) //edit
if ( dataList ! = null ) //edit
{
if ( dataList . Count > 0 )
{
if ( dataList . Count > 0 )
MsCrmPriceCarrier headRow = dataList [ 0 ] ;
if ( ! headRow . LOCKFLAG & & ! headRow . ISISSUE ) //判断是否锁定或发布的数据,不是则覆盖数据
{
MsCrmPriceCarrier headRow = dataList [ 0 ] ;
if ( ! headRow . LOCKFLAG & & ! headRow . ISISSUE ) //判断是否锁定或发布的数据,不是则覆盖数据
{
sGID = headRow . GID . ToString ( ) ;
UpdateCount + + ; //更新条数
}
else
{
iError + + ; //失败(更新)条数
continue ;
}
sGID = headRow . GID . ToString ( ) ;
UpdateCount + + ; //更新条数
}
else //add
else
{
isAdd = true ;
iError + + ; //失败(更新)条数
continue ;
}
}
else //add
{
isAdd = true ;
}
if ( isAdd ) //add
}
else //add
{
isAdd = true ;
}
if ( isAdd ) //add
{
MsCrmPriceCarrier headRow = new MsCrmPriceCarrier ( ) ;
#region 默认值
headRow . LANE = table . Rows [ i ] [ "航线" ] . ToString ( ) ; //航线
headRow . PODLOAD = table . Rows [ i ] [ "装货港" ] . ToString ( ) ; //装货港
headRow . PORTDISCHARGEID = table . Rows [ i ] [ "卸货港" ] . ToString ( ) ; //卸货港ID
headRow . PORTDISCHARGE = table . Rows [ i ] [ "卸货港中文" ] . ToString ( ) ; //卸货港中文
headRow . CARRIER = table . Rows [ i ] [ "船公司" ] . ToString ( ) ; //船公司
headRow . VIA = table . Rows [ i ] [ "中转港" ] . ToString ( ) ; //中转港
headRow . ETD = table . Rows [ i ] [ "船期" ] . ToString ( ) ; //开航日/船期
headRow . TT = table . Rows [ i ] [ "航程" ] . ToString ( ) ; //航程
headRow . REMARK = table . Rows [ i ] [ "备注" ] . ToString ( ) ; //备注
if ( table . Rows [ i ] [ "开始日期" ] . ToString ( ) ! = "" )
{
MsCrmPriceCarrier headRow = new MsCrmPriceCarrier ( ) ;
#region 默认值
headRow . LANE = table . Rows [ i ] [ "航线" ] . ToString ( ) ; //航线
headRow . PODLOAD = table . Rows [ i ] [ "装货港" ] . ToString ( ) ; //装货港
headRow . PORTDISCHARGEID = table . Rows [ i ] [ "卸货港" ] . ToString ( ) ; //卸货港ID
headRow . PORTDISCHARGE = table . Rows [ i ] [ "卸货港中文" ] . ToString ( ) ; //卸货港中文
headRow . CARRIER = table . Rows [ i ] [ "船公司" ] . ToString ( ) ; //船公司
headRow . VIA = table . Rows [ i ] [ "中转港" ] . ToString ( ) ; //中转港
headRow . ETD = table . Rows [ i ] [ "船期" ] . ToString ( ) ; //开航日/船期
headRow . TT = table . Rows [ i ] [ "航程" ] . ToString ( ) ; //航程
headRow . REMARK = table . Rows [ i ] [ "备注" ] . ToString ( ) ; //备注
if ( table . Rows [ i ] [ "开始日期" ] . ToString ( ) ! = "" )
{
headRow . EFFECTIVEDATE = DateTime . Parse ( table . Rows [ i ] [ "开始日期" ] . ToString ( ) ) ; //生效期/开始日期
}
else
{
if ( sError . IndexOf ( "不能导入“开始日期”为空的数据!" ) < 0 )
{
sError + = "不能导入“开始日期”为空的数据!" ;
}
}
if ( table . Rows [ i ] [ "结束日期" ] . ToString ( ) ! = "" )
{
headRow . VALIDDATE = DateTime . Parse ( table . Rows [ i ] [ "结束日期" ] . ToString ( ) ) ; //有效期/结束日期
}
else
{
if ( sError . IndexOf ( "不能导入“结束日期”为空的数据!" ) < 0 )
{
sError + = "不能导入“结束日期”为空的数据!" ;
}
}
headRow . COMMODITY = table . Rows [ i ] [ "特殊商品" ] . ToString ( ) ; //品名/特殊商品
headRow . LOCKFLAG = false ;
headRow . ISISSUE = false ;
headRow . INPUTBY = Convert . ToString ( Session [ "USERID" ] ) ; //制单人GID
headRow . INPUTTIME = DateTime . Now ; //创建时间
headRow . MODIFIEDUSER = Convert . ToString ( Session [ "USERID" ] ) ; //最后一次更改操作人GID
headRow . MODIFYTIME = DateTime . Now ; //最后一次更改操作时间
headRow . GID = Guid . NewGuid ( ) . ToString ( ) ;
sGID = headRow . GID . ToString ( ) ;
headRow . DbOperationType = DbOperationType . DbotIns ;
# endregion
var modb = new ModelObjectDB ( ) ;
DBResult result = modb . Save ( headRow ) ;
if ( ! result . Success )
headRow . EFFECTIVEDATE = DateTime . Parse ( table . Rows [ i ] [ "开始日期" ] . ToString ( ) ) ; //生效期/开始日期
}
else
{
if ( sError . IndexOf ( "不能导入“开始日期”为空的数据!" ) < 0 )
{
iError + + ; //失败(更新)条数
continue ;
sError + = "不能导入“开始日期”为空的数据!" ;
}
else
}
if ( table . Rows [ i ] [ "结束日期" ] . ToString ( ) ! = "" )
{
headRow . VALIDDATE = DateTime . Parse ( table . Rows [ i ] [ "结束日期" ] . ToString ( ) ) ; //有效期/结束日期
}
else
{
if ( sError . IndexOf ( "不能导入“结束日期”为空的数据!" ) < 0 )
{
InsertCount + + ; //新增条数
sError + = "不能导入“结束日期”为空的数据!" ;
}
}
var XGYJ = table . Rows [ i ] [ "小柜" ] . ToString ( ) ;
if ( XGYJ = = "" ) XGYJ = "0" ;
var DGYJ = table . Rows [ i ] [ "大柜" ] . ToString ( ) ;
if ( DGYJ = = "" ) DGYJ = "0" ;
var CGYJ = table . Rows [ i ] [ "超高" ] . ToString ( ) ;
if ( CGYJ = = "" ) CGYJ = "0" ;
var XDYJ = table . Rows [ i ] [ "小冻" ] . ToString ( ) ;
if ( XDYJ = = "" ) XDYJ = "0" ;
var CDYJ = table . Rows [ i ] [ "超冻" ] . ToString ( ) ;
if ( CDYJ = = "" ) CDYJ = "0" ;
var XGYJBJ = table . Rows [ i ] [ "小柜报价" ] . ToString ( ) ;
if ( XGYJBJ = = "" ) XGYJBJ = "0" ;
var DGYJBJ = table . Rows [ i ] [ "大柜报价" ] . ToString ( ) ;
if ( DGYJBJ = = "" ) DGYJBJ = "0" ;
var CGYJBJ = table . Rows [ i ] [ "超高报价" ] . ToString ( ) ;
if ( CGYJBJ = = "" ) CGYJBJ = "0" ;
var XDYJBJ = table . Rows [ i ] [ "小冻报价" ] . ToString ( ) ;
if ( XDYJBJ = = "" ) XDYJBJ = "0" ;
var CDYJBJ = table . Rows [ i ] [ "超冻报价" ] . ToString ( ) ;
if ( CDYJBJ = = "" ) CDYJBJ = "0" ;
#region 根据动态字段名,更新集装箱与费用信息
string sSQL = "update crm_price_carrier_2 set [" + sXG + "]='" + XGYJ + "',[" + sDG + "]='" + DGYJ + "',[" + sCG + "]='" + CGYJ + "',[" + sXD + "]='"
+ XDYJ + "',[" + sCD + "]='" + CDYJ + "',[" + sXGBJ + "]='" + XGYJBJ + "',[" + sDGBJ + "]='" + DGYJBJ + "',[" + sCGBJ + "]='" + CGYJBJ + "',[" + sXDBJ + "]='"
+ XDYJBJ + "',[" + sCDBJ + "]='" + CDYJBJ + "',[" + sFJF + "]='" + table . Rows [ i ] [ "附加费" ] . ToString ( ) + "' where gid='" + sGID + "'" ;
// string sSQL = "update crm_price_carrier_2 set [" + sXG + "]='" + ds.Tables[0].Rows[i]["小柜"].ToString() + "',[" + sDG + "]='" + ds.Tables[0].Rows[i]["大柜"].ToString() + "',[" + sCG + "]='" + ds.Tables[0].Rows[i]["超高"].ToString() + "',[" + sFJF + "]='" + ds.Tables[0].Rows[i]["附加费"].ToString() + "' where gid='" + sGID + "'";
headRow . COMMODITY = table . Rows [ i ] [ "特殊商品" ] . ToString ( ) ; //品名/特殊商品
headRow . LOCKFLAG = false ;
headRow . ISISSUE = false ;
headRow . INPUTBY = Convert . ToString ( Session [ "USERID" ] ) ; //制单人GID
headRow . INPUTTIME = DateTime . Now ; //创建时间
headRow . MODIFIEDUSER = Convert . ToString ( Session [ "USERID" ] ) ; //最后一次更改操作人GID
headRow . MODIFYTIME = DateTime . Now ; //最后一次更改操作时间
headRow . GID = Guid . NewGuid ( ) . ToString ( ) ;
sGID = headRow . GID . ToString ( ) ;
headRow . DbOperationType = DbOperationType . DbotIns ;
# endregion
bool bl = T_ALL_DA . GetExecuteSqlCommand ( sSQL ) ;
if ( ! bl )
var modb = new ModelObjectDB ( ) ;
DBResult result = modb . Save ( headRow ) ;
if ( ! result . Success )
{
iError + + ; //失败(更新)条数
continue ;
}
else
{
InsertCount + + ; //新增条数
}
}
}
/ /
if ( System . IO . File . Exists ( fileName ) )
{
System . IO . File . Delete ( fileName ) ;
}
if ( sError . Trim ( ) ! = "" )
{
jsonRespose . Success = false ;
jsonRespose . Message = "操作完成,共处理" + Convert . ToString ( iheadList ) + "条数据,其中新增" + Convert . ToString ( InsertCount ) + "条,覆盖" + Convert . ToString ( UpdateCount ) + "条,出错" + Convert . ToString ( iError ) + "条!错误原因:" + sError ;
return new ContentResult ( ) { Content = JsonConvert . Serialize ( jsonRespose ) } ;
}
else
{
jsonRespose . Success = true ;
jsonRespose . Message = "操作完成,共处理" + Convert . ToString ( iheadList ) + "条数据,其中新增" + Convert . ToString ( InsertCount ) + "条,覆盖" + Convert . ToString ( UpdateCount ) + "条,出错" + Convert . ToString ( iError ) + "条!" ;
return new ContentResult ( ) { Content = JsonConvert . Serialize ( jsonRespose ) } ;
var XGYJ = table . Rows [ i ] [ "小柜" ] . ToString ( ) ;
if ( XGYJ = = "" ) XGYJ = "0" ;
var DGYJ = table . Rows [ i ] [ "大柜" ] . ToString ( ) ;
if ( DGYJ = = "" ) DGYJ = "0" ;
var CGYJ = table . Rows [ i ] [ "超高" ] . ToString ( ) ;
if ( CGYJ = = "" ) CGYJ = "0" ;
var XKDYJ = table . Rows [ i ] [ "小开顶" ] . ToString ( ) ;
if ( XKDYJ = = "" ) XKDYJ = "0" ;
var DKDYJ = table . Rows [ i ] [ "大开顶" ] . ToString ( ) ;
if ( DKDYJ = = "" ) DKDYJ = "0" ;
var XKJYJ = table . Rows [ i ] [ "小框架" ] . ToString ( ) ;
if ( XKJYJ = = "" ) XKJYJ = "0" ;
var DKJYJ = table . Rows [ i ] [ "大框架" ] . ToString ( ) ;
if ( DKJYJ = = "" ) DKJYJ = "0" ;
var XGYJBJ = table . Rows [ i ] [ "小柜报价" ] . ToString ( ) ;
if ( XGYJBJ = = "" ) XGYJBJ = "0" ;
var DGYJBJ = table . Rows [ i ] [ "大柜报价" ] . ToString ( ) ;
if ( DGYJBJ = = "" ) DGYJBJ = "0" ;
var CGYJBJ = table . Rows [ i ] [ "超高报价" ] . ToString ( ) ;
if ( CGYJBJ = = "" ) CGYJBJ = "0" ;
var XKDYJBJ = table . Rows [ i ] [ "小开顶报价" ] . ToString ( ) ;
if ( XKDYJBJ = = "" ) XKDYJBJ = "0" ;
var DKDYJBJ = table . Rows [ i ] [ "小开顶报价" ] . ToString ( ) ;
if ( DKDYJBJ = = "" ) DKDYJBJ = "0" ;
var XKJYJBJ = table . Rows [ i ] [ "小框架报价" ] . ToString ( ) ;
if ( XKJYJBJ = = "" ) XKJYJBJ = "0" ;
var DKJYJBJ = table . Rows [ i ] [ "大框架报价" ] . ToString ( ) ;
if ( DKJYJBJ = = "" ) DKJYJBJ = "0" ;
#region 根据动态字段名,更新集装箱与费用信息
string sSQL = "" ;
sSQL = $"update crm_price_carrier_2 set " +
$"[{sXG}]='{XGYJ }',[{sDG }]='{DGYJ }',[{sCG }]='{CGYJ }',[{sXKD}]='{XKDYJ}',[{sDKD}]='{DKDYJ}',[{sXKJ}]= '{XKJYJ}',[{sDKJ}]='{DKJYJ}'" +
$",[{sXGBJ }]='{XGYJBJ }',[{sDGBJ }]='{DGYJBJ }',[{sCGBJ }]='{CGYJBJ }',[{sXKDBJ}]='{XKDYJBJ}',[{sDKDBJ}]='{DKDYJBJ}',[{sXKJBJ}]='{XKJYJBJ}',[{sDKJBJ}]='{DKJYJBJ}'" +
$",[{sFJF }]='{table.Rows[i][" 附 加 费 "].ToString() }' where gid='{sGID }'" ;
# endregion
bool bl = T_ALL_DA . GetExecuteSqlCommand ( sSQL ) ;
if ( ! bl )
{
continue ;
}
}
}
/ /
if ( System . IO . File . Exists ( fileName ) )
{
System . IO . File . Delete ( fileName ) ;
}
if ( sError . Trim ( ) ! = "" )
{
jsonRespose . Success = false ;
jsonRespose . Message = "操作完成,共处理" + Convert . ToString ( iheadList ) + "条数据,其中新增" + Convert . ToString ( InsertCount ) + "条,覆盖" + Convert . ToString ( UpdateCount ) + "条,出错" + Convert . ToString ( iError ) + "条!错误原因:" + sError ;
return new ContentResult ( ) { Content = JsonConvert . Serialize ( jsonRespose ) } ;
}
else
{
jsonRespose . Success = true ;
jsonRespose . Message = "操作完成,共处理" + Convert . ToString ( iheadList ) + "条数据,其中新增" + Convert . ToString ( InsertCount ) + "条,覆盖" + Convert . ToString ( UpdateCount ) + "条,出错" + Convert . ToString ( iError ) + "条!" ;
return new ContentResult ( ) { Content = JsonConvert . Serialize ( jsonRespose ) } ;
}
}
# endregion