ERP:初始化销售出库 30%

This commit is contained in:
YunaiV 2024-02-10 18:20:59 +08:00
parent d06a22dab3
commit 3c6ab397f9
20 changed files with 1130 additions and 16 deletions

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.erp.controller.admin.finance; package cn.iocoder.yudao.module.erp.controller.admin.finance;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
@ -26,6 +27,7 @@ import java.io.IOException;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - ERP 结算账户") @Tag(name = "管理后台 - ERP 结算账户")
@ -82,6 +84,14 @@ public class ErpAccountController {
return success(BeanUtils.toBean(account, ErpAccountRespVO.class)); return success(BeanUtils.toBean(account, ErpAccountRespVO.class));
} }
@GetMapping("/simple-list")
@Operation(summary = "获得结算账户精简列表", description = "只包含被开启的结算账户,主要用于前端的下拉选项")
public CommonResult<List<ErpAccountRespVO>> getWarehouseSimpleList() {
List<ErpAccountDO> list = accountService.getAccountListByStatus(CommonStatusEnum.ENABLE.getStatus());
return success(convertList(list, account -> new ErpAccountRespVO().setId(account.getId())
.setName(account.getName()).setDefaultStatus(account.getDefaultStatus())));
}
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得结算账户分页") @Operation(summary = "获得结算账户分页")
@PreAuthorize("@ss.hasPermission('erp:account:query')") @PreAuthorize("@ss.hasPermission('erp:account:query')")

View File

@ -1,4 +0,0 @@
### 请求 /transfer
GET {{baseUrl}}/erp/sale-order/demo
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}

View File

@ -0,0 +1,165 @@
package cn.iocoder.yudao.module.erp.controller.admin.sale;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutSaveReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpCustomerDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutItemDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.erp.service.sale.ErpCustomerService;
import cn.iocoder.yudao.module.erp.service.sale.ErpSaleOutService;
import cn.iocoder.yudao.module.erp.service.stock.ErpStockService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - ERP 销售出库")
@RestController
@RequestMapping("/erp/sale-out")
@Validated
public class ErpSaleOutController {
@Resource
private ErpSaleOutService saleOutService;
@Resource
private ErpStockService stockService;
@Resource
private ErpProductService productService;
@Resource
private ErpCustomerService customerService;
@Resource
private AdminUserApi adminUserApi;
@PostMapping("/create")
@Operation(summary = "创建销售出库")
@PreAuthorize("@ss.hasPermission('erp:stock-out:create')")
public CommonResult<Long> createSaleOut(@Valid @RequestBody ErpSaleOutSaveReqVO createReqVO) {
return success(saleOutService.createSaleOut(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新销售出库")
@PreAuthorize("@ss.hasPermission('erp:stock-out:update')")
public CommonResult<Boolean> updateSaleOut(@Valid @RequestBody ErpSaleOutSaveReqVO updateReqVO) {
saleOutService.updateSaleOut(updateReqVO);
return success(true);
}
@PutMapping("/update-status")
@Operation(summary = "更新销售出库的状态")
@PreAuthorize("@ss.hasPermission('erp:stock-out:update-status')")
public CommonResult<Boolean> updateSaleOutStatus(@RequestParam("id") Long id,
@RequestParam("status") Integer status) {
saleOutService.updateSaleOutStatus(id, status);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除销售出库")
@Parameter(name = "ids", description = "编号数组", required = true)
@PreAuthorize("@ss.hasPermission('erp:stock-out:delete')")
public CommonResult<Boolean> deleteSaleOut(@RequestParam("ids") List<Long> ids) {
saleOutService.deleteSaleOut(ids);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得销售出库")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('erp:stock-out:query')")
public CommonResult<ErpSaleOutRespVO> getSaleOut(@RequestParam("id") Long id) {
ErpSaleOutDO saleOut = saleOutService.getSaleOut(id);
if (saleOut == null) {
return success(null);
}
List<ErpSaleOutItemDO> saleOutItemList = saleOutService.getSaleOutItemListByOutId(id);
Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(
convertSet(saleOutItemList, ErpSaleOutItemDO::getProductId));
return success(BeanUtils.toBean(saleOut, ErpSaleOutRespVO.class, saleOutVO ->
saleOutVO.setItems(BeanUtils.toBean(saleOutItemList, ErpSaleOutRespVO.Item.class, item -> {
ErpStockDO stock = stockService.getStock(item.getProductId(), item.getWarehouseId());
item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO);
MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName())
.setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName()));
}))));
}
@GetMapping("/page")
@Operation(summary = "获得销售出库分页")
@PreAuthorize("@ss.hasPermission('erp:stock-out:query')")
public CommonResult<PageResult<ErpSaleOutRespVO>> getSaleOutPage(@Valid ErpSaleOutPageReqVO pageReqVO) {
PageResult<ErpSaleOutDO> pageResult = saleOutService.getSaleOutPage(pageReqVO);
return success(buildSaleOutVOPageResult(pageResult));
}
@GetMapping("/export-excel")
@Operation(summary = "导出销售出库 Excel")
@PreAuthorize("@ss.hasPermission('erp:stock-out:export')")
@OperateLog(type = EXPORT)
public void exportSaleOutExcel(@Valid ErpSaleOutPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<ErpSaleOutRespVO> list = buildSaleOutVOPageResult(saleOutService.getSaleOutPage(pageReqVO)).getList();
// 导出 Excel
ExcelUtils.write(response, "销售出库.xls", "数据", ErpSaleOutRespVO.class, list);
}
private PageResult<ErpSaleOutRespVO> buildSaleOutVOPageResult(PageResult<ErpSaleOutDO> pageResult) {
if (CollUtil.isEmpty(pageResult.getList())) {
return PageResult.empty(pageResult.getTotal());
}
// 1.1 出库项
List<ErpSaleOutItemDO> saleOutItemList = saleOutService.getSaleOutItemListByOutIds(
convertSet(pageResult.getList(), ErpSaleOutDO::getId));
Map<Long, List<ErpSaleOutItemDO>> saleOutItemMap = convertMultiMap(saleOutItemList, ErpSaleOutItemDO::getOutId);
// 1.2 商品信息
Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(
convertSet(saleOutItemList, ErpSaleOutItemDO::getProductId));
// 1.3 客户信息
Map<Long, ErpCustomerDO> customerMap = customerService.getCustomerMap(
convertSet(pageResult.getList(), ErpSaleOutDO::getCustomerId));
// 1.4 管理员信息
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
convertSet(pageResult.getList(), erpStockRecordDO -> Long.parseLong(erpStockRecordDO.getCreator())));
// 2. 开始拼接
return BeanUtils.toBean(pageResult, ErpSaleOutRespVO.class, saleOut -> {
saleOut.setItems(BeanUtils.toBean(saleOutItemMap.get(saleOut.getId()), ErpSaleOutRespVO.Item.class,
item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName())
.setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName()))));
saleOut.setProductNames(CollUtil.join(saleOut.getItems(), "", ErpSaleOutRespVO.Item::getProductName));
MapUtils.findAndThen(customerMap, saleOut.getCustomerId(), supplier -> saleOut.setCustomerName(supplier.getName()));
MapUtils.findAndThen(userMap, Long.parseLong(saleOut.getCreator()), user -> saleOut.setCreatorName(user.getNickname()));
});
}
}

View File

@ -64,7 +64,6 @@ public class ErpSaleOrderRespVO {
private BigDecimal discountPrice; private BigDecimal discountPrice;
@Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127") @Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
@NotNull(message = "定金金额,单位:元不能为空")
private BigDecimal depositPrice; private BigDecimal depositPrice;
@Schema(description = "附件地址", example = "https://www.iocoder.cn") @Schema(description = "附件地址", example = "https://www.iocoder.cn")

View File

@ -0,0 +1,54 @@
package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - ERP 销售出库分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ErpSaleOutPageReqVO extends PageParam {
@Schema(description = "销售单编号", example = "XS001")
private String no;
@Schema(description = "客户编号", example = "1724")
private Long customerId;
@Schema(description = "出库时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] outTime;
@Schema(description = "备注", example = "你猜")
private String remark;
@Schema(description = "销售状态", example = "2")
private Integer status;
@Schema(description = "创建者")
private String creator;
@Schema(description = "产品编号", example = "1")
private Long productId;
@Schema(description = "仓库编号", example = "1")
private Long warehouseId;
@Schema(description = "结算账号编号", example = "1")
private Long accountId;
@Schema(description = "是否欠款", example = "true")
private Boolean debtStatus;
@Schema(description = "销售单号", example = "1")
private String orderNo;
}

View File

@ -0,0 +1,152 @@
package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - ERP 出库出库 Response VO")
@Data
@ExcelIgnoreUnannotated
public class ErpSaleOutRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386")
@ExcelProperty("编号")
private Long id;
@Schema(description = "出库单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "XS001")
@ExcelProperty("出库单编号")
private String no;
@Schema(description = "出库状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@ExcelProperty("出库状态")
private Integer status;
@Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1724")
private Long customerId;
@Schema(description = "客户名称", example = "芋道")
@ExcelProperty("客户名称")
private String customerName;
@Schema(description = "结算账户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "311.89")
@ExcelProperty("结算账户编号")
private Long accountId;
@Schema(description = "出库员编号", example = "1888")
private Long saleUserId;
@Schema(description = "出库时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("出库时间")
private LocalDateTime outTime;
@Schema(description = "销售订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386")
private Long orderId;
@Schema(description = "销售订单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "XS001")
private Long orderNo;
@Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663")
@ExcelProperty("合计数量")
private BigDecimal totalCount;
@Schema(description = "最终合计价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "24906")
@ExcelProperty("最终合计价格")
private BigDecimal totalPrice;
@Schema(description = "合计产品价格,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
private BigDecimal totalProductPrice;
@Schema(description = "合计税额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
private BigDecimal totalTaxPrice;
@Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88")
private BigDecimal discountPercent;
@Schema(description = "优惠金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
private BigDecimal discountPrice;
@Schema(description = "定金金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
private BigDecimal otherPrice;
@Schema(description = "本次收款,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
private BigDecimal payPrice;
@Schema(description = "本次欠款,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "666")
private BigDecimal debtPrice;
@Schema(description = "附件地址", example = "https://www.iocoder.cn")
@ExcelProperty("附件地址")
private String fileUrl;
@Schema(description = "备注", example = "你猜")
@ExcelProperty("备注")
private String remark;
@Schema(description = "审核人", example = "芋道")
private String creator;
@Schema(description = "审核人名称", example = "芋道")
private String creatorName;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "出库项列表", requiredMode = Schema.RequiredMode.REQUIRED)
private List<Item> items;
@Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("产品信息")
private String productNames;
@Data
public static class Item {
@Schema(description = "出库项编号", example = "11756")
private Long id;
@Schema(description = "销售订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756")
private Long orderItemId;
@Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113")
private Long warehouseId;
@Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113")
private Long productId;
@Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113")
private Long productUnitId;
@Schema(description = "产品单价", example = "100.00")
private BigDecimal productPrice;
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
@NotNull(message = "产品数量不能为空")
private BigDecimal count;
@Schema(description = "税率,百分比", example = "99.88")
private BigDecimal taxPercent;
@Schema(description = "税额,单位:元", example = "100.00")
private BigDecimal taxPrice;
@Schema(description = "备注", example = "随便")
private String remark;
// ========== 关联字段 ==========
@Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "巧克力")
private String productName;
@Schema(description = "产品条码", requiredMode = Schema.RequiredMode.REQUIRED, example = "A9985")
private String productBarCode;
@Schema(description = "产品单位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "")
private String productUnitName;
@Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
private BigDecimal stockCount; // 该字段仅仅在详情编辑时使用
}
}

View File

@ -0,0 +1,88 @@
package cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - ERP 销售出库新增/修改 Request VO")
@Data
public class ErpSaleOutSaveReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386")
private Long id;
@Schema(description = "结算账户编号", example = "31189")
private Long accountId;
@Schema(description = "销售员编号", example = "1888")
private Long saleUserId;
@Schema(description = "出库时间", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "出库时间不能为空")
private LocalDateTime outTime;
@Schema(description = "销售订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "17386")
@NotNull(message = "销售订单编号不能为空")
private Long orderId;
@Schema(description = "优惠率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "99.88")
private BigDecimal discountPercent;
@Schema(description = "其它金额,单位:元", example = "7127")
private BigDecimal otherPrice;
@Schema(description = "本次收款,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "7127")
@NotNull(message = "本次收款不能为空")
private BigDecimal payPrice;
@Schema(description = "附件地址", example = "https://www.iocoder.cn")
private String fileUrl;
@Schema(description = "备注", example = "你猜")
private String remark;
@Schema(description = "出库清单列表")
private List<Item> items;
@Data
public static class Item {
@Schema(description = "出库项编号", example = "11756")
private Long id;
@Schema(description = "销售订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756")
@NotNull(message = "销售订单项编号不能为空")
private Long orderItemId;
@Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113")
@NotNull(message = "仓库编号不能为空")
private Long warehouseId;
@Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113")
@NotNull(message = "产品编号不能为空")
private Long productId;
@Schema(description = "产品单位单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113")
@NotNull(message = "产品单位单位不能为空")
private Long productUnitId;
@Schema(description = "产品单价", example = "100.00")
private BigDecimal productPrice;
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
@NotNull(message = "产品数量不能为空")
private BigDecimal count;
@Schema(description = "税率,百分比", example = "99.88")
private BigDecimal taxPercent;
@Schema(description = "备注", example = "随便")
private String remark;
}
}

View File

@ -27,6 +27,7 @@ import java.io.IOException;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Tag(name = "管理后台 - ERP 仓库") @Tag(name = "管理后台 - ERP 仓库")
@ -95,7 +96,8 @@ public class ErpWarehouseController {
@Operation(summary = "获得仓库精简列表", description = "只包含被开启的仓库,主要用于前端的下拉选项") @Operation(summary = "获得仓库精简列表", description = "只包含被开启的仓库,主要用于前端的下拉选项")
public CommonResult<List<ErpWarehouseRespVO>> getWarehouseSimpleList() { public CommonResult<List<ErpWarehouseRespVO>> getWarehouseSimpleList() {
List<ErpWarehouseDO> list = warehouseService.getWarehouseListByStatus(CommonStatusEnum.ENABLE.getStatus()); List<ErpWarehouseDO> list = warehouseService.getWarehouseListByStatus(CommonStatusEnum.ENABLE.getStatus());
return success(BeanUtils.toBean(list, ErpWarehouseRespVO.class)); return success(convertList(list, warehouse -> new ErpWarehouseRespVO().setId(warehouse.getId())
.setName(warehouse.getName()).setDefaultStatus(warehouse.getDefaultStatus())));
} }
@GetMapping("/export-excel") @GetMapping("/export-excel")

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.erp.dal.dataobject.sale; package cn.iocoder.yudao.module.erp.dal.dataobject.sale;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
@ -30,7 +31,7 @@ public class ErpSaleOrderDO extends BaseDO {
@TableId @TableId
private Long id; private Long id;
/** /**
* 销售 * 销售单号
*/ */
private String no; private String no;
/** /**
@ -48,7 +49,7 @@ public class ErpSaleOrderDO extends BaseDO {
/** /**
* 结算账户编号 * 结算账户编号
* *
* TODO 芋艿关联 * 关联 {@link ErpAccountDO#getId()}
*/ */
private Long accountId; private Long accountId;
/** /**

View File

@ -10,7 +10,7 @@ import lombok.*;
import java.math.BigDecimal; import java.math.BigDecimal;
/** /**
* ERP 销售订单明细 DO * ERP 销售订单 DO
* *
* @author 芋道源码 * @author 芋道源码
*/ */
@ -35,7 +35,6 @@ public class ErpSaleOrderItemDO extends BaseDO {
* 关联 {@link ErpSaleOrderDO#getId()} * 关联 {@link ErpSaleOrderDO#getId()}
*/ */
private Long orderId; private Long orderId;
/** /**
* 产品编号 * 产品编号
* *

View File

@ -0,0 +1,135 @@
package cn.iocoder.yudao.module.erp.dal.dataobject.sale;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* ERP 销售出库 DO
*
* @author 芋道源码
*/
@TableName(value = "erp_sale_out")
@KeySequence("erp_sale_out_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ErpSaleOutDO extends BaseDO {
/**
* 编号
*/
@TableId
private Long id;
/**
* 销售出库单号
*/
private String no;
/**
* 出库状态
*
* 枚举 {@link cn.iocoder.yudao.module.erp.enums.ErpAuditStatus}
*/
private Integer status;
/**
* 客户编号
*
* 关联 {@link ErpCustomerDO#getId()}
*/
private Long customerId;
/**
* 结算账户编号
*
* 关联 {@link ErpAccountDO#getId()}
*/
private Long accountId;
/**
* 销售员编号
*
* 关联 AdminUserDO id 字段
*/
private Long saleUserId;
/**
* 出库时间
*/
private LocalDateTime outTime;
/**
* 销售订单编号
*
* 关联 {@link ErpSaleOrderDO#getId()}
*/
private Long orderId;
/**
* 销售订单号
*
* 冗余 {@link ErpSaleOrderDO#getNo()}
*/
private Long orderNo;
/**
* 合计数量
*/
private BigDecimal totalCount;
/**
* 最终合计价格单位
*
* totalPrice = totalProductPrice + totalTaxPrice - discountPrice
*/
private BigDecimal totalPrice;
/**
* 合计产品价格单位
*/
private BigDecimal totalProductPrice;
/**
* 合计税额单位
*/
private BigDecimal totalTaxPrice;
/**
* 优惠率百分比
*/
private BigDecimal discountPercent;
/**
* 优惠金额单位
*
* discountPrice = (totalProductPrice + totalTaxPrice) * discountPercent
*/
private BigDecimal discountPrice;
/**
* 其它金额单位
*
* 注意它不算在 {@link #totalPrice}
*/
private BigDecimal otherPrice;
/**
* 本次收款单位
*
* payPrice = totalPrice + otherPrice - debtPrice
*/
private BigDecimal payPrice;
/**
* 本次欠款单位
*/
private BigDecimal debtPrice;
/**
* 附件地址
*/
private String fileUrl;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,96 @@
package cn.iocoder.yudao.module.erp.dal.dataobject.sale;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.math.BigDecimal;
/**
* ERP 销售出库项 DO
*
* @author 芋道源码
*/
@TableName("erp_sale_order_items")
@KeySequence("erp_sale_order_items_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ErpSaleOutItemDO extends BaseDO {
/**
* 编号
*/
@TableId
private Long id;
/**
* 销售出库编号
*
* 关联 {@link ErpStockOutDO##getId()}
*/
private Long outId;
/**
* 销售订单项编号
*
* 关联 {@link ErpSaleOrderItemDO#getId()}
* 目的方便更新关联的销售订单项的出库数量
*/
private Long orderItemId;
/**
* 仓库编号
*
* 关联 {@link ErpWarehouseDO#getId()}
*/
private Long warehouseId;
/**
* 产品编号
*
* 关联 {@link ErpProductDO#getId()}
*/
private Long productId;
/**
* 产品单位单位
*
* 冗余 {@link ErpProductDO#getUnitId()}
*/
private Long productUnitId;
/**
* 产品单位单价单位
*/
private BigDecimal productPrice;
/**
* 数量
*/
private BigDecimal count;
/**
* 总价单位
*
* totalPrice = productPrice * count
*/
private BigDecimal totalPrice;
/**
* 税率百分比
*/
private BigDecimal taxPercent;
/**
* 税额单位
*
* taxPrice = totalPrice * taxPercent
*/
private BigDecimal taxPrice;
/**
* 备注
*/
private String remark;
}

View File

@ -8,7 +8,7 @@ import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
* ERP 销售订单明 Mapper * ERP 销售订单明项目 Mapper
* *
* @author 芋道源码 * @author 芋道源码
*/ */

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.erp.dal.mysql.sale;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutItemDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
/**
* ERP 销售出库项 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface ErpSaleOutItemMapper extends BaseMapperX<ErpSaleOutItemDO> {
default List<ErpSaleOutItemDO> selectListByOutId(Long orderId) {
return selectList(ErpSaleOutItemDO::getOutId, orderId);
}
default List<ErpSaleOutItemDO> selectListByOutIds(Collection<Long> orderIds) {
return selectList(ErpSaleOutItemDO::getOutId, orderIds);
}
default int deleteByOutId(Long orderId) {
return delete(ErpSaleOutItemDO::getOutId, orderId);
}
}

View File

@ -0,0 +1,53 @@
package cn.iocoder.yudao.module.erp.dal.mysql.sale;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutPageReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutItemDO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.math.BigDecimal;
/**
* ERP 销售出库 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface ErpSaleOutMapper extends BaseMapperX<ErpSaleOutDO> {
default PageResult<ErpSaleOutDO> selectPage(ErpSaleOutPageReqVO reqVO) {
MPJLambdaWrapperX<ErpSaleOutDO> query = new MPJLambdaWrapperX<ErpSaleOutDO>()
.eqIfPresent(ErpSaleOutDO::getNo, reqVO.getNo())
.eqIfPresent(ErpSaleOutDO::getCustomerId, reqVO.getCustomerId())
.betweenIfPresent(ErpSaleOutDO::getOutTime, reqVO.getOutTime())
.eqIfPresent(ErpSaleOutDO::getStatus, reqVO.getStatus())
.likeIfPresent(ErpSaleOutDO::getRemark, reqVO.getRemark())
.eqIfPresent(ErpSaleOutDO::getCreator, reqVO.getCreator())
.eqIfPresent(ErpSaleOutDO::getAccountId, reqVO.getAccountId())
.likeIfPresent(ErpSaleOutDO::getOrderNo, reqVO.getOrderNo())
.orderByDesc(ErpSaleOutDO::getId);
query.gt(Boolean.TRUE.equals(reqVO.getDebtStatus()), ErpSaleOutDO::getDebtPrice, BigDecimal.ZERO);
if (reqVO.getWarehouseId() != null && reqVO.getProductId() != null) {
query.leftJoin(ErpSaleOutItemDO.class, ErpSaleOutItemDO::getOutId, ErpSaleOutDO::getId)
.eq(reqVO.getWarehouseId() != null, ErpSaleOutItemDO::getWarehouseId, reqVO.getWarehouseId())
.eq(reqVO.getProductId() != null, ErpSaleOutItemDO::getProductId, reqVO.getProductId())
.groupBy(ErpSaleOutDO::getId); // 避免 1 对多查询产生相同的 1
}
return selectJoinPage(reqVO, ErpSaleOutDO.class, query);
}
default int updateByIdAndStatus(Long id, Integer status, ErpSaleOutDO updateObj) {
return update(updateObj, new LambdaUpdateWrapper<ErpSaleOutDO>()
.eq(ErpSaleOutDO::getId, id).eq(ErpSaleOutDO::getStatus, status));
}
default ErpSaleOutDO selectByNo(String no) {
return selectOne(ErpSaleOutDO::getNo, no);
}
}

View File

@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.erp.controller.admin.finance.vo.ErpAccountSaveReq
import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO; import cn.iocoder.yudao.module.erp.dal.dataobject.finance.ErpAccountDO;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import java.util.List;
/** /**
* ERP 结算账户 Service 接口 * ERP 结算账户 Service 接口
* *
@ -59,6 +61,14 @@ public interface ErpAccountService {
*/ */
ErpAccountDO validateAccount(Long id); ErpAccountDO validateAccount(Long id);
/**
* 获得指定状态的结算账户列表
*
* @param status 状态
* @return 结算账户
*/
List<ErpAccountDO> getAccountListByStatus(Integer status);
/** /**
* 获得结算账户分页 * 获得结算账户分页
* *

View File

@ -11,6 +11,8 @@ import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
@ -91,6 +93,11 @@ public class ErpAccountServiceImpl implements ErpAccountService {
return account; return account;
} }
@Override
public List<ErpAccountDO> getAccountListByStatus(Integer status) {
return accountMapper.selectListByStatus(status);
}
@Override @Override
public PageResult<ErpAccountDO> getAccountPage(ErpAccountPageReqVO pageReqVO) { public PageResult<ErpAccountDO> getAccountPage(ErpAccountPageReqVO pageReqVO) {
return accountMapper.selectPage(pageReqVO); return accountMapper.selectPage(pageReqVO);

View File

@ -222,16 +222,16 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService {
// ==================== 订单项 ==================== // ==================== 订单项 ====================
@Override @Override
public List<ErpSaleOrderItemDO> getSaleOrderItemListByOrderId(Long moveId) { public List<ErpSaleOrderItemDO> getSaleOrderItemListByOrderId(Long orderId) {
return saleOrderItemMapper.selectListByOrderId(moveId); return saleOrderItemMapper.selectListByOrderId(orderId);
} }
@Override @Override
public List<ErpSaleOrderItemDO> getSaleOrderItemListByOrderIds(Collection<Long> moveIds) { public List<ErpSaleOrderItemDO> getSaleOrderItemListByOrderIds(Collection<Long> orderIds) {
if (CollUtil.isEmpty(moveIds)) { if (CollUtil.isEmpty(orderIds)) {
return Collections.emptyList(); return Collections.emptyList();
} }
return saleOrderItemMapper.selectListByOrderIds(moveIds); return saleOrderItemMapper.selectListByOrderIds(orderIds);
} }
} }

View File

@ -0,0 +1,84 @@
package cn.iocoder.yudao.module.erp.service.sale;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutSaveReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutItemDO;
import jakarta.validation.Valid;
import java.util.Collection;
import java.util.List;
/**
* ERP 销售出库 Service 接口
*
* @author 芋道源码
*/
public interface ErpSaleOutService {
/**
* 创建销售出库
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createSaleOut(@Valid ErpSaleOutSaveReqVO createReqVO);
/**
* 更新销售出库
*
* @param updateReqVO 更新信息
*/
void updateSaleOut(@Valid ErpSaleOutSaveReqVO updateReqVO);
/**
* 更新销售出库的状态
*
* @param id 编号
* @param status 状态
*/
void updateSaleOutStatus(Long id, Integer status);
/**
* 删除销售出库
*
* @param ids 编号数组
*/
void deleteSaleOut(List<Long> ids);
/**
* 获得销售出库
*
* @param id 编号
* @return 销售出库
*/
ErpSaleOutDO getSaleOut(Long id);
/**
* 获得销售出库分页
*
* @param pageReqVO 分页查询
* @return 销售出库分页
*/
PageResult<ErpSaleOutDO> getSaleOutPage(ErpSaleOutPageReqVO pageReqVO);
// ==================== 销售出库项 ====================
/**
* 获得销售出库项列表
*
* @param outId 销售出库编号
* @return 销售出库项列表
*/
List<ErpSaleOutItemDO> getSaleOutItemListByOutId(Long outId);
/**
* 获得销售出库项 List
*
* @param outIds 销售出库编号数组
* @return 销售出库项 List
*/
List<ErpSaleOutItemDO> getSaleOutItemListByOutIds(Collection<Long> outIds);
}

View File

@ -0,0 +1,233 @@
package cn.iocoder.yudao.module.erp.service.sale;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.sale.vo.out.ErpSaleOutSaveReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutItemDO;
import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOutItemMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOutMapper;
import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO;
import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus;
import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;
// TODO 芋艿记录操作日志
/**
* ERP 销售订单 Service 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class ErpSaleOutServiceImpl implements ErpSaleOutService {
@Resource
private ErpSaleOutMapper saleOutMapper;
@Resource
private ErpSaleOutItemMapper saleOutItemMapper;
@Resource
private ErpNoRedisDAO noRedisDAO;
@Resource
private ErpProductService productService;
@Resource
private ErpCustomerService customerService;
@Resource
private ErpAccountService accountService;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createSaleOut(ErpSaleOutSaveReqVO createReqVO) {
// 1.1 校验订单项的有效性
List<ErpSaleOutItemDO> saleOutItems = validateSaleOutItems(createReqVO.getItems());
// 1.2 校验客户 TODO 芋艿需要在瞅瞅
// customerService.validateCustomer(createReqVO.getCustomerId());
// 1.3 校验结算账户
accountService.validateAccount(createReqVO.getAccountId());
// 1.4 生成调拨单号并校验唯一性
String no = noRedisDAO.generate(ErpNoRedisDAO.SALE_ORDER_NO_PREFIX);
if (saleOutMapper.selectByNo(no) != null) {
throw exception(SALE_ORDER_NO_EXISTS);
}
// 2.1 插入订单
ErpSaleOutDO saleOut = BeanUtils.toBean(createReqVO, ErpSaleOutDO.class, in -> in
.setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()));
calculateTotalPrice(saleOut, saleOutItems);
saleOutMapper.insert(saleOut);
// 2.2 插入订单项
saleOutItems.forEach(o -> o.setOutId(saleOut.getId()));
saleOutItemMapper.insertBatch(saleOutItems);
return saleOut.getId();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateSaleOut(ErpSaleOutSaveReqVO updateReqVO) {
// 1.1 校验存在
ErpSaleOutDO saleOut = validateSaleOutExists(updateReqVO.getId());
if (ErpAuditStatus.APPROVE.getStatus().equals(saleOut.getStatus())) {
throw exception(SALE_ORDER_UPDATE_FAIL_APPROVE, saleOut.getNo());
}
// 1.2 校验客户 TODO 芋艿需要在瞅瞅
// customerService.validateCustomer(updateReqVO.getCustomerId());
// 1.3 校验结算账户
accountService.validateAccount(updateReqVO.getAccountId());
// 1.4 校验订单项的有效性
List<ErpSaleOutItemDO> saleOutItems = validateSaleOutItems(updateReqVO.getItems());
// 2.1 更新订单
ErpSaleOutDO updateObj = BeanUtils.toBean(updateReqVO, ErpSaleOutDO.class);
calculateTotalPrice(updateObj, saleOutItems);
saleOutMapper.updateById(updateObj);
// 2.2 更新订单项
updateSaleOutItemList(updateReqVO.getId(), saleOutItems);
}
private void calculateTotalPrice(ErpSaleOutDO saleOut, List<ErpSaleOutItemDO> saleOutItems) {
saleOut.setTotalCount(getSumValue(saleOutItems, ErpSaleOutItemDO::getCount, BigDecimal::add));
saleOut.setTotalProductPrice(getSumValue(saleOutItems, ErpSaleOutItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO));
saleOut.setTotalTaxPrice(getSumValue(saleOutItems, ErpSaleOutItemDO::getTaxPrice, BigDecimal::add, BigDecimal.ZERO));
saleOut.setTotalPrice(saleOut.getTotalProductPrice().add(saleOut.getTotalTaxPrice()));
// 计算优惠价格
if (saleOut.getDiscountPercent() == null) {
saleOut.setDiscountPercent(BigDecimal.ZERO);
}
saleOut.setDiscountPrice(MoneyUtils.priceMultiply(saleOut.getTotalPrice(), saleOut.getDiscountPercent()));
saleOut.setTotalPrice(saleOut.getTotalPrice().subtract(saleOut.getDiscountPrice()));
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateSaleOutStatus(Long id, Integer status) {
boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status);
// 1.1 校验存在
ErpSaleOutDO saleOut = validateSaleOutExists(id);
// 1.2 校验状态
if (saleOut.getStatus().equals(status)) {
throw exception(approve ? SALE_ORDER_APPROVE_FAIL : SALE_ORDER_PROCESS_FAIL);
}
// TODO @芋艿需要校验是不是有入库有退货
// 2. 更新状态
int updateCount = saleOutMapper.updateByIdAndStatus(id, saleOut.getStatus(),
new ErpSaleOutDO().setStatus(status));
if (updateCount == 0) {
throw exception(approve ? SALE_ORDER_APPROVE_FAIL : SALE_ORDER_PROCESS_FAIL);
}
}
private List<ErpSaleOutItemDO> validateSaleOutItems(List<ErpSaleOutSaveReqVO.Item> list) {
// 1. 校验产品存在
List<ErpProductDO> productList = productService.validProductList(
convertSet(list, ErpSaleOutSaveReqVO.Item::getProductId));
Map<Long, ErpProductDO> productMap = convertMap(productList, ErpProductDO::getId);
// 2. 转化为 ErpSaleOutItemDO 列表
return convertList(list, o -> BeanUtils.toBean(o, ErpSaleOutItemDO.class, item -> {
item.setProductUnitId(productMap.get(item.getProductId()).getUnitId());
item.setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount()));
if (item.getTotalPrice() == null) {
return;
}
item.setTaxPrice(MoneyUtils.priceMultiply(item.getTotalPrice(), item.getTaxPercent()));
item.setTotalPrice(item.getTotalPrice().add(item.getTaxPrice()));
}));
}
private void updateSaleOutItemList(Long id, List<ErpSaleOutItemDO> newList) {
// 第一步对比新老数据获得添加修改删除的列表
List<ErpSaleOutItemDO> oldList = saleOutItemMapper.selectListByOutId(id);
List<List<ErpSaleOutItemDO>> diffList = diffList(oldList, newList, // id 不同就认为是不同的记录
(oldVal, newVal) -> oldVal.getId().equals(newVal.getId()));
// 第二步批量添加修改删除
if (CollUtil.isNotEmpty(diffList.get(0))) {
diffList.get(0).forEach(o -> o.setOutId(id));
saleOutItemMapper.insertBatch(diffList.get(0));
}
if (CollUtil.isNotEmpty(diffList.get(1))) {
saleOutItemMapper.updateBatch(diffList.get(1));
}
if (CollUtil.isNotEmpty(diffList.get(2))) {
saleOutItemMapper.deleteBatchIds(convertList(diffList.get(2), ErpSaleOutItemDO::getId));
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteSaleOut(List<Long> ids) {
// 1. 校验不处于已审批
List<ErpSaleOutDO> saleOuts = saleOutMapper.selectBatchIds(ids);
if (CollUtil.isEmpty(saleOuts)) {
return;
}
saleOuts.forEach(saleOut -> {
if (ErpAuditStatus.APPROVE.getStatus().equals(saleOut.getStatus())) {
throw exception(SALE_ORDER_DELETE_FAIL_APPROVE, saleOut.getNo());
}
});
// 2. 遍历删除并记录操作日志
saleOuts.forEach(saleOut -> {
// 2.1 删除订单
saleOutMapper.deleteById(saleOut.getId());
// 2.2 删除订单项
saleOutItemMapper.deleteByOutId(saleOut.getId());
});
}
private ErpSaleOutDO validateSaleOutExists(Long id) {
ErpSaleOutDO saleOut = saleOutMapper.selectById(id);
if (saleOut == null) {
throw exception(SALE_ORDER_NOT_EXISTS);
}
return saleOut;
}
@Override
public ErpSaleOutDO getSaleOut(Long id) {
return saleOutMapper.selectById(id);
}
@Override
public PageResult<ErpSaleOutDO> getSaleOutPage(ErpSaleOutPageReqVO pageReqVO) {
return saleOutMapper.selectPage(pageReqVO);
}
// ==================== 订单项 ====================
@Override
public List<ErpSaleOutItemDO> getSaleOutItemListByOutId(Long outId) {
return saleOutItemMapper.selectListByOutId(outId);
}
@Override
public List<ErpSaleOutItemDO> getSaleOutItemListByOutIds(Collection<Long> outIds) {
if (CollUtil.isEmpty(outIds)) {
return Collections.emptyList();
}
return saleOutItemMapper.selectListByOutIds(outIds);
}
}