Commit 2c6e054c by guojuxing

门店分组

parent 07ede38e
package com.gic.store.constant;
/**
* @author guojx
* @date 2019/6/26 6:22 PM
*/
public class StoreGroupConstant {
/**
* 分组第一级
*/
public final static int FIRST_STORE_GROUP_LEVEL = 1;
/**
* 所有门店层级
*/
public final static int ALL_STORE_LEVEL = 0;
/**
* 排序,上移
*/
public final static int SORT_UP = 1;
/**
* 排序,下移
*/
public final static int SORT_DOWN = 2;
}
package com.gic.store.constant;
/**
* @author guojx
* @date 2019/6/26 1:46 PM
*/
public enum StoreGroupErrorEnum {
Error("9999", "门店分组服务异常"),
DeleteError("1000", "该分组下存在门店,不能删除"),
GroupLevelError("2000", "分组层级参数数据错误"),
AllStoreGroupError("3000", "所有门店已存在"),
ParentStoreGroupParamError("4000", "父级ID参数错误");
private String code;
private String message;
private StoreGroupErrorEnum(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
package com.gic.store.dto;
import java.io.Serializable;
import java.util.Date;
/**
* @author guojx
* @date 2019/6/26 1:57 PM
*/
public class StoreGroupDTO implements Serializable{
private static final long serialVersionUID = 5358954654155895008L;
/**
*
*/
private Integer storeGroupId;
/**
* 分组名称
*/
private String storeGroupName;
/**
* 父级分组id
*/
private Integer parentStoreGroupId;
/**
*
*/
private Integer enterpriseId;
/**
* 分组层级
*/
private Integer groupLevel;
/**
* 分组链id
*/
private String storeGroupChain;
/**
* 分组排序
*/
private Integer sort;
/**
* 状态值
*/
private Integer status;
/**
*
*/
private Date createTime;
/**
*
*/
private Date updateTime;
/**
* 是否是默认门店,初始化品牌的时候会建立一条默认门店:未分组门店,1:是 0:否
*/
private Integer isDefault;
public Integer getStoreGroupId() {
return storeGroupId;
}
public void setStoreGroupId(Integer storeGroupId) {
this.storeGroupId = storeGroupId;
}
public String getStoreGroupName() {
return storeGroupName;
}
public void setStoreGroupName(String storeGroupName) {
this.storeGroupName = storeGroupName;
}
public Integer getParentStoreGroupId() {
return parentStoreGroupId;
}
public void setParentStoreGroupId(Integer parentStoreGroupId) {
this.parentStoreGroupId = parentStoreGroupId;
}
public Integer getEnterpriseId() {
return enterpriseId;
}
public void setEnterpriseId(Integer enterpriseId) {
this.enterpriseId = enterpriseId;
}
public Integer getGroupLevel() {
return groupLevel;
}
public void setGroupLevel(Integer groupLevel) {
this.groupLevel = groupLevel;
}
public String getStoreGroupChain() {
return storeGroupChain;
}
public void setStoreGroupChain(String storeGroupChain) {
this.storeGroupChain = storeGroupChain;
}
public Integer getSort() {
return sort;
}
public void setSort(Integer sort) {
this.sort = sort;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public Integer getIsDefault() {
return isDefault;
}
public void setIsDefault(Integer isDefault) {
this.isDefault = isDefault;
}
}
package com.gic.store.exception;
/**
* @author guojx
* @date 2019/6/26 2:03 PM
*/
public class StoreGroupException extends RuntimeException{
private String errorCode;
public StoreGroupException(String errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public String getErrorCode() {
return errorCode;
}
}
package com.gic.store.service;
import com.gic.store.dto.StoreGroupDTO;
import java.util.List;
/**
* @author guojx
* @date 2019/6/26 2:14 PM
*/
public interface StoreGroupApiService {
/**
* 新增
* @param storeGroupDTO
* @return 返回新增的门店分组主键ID值
*/
int save(StoreGroupDTO storeGroupDTO);
/**
* 更新分组数据:名称、
* @param storeGroupDTO
* @return
*/
int update(StoreGroupDTO storeGroupDTO);
/**
* 分组上移下移排序
* @param storeGroupDTO
* @param isUp 是否是上移
* @return
*/
int sort(StoreGroupDTO storeGroupDTO, boolean isUp);
/**
* 查询分组列表
* @param enterpriseId
* @param search 门店分组名称
* @return
*/
List<StoreGroupDTO> listStoreGroup(StoreGroupDTO storeGroupDTO);
/**
* 根据主键删除分组
* @param storeGroupId
* @return
*/
int remove(int storeGroupId);
}
package com.gic.store.dao.mapper;
import com.gic.store.entity.TabStoreGroup;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface TabStoreGroupMapper {
/**
......@@ -15,7 +18,7 @@ public interface TabStoreGroupMapper {
* 插入一条记录
*
* @param record 实体对象
* @return 更新条目数
* @return 主键ID
*/
int insert(TabStoreGroup record);
......@@ -50,4 +53,65 @@ public interface TabStoreGroupMapper {
* @return 更新条目数
*/
int updateByPrimaryKey(TabStoreGroup record);
/**
* 查询分组列表
* @param record
* @return
*/
List<TabStoreGroup> listStoreGroup(TabStoreGroup record);
/**
* 查询最大排序值
* @param enterpriseId
* @param groupLevel
* @return
*/
int selectStoreGroupMaxSort(@Param("enterpriseId") Integer enterpriseId, @Param("groupLevel") Integer groupLevel);
/**
* 批量更新分组所有子集的分组链数据,当分组更新上级分组的时候
* @param storeGroupId
* @param fromStoreGroupId 分组链需要被替换的字符串
* @param toStoreGroupId 分组链替换的字符串数据
* @return
*/
int updateStoreGroupChainByStoreGroupId(@Param("storeGroupId") Integer storeGroupId,
@Param("fromStoreGroupId") Integer fromStoreGroupId,
@Param("toStoreGroupId") Integer toStoreGroupId);
/**
* 获取大于该序号的,最小序号记录
* @param enterpriseId
* @param groupLevel
* @param sort
* @return
*/
TabStoreGroup getStoreGroupWhenMinSort(@Param("enterpriseId") Integer enterpriseId, @Param("groupLevel") Integer groupLevel, @Param("sort") Integer sort);
/**
* 获取小于该序号的,最大序号记录
* @param enterpriseId
* @param groupLevel
* @param sort
* @return
*/
TabStoreGroup getStoreGroupWhenMaxSort(@Param("enterpriseId") Integer enterpriseId, @Param("groupLevel") Integer groupLevel, @Param("sort") Integer sort);
/**
* 查询所有门店
* @param enterpriseId
* @param groupLevel
* @return
*/
TabStoreGroup selectAllStoreGroup(Integer enterpriseId, Integer groupLevel);
/**
* 根据父级ID,统计下面是否有子节点
* @param parentId
* @return
*/
int countByParentId(Integer parentId);
}
\ No newline at end of file
......@@ -55,6 +55,10 @@ public class TabStoreGroup {
*
*/
private Date updateTime;
/**
* 是否是默认门店,初始化品牌的时候会建立一条默认门店:未分组门店,1:是 0:否
*/
private Integer isDefault;
public Integer getStoreGroupId() {
return storeGroupId;
......@@ -135,4 +139,12 @@ public class TabStoreGroup {
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public Integer getIsDefault() {
return isDefault;
}
public void setIsDefault(Integer isDefault) {
this.isDefault = isDefault;
}
}
\ No newline at end of file
......@@ -21,4 +21,7 @@
<dubbo:reference interface="com.gic.bizdict.api.service.BizdictService" id="bizdictService " timeout="6000" retries="0"/>
<!--分组-->
<dubbo:service interface="com.gic.store.service.StoreGroupApiService" ref="storeGroupApiService" timeout="60000" />
</beans>
......@@ -12,10 +12,11 @@
<result column="status" jdbcType="INTEGER" property="status" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
<result column="is_default" jdbcType="INTEGER" property="isDefault" />
</resultMap>
<sql id="Base_Column_List">
store_group_id, store_group_name, parent_store_group_id, enterprise_id, group_level,
store_group_chain, sort, status, create_time, update_time
store_group_chain, sort, status, create_time, update_time, is_default
</sql>
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
......@@ -27,15 +28,15 @@
delete from tab_store_group
where store_group_id = #{storeGroupId,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="com.gic.store.entity.TabStoreGroup">
<insert id="insert" parameterType="com.gic.store.entity.TabStoreGroup" useGeneratedKeys="true" keyProperty="storeGroupId">
insert into tab_store_group (store_group_id, store_group_name, parent_store_group_id,
enterprise_id, group_level, store_group_chain,
sort, status, create_time,
update_time)
update_time, is_default)
values (#{storeGroupId,jdbcType=INTEGER}, #{storeGroupName,jdbcType=VARCHAR}, #{parentStoreGroupId,jdbcType=INTEGER},
#{enterpriseId,jdbcType=INTEGER}, #{groupLevel,jdbcType=INTEGER}, #{storeGroupChain,jdbcType=VARCHAR},
#{sort,jdbcType=INTEGER}, #{status,jdbcType=INTEGER}, #{createTime,jdbcType=TIMESTAMP},
#{updateTime,jdbcType=TIMESTAMP})
#{updateTime,jdbcType=TIMESTAMP}, #{isDefault,jdbcType=INTEGER})
</insert>
<insert id="insertSelective" parameterType="com.gic.store.entity.TabStoreGroup">
insert into tab_store_group
......@@ -70,6 +71,9 @@
<if test="updateTime != null">
update_time,
</if>
<if test="isDefault != null">
is_default,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="storeGroupId != null">
......@@ -102,6 +106,9 @@
<if test="updateTime != null">
#{updateTime,jdbcType=TIMESTAMP},
</if>
<if test="isDefault != null">
#{isDefault,jdbcType=INTEGER},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.gic.store.entity.TabStoreGroup">
......@@ -134,6 +141,9 @@
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=TIMESTAMP},
</if>
<if test="isDefault != null">
is_default = #{isDefault,jdbcType=INTEGER},
</if>
</set>
where store_group_id = #{storeGroupId,jdbcType=INTEGER}
</update>
......@@ -147,7 +157,75 @@
sort = #{sort,jdbcType=INTEGER},
status = #{status,jdbcType=INTEGER},
create_time = #{createTime,jdbcType=TIMESTAMP},
update_time = #{updateTime,jdbcType=TIMESTAMP}
update_time = #{updateTime,jdbcType=TIMESTAMP},
is_default = #{isDefault,jdbcType=INTEGER}
where store_group_id = #{storeGroupId,jdbcType=INTEGER}
</update>
<select id="listStoreGroup" resultMap="BaseResultMap" parameterType="com.gic.store.entity.TabStoreGroup">
select
<include refid="Base_Column_List" />
from
tab_store_group where status = 1 and enterprise_id = #{enterpriseId}
<if test="storeGroupName != null and storeGroupName != '' ">
and store_group_name like concat('%', #{storeGroupName}, '%')
</if>
<if test="storeGroupId != null and storeGroupId != '' ">
and store_group_chain like concat('%_', #{storeGroupId}, '_%')
</if>
<if test="groupLevel != null and groupLevel != '' ">
and group_level = #{groupLevel}
</if>
order by group_level, sort
</select>
<select id="selectStoreGroupMaxSort" resultMap="BaseResultMap">
select
ifnull(max(sort), 0)
from
tab_store_group where status = 1 and enterprise_id = #{enterpriseId} and group_level = #{groupLevel}
</select>
<update id="updateStoreGroupChainByStoreGroupId">
UPDATE
tab_store_group
SET store_group_chain = replace(store_group_chain, concat('_', #{fromStoreGroupId}), '_'), concat('_', #{toStoreGroupId}, '_'))
where status = 1 and store_group_chain like concat('%_', #{storeGroupId}, '_%')
</update>
<select id="getStoreGroupWhenMinSort" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from
tab_store_group where status = 1 and enterprise_id = #{enterpriseId} and group_level = #{groupLevel} and sort > #{sort}
order by sort
limit 1
</select>
<select id="getStoreGroupWhenMaxSort" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from
tab_store_group where status = 1 and enterprise_id = #{enterpriseId} and group_level = #{groupLevel} and sort &lt; #{sort}
order by sort desc
limit 1
</select>
<select id="selectAllStoreGroup" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from
tab_store_group where status = 1 and enterprise_id = #{enterpriseId} and group_level = #{groupLevel}
limit 1
</select>
<select id="countByParentId" resultMap="BaseResultMap">
select
count(1)
from
tab_store_group where status = 1 and parent_store_group_id = #{parentId}
</select>
</mapper>
\ No newline at end of file
package com.gic.store.web.controller;
import com.gic.commons.util.EntityUtil;
import com.gic.commons.webapi.reponse.RestResponse;
import com.gic.store.constant.StoreGroupConstant;
import com.gic.store.dto.StoreGroupDTO;
import com.gic.store.service.StoreGroupApiService;
import com.gic.store.web.qo.storegroup.StoreGroupQO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 门店分组
* @author guojx
* @date 2019/6/26 11:03 AM
*/
@RestController
@RequestMapping("/store-group")
public class StoreGroupController {
private static final Logger logger = LoggerFactory.getLogger(StoreGroupController.class);
private static final int ENTERPRISE_ID = 10000;
@Autowired
private StoreGroupApiService storeGroupApiService;
@RequestMapping("/list")
public RestResponse listStoreGroup(StoreGroupQO storeGroupQO) {
StoreGroupDTO storeGroupDTO = EntityUtil.changeEntityNew(StoreGroupDTO.class, storeGroupQO);
List<StoreGroupDTO> list = storeGroupApiService.listStoreGroup(storeGroupDTO);
return RestResponse.success(changeListToTree(StoreGroupConstant.ALL_STORE_LEVEL, list));
}
@RequestMapping("/save")
public RestResponse save(@Validated({StoreGroupQO.SaveValidView.class}) StoreGroupQO storeGroupQO) {
StoreGroupDTO storeGroupDTO = EntityUtil.changeEntityNew(StoreGroupDTO.class, storeGroupQO);
storeGroupDTO.setEnterpriseId(ENTERPRISE_ID);
return RestResponse.success(storeGroupApiService.save(storeGroupDTO));
}
@RequestMapping("/edit")
public RestResponse edit(@Validated({StoreGroupQO.SaveValidView.class}) StoreGroupQO storeGroupQO) {
StoreGroupDTO storeGroupDTO = EntityUtil.changeEntityNew(StoreGroupDTO.class, storeGroupQO);
storeGroupDTO.setEnterpriseId(ENTERPRISE_ID);
return RestResponse.success(storeGroupApiService.update(storeGroupDTO));
}
@RequestMapping("/sort")
public RestResponse sort(@Validated({StoreGroupQO.SortValidView.class}) StoreGroupQO storeGroupQO) {
StoreGroupDTO storeGroupDTO = EntityUtil.changeEntityNew(StoreGroupDTO.class, storeGroupQO);
storeGroupDTO.setEnterpriseId(ENTERPRISE_ID);
return RestResponse.success(storeGroupApiService.sort(storeGroupDTO, storeGroupQO.isUp()));
}
@RequestMapping("/remove")
public RestResponse remove(StoreGroupDTO storeGroupDTO) {
storeGroupDTO.setEnterpriseId(ENTERPRISE_ID);
return RestResponse.success(storeGroupApiService.remove(storeGroupDTO.getStoreGroupId()));
}
private List<Map<String, Object>> changeListToTree(int storeGroupId, List<StoreGroupDTO> list) {
List<Map<String, Object>> result = new ArrayList<>();
if (list != null) {
for (StoreGroupDTO t : list) {
if (storeGroupId == t.getParentStoreGroupId()) {
Map<String, Object> data = new HashMap<>(16);
data.put("parentGroupId", t.getParentStoreGroupId());
data.put("storeGroupId", t.getStoreGroupId());
data.put("storeGroupName", t.getStoreGroupName());
data.put("sort", t.getSort());
data.put("isDefault", t.getIsDefault());
data.put("groupLevel", t.getGroupLevel());
List<Map<String, Object>> children = this.changeListToTree(t.getStoreGroupId(), list);
data.put("children", children);
result.add(data);
}
}
}
return result;
}
}
package com.gic.store.web.exception;
import com.gic.commons.webapi.reponse.RestResponse;
import com.gic.store.constant.StoreGroupErrorEnum;
import com.gic.store.exception.StoreGroupException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.util.List;
/**
* 全局异常处理类
*
* @author hua
*/
@ControllerAdvice
public class GlobalExceptionHandler {
private static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ResponseBody
@ExceptionHandler(Exception.class)
public RestResponse controllerException(HttpServletResponse response, Exception ex) {
logger.error("err", ex);
RestResponse failureResponse = getRestResponse(StoreGroupErrorEnum.Error.getCode(), StoreGroupErrorEnum.Error.getMessage());
StringBuilder sb = new StringBuilder();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (PrintWriter printWriter = new PrintWriter(baos)) {
ex.printStackTrace(printWriter);
}
try {
sb.append(baos.toString());
} catch (Exception ignored) {
}
if (sb.length() == 0) {
sb.append(ex.getMessage());
}
// 输出详细错误信息,便于调试
failureResponse.setDetailError(sb.toString());
return failureResponse;
}
/**
* 参数校验异常统一处理
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(BindException.class)
public RestResponse customException(BindException e) {
List<FieldError> fieldErrors = e.getFieldErrors();
StringBuilder errorMessage = new StringBuilder();
fieldErrors.forEach(fieldError -> {
errorMessage.append(fieldError.getField())
.append(":")
.append(fieldError.getDefaultMessage())
.append(",");
});
return getRestResponse(StoreGroupErrorEnum.Error.getCode(), errorMessage.toString());
}
/**
* 自定义异常统一处理
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(StoreGroupException.class)
public RestResponse customException(StoreGroupException e) {
return getRestResponse(e.getErrorCode(), e.getMessage());
}
private RestResponse getRestResponse(String errorCode, String message) {
return RestResponse.failure(errorCode, message);
}
}
package com.gic.store.web.qo.storegroup;
import com.gic.store.constant.StoreGroupConstant;
import javax.validation.constraints.*;
import java.io.Serializable;
import java.util.Date;
/**
* @author guojx
* @date 2019/6/27 2:14 PM
*/
public class StoreGroupQO implements Serializable{
private static final long serialVersionUID = -6732142611051879496L;
public interface SaveValidView {
}
public interface SortValidView {
}
/**
*
*
*/
private Integer storeGroupId;
/**
* 分组名称
*/
@NotBlank(message = "名称不能为空", groups = {SaveValidView.class, SortValidView.class})
private String storeGroupName;
/**
* 父级分组id
*/
private Integer parentStoreGroupId;
/**
*
*/
private Integer enterpriseId;
/**
* 分组层级
*/
@NotNull(message = "名称不能为空", groups = {SaveValidView.class})
private Integer groupLevel;
/**
* 分组链id
*/
private String storeGroupChain;
/**
* 分组排序
*/
private Integer sort;
/**
* 状态值
*/
private Integer status;
/**
*
*/
private Date createTime;
/**
*
*/
private Date updateTime;
/**
* 是否是默认门店,初始化品牌的时候会建立一条默认门店:未分组门店,1:是 0:否
*/
private Integer isDefault;
/**
* 上移或者下移
*/
@NotNull(message = "移动标志参数值不能为空", groups = {SortValidView.class})
@Min(value = StoreGroupConstant.SORT_UP, message = "移动标志参数值错误,小于1", groups = {SortValidView.class})
@Max(value = StoreGroupConstant.SORT_DOWN, message = "移动标志参数值错误,大于2", groups = {SortValidView.class})
private Integer upOrDown;
private boolean isUp;
public Integer getStoreGroupId() {
return storeGroupId;
}
public void setStoreGroupId(Integer storeGroupId) {
this.storeGroupId = storeGroupId;
}
public String getStoreGroupName() {
return storeGroupName;
}
public void setStoreGroupName(String storeGroupName) {
this.storeGroupName = storeGroupName;
}
public Integer getParentStoreGroupId() {
return parentStoreGroupId;
}
public void setParentStoreGroupId(Integer parentStoreGroupId) {
this.parentStoreGroupId = parentStoreGroupId;
}
public Integer getEnterpriseId() {
return enterpriseId;
}
public void setEnterpriseId(Integer enterpriseId) {
this.enterpriseId = enterpriseId;
}
public Integer getGroupLevel() {
return groupLevel;
}
public void setGroupLevel(Integer groupLevel) {
this.groupLevel = groupLevel;
}
public String getStoreGroupChain() {
return storeGroupChain;
}
public void setStoreGroupChain(String storeGroupChain) {
this.storeGroupChain = storeGroupChain;
}
public Integer getSort() {
return sort;
}
public void setSort(Integer sort) {
this.sort = sort;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public Integer getIsDefault() {
return isDefault;
}
public void setIsDefault(Integer isDefault) {
this.isDefault = isDefault;
}
public Integer getUpOrDown() {
return upOrDown;
}
public void setUpOrDown(Integer upOrDown) {
this.upOrDown = upOrDown;
}
public boolean isUp() {
if (upOrDown == StoreGroupConstant.SORT_UP) {
return true;
} else {
return false;
}
}
}
......@@ -18,4 +18,7 @@
<dubbo:reference interface="com.gic.store.service.StoreBrandApiService" id="storeBrandApiService" timeout="60000" retries="0"/>
<dubbo:reference interface="com.gic.store.service.StoreDictApiService" id="storeDictApiService" timeout="6000" retries="0"/>
<!--分组服务-->
<dubbo:reference interface="com.gic.store.service.StoreGroupApiService" id="storeGroupApiService" timeout="60000" retries="0"/>
</beans>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment