电子面单接口完善,商家导入商品功能

This commit is contained in:
chc 2022-08-31 17:37:07 +08:00
parent 05f29a264e
commit b873ec2095
10 changed files with 496 additions and 4 deletions

View File

@ -0,0 +1,10 @@
/**增加电子面单店铺信息**/
ALTER TABLE `li_store_logistics` ADD `customer_name` varchar(255) DEFAULT NULL COMMENT '客户代码';
ALTER TABLE `li_store_logistics` ADD `customer_pwd` varchar(255) DEFAULT NULL COMMENT '客户密码';
ALTER TABLE `li_store_logistics` ADD `month_code` varchar(255) DEFAULT NULL COMMENT '月结号/密钥';
ALTER TABLE `li_store_logistics` ADD `send_site` varchar(255) DEFAULT NULL COMMENT '归属网点';
ALTER TABLE `li_store_logistics` ADD `send_staff` varchar(255) DEFAULT NULL COMMENT '收件快递员';
ALTER TABLE `li_store_logistics` ADD `face_sheet_flag` bit(1) DEFAULT NULL COMMENT '是否使用电子面单';
ALTER TABLE `li_store_logistics` ADD `pay_type` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '支付方式';
ALTER TABLE `li_store_logistics` ADD `exp_type` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '快递类型';

View File

@ -0,0 +1,67 @@
package cn.lili.modules.goods.entity.dto;
import cn.lili.modules.goods.entity.dos.Category;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Map;
/**
* 商品导入DTO
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class GoodsImportDTO {
@ApiModelProperty(value = "商品名称")
private String goodsName;
@ApiModelProperty(value = "商品卖点")
private String sellingPoint;
@ApiModelProperty(value = "商品分类")
private Category category;
@ApiModelProperty(value = "运费模板")
private String template;
@ApiModelProperty(value = "计量单位")
private String goodsUnit;
@ApiModelProperty(value = "发布状态")
private Boolean release;
@ApiModelProperty(value = "商品图片")
private List<Map<String, String>> images;
private List<String> goodsGalleryList;
@ApiModelProperty(value = "成本价")
private Double cost;
@ApiModelProperty(value = "销售价")
private Double price;
@ApiModelProperty(value = "库存")
private Integer quantity;
@ApiModelProperty(value = "重量")
private Double weight;
@ApiModelProperty(value = "货号")
private String sn;
@ApiModelProperty(value = "详情")
private String intro;
@ApiModelProperty(value = "规格项")
private String skuKey;
@ApiModelProperty(value = "规格值")
private String skuValue;
}

View File

@ -1,6 +1,9 @@
package cn.lili.modules.goods.entity.dto;
import cn.lili.common.validation.EnumValue;
import cn.lili.modules.goods.entity.enums.GoodsSalesModeEnum;
import cn.lili.modules.goods.entity.enums.GoodsStatusEnum;
import cn.lili.modules.goods.entity.enums.GoodsTypeEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.ToString;
@ -9,6 +12,8 @@ import org.hibernate.validator.constraints.Length;
import javax.validation.Valid;
import javax.validation.constraints.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -122,9 +127,49 @@ public class GoodsOperationDTO implements Serializable {
@ApiModelProperty(value = "批发商品规则")
private List<WholesaleDTO> wholesaleList;
@ApiModelProperty(value = "注意事项")
private String needingAttention;
@ApiModelProperty(value = "是否为年度会员专属")
private Boolean annualFeeExclusive;
@ApiModelProperty(value = "浏览权限")
private String browsePermissions;
public String getGoodsName() {
//对商品对名称做一个极限处理这里没有用xss过滤是因为xss过滤为全局过滤影响很大
// 业务中全局代码中只有商品名称不能拥有英文逗号是由于商品名称存在一个数据库联合查询结果要根据逗号分组
return goodsName.replace(",", "");
}
public GoodsOperationDTO(GoodsImportDTO goodsImportDTO) {
this.price = goodsImportDTO.getPrice();
this.goodsName = goodsImportDTO.getGoodsName();
this.intro = goodsImportDTO.getIntro();
this.mobileIntro = goodsImportDTO.getIntro();
this.quantity = goodsImportDTO.getQuantity();
this.goodsGalleryList = goodsImportDTO.getGoodsGalleryList();
this.templateId = goodsImportDTO.getTemplate();
this.sellingPoint = goodsImportDTO.getSellingPoint();
this.salesModel = GoodsSalesModeEnum.RETAIL.name();
this.goodsUnit = goodsImportDTO.getGoodsUnit();
this.goodsType = GoodsTypeEnum.PHYSICAL_GOODS.name();
this.release = goodsImportDTO.getRelease();
this.recommend=false;
Map<String, Object> map = new HashMap<>();
map.put("sn", goodsImportDTO.getSn());
map.put("price", goodsImportDTO.getPrice());
map.put("cost", goodsImportDTO.getCost());
map.put("weight", goodsImportDTO.getWeight());
map.put("quantity", goodsImportDTO.getQuantity());
map.put(goodsImportDTO.getSkuKey(), goodsImportDTO.getSkuValue());
map.put("images", goodsImportDTO.getImages());
List<Map<String, Object>> skuList = new ArrayList<>();
skuList.add(map);
this.skuList = skuList;
}
}

View File

@ -0,0 +1,20 @@
package cn.lili.modules.goods.service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
public interface GoodsImportService {
/**
* 下载导入列表
* @param response
*/
void download(HttpServletResponse response);
/**
* 导入商品
*/
void importExcel(MultipartFile files) throws Exception;
}

View File

@ -0,0 +1,281 @@
package cn.lili.modules.goods.serviceimpl;
import cn.hutool.core.convert.Convert;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.lili.common.exception.ServiceException;
import cn.lili.modules.goods.entity.dos.Category;
import cn.lili.modules.goods.entity.dos.GoodsUnit;
import cn.lili.modules.goods.entity.dto.GoodsImportDTO;
import cn.lili.modules.goods.entity.dto.GoodsOperationDTO;
import cn.lili.modules.goods.entity.vos.CategoryVO;
import cn.lili.modules.goods.service.CategoryService;
import cn.lili.modules.goods.service.GoodsService;
import cn.lili.modules.goods.service.GoodsUnitService;
import cn.lili.modules.goods.service.GoodsImportService;
import cn.lili.modules.store.entity.vos.FreightTemplateVO;
import cn.lili.modules.store.service.FreightTemplateService;
import cn.lili.modules.store.service.StoreDetailService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.DVConstraint;
import org.apache.poi.hssf.usermodel.HSSFDataValidation;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Service
public class GoodsImportServiceImpl implements GoodsImportService {
@Autowired
private FreightTemplateService freightTemplateService;
@Autowired
private StoreDetailService storeDetailService;
@Autowired
private CategoryService categoryService;
@Autowired
private GoodsUnitService goodsUnitService;
@Autowired
private GoodsService goodsService;
@Override
public void download(HttpServletResponse response) {
String storeId = "1376369067769724928";
// //Objects.requireNonNull(UserContext.getCurrentUser()).getStoreId();
//创建Excel工作薄对象
Workbook workbook = new HSSFWorkbook();
//生成一个表格 设置页签
Sheet sheet = workbook.createSheet("导入模板");
//创建第1行
Row row0 = sheet.createRow(0);
row0.createCell(0).setCellValue("商品名称");
row0.createCell(1).setCellValue("商品卖点");
row0.createCell(2).setCellValue("商品分类");
row0.createCell(3).setCellValue("运费模板");
row0.createCell(4).setCellValue("计量单位");
row0.createCell(5).setCellValue("发布状态");
row0.createCell(6).setCellValue("商品图片");
row0.createCell(7).setCellValue("成本价");
row0.createCell(8).setCellValue("销售价");
row0.createCell(9).setCellValue("库存");
row0.createCell(10).setCellValue("重量");
row0.createCell(11).setCellValue("货号");
row0.createCell(12).setCellValue("详情");
row0.createCell(13).setCellValue("规格项");
row0.createCell(14).setCellValue("规格值");
sheet.setColumnWidth(0, 7000);
sheet.setColumnWidth(1, 7000);
sheet.setColumnWidth(2, 7000);
sheet.setColumnWidth(3, 7000);
sheet.setColumnWidth(4, 7000);
sheet.setColumnWidth(5, 3000);
sheet.setColumnWidth(6, 7000);
sheet.setColumnWidth(7, 3000);
sheet.setColumnWidth(8, 3000);
sheet.setColumnWidth(9, 3000);
sheet.setColumnWidth(10, 3000);
sheet.setColumnWidth(11, 7000);
sheet.setColumnWidth(12, 7000);
sheet.setColumnWidth(13, 3000);
sheet.setColumnWidth(14, 3000);
String goodsManagementCategory = storeDetailService.getStoreDetail(storeId).getGoodsManagementCategory();
List<CategoryVO> categoryVOList = this.categoryService.getStoreCategory(goodsManagementCategory.split(","));
List<String> categoryNameList = new ArrayList<>();
//先简单写后期优化
//循环三次添加值
//循环列表存放ID-分类名称
for (CategoryVO categoryVO1 : categoryVOList) {
for (CategoryVO categoryVO2 : categoryVO1.getChildren()) {
for (CategoryVO categoryVO3 : categoryVO2.getChildren()) {
categoryNameList.add(categoryVO3.getId() + "-" + categoryVO3.getName());
}
}
}
List<String> freightTemplateNameList = new ArrayList<>();
//循环列表存放ID-运费模板名称
for (FreightTemplateVO freightTemplateVO : freightTemplateService.getFreightTemplateList(storeId)) {
freightTemplateNameList.add(freightTemplateVO.getId() + "-" + freightTemplateVO.getName());
}
//获取计量单位
List<String> goodsUnitList = new ArrayList<>();
List<GoodsUnit> goodsUnitListVO = goodsUnitService.list();
for (GoodsUnit goodsUnit : goodsUnitListVO) {
goodsUnitList.add(goodsUnit.getId() + "-" + goodsUnit.getName());
}
//添加分类
this.excelTo255(workbook, "hiddenCategoryVO", 1, categoryNameList.toArray(new String[]{}), 1, 5000, 2, 2);
//添加运费模板
this.excelTo255(workbook, "hiddenFreightTemplateVO", 2, freightTemplateNameList.toArray(new String[]{}), 1, 5000, 3, 3);
//添加计量单位
this.excelTo255(workbook, "hiddenGoodsUnit", 3, goodsUnitList.toArray(new String[]{}), 1, 5000, 4, 4);
//添加计量单位
this.excelTo255(workbook, "hiddenRelease", 4, new String[]{"上架", "仓库中"}, 1, 5000, 5, 5);
ServletOutputStream out = null;
try {
//设置公共属性列表名称
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("下载商品导入模板", "UTF8") + ".xls");
out = response.getOutputStream();
workbook.write(out);
} catch (Exception e) {
log.error("下载商品导入模板错误", e);
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void importExcel(MultipartFile files) throws Exception {
InputStream inputStream;
List<GoodsImportDTO> goodsImportDTOList = new ArrayList<>();
inputStream = files.getInputStream();
ExcelReader excelReader = ExcelUtil.getReader(inputStream);
// 读取列表
// 检测数据-查看分类模板计量单位是否存在
List<List<Object>> read = excelReader.read(1, excelReader.getRowCount());
for (List<Object> objects : read) {
GoodsImportDTO goodsImportDTO = new GoodsImportDTO();
String categoryId = objects.get(2).toString().substring(0, objects.get(2).toString().indexOf("-"));
Category category = categoryService.getCategoryById(categoryId);
if (category == null) {
throw new ServiceException("商品分类不存在:" + objects.get(2).toString().substring(objects.get(2).toString().indexOf("-")));
}
String templateId = objects.get(3).toString().substring(0, objects.get(3).toString().indexOf("-"));
FreightTemplateVO freightTemplateVO = freightTemplateService.getFreightTemplate(templateId);
if (freightTemplateVO == null) {
throw new ServiceException("配送模板不存在:" + objects.get(3).toString().substring(objects.get(3).toString().indexOf("-")));
}
goodsImportDTO.setGoodsName(objects.get(0).toString());
goodsImportDTO.setSellingPoint(objects.get(1).toString());
goodsImportDTO.setCategory(category);
goodsImportDTO.setTemplate(templateId);
goodsImportDTO.setGoodsUnit(objects.get(4).toString().substring(objects.get(4).toString().indexOf("-") + 1));
goodsImportDTO.setRelease(objects.get(5).toString().equals("上架") ? true : false);
List<Map<String, String>> images = new ArrayList<>();
List<String> goodsGalleryList = new ArrayList<>();
Map<String, String> map = new HashMap<>();
map.put("url", objects.get(6).toString());
images.add(map);
goodsGalleryList.add(objects.get(6).toString());
goodsImportDTO.setImages(images);
goodsImportDTO.setGoodsGalleryList(goodsGalleryList);
goodsImportDTO.setCost(Convert.toDouble(objects.get(7)));
goodsImportDTO.setPrice(Convert.toDouble(objects.get(8)));
goodsImportDTO.setQuantity(Convert.toInt(objects.get(9)));
goodsImportDTO.setWeight(Convert.toDouble(objects.get(10)));
goodsImportDTO.setSn(objects.get(11).toString());
goodsImportDTO.setIntro("<p>" + objects.get(12).toString() + "</p>");
goodsImportDTO.setSkuKey(objects.get(13).toString());
goodsImportDTO.setSkuValue(objects.get(14).toString());
goodsImportDTOList.add(goodsImportDTO);
}
//添加商品
addGoodsList(goodsImportDTOList);
}
/**
* 添加商品
*
* @param goodsImportDTOList
*/
private void addGoodsList(List<GoodsImportDTO> goodsImportDTOList) {
for (GoodsImportDTO goodsImportDTO : goodsImportDTOList) {
GoodsOperationDTO goodsOperationDTO = new GoodsOperationDTO(goodsImportDTO);
//获取父
Category parentCategory = categoryService.getCategoryById(goodsImportDTO.getCategory().getParentId());
goodsOperationDTO.setCategoryPath(parentCategory.getParentId() + "," + parentCategory.getId() + "," + goodsImportDTO.getCategory().getParentId());
//添加商品
goodsService.addGoods(goodsOperationDTO);
}
}
/**
* 表格
*
* @param workbook 表格
* @param sheetName sheet名称
* @param sheetNameIndex 开始
* @param sheetData 数据
* @param firstRow 开始行
* @param lastRow 结束行
* @param firstCol 开始列
* @param lastCol 结束列
*/
private void excelTo255(Workbook workbook, String sheetName, int sheetNameIndex, String[] sheetData,
int firstRow, int lastRow, int firstCol, int lastCol) {
//将下拉框数据放到新的sheet里然后excle通过新的sheet数据加载下拉框数据
Sheet hidden = workbook.createSheet(sheetName);
//创建单元格对象
Cell cell = null;
//遍历我们上面的数组将数据取出来放到新sheet的单元格中
for (int i = 0, length = sheetData.length; i < length; i++) {
//取出数组中的每个元素
String name = sheetData[i];
//根据i创建相应的行对象说明我们将会把每个元素单独放一行
Row row = hidden.createRow(i);
//创建每一行中的第一个单元格
cell = row.createCell(0);
//然后将数组中的元素赋值给这个单元格
cell.setCellValue(name);
}
// 创建名称可被其他单元格引用
Name namedCell = workbook.createName();
namedCell.setNameName(sheetName);
// 设置名称引用的公式
namedCell.setRefersToFormula(sheetName + "!$A$1:$A$" + sheetData.length);
//加载数据,将名称为hidden的sheet中的数据转换为List形式
DVConstraint constraint = DVConstraint.createFormulaListConstraint(sheetName);
// 设置第一列的3-65534行为下拉列表
// (3, 65534, 2, 2) ====> (起始行,结束行,起始列,结束列)
CellRangeAddressList regions = new CellRangeAddressList(firstRow, lastRow, firstCol, lastCol);
// 将设置下拉选的位置和数据的对应关系 绑定到一起
DataValidation dataValidation = new HSSFDataValidation(regions, constraint);
//将第二个sheet设置为隐藏
workbook.setSheetHidden(sheetNameIndex, true);
//将数据赋给下拉列表
workbook.getSheetAt(0).addValidationData(dataValidation);
}
}

View File

@ -110,7 +110,7 @@ public class KdNiaoServiceImpl implements KdNiaoService {
String AppKey = kuaidiSetting.getAppKey();
//请求url
String ReqURL = kuaidiSetting.getReqURL();
String ReqURL = kuaidiSetting.getSheetReqURL();
//如果订单未发货并且订单状态值等于待发货
if (order.getDeliverStatus().equals(DeliverStatusEnum.UNDELIVERED.name()) && order.getOrderStatus().equals(OrderStatusEnum.UNDELIVERED.name())) {
@ -145,8 +145,8 @@ public class KdNiaoServiceImpl implements KdNiaoService {
"'MonthCode': '"+storeLogistics.getMonthCode()+"'," + //密钥
"'SendSite': '"+storeLogistics.getSendSite()+"'," + //归属网点
"'SendStaff': '"+storeLogistics.getSendStaff()+"'," + //收件快递员
"'PayType': 1," +
"'ExpType': 1," +
"'PayType': "+storeLogistics.getPayType()+"," +
"'ExpType': "+storeLogistics.getExpType()+"," +
//发件人信息
"'Sender': {" +
"'Name': '" + storeDeliverGoodsAddressDTO.getSalesConsignorName() + "'," +
@ -176,7 +176,7 @@ public class KdNiaoServiceImpl implements KdNiaoService {
"},";
}
resultDate = resultDate + "]," +
"'Quantity': 1," + //包裹数
"'Quantity': "+orderItems.size()+"," + //包裹数
"'IsReturnPrintTemplate':1,"+ //生成电子面单模板
"'Remark': '" + order.getRemark() + "'"+//商家备注
"}";

View File

@ -51,6 +51,12 @@ public class StoreLogistics extends BaseEntity {
@ApiModelProperty(value = "是否使用电子面单")
private boolean faceSheetFlag;
@ApiModelProperty(value = "支付方式")
private String payType;
@ApiModelProperty(value = "快递类型")
private String expType;
public StoreLogistics(StoreLogisticsCustomerDTO storeLogisticsCustomerDTO){
this.customerName=storeLogisticsCustomerDTO.getCustomerName();
this.customerPwd=storeLogisticsCustomerDTO.getCustomerPwd();
@ -58,7 +64,10 @@ public class StoreLogistics extends BaseEntity {
this.sendStaff=storeLogisticsCustomerDTO.getSendStaff();
this.monthCode=storeLogisticsCustomerDTO.getMonthCode();
this.faceSheetFlag=storeLogisticsCustomerDTO.isFaceSheetFlag();
this.payType = storeLogisticsCustomerDTO.getPayType();
this.expType = storeLogisticsCustomerDTO.getExpType();
}
}

View File

@ -32,4 +32,10 @@ public class StoreLogisticsCustomerDTO {
@ApiModelProperty(value = "是否使用电子面单")
private boolean faceSheetFlag;
@ApiModelProperty(value = "支付方式")
private String payType;
@ApiModelProperty(value = "快递类型")
private String expType;
}

View File

@ -25,4 +25,9 @@ public class KuaidiSetting implements Serializable {
* api地址
*/
private String reqURL;
/**
* 电子面单api地址
*/
private String sheetReqURL;
}

View File

@ -0,0 +1,49 @@
package cn.lili.controller.goods;
import cn.lili.common.context.ThreadContextHolder;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.enums.ResultUtil;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.vo.ResultMessage;
import cn.lili.modules.goods.service.GoodsImportService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
/**
* @author chc
* @since 2022/6/2114:46
*/
public class GoodsImportController {
@Autowired
private GoodsImportService goodsImportService;
@PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ApiOperation(value = "上传文件,商品批量添加")
public ResultMessage<Object> importExcel(@RequestPart("files") MultipartFile files) {
try {
goodsImportService.importExcel(files);
return ResultUtil.success(ResultCode.SUCCESS);
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException(ResultCode.ERROR);
}
}
@ApiOperation(value = "下载导入模板", produces = "application/octet-stream")
@GetMapping(value = "/downLoad")
public void download() {
HttpServletResponse response = ThreadContextHolder.getHttpResponse();
goodsImportService.download(response);
}
}