From 8504fa121de42413d7816a8699dd624fed901045 Mon Sep 17 00:00:00 2001 From: c Date: Thu, 12 Mar 2026 16:26:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=20SN=20=E6=BA=AF=E6=BA=90?= =?UTF-8?q?=E3=80=81=E9=94=80=E5=94=AE=E7=AE=A1=E7=90=86=E5=92=8C=E7=BB=B4?= =?UTF-8?q?=E4=BF=AE=E8=AE=B0=E5=BD=95=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FinishedProductShipmentServiceImpl.java | 4 +- .../sale/controller/DeviceController.java | 98 +------ .../controller/RepairRecordController.java | 86 +----- .../sale/controller/SaleOrderController.java | 74 ++--- .../module/sale/controller/dto/DeviceDto.java | 56 +--- .../sale/controller/dto/RepairRecordDto.java | 64 ++--- .../sale/controller/dto/SaleOrderDto.java | 29 +- .../sale/controller/dto/SaleOrderItemDto.java | 22 +- .../sale/converter/SaleOrderConverter.java | 29 +- .../erp/module/sale/mapper/DeviceMapper.java | 11 + .../sale/mapper/RepairRecordMapper.java | 10 + .../module/sale/service/DeviceService.java | 20 +- .../sale/service/RepairRecordService.java | 17 +- .../module/sale/service/SaleOrderService.java | 3 +- .../sale/service/impl/DeviceServiceImpl.java | 69 +---- .../service/impl/RepairRecordServiceImpl.java | 119 ++++++--- .../service/impl/SaleOrderServiceImpl.java | 252 +++++++++++++++--- .../sys/controller/KeyAccountController.java | 8 + .../module/sys/service/KeyAccountService.java | 3 + .../service/impl/KeyAccountServiceImpl.java | 31 +++ .../resources/i18n/messages_zh_CN.properties | 4 + .../resources/mapper/sale/DeviceMapper.xml | 29 ++ .../mapper/sale/RepairRecordMapper.xml | 33 +++ .../resources/sql/dev/permission-schema.sql | 2 +- 24 files changed, 574 insertions(+), 499 deletions(-) diff --git a/src/main/java/com/niuan/erp/module/production/service/impl/FinishedProductShipmentServiceImpl.java b/src/main/java/com/niuan/erp/module/production/service/impl/FinishedProductShipmentServiceImpl.java index 5e3afec..a8ccd4d 100644 --- a/src/main/java/com/niuan/erp/module/production/service/impl/FinishedProductShipmentServiceImpl.java +++ b/src/main/java/com/niuan/erp/module/production/service/impl/FinishedProductShipmentServiceImpl.java @@ -131,7 +131,7 @@ public class FinishedProductShipmentServiceImpl extends ServiceImpl materialEntities = finishedProductShipmentConverter.toMaterialEntityList(shipmentItems); diff --git a/src/main/java/com/niuan/erp/module/sale/controller/DeviceController.java b/src/main/java/com/niuan/erp/module/sale/controller/DeviceController.java index b267c74..9cd3bab 100644 --- a/src/main/java/com/niuan/erp/module/sale/controller/DeviceController.java +++ b/src/main/java/com/niuan/erp/module/sale/controller/DeviceController.java @@ -1,30 +1,22 @@ package com.niuan.erp.module.sale.controller; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; -import com.niuan.erp.common.annotation.ApiLog; import com.niuan.erp.common.annotation.ModuleLog; -import com.niuan.erp.common.base.BaseDeleteBody; import com.niuan.erp.common.base.BasePageReqParams; import com.niuan.erp.common.base.BaseResult; -import com.niuan.erp.common.base.BaseSelectDto; import com.niuan.erp.common.base.CommonValidateGroup.*; -import com.niuan.erp.common.base.OperationType; -import com.niuan.erp.module.sale.controller.dto.DeviceDto; -import com.niuan.erp.module.sale.entity.Device; +import com.niuan.erp.module.sale.controller.dto.DeviceQueryDto; +import com.niuan.erp.module.sale.controller.dto.DeviceResultDto; import com.niuan.erp.module.sale.service.DeviceService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.util.StringUtils; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import java.util.List; - -@Tag(name = "Device") -@ModuleLog("Device管理") +@Tag(name = "SN溯源") +@ModuleLog("SN溯源管理") @RestController @RequestMapping("/sale/device") @RequiredArgsConstructor @@ -32,81 +24,11 @@ public class DeviceController { private final DeviceService deviceService; - @Operation(summary = "分页查询Device数据", operationId = "getDevicePage") - @GetMapping("/getDevicePage") - @PreAuthorize("hasAuthority('device:index')") - public BaseResult> getDevicePage(@Validated BasePageReqParams pageParams, - @Validated(Get.class) DeviceDto searchParams) { - var wrapper = new LambdaQueryWrapper(); - if (searchParams != null) { - if (StringUtils.hasText(searchParams.searchCode())) { - wrapper.like(Device::getProductSn, searchParams.searchCode()) - .or().like(Device::getMac, searchParams.searchCode()); - } - if (searchParams.keyAccountId() != null) { - wrapper.eq(Device::getKeyAccountId, searchParams.keyAccountId()); - } - if (searchParams.status() != null) { - wrapper.eq(Device::getStatus, searchParams.status()); - } - if (searchParams.startDate() != null) { - wrapper.gt(Device::getCreateDate, searchParams.startDate()); - } - if (searchParams.endDate() != null) { - wrapper.lt(Device::getCreateDate, searchParams.endDate()); - } - if (StringUtils.hasText(searchParams.orderFiled())) { - boolean isDesc = "desc".equalsIgnoreCase(searchParams.orderByType()); - if (isDesc) { - wrapper.orderByDesc(true, Device::getId); - } else { - wrapper.orderByAsc(true, Device::getId); - } - } - } - return BaseResult.successWithData(deviceService.getDevicePage(pageParams, wrapper)); - } - - @Operation(summary = "获取客户信息", operationId = "getKeyAccount") - @GetMapping("/getKeyAccount") - @PreAuthorize("hasAuthority('device:index')") - public BaseResult> getKeyAccount() { - return BaseResult.successWithData(deviceService.getKeyAccount()); - } - - @ApiLog(type = OperationType.ADD, remark = "新增一条Device记录") - @Operation(summary = "新增Device", operationId = "addDevice") - @PostMapping("/addDevice") - @PreAuthorize("hasAuthority('device:add')") - public BaseResult addDevice(@Validated(Add.class) @RequestBody DeviceDto dto) { - deviceService.addDevice(dto); - return BaseResult.success(); - } - - @ApiLog(type = OperationType.UPDATE, remark = "更新一条Device记录") - @Operation(summary = "更新Device", operationId = "updateDevice") - @PostMapping("/updateDevice") - @PreAuthorize("hasAuthority('device:update')") - public BaseResult updateDevice(@Validated(Update.class) @RequestBody DeviceDto dto) { - deviceService.updateDevice(dto); - return BaseResult.success(); - } - - @ApiLog(type = OperationType.DELETE, remark = "删除一条Device记录") - @Operation(summary = "删除Device", operationId = "deleteDevice") - @PostMapping("/deleteDevice") - @PreAuthorize("hasAuthority('device:delete')") - public BaseResult deleteDevice(@Validated(DeleteOne.class) @RequestBody BaseDeleteBody req) { - deviceService.deleteDevice(req.id()); - return BaseResult.success(); - } - - @ApiLog(type = OperationType.DELETE, remark = "批量删除Device记录") - @Operation(summary = "批量删除Device", operationId = "deleteDeviceBatch") - @PostMapping("/deleteDeviceBatch") - @PreAuthorize("hasAuthority('device:deleteBatch')") - public BaseResult deleteDeviceBatch(@Validated(DeleteBatch.class) @RequestBody BaseDeleteBody req) { - deviceService.deleteBatch(req.ids()); - return BaseResult.success(); + @Operation(summary = "分页查询SN溯源数据", operationId = "getDeviceSnPage") + @GetMapping("/getDeviceSnPage") + @PreAuthorize("hasAuthority('device_sn:index')") + public BaseResult> getDeviceSnPage(@Validated BasePageReqParams pageParams, + @Validated(Get.class) DeviceQueryDto searchParams) { + return BaseResult.successWithData(deviceService.getDeviceSnPage(pageParams, searchParams)); } } diff --git a/src/main/java/com/niuan/erp/module/sale/controller/RepairRecordController.java b/src/main/java/com/niuan/erp/module/sale/controller/RepairRecordController.java index eea4262..1a388fa 100644 --- a/src/main/java/com/niuan/erp/module/sale/controller/RepairRecordController.java +++ b/src/main/java/com/niuan/erp/module/sale/controller/RepairRecordController.java @@ -1,26 +1,25 @@ package com.niuan.erp.module.sale.controller; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.niuan.erp.common.annotation.ApiLog; import com.niuan.erp.common.annotation.ModuleLog; -import com.niuan.erp.common.base.*; +import com.niuan.erp.common.base.BasePageReqParams; +import com.niuan.erp.common.base.BaseResult; import com.niuan.erp.common.base.CommonValidateGroup.*; +import com.niuan.erp.common.base.OperationType; import com.niuan.erp.module.sale.controller.dto.RepairRecordDto; +import com.niuan.erp.module.sale.controller.dto.RepairRecordQueryDto; +import com.niuan.erp.module.sale.controller.dto.RepairRecordResultDto; import com.niuan.erp.module.sale.service.RepairRecordService; -import com.niuan.erp.module.sale.entity.RepairRecord; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import org.springframework.validation.annotation.Validated; -import java.util.List; - -@Tag(name = "RepairRecord") -@ModuleLog("RepairRecord管理") +@Tag(name = "返修报表") +@ModuleLog("返修报表管理") @RestController @RequestMapping("/sale/repairrecord") @RequiredArgsConstructor @@ -28,46 +27,12 @@ public class RepairRecordController { private final RepairRecordService repairRecordService; - @Operation(summary = "分页查询RepairRecord数据", operationId = "getRepairRecordPage") - @GetMapping("/getRepairRecordPage") + @Operation(summary = "分页查询返修报表数据", operationId = "getRepairReportPage") + @GetMapping("/getRepairReportPage") @PreAuthorize("hasAuthority('repair_record:index')") - public BaseResult> getRepairRecordPage(@Validated BasePageReqParams pageParams, - @Validated(Get.class) RepairRecordDto searchParams) { - var wrapper = new LambdaQueryWrapper(); - if (searchParams != null) { - if (StringUtils.hasText(searchParams.searchCode())) { - wrapper.like(RepairRecord::getProductSn, searchParams.searchCode()) - .or().like(RepairRecord::getMac, searchParams.searchCode()); - } - if (searchParams.keyAccountIdSearch() != null) { - wrapper.eq(RepairRecord::getKeyAccountId, searchParams.keyAccountIdSearch()); - } - if (searchParams.status() != null) { - wrapper.eq(RepairRecord::getStatus, searchParams.status()); - } - if (searchParams.startDate() != null) { - wrapper.gt(RepairRecord::getCreateDate, searchParams.startDate()); - } - if (searchParams.endDate() != null) { - wrapper.lt(RepairRecord::getCreateDate, searchParams.endDate()); - } - if (StringUtils.hasText(searchParams.orderFiled())) { - boolean isDesc = "desc".equalsIgnoreCase(searchParams.orderByType()); - if (isDesc) { - wrapper.orderByDesc(true, RepairRecord::getId); - } else { - wrapper.orderByAsc(true, RepairRecord::getId); - } - } - } - return BaseResult.successWithData(repairRecordService.getRepairRecordPage(pageParams, wrapper)); - } - - @Operation(summary = "获取客户信息", operationId = "getKeyAccount") - @GetMapping("/getKeyAccount") - @PreAuthorize("hasAuthority('repair_record:index')") - public BaseResult> getKeyAccount() { - return BaseResult.successWithData(repairRecordService.getKeyAccount()); + public BaseResult> getRepairReportPage(@Validated BasePageReqParams pageParams, + @Validated(Get.class) RepairRecordQueryDto searchParams) { + return BaseResult.successWithData(repairRecordService.getRepairReportPage(pageParams, searchParams)); } @ApiLog(type = OperationType.ADD, remark = "新增一条RepairRecord记录") @@ -78,31 +43,4 @@ public class RepairRecordController { repairRecordService.addRepairRecord(dto); return BaseResult.success(); } - - @ApiLog(type = OperationType.UPDATE, remark = "更新一条RepairRecord记录") - @Operation(summary = "更新RepairRecord", operationId = "updateRepairRecord") - @PostMapping("/updateRepairRecord") - @PreAuthorize("hasAuthority('repair_record:update')") - public BaseResult updateRepairRecord(@Validated(Update.class) @RequestBody RepairRecordDto dto) { - repairRecordService.updateRepairRecord(dto); - return BaseResult.success(); - } - - @ApiLog(type = OperationType.DELETE, remark = "删除一条RepairRecord记录") - @Operation(summary = "删除RepairRecord", operationId = "deleteRepairRecord") - @PostMapping("/deleteRepairRecord") - @PreAuthorize("hasAuthority('repair_record:delete')") - public BaseResult deleteRepairRecord(@Validated(DeleteOne.class) @RequestBody BaseDeleteBody req) { - repairRecordService.deleteRepairRecord(req.id()); - return BaseResult.success(); - } - - @ApiLog(type = OperationType.DELETE, remark = "批量删除RepairRecord记录") - @Operation(summary = "批量删除RepairRecord", operationId = "deleteRepairRecordBatch") - @PostMapping("/deleteRepairRecordBatch") - @PreAuthorize("hasAuthority('repair_record:deleteBatch')") - public BaseResult deleteRepairRecordBatch(@Validated(DeleteBatch.class) @RequestBody BaseDeleteBody req) { - repairRecordService.deleteBatch(req.ids()); - return BaseResult.success(); - } } diff --git a/src/main/java/com/niuan/erp/module/sale/controller/SaleOrderController.java b/src/main/java/com/niuan/erp/module/sale/controller/SaleOrderController.java index 1ded67f..991bc39 100644 --- a/src/main/java/com/niuan/erp/module/sale/controller/SaleOrderController.java +++ b/src/main/java/com/niuan/erp/module/sale/controller/SaleOrderController.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.niuan.erp.common.annotation.ApiLog; import com.niuan.erp.common.annotation.ModuleLog; +import com.niuan.erp.common.base.BaseApproveAndRejectDto; import com.niuan.erp.common.base.BaseDeleteBody; import com.niuan.erp.common.base.BasePageReqParams; import com.niuan.erp.common.base.BaseResult; @@ -13,6 +14,7 @@ import com.niuan.erp.module.common.entity.Document; import com.niuan.erp.module.sale.controller.dto.SaleOrderAddDto; import com.niuan.erp.module.sale.controller.dto.SaleOrderDto; import com.niuan.erp.module.sale.controller.dto.SaleOrderItemDto; +import com.niuan.erp.module.sale.controller.dto.SaleOrderUpdateDto; import com.niuan.erp.module.sale.service.SaleOrderService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -26,8 +28,8 @@ import org.springframework.web.multipart.MultipartFile; import java.util.List; -@Tag(name = "SaleOrder") -@ModuleLog("SaleOrder管理") +@Tag(name = "销售订单") +@ModuleLog("销售订单管理") @RestController @RequestMapping("/sale/saleorder") @RequiredArgsConstructor @@ -35,23 +37,23 @@ public class SaleOrderController { private final SaleOrderService saleOrderService; - @Operation(summary = "分页查询SaleOrder数据", operationId = "getSaleOrderPage") + @Operation(summary = "分页查询销售订单数据", operationId = "getSaleOrderPage") @GetMapping("/getSaleOrderPage") @PreAuthorize("hasAuthority('sale_order:index')") public BaseResult> getSaleOrderPage(@Validated BasePageReqParams pageParams, @Validated(Get.class) SaleOrderDto searchParams) { var wrapper = new LambdaQueryWrapper(); - if (searchParams != null) { - if (StringUtils.hasText(searchParams.customerName())) { - wrapper.like(Document::getCustomerId, searchParams.customerId()); - } + if (searchParams != null) { + if (StringUtils.hasText(searchParams.customerName())) { + wrapper.like(Document::getStoreName, searchParams.customerName()); } + } return BaseResult.successWithData(saleOrderService.getSaleOrderPage(pageParams, wrapper)); } - @ApiLog(type = OperationType.ADD, remark = "新增一条SaleOrder记录") - @Operation(summary = "新增SaleOrder", operationId = "addSaleOrder") + @ApiLog(type = OperationType.ADD, remark = "新增一条销售订单记录") + @Operation(summary = "新增销售订单", operationId = "addSaleOrder") @PostMapping("/addSaleOrder") @PreAuthorize("hasAuthority('sale_order:add')") public BaseResult addSaleOrder(@Validated(Add.class) @RequestBody SaleOrderAddDto dto) { @@ -59,62 +61,60 @@ public class SaleOrderController { return BaseResult.success(); } - @ApiLog(type = OperationType.UPDATE, remark = "更新一条SaleOrder记录") - @Operation(summary = "更新SaleOrder", operationId = "updateSaleOrder") + @ApiLog(type = OperationType.UPDATE, remark = "更新一条销售订单记录") + @Operation(summary = "更新销售订单", operationId = "updateSaleOrder") @PostMapping("/updateSaleOrder") - @PreAuthorize("hasAuthority('sale_order:update')") - public BaseResult updateSaleOrder(@Validated(Update.class) @RequestBody SaleOrderDto dto) { + @PreAuthorize("hasAuthority('sale_order:edit')") + public BaseResult updateSaleOrder(@Validated(Update.class) @RequestBody SaleOrderUpdateDto dto) { saleOrderService.updateSaleOrder(dto); return BaseResult.success(); } - @ApiLog(type = OperationType.DELETE, remark = "删除一条SaleOrder记录") - @Operation(summary = "删除SaleOrder", operationId = "deleteSaleOrder") + @ApiLog(type = OperationType.DELETE, remark = "删除一条销售订单记录") + @Operation(summary = "删除销售订单", operationId = "deleteSaleOrder") @PostMapping("/deleteSaleOrder") - @PreAuthorize("hasAuthority('sale_order:delete')") + @PreAuthorize("hasAuthority('sale_order:remove')") public BaseResult deleteSaleOrder(@Validated(DeleteOne.class) @RequestBody BaseDeleteBody req) { saleOrderService.deleteSaleOrder(req.id()); return BaseResult.success(); } - @ApiLog(type = OperationType.DELETE, remark = "批量删除SaleOrder记录") - @Operation(summary = "批量删除SaleOrder", operationId = "deleteSaleOrderBatch") + @ApiLog(type = OperationType.DELETE, remark = "批量删除销售订单记录") + @Operation(summary = "批量删除销售订单", operationId = "deleteSaleOrderBatch") @PostMapping("/deleteSaleOrderBatch") - @PreAuthorize("hasAuthority('sale_order:deleteBatch')") + @PreAuthorize("hasAuthority('sale_order:remove')") public BaseResult deleteSaleOrderBatch(@Validated(DeleteBatch.class) @RequestBody BaseDeleteBody req) { saleOrderService.deleteBatch(req.ids()); return BaseResult.success(); } - @ApiLog(type = OperationType.UPDATE, remark = "审核SaleOrder") - @Operation(summary = "审核SaleOrder", operationId = "approveSaleOrder") + @ApiLog(type = OperationType.UPDATE, remark = "审核销售订单") + @Operation(summary = "审核销售订单", operationId = "approveSaleOrder") @PostMapping("/approveSaleOrder") @PreAuthorize("hasAuthority('sale_order:approve')") - public BaseResult approveSaleOrder( - @Parameter(description = "销售订单ID") @RequestParam Long id) { - saleOrderService.approve(id); + public BaseResult approveSaleOrder(@Validated @RequestBody BaseApproveAndRejectDto dto) { + saleOrderService.approve(dto.id()); return BaseResult.success(); } - @ApiLog(type = OperationType.UPDATE, remark = "反审核SaleOrder") - @Operation(summary = "反审核SaleOrder", operationId = "unapproveSaleOrder") + @ApiLog(type = OperationType.UPDATE, remark = "反审核销售订单") + @Operation(summary = "反审核销售订单", operationId = "unapproveSaleOrder") @PostMapping("/unapproveSaleOrder") - @PreAuthorize("hasAuthority('sale_order:unapprove')") - public BaseResult unapproveSaleOrder( - @Parameter(description = "销售订单ID") @RequestParam Long id) { - saleOrderService.unapprove(id); + @PreAuthorize("hasAuthority('sale_order:reject')") + public BaseResult unapproveSaleOrder(@Validated @RequestBody BaseApproveAndRejectDto dto) { + saleOrderService.unapprove(dto.id()); return BaseResult.success(); } - @Operation(summary = "获取SaleOrder明细", operationId = "getSaleOrderDetail") - @GetMapping("/getSaleOrderDetail") - @PreAuthorize("hasAuthority('saleorder:index')") - public BaseResult> getSaleOrderDetail( - @Parameter(description = "销售订单ID") @RequestParam Long id) { - return BaseResult.successWithData(saleOrderService.getDetail(id)); + @Operation(summary = "获取销售订单明细列表", operationId = "getSaleOrderItemList") + @GetMapping("/getSaleOrderItemList") + @PreAuthorize("hasAuthority('sale_order:showItem')") + public BaseResult> getSaleOrderItemList( + @Parameter(description = "销售订单ID") @RequestParam("saleOrderId") Long saleOrderId) { + return BaseResult.successWithData(saleOrderService.getDetail(saleOrderId)); } - @Operation(summary = "导入SaleOrder明细", operationId = "importSaleOrderItems") + @Operation(summary = "导入销售订单明细", operationId = "importSaleOrderItems") @PostMapping("/importSaleOrderItems") @PreAuthorize("hasAuthority('sale_order:import')") public BaseResult> importSaleOrderItems( diff --git a/src/main/java/com/niuan/erp/module/sale/controller/dto/DeviceDto.java b/src/main/java/com/niuan/erp/module/sale/controller/dto/DeviceDto.java index 8ac1572..4d37a88 100644 --- a/src/main/java/com/niuan/erp/module/sale/controller/dto/DeviceDto.java +++ b/src/main/java/com/niuan/erp/module/sale/controller/dto/DeviceDto.java @@ -4,27 +4,9 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.time.LocalDateTime; -@Schema(description = "设备DTO") +@Schema(description = "SN溯源DTO") public record DeviceDto( - @Schema(description = "ID") - Long id, - @Schema(description = "状态") - Integer status, - @Schema(description = "创建时间") - LocalDateTime createDate, - @Schema(description = "创建用户ID") - Long createUserId, - @Schema(description = "创建用户名") - String createUserName, - @Schema(description = "更新时间") - LocalDateTime updateDate, - @Schema(description = "更新用户ID") - Long updateUserId, - @Schema(description = "更新用户名") - String updateUserName, - @Schema(description = "单据编号") - Integer documentNo, - @Schema(description = "产品类型") + @Schema(description = "产品类型/型号") String productType, @Schema(description = "产品SN") String productSn, @@ -34,36 +16,10 @@ public record DeviceDto( String serialNum, @Schema(description = "软件版本") String softVersion, - @Schema(description = "AL版本") + @Schema(description = "算法版本") String alVersion, - @Schema(description = "AL编号") - String alNum, - @Schema(description = "AL状态") - Boolean alStatus, - @Schema(description = "维修状态") - Integer repairStatus, - @Schema(description = "备注") - String mark, - @Schema(description = "客户ID") - Integer customerId, - @Schema(description = "出库状态") - Boolean outStatus, - @Schema(description = "出库日期") + @Schema(description = "出库日期/出货日期") LocalDateTime outProductDate, - @Schema(description = "维修备注") - String repairMark, - @Schema(description = "产品SN显示") - String productSnDisplay, - @Schema(description = "搜索代码") - String searchCode, - @Schema(description = "客户ID") - Integer keyAccountId, - @Schema(description = "开始日期") - LocalDateTime startDate, - @Schema(description = "结束日期") - LocalDateTime endDate, - @Schema(description = "排序字段") - String orderFiled, - @Schema(description = "排序类型") - String orderByType + @Schema(description = "返修记录拼接字符串") + String repairRecords ) {} diff --git a/src/main/java/com/niuan/erp/module/sale/controller/dto/RepairRecordDto.java b/src/main/java/com/niuan/erp/module/sale/controller/dto/RepairRecordDto.java index fbbc73c..1e8255a 100644 --- a/src/main/java/com/niuan/erp/module/sale/controller/dto/RepairRecordDto.java +++ b/src/main/java/com/niuan/erp/module/sale/controller/dto/RepairRecordDto.java @@ -4,60 +4,26 @@ import io.swagger.v3.oas.annotations.media.Schema; import java.time.LocalDateTime; -@Schema(description = "返修记录DTO") +@Schema(description = "返修报表DTO") public record RepairRecordDto( - @Schema(description = "ID") - Long id, - @Schema(description = "状态") - Integer status, - @Schema(description = "创建时间") - LocalDateTime createDate, - @Schema(description = "创建用户ID") - Long createUserId, - @Schema(description = "创建用户名") - String createUserName, - @Schema(description = "更新时间") - LocalDateTime updateDate, - @Schema(description = "更新用户ID") - Long updateUserId, - @Schema(description = "更新用户名") - String updateUserName, - @Schema(description = "产品类型") + @Schema(description = "产品类型/型号") String productType, @Schema(description = "产品SN") String productSn, @Schema(description = "MAC地址") String mac, - @Schema(description = "维修状态") - Integer repairStatus, - @Schema(description = "备注") - String mark, - @Schema(description = "保留字段1") - Integer reserve1, - @Schema(description = "保留字段2") - String reserve2, - @Schema(description = "客户ID") - Integer keyAccountId, - @Schema(description = "客户ID") - Integer customerId, - @Schema(description = "出库状态") - Boolean outStatus, - @Schema(description = "出库日期") + @Schema(description = "序列号") + String serialNum, + @Schema(description = "软件版本") + String softVersion, + @Schema(description = "算法版本") + String alVersion, + @Schema(description = "出库日期/出货日期") LocalDateTime outProductDate, - @Schema(description = "维修日期") - LocalDateTime repairDate, - @Schema(description = "维修备注") - String repairMark, - @Schema(description = "搜索代码") - String searchCode, - @Schema(description = "客户ID") - Integer keyAccountIdSearch, - @Schema(description = "开始日期") - LocalDateTime startDate, - @Schema(description = "结束日期") - LocalDateTime endDate, - @Schema(description = "排序字段") - String orderFiled, - @Schema(description = "排序类型") - String orderByType + @Schema(description = "创建时间") + LocalDateTime createDate, + @Schema(description = "维修次数") + Integer repairCount, + @Schema(description = "返修记录") + String repairMark ) {} diff --git a/src/main/java/com/niuan/erp/module/sale/controller/dto/SaleOrderDto.java b/src/main/java/com/niuan/erp/module/sale/controller/dto/SaleOrderDto.java index 92d9875..2598769 100644 --- a/src/main/java/com/niuan/erp/module/sale/controller/dto/SaleOrderDto.java +++ b/src/main/java/com/niuan/erp/module/sale/controller/dto/SaleOrderDto.java @@ -1,30 +1,21 @@ package com.niuan.erp.module.sale.controller.dto; +import com.fasterxml.jackson.annotation.JsonInclude; + import java.time.LocalDateTime; +/** + * 销售订单返回 DTO - 前端展示用 + */ +@JsonInclude(JsonInclude.Include.NON_NULL) public record SaleOrderDto( Long id, - Integer status, LocalDateTime createDate, - Long createUserId, - String createUserName, - LocalDateTime updateDate, - Long updateUserId, - String updateUserName, - Integer storeNo, - String storeName, - Integer formType, String formCode, String formName, - Integer formStatus, String formMark, - Integer reserve1, - String reserve2, - Integer vendorNo, - String vendorName, - Double totalValue, - Integer outStoreNo, - String outStoreName, - Integer groupId, + Integer formStatus, Integer customerId, - String customerName) {} \ No newline at end of file + String customerName, + Double totalValue +) {} diff --git a/src/main/java/com/niuan/erp/module/sale/controller/dto/SaleOrderItemDto.java b/src/main/java/com/niuan/erp/module/sale/controller/dto/SaleOrderItemDto.java index 596c226..a25f5c5 100644 --- a/src/main/java/com/niuan/erp/module/sale/controller/dto/SaleOrderItemDto.java +++ b/src/main/java/com/niuan/erp/module/sale/controller/dto/SaleOrderItemDto.java @@ -1,24 +1,18 @@ package com.niuan.erp.module.sale.controller.dto; -import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonInclude; +/** + * 销售订单明细返回 DTO - 前端展示用 + */ +@JsonInclude(JsonInclude.Include.NON_NULL) public record SaleOrderItemDto( Long id, - Integer status, - LocalDateTime createDate, - Long createUserId, - String createUserName, - LocalDateTime updateDate, - Long updateUserId, - String updateUserName, - Integer documentNo, - String documentCode, - String projectName, String partNumber, + String productSpecs, Integer saleCount, Double price, Double totalPrice, Integer sendCount, - String saleMark, - Integer reserve1, - String reserve2) {} \ No newline at end of file + String saleMark +) {} diff --git a/src/main/java/com/niuan/erp/module/sale/converter/SaleOrderConverter.java b/src/main/java/com/niuan/erp/module/sale/converter/SaleOrderConverter.java index e8a0cb3..32d1ab8 100644 --- a/src/main/java/com/niuan/erp/module/sale/converter/SaleOrderConverter.java +++ b/src/main/java/com/niuan/erp/module/sale/converter/SaleOrderConverter.java @@ -1,26 +1,39 @@ package com.niuan.erp.module.sale.converter; import com.niuan.erp.module.common.entity.Document; -import com.niuan.erp.module.sale.controller.dto.SaleOrderAddDto; import com.niuan.erp.module.sale.controller.dto.SaleOrderDto; -import com.niuan.erp.module.sale.controller.dto.SaleOrderItemAddDto; import com.niuan.erp.module.sale.controller.dto.SaleOrderItemDto; import com.niuan.erp.module.sale.entity.SaleOrderItem; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; import org.mapstruct.ReportingPolicy; import java.util.List; @Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) public interface SaleOrderConverter { - Document toEntity(SaleOrderDto dto); - Document toEntity(SaleOrderAddDto dto); + + @Mapping(source = "id", target = "id") + @Mapping(source = "createDate", target = "createDate") + @Mapping(source = "formCode", target = "formCode") + @Mapping(source = "formName", target = "formName") + @Mapping(source = "formMark", target = "formMark") + @Mapping(source = "formStatus.value", target = "formStatus") + @Mapping(source = "customerId", target = "customerId") + @Mapping(source = "storeName", target = "customerName") + @Mapping(source = "totalValue", target = "totalValue") SaleOrderDto toDto(Document entity); + List toDtoList(List entities); - SaleOrderItem toEntity(SaleOrderItemAddDto dto); - List toEntityList(List dtoList); - + @Mapping(source = "id", target = "id") + @Mapping(source = "partNumber", target = "partNumber") + @Mapping(source = "saleCount", target = "saleCount") + @Mapping(source = "price", target = "price") + @Mapping(source = "totalPrice", target = "totalPrice") + @Mapping(source = "sendCount", target = "sendCount") + @Mapping(source = "saleMark", target = "saleMark") SaleOrderItemDto toDto(SaleOrderItem entity); + List toSaleOrderItemDtoList(List entities); -} \ No newline at end of file +} diff --git a/src/main/java/com/niuan/erp/module/sale/mapper/DeviceMapper.java b/src/main/java/com/niuan/erp/module/sale/mapper/DeviceMapper.java index ea17c9e..c2fec17 100644 --- a/src/main/java/com/niuan/erp/module/sale/mapper/DeviceMapper.java +++ b/src/main/java/com/niuan/erp/module/sale/mapper/DeviceMapper.java @@ -1,9 +1,20 @@ package com.niuan.erp.module.sale.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.niuan.erp.module.sale.controller.dto.DeviceResultDto; import com.niuan.erp.module.sale.entity.Device; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; @Mapper public interface DeviceMapper extends BaseMapper { + + /** + * SN溯源分页查询 + */ + IPage selectDeviceSnPage(Page page, + @Param("searchCode") String searchCode, + @Param("keyAccountId") Integer keyAccountId); } diff --git a/src/main/java/com/niuan/erp/module/sale/mapper/RepairRecordMapper.java b/src/main/java/com/niuan/erp/module/sale/mapper/RepairRecordMapper.java index 112776b..1d397a8 100644 --- a/src/main/java/com/niuan/erp/module/sale/mapper/RepairRecordMapper.java +++ b/src/main/java/com/niuan/erp/module/sale/mapper/RepairRecordMapper.java @@ -1,7 +1,11 @@ package com.niuan.erp.module.sale.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.niuan.erp.module.sale.controller.dto.RepairRecordResultDto; import com.niuan.erp.module.sale.entity.RepairRecord; +import org.apache.ibatis.annotations.Param; /** *

@@ -13,4 +17,10 @@ import com.niuan.erp.module.sale.entity.RepairRecord; */ public interface RepairRecordMapper extends BaseMapper { + /** + * 返修报表分页查询 + */ + IPage selectRepairReportPage(Page page, + @Param("searchCode") String searchCode, + @Param("keyAccountIdSearch") Integer keyAccountIdSearch); } diff --git a/src/main/java/com/niuan/erp/module/sale/service/DeviceService.java b/src/main/java/com/niuan/erp/module/sale/service/DeviceService.java index 1be69cf..9b599c9 100644 --- a/src/main/java/com/niuan/erp/module/sale/service/DeviceService.java +++ b/src/main/java/com/niuan/erp/module/sale/service/DeviceService.java @@ -1,25 +1,11 @@ package com.niuan.erp.module.sale.service; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.niuan.erp.common.base.BasePageReqParams; -import com.niuan.erp.common.base.BaseSelectDto; -import com.niuan.erp.module.sale.controller.dto.DeviceDto; -import com.niuan.erp.module.sale.entity.Device; - -import java.util.List; +import com.niuan.erp.module.sale.controller.dto.DeviceQueryDto; +import com.niuan.erp.module.sale.controller.dto.DeviceResultDto; public interface DeviceService { - IPage getDevicePage(BasePageReqParams pageParams, LambdaQueryWrapper wrapper); - - void addDevice(DeviceDto dto); - - void updateDevice(DeviceDto dto); - - void deleteDevice(long id); - - void deleteBatch(List ids); - - List getKeyAccount(); + IPage getDeviceSnPage(BasePageReqParams pageParams, DeviceQueryDto searchParams); } diff --git a/src/main/java/com/niuan/erp/module/sale/service/RepairRecordService.java b/src/main/java/com/niuan/erp/module/sale/service/RepairRecordService.java index 930455d..6d36c7d 100644 --- a/src/main/java/com/niuan/erp/module/sale/service/RepairRecordService.java +++ b/src/main/java/com/niuan/erp/module/sale/service/RepairRecordService.java @@ -1,25 +1,14 @@ package com.niuan.erp.module.sale.service; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.niuan.erp.common.base.BasePageReqParams; -import com.niuan.erp.common.base.BaseSelectDto; import com.niuan.erp.module.sale.controller.dto.RepairRecordDto; -import com.niuan.erp.module.sale.entity.RepairRecord; - -import java.util.List; +import com.niuan.erp.module.sale.controller.dto.RepairRecordQueryDto; +import com.niuan.erp.module.sale.controller.dto.RepairRecordResultDto; public interface RepairRecordService { - IPage getRepairRecordPage(BasePageReqParams pageParams, LambdaQueryWrapper wrapper); + IPage getRepairReportPage(BasePageReqParams pageParams, RepairRecordQueryDto searchParams); void addRepairRecord(RepairRecordDto dto); - - void updateRepairRecord(RepairRecordDto dto); - - void deleteRepairRecord(long id); - - void deleteBatch(List ids); - - List getKeyAccount(); } diff --git a/src/main/java/com/niuan/erp/module/sale/service/SaleOrderService.java b/src/main/java/com/niuan/erp/module/sale/service/SaleOrderService.java index 542192e..7613444 100644 --- a/src/main/java/com/niuan/erp/module/sale/service/SaleOrderService.java +++ b/src/main/java/com/niuan/erp/module/sale/service/SaleOrderService.java @@ -7,6 +7,7 @@ import com.niuan.erp.module.common.entity.Document; import com.niuan.erp.module.sale.controller.dto.SaleOrderAddDto; import com.niuan.erp.module.sale.controller.dto.SaleOrderDto; import com.niuan.erp.module.sale.controller.dto.SaleOrderItemDto; +import com.niuan.erp.module.sale.controller.dto.SaleOrderUpdateDto; import org.springframework.web.multipart.MultipartFile; import java.util.List; @@ -17,7 +18,7 @@ public interface SaleOrderService { void addSaleOrder(SaleOrderAddDto dto); - void updateSaleOrder(SaleOrderDto dto); + void updateSaleOrder(SaleOrderUpdateDto dto); void deleteSaleOrder(long id); diff --git a/src/main/java/com/niuan/erp/module/sale/service/impl/DeviceServiceImpl.java b/src/main/java/com/niuan/erp/module/sale/service/impl/DeviceServiceImpl.java index 1933612..0ba58e3 100644 --- a/src/main/java/com/niuan/erp/module/sale/service/impl/DeviceServiceImpl.java +++ b/src/main/java/com/niuan/erp/module/sale/service/impl/DeviceServiceImpl.java @@ -1,24 +1,18 @@ package com.niuan.erp.module.sale.service.impl; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.niuan.erp.common.base.BasePageReqParams; -import com.niuan.erp.common.base.BaseSelectDto; -import com.niuan.erp.common.utils.SecurityUtils; -import com.niuan.erp.module.sale.controller.dto.DeviceDto; -import com.niuan.erp.module.sale.converter.DeviceConverter; +import com.niuan.erp.common.exception.BusinessException; +import com.niuan.erp.module.sale.controller.dto.DeviceQueryDto; +import com.niuan.erp.module.sale.controller.dto.DeviceResultDto; import com.niuan.erp.module.sale.entity.Device; import com.niuan.erp.module.sale.mapper.DeviceMapper; import com.niuan.erp.module.sale.service.DeviceService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.StringUtils; - -import java.time.LocalDateTime; -import java.util.List; @Service @@ -26,53 +20,16 @@ import java.util.List; @RequiredArgsConstructor public class DeviceServiceImpl extends ServiceImpl implements DeviceService { - - private final DeviceConverter deviceConverter; - @Override - public IPage getDevicePage(BasePageReqParams pageParams, LambdaQueryWrapper wrapper) { - IPage result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper); - return result.convert(deviceConverter::toDto); - } - - @Override - public void addDevice(DeviceDto dto) { - Device entity = deviceConverter.toEntity(dto); - entity.setCreateUserId(SecurityUtils.getUserId()); - entity.setCreateUserName(SecurityUtils.getUserName()); - entity.setCreateDate(LocalDateTime.now()); - entity.setStatus(0); - this.baseMapper.insert(entity); - } - - @Override - public void updateDevice(DeviceDto dto) { - Device entity = deviceConverter.toEntity(dto); - entity.setUpdateUserId(SecurityUtils.getUserId()); - entity.setUpdateUserName(SecurityUtils.getUserName()); - entity.setUpdateDate(LocalDateTime.now()); - this.baseMapper.updateById(entity); - } - - @Override - public void deleteDevice(long id) { - this.baseMapper.deleteById(id); - } - - @Override - public void deleteBatch(List ids) { - this.baseMapper.deleteBatchIds(ids); - } - - @Override - public List getKeyAccount() { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.select(Device::getKeyAccountId); - wrapper.isNotNull(Device::getKeyAccountId); - wrapper.groupBy(Device::getKeyAccountId); - List devices = this.baseMapper.selectList(wrapper); - return devices.stream() - .map(device -> new BaseSelectDto(device.getKeyAccountId().toString(), device.getKeyAccountId().toString())) - .toList(); + public IPage getDeviceSnPage(BasePageReqParams pageParams, DeviceQueryDto searchParams) { + if (pageParams == null) { + throw new BusinessException("common.validate.page_params.not_null"); + } + String searchCode = searchParams != null ? searchParams.searchCode() : null; + Integer keyAccountId = searchParams != null ? searchParams.keyAccountId() : null; + return this.baseMapper.selectDeviceSnPage( + new Page<>(pageParams.page(), pageParams.pageSize()), + searchCode, + keyAccountId); } } diff --git a/src/main/java/com/niuan/erp/module/sale/service/impl/RepairRecordServiceImpl.java b/src/main/java/com/niuan/erp/module/sale/service/impl/RepairRecordServiceImpl.java index 41082e8..5a27e87 100644 --- a/src/main/java/com/niuan/erp/module/sale/service/impl/RepairRecordServiceImpl.java +++ b/src/main/java/com/niuan/erp/module/sale/service/impl/RepairRecordServiceImpl.java @@ -5,19 +5,22 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.niuan.erp.common.base.BasePageReqParams; -import com.niuan.erp.common.base.BaseSelectDto; +import com.niuan.erp.common.exception.BusinessException; import com.niuan.erp.common.utils.SecurityUtils; import com.niuan.erp.module.sale.controller.dto.RepairRecordDto; -import com.niuan.erp.module.sale.converter.RepairRecordConverter; +import com.niuan.erp.module.sale.controller.dto.RepairRecordQueryDto; +import com.niuan.erp.module.sale.controller.dto.RepairRecordResultDto; +import com.niuan.erp.module.sale.entity.Device; import com.niuan.erp.module.sale.entity.RepairRecord; +import com.niuan.erp.module.sale.mapper.DeviceMapper; import com.niuan.erp.module.sale.mapper.RepairRecordMapper; import com.niuan.erp.module.sale.service.RepairRecordService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; import java.time.LocalDateTime; -import java.util.List; @Service @@ -25,53 +28,101 @@ import java.util.List; @RequiredArgsConstructor public class RepairRecordServiceImpl extends ServiceImpl implements RepairRecordService { - - private final RepairRecordConverter repairRecordConverter; + private final DeviceMapper deviceMapper; @Override - public IPage getRepairRecordPage(BasePageReqParams pageParams, LambdaQueryWrapper wrapper) { - IPage result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper); - return result.convert(repairRecordConverter::toDto); + public IPage getRepairReportPage(BasePageReqParams pageParams, RepairRecordQueryDto searchParams) { + if (pageParams == null) { + throw new BusinessException("common.validate.page_params.not_null"); + } + String searchCode = searchParams != null ? searchParams.searchCode() : null; + Integer keyAccountIdSearch = searchParams != null ? searchParams.keyAccountIdSearch() : null; + return this.baseMapper.selectRepairReportPage( + new Page<>(pageParams.page(), pageParams.pageSize()), + searchCode, + keyAccountIdSearch); } @Override public void addRepairRecord(RepairRecordDto dto) { - RepairRecord entity = repairRecordConverter.toEntity(dto); + // 从 Device 查询补充信息 + Device device = findDevice(dto); + + // 构建 RepairRecord 实体 + RepairRecord entity = new RepairRecord(); + entity.setProductSn(StringUtils.hasText(dto.productSn()) ? dto.productSn() : (device != null ? device.getProductSn() : null)); + entity.setMac(StringUtils.hasText(dto.mac()) ? dto.mac() : (device != null ? device.getMac() : null)); + entity.setProductType(StringUtils.hasText(dto.productType()) ? dto.productType() : (device != null ? device.getProductType() : null)); + entity.setOutProductDate(dto.outProductDate() != null ? dto.outProductDate() : (device != null ? device.getOutProductDate() : null)); + entity.setRepairMark(dto.repairMark()); entity.setCreateUserId(SecurityUtils.getUserId()); entity.setCreateUserName(SecurityUtils.getUserName()); entity.setCreateDate(LocalDateTime.now()); entity.setStatus(0); + + // 设置客户ID(从 Device 获取) + if (device != null && device.getKeyAccountId() != null) { + entity.setKeyAccountId(device.getKeyAccountId()); + } + this.baseMapper.insert(entity); + + // 更新 Device 信息(前端有值则覆盖) + if (device != null) { + updateDeviceInfo(dto, device); + } } - @Override - public void updateRepairRecord(RepairRecordDto dto) { - RepairRecord entity = repairRecordConverter.toEntity(dto); - entity.setUpdateUserId(SecurityUtils.getUserId()); - entity.setUpdateUserName(SecurityUtils.getUserName()); - entity.setUpdateDate(LocalDateTime.now()); - this.baseMapper.updateById(entity); + private Device findDevice(RepairRecordDto dto) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + if (StringUtils.hasText(dto.productSn())) { + wrapper.eq(Device::getProductSn, dto.productSn()); + } else if (StringUtils.hasText(dto.mac())) { + wrapper.eq(Device::getMac, dto.mac()); + } else if (StringUtils.hasText(dto.serialNum())) { + wrapper.eq(Device::getSerialNum, dto.serialNum()); + } else { + return null; + } + // MAC可能重复,取第一条 + wrapper.orderByAsc(Device::getId); + wrapper.last("LIMIT 1"); + return deviceMapper.selectOne(wrapper); } - @Override - public void deleteRepairRecord(long id) { - this.baseMapper.deleteById(id); - } + private void updateDeviceInfo(RepairRecordDto dto, Device device) { + boolean updated = false; - @Override - public void deleteBatch(List ids) { - this.baseMapper.deleteBatchIds(ids); - } + if (StringUtils.hasText(dto.productType())) { + device.setProductType(dto.productType()); + updated = true; + } + if (StringUtils.hasText(dto.mac())) { + device.setMac(dto.mac()); + updated = true; + } + if (StringUtils.hasText(dto.serialNum())) { + device.setSerialNum(dto.serialNum()); + updated = true; + } + if (StringUtils.hasText(dto.softVersion())) { + device.setSoftVersion(dto.softVersion()); + updated = true; + } + if (StringUtils.hasText(dto.alVersion())) { + device.setAlVersion(dto.alVersion()); + updated = true; + } + if (dto.outProductDate() != null) { + device.setOutProductDate(dto.outProductDate()); + updated = true; + } - @Override - public List getKeyAccount() { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.select(RepairRecord::getKeyAccountId); - wrapper.isNotNull(RepairRecord::getKeyAccountId); - wrapper.groupBy(RepairRecord::getKeyAccountId); - List repairRecords = this.baseMapper.selectList(wrapper); - return repairRecords.stream() - .map(repairRecord -> new BaseSelectDto(repairRecord.getKeyAccountId().toString(), repairRecord.getKeyAccountId().toString())) - .toList(); + if (updated) { + device.setUpdateUserId(SecurityUtils.getUserId()); + device.setUpdateUserName(SecurityUtils.getUserName()); + device.setUpdateDate(LocalDateTime.now()); + deviceMapper.updateById(device); + } } } diff --git a/src/main/java/com/niuan/erp/module/sale/service/impl/SaleOrderServiceImpl.java b/src/main/java/com/niuan/erp/module/sale/service/impl/SaleOrderServiceImpl.java index 474389a..2a09c9b 100644 --- a/src/main/java/com/niuan/erp/module/sale/service/impl/SaleOrderServiceImpl.java +++ b/src/main/java/com/niuan/erp/module/sale/service/impl/SaleOrderServiceImpl.java @@ -16,10 +16,16 @@ import com.niuan.erp.module.sale.controller.dto.SaleOrderAddDto; import com.niuan.erp.module.sale.controller.dto.SaleOrderDto; import com.niuan.erp.module.sale.controller.dto.SaleOrderItemAddDto; import com.niuan.erp.module.sale.controller.dto.SaleOrderItemDto; +import com.niuan.erp.module.sale.controller.dto.SaleOrderItemUpdateDto; +import com.niuan.erp.module.sale.controller.dto.SaleOrderUpdateDto; import com.niuan.erp.module.sale.converter.SaleOrderConverter; import com.niuan.erp.module.sale.entity.SaleOrderItem; import com.niuan.erp.module.sale.mapper.SaleOrderItemMapper; import com.niuan.erp.module.sale.service.SaleOrderService; +import com.niuan.erp.module.warehouse.entity.Stock; +import com.niuan.erp.module.warehouse.entity.WarehouseItem; +import com.niuan.erp.module.warehouse.mapper.StockMapper; +import com.niuan.erp.module.warehouse.mapper.WarehouseItemMapper; import lombok.RequiredArgsConstructor; import org.apache.poi.ss.usermodel.*; import org.springframework.stereotype.Service; @@ -29,7 +35,10 @@ import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.time.LocalDateTime; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; @@ -43,10 +52,17 @@ public class SaleOrderServiceImpl extends ServiceImpl private final SaleOrderItemMapper saleOrderItemMapper; + private final StockMapper stockMapper; + + private final WarehouseItemMapper warehouseItemMapper; + @Override public IPage getSaleOrderPage(BasePageReqParams pageParams, LambdaQueryWrapper wrapper) { wrapper.eq(Document::getFormType, DocumentType.SALES_ORDER); - IPage result = this.baseMapper.selectPage(new Page<>(pageParams.page(), pageParams.pageSize()), wrapper); + IPage result = this.baseMapper.selectPage( + new Page<>(pageParams.page(), pageParams.pageSize()), + wrapper + ); return result.convert(saleOrderConverter::toDto); } @@ -54,37 +70,52 @@ public class SaleOrderServiceImpl extends ServiceImpl public void addSaleOrder(SaleOrderAddDto dto) { List saleOrderItems = dto.saleOrderItems(); - if (saleOrderItems == null || saleOrderItems.isEmpty()) { - throw new BusinessException("sale.sale_order.exception.no_sale_order_items"); - } + // 计算订单总额 + double totalValue = saleOrderItems.stream() + .mapToDouble(item -> item.saleCount() * item.price()) + .sum(); - Document entity = saleOrderConverter.toEntity(dto); + // 创建主单据 + Document entity = new Document(); + entity.setFormCode(dto.formCode()); + entity.setFormName(dto.formName()); + entity.setFormMark(dto.formMark()); + entity.setCustomerId(dto.customerId()); + entity.setStoreName(dto.customerName()); + entity.setTotalValue(totalValue); + entity.setFormType(DocumentType.SALES_ORDER); + entity.setFormStatus(FormStatus.NO_APPROVE); + entity.setStatus(0); entity.setCreateUserId(SecurityUtils.getUserId()); entity.setCreateUserName(SecurityUtils.getUserName()); entity.setCreateDate(LocalDateTime.now()); - entity.setStatus(0); - entity.setFormType(DocumentType.SALES_ORDER); - entity.setFormStatus(FormStatus.NO_APPROVE); - entity.setCustomerId(SecurityUtils.getCustomerId()); + this.baseMapper.insert(entity); - List saleOrderItemEntities = saleOrderConverter.toEntityList(saleOrderItems); - - for (SaleOrderItem saleOrderItem : saleOrderItemEntities) { - saleOrderItem.setDocumentNo(entity.getId().intValue()); - saleOrderItem.setDocumentCode(entity.getFormCode()); - saleOrderItem.setCreateDate(LocalDateTime.now()); - saleOrderItem.setCreateUserId(SecurityUtils.getUserId()); - saleOrderItem.setCreateUserName(SecurityUtils.getUserName()); - saleOrderItem.setStatus(0); - saleOrderItem.setSendCount(0); + // 创建明细 + List itemEntities = new ArrayList<>(); + for (SaleOrderItemAddDto itemDto : saleOrderItems) { + SaleOrderItem item = new SaleOrderItem(); + item.setDocumentNo(entity.getId().intValue()); + item.setDocumentCode(entity.getFormCode()); + item.setPartNumber(itemDto.partNumber()); + item.setSaleCount(itemDto.saleCount()); + item.setPrice(itemDto.price()); + item.setTotalPrice(itemDto.saleCount() * itemDto.price()); + item.setSaleMark(itemDto.saleMark()); + item.setSendCount(0); + item.setStatus(0); + item.setCreateUserId(SecurityUtils.getUserId()); + item.setCreateUserName(SecurityUtils.getUserName()); + item.setCreateDate(LocalDateTime.now()); + itemEntities.add(item); } - saleOrderItemMapper.insert(saleOrderItemEntities); + saleOrderItemMapper.insert(itemEntities); } @Override - public void updateSaleOrder(SaleOrderDto dto) { + public void updateSaleOrder(SaleOrderUpdateDto dto) { Document existingEntity = this.baseMapper.selectById(dto.id()); if (existingEntity == null) { throw new BusinessException("sale.sale_order.exception.not_found"); @@ -93,11 +124,48 @@ public class SaleOrderServiceImpl extends ServiceImpl throw new BusinessException("sale.sale_order.exception.cannot_update_approved"); } - Document entity = saleOrderConverter.toEntity(dto); - entity.setUpdateUserId(SecurityUtils.getUserId()); - entity.setUpdateUserName(SecurityUtils.getUserName()); - entity.setUpdateDate(LocalDateTime.now()); - this.baseMapper.updateById(entity); + // 计算新的订单总额 + double totalValue = dto.saleOrderItems().stream() + .mapToDouble(item -> item.saleCount() * item.price()) + .sum(); + + // 更新主单据 + existingEntity.setFormName(dto.formName()); + existingEntity.setFormMark(dto.formMark()); + existingEntity.setCustomerId(dto.customerId()); + existingEntity.setStoreName(dto.customerName()); + existingEntity.setTotalValue(totalValue); + existingEntity.setUpdateUserId(SecurityUtils.getUserId()); + existingEntity.setUpdateUserName(SecurityUtils.getUserName()); + existingEntity.setUpdateDate(LocalDateTime.now()); + + this.baseMapper.updateById(existingEntity); + + // 删除旧明细 + LambdaQueryWrapper deleteWrapper = new LambdaQueryWrapper<>(); + deleteWrapper.eq(SaleOrderItem::getDocumentNo, dto.id()); + saleOrderItemMapper.delete(deleteWrapper); + + // 插入新明细 + List itemEntities = new ArrayList<>(); + for (SaleOrderItemUpdateDto itemDto : dto.saleOrderItems()) { + SaleOrderItem item = new SaleOrderItem(); + item.setDocumentNo(existingEntity.getId().intValue()); + item.setDocumentCode(existingEntity.getFormCode()); + item.setPartNumber(itemDto.partNumber()); + item.setSaleCount(itemDto.saleCount()); + item.setPrice(itemDto.price()); + item.setTotalPrice(itemDto.saleCount() * itemDto.price()); + item.setSaleMark(itemDto.saleMark()); + item.setSendCount(0); + item.setStatus(0); + item.setCreateUserId(SecurityUtils.getUserId()); + item.setCreateUserName(SecurityUtils.getUserName()); + item.setCreateDate(LocalDateTime.now()); + itemEntities.add(item); + } + + saleOrderItemMapper.insert(itemEntities); } @Override @@ -155,6 +223,50 @@ public class SaleOrderServiceImpl extends ServiceImpl throw new BusinessException("sale.sale_order.exception.no_sale_order_items"); } + // 验证并扣除库存 + for (SaleOrderItem item : items) { + LambdaQueryWrapper stockWrapper = new LambdaQueryWrapper<>(); + stockWrapper.eq(Stock::getPartNumber, item.getPartNumber()); + // 如果指定了仓库,则按仓库查询 + if (entity.getStoreNo() != null) { + stockWrapper.eq(Stock::getStoreNo, entity.getStoreNo()); + } + + Stock stock; + if (entity.getStoreNo() != null) { + // 指定了仓库,使用 selectOne + stock = stockMapper.selectOne(stockWrapper); + } else { + // 未指定仓库,查询所有仓库库存并汇总 + List stockList = stockMapper.selectList(stockWrapper); + if (stockList == null || stockList.isEmpty()) { + stock = null; + } else if (stockList.size() == 1) { + stock = stockList.get(0); + } else { + // 多条记录,取第一条并汇总数量 + stock = stockList.get(0); + int totalCount = stockList.stream().mapToInt(Stock::getProductCount).sum(); + stock.setProductCount(totalCount); + } + } + + if (stock == null) { + throw new BusinessException("warehouse.stock_transfer_order.exception.stock_not_found"); + } + + if (stock.getProductCount() < item.getSaleCount()) { + throw new BusinessException("warehouse.stock_transfer_order.exception.insufficient_stock"); + } + + // 扣除库存 - 如果有多条记录,只更新第一条 + stock.setProductCount(stock.getProductCount() - item.getSaleCount()); + stock.setUpdateDate(LocalDateTime.now()); + stock.setUpdateUserId(SecurityUtils.getUserId()); + stock.setUpdateUserName(SecurityUtils.getUserName()); + stockMapper.updateById(stock); + } + entity.setFormStatus(FormStatus.APPROVE); entity.setUpdateDate(LocalDateTime.now()); entity.setUpdateUserId(SecurityUtils.getUserId()); @@ -183,6 +295,7 @@ public class SaleOrderServiceImpl extends ServiceImpl itemWrapper.eq(SaleOrderItem::getDocumentNo, id); List items = saleOrderItemMapper.selectList(itemWrapper); + // 检查是否有已出货数量 Long shippedCount = items.stream() .filter(item -> item.getSendCount() != null && item.getSendCount() > 0) .count(); @@ -191,6 +304,42 @@ public class SaleOrderServiceImpl extends ServiceImpl throw new BusinessException("sale.sale_order.exception.cannot_unapprove_with_shipped"); } + // 恢复库存 + for (SaleOrderItem item : items) { + LambdaQueryWrapper stockWrapper = new LambdaQueryWrapper<>(); + stockWrapper.eq(Stock::getPartNumber, item.getPartNumber()); + // 如果指定了仓库,则按仓库查询 + if (entity.getStoreNo() != null) { + stockWrapper.eq(Stock::getStoreNo, entity.getStoreNo()); + } + + Stock stock; + if (entity.getStoreNo() != null) { + // 指定了仓库,使用 selectOne + stock = stockMapper.selectOne(stockWrapper); + } else { + // 未指定仓库,查询所有仓库库存 + List stockList = stockMapper.selectList(stockWrapper); + if (stockList == null || stockList.isEmpty()) { + stock = null; + } else { + // 取第一条记录 + stock = stockList.get(0); + } + } + + if (stock == null) { + throw new BusinessException("warehouse.stock_transfer_order.exception.stock_not_found"); + } + + // 恢复库存 - 只更新第一条记录 + stock.setProductCount(stock.getProductCount() + item.getSaleCount()); + stock.setUpdateDate(LocalDateTime.now()); + stock.setUpdateUserId(SecurityUtils.getUserId()); + stock.setUpdateUserName(SecurityUtils.getUserName()); + stockMapper.updateById(stock); + } + entity.setFormStatus(FormStatus.NO_APPROVE); entity.setUpdateDate(LocalDateTime.now()); entity.setUpdateUserId(SecurityUtils.getUserId()); @@ -210,7 +359,40 @@ public class SaleOrderServiceImpl extends ServiceImpl LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(SaleOrderItem::getDocumentNo, id); List items = saleOrderItemMapper.selectList(wrapper); - return saleOrderConverter.toSaleOrderItemDtoList(items); + + // 获取所有物料编号 + List partNumbers = items.stream() + .map(SaleOrderItem::getPartNumber) + .filter(StringUtils::hasText) + .distinct() + .toList(); + + // 查询物料型号信息 + Map productSpecsMap = new HashMap<>(); + if (!partNumbers.isEmpty()) { + LambdaQueryWrapper warehouseWrapper = new LambdaQueryWrapper<>(); + warehouseWrapper.in(WarehouseItem::getPartNumber, partNumbers); + List warehouseItems = warehouseItemMapper.selectList(warehouseWrapper); + productSpecsMap = warehouseItems.stream() + .collect(Collectors.toMap( + WarehouseItem::getPartNumber, + WarehouseItem::getProductSpecs, + (a, b) -> a + )); + } + + // 转换为 DTO 并设置 productSpecs + Map finalProductSpecsMap = productSpecsMap; + return items.stream().map(item -> new SaleOrderItemDto( + item.getId(), + item.getPartNumber(), + finalProductSpecsMap.getOrDefault(item.getPartNumber(), ""), + item.getSaleCount(), + item.getPrice(), + item.getTotalPrice(), + item.getSendCount(), + item.getSaleMark() + )).toList(); } @Override @@ -228,19 +410,19 @@ public class SaleOrderServiceImpl extends ServiceImpl if (row == null) continue; String partNumber = getCellValueAsString(row.getCell(0)); - String saleCountStr = getCellValueAsString(row.getCell(1)); - String priceStr = getCellValueAsString(row.getCell(2)); - String saleMark = getCellValueAsString(row.getCell(3)); + String productSpecs = getCellValueAsString(row.getCell(1)); + String saleCountStr = getCellValueAsString(row.getCell(2)); + String priceStr = getCellValueAsString(row.getCell(3)); + String saleMark = getCellValueAsString(row.getCell(4)); if (!StringUtils.hasText(partNumber)) continue; Integer saleCount = StringUtils.hasText(saleCountStr) ? Integer.parseInt(saleCountStr) : 0; Double price = StringUtils.hasText(priceStr) ? Double.parseDouble(priceStr) : 0.0; + Double totalPrice = saleCount * price; SaleOrderItemDto item = new SaleOrderItemDto( - null, null, null, null, null, null, null, null, - null, null, null, partNumber, saleCount, price, - saleCount * price, 0, saleMark, null, null + null, partNumber, productSpecs, saleCount, price, totalPrice, 0, saleMark ); items.add(item); } @@ -262,4 +444,4 @@ public class SaleOrderServiceImpl extends ServiceImpl default -> ""; }; } -} \ No newline at end of file +} diff --git a/src/main/java/com/niuan/erp/module/sys/controller/KeyAccountController.java b/src/main/java/com/niuan/erp/module/sys/controller/KeyAccountController.java index 0af6c4a..49efffe 100644 --- a/src/main/java/com/niuan/erp/module/sys/controller/KeyAccountController.java +++ b/src/main/java/com/niuan/erp/module/sys/controller/KeyAccountController.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.niuan.erp.common.base.BaseDeleteBody; import com.niuan.erp.common.base.BasePageReqParams; import com.niuan.erp.common.base.BaseResult; +import com.niuan.erp.common.base.BaseTree; import com.niuan.erp.common.base.CommonValidateGroup.DeleteBatch; import com.niuan.erp.common.base.CommonValidateGroup.DeleteOne; import com.niuan.erp.common.base.BaseSelectDto; @@ -45,6 +46,13 @@ public class KeyAccountController { return BaseResult.successWithData(keyAccountService.getKeyAccountSelectList()); } + @Operation(summary = "查询客户树结构", operationId = "getKeyAccountTree") + @GetMapping("/getKeyAccountTree") + @PreAuthorize("hasAnyAuthority('device_sn:index', 'repair_record:index')") + public BaseResult> getKeyAccountTree() { + return BaseResult.successWithData(keyAccountService.getKeyAccountTree()); + } + @PostMapping("/addKeyAccount") public BaseResult addKeyAccount(@Valid @RequestBody KeyAccountDto dto) { keyAccountService.addKeyAccount(dto); diff --git a/src/main/java/com/niuan/erp/module/sys/service/KeyAccountService.java b/src/main/java/com/niuan/erp/module/sys/service/KeyAccountService.java index e126273..6ee0d7f 100644 --- a/src/main/java/com/niuan/erp/module/sys/service/KeyAccountService.java +++ b/src/main/java/com/niuan/erp/module/sys/service/KeyAccountService.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.niuan.erp.common.base.BasePageReqParams; import com.niuan.erp.common.base.BaseSelectDto; +import com.niuan.erp.common.base.BaseTree; import com.niuan.erp.module.sys.controller.dto.KeyAccountDto; import com.niuan.erp.module.sys.entity.KeyAccount; @@ -15,6 +16,8 @@ public interface KeyAccountService { List getKeyAccountSelectList(); + List getKeyAccountTree(); + void addKeyAccount(KeyAccountDto dto); void updateKeyAccount(KeyAccountDto dto); diff --git a/src/main/java/com/niuan/erp/module/sys/service/impl/KeyAccountServiceImpl.java b/src/main/java/com/niuan/erp/module/sys/service/impl/KeyAccountServiceImpl.java index b2c74ad..aea3c47 100644 --- a/src/main/java/com/niuan/erp/module/sys/service/impl/KeyAccountServiceImpl.java +++ b/src/main/java/com/niuan/erp/module/sys/service/impl/KeyAccountServiceImpl.java @@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.niuan.erp.common.base.BasePageReqParams; import com.niuan.erp.common.base.BaseSelectDto; +import com.niuan.erp.common.base.BaseTree; import com.niuan.erp.common.utils.SecurityUtils; import com.niuan.erp.module.sys.controller.dto.KeyAccountDto; import com.niuan.erp.module.sys.converter.KeyAccountConverter; @@ -17,7 +18,10 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Service @@ -39,6 +43,33 @@ public class KeyAccountServiceImpl extends ServiceImpl getKeyAccountTree() { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(KeyAccount::getStatus, 1); + wrapper.orderByAsc(KeyAccount::getLevelPath); + List keyAccounts = this.baseMapper.selectList(wrapper); + + Map> parentMap = keyAccounts.stream() + .collect(Collectors.groupingBy(ka -> ka.getParentId() != null ? ka.getParentId() : 0L)); + + return buildTree(parentMap, 0L); + } + + private List buildTree(Map> parentMap, Long parentId) { + List children = parentMap.get(parentId); + if (children == null || children.isEmpty()) { + return new ArrayList<>(); + } + + List treeList = new ArrayList<>(); + for (KeyAccount ka : children) { + List childTrees = buildTree(parentMap, ka.getId()); + treeList.add(new BaseTree(ka.getId(), ka.getKeyAccountName(), childTrees)); + } + return treeList; + } + @Override public void addKeyAccount(KeyAccountDto dto) { KeyAccount entity = keyAccountConverter.toEntity(dto); diff --git a/src/main/resources/i18n/messages_zh_CN.properties b/src/main/resources/i18n/messages_zh_CN.properties index 1bde00c..81cf504 100644 --- a/src/main/resources/i18n/messages_zh_CN.properties +++ b/src/main/resources/i18n/messages_zh_CN.properties @@ -1,5 +1,6 @@ result.success=请求成功 result.error=请求失败 +common.validate.page_params.not_null=分页参数不能为空 production.productionreturn.exception.not_exist=退料单不存在 production.productionreturn.exception.already_approved=退料单已经审核 production.productionreturn.exception.no_material=退料单没有明细 @@ -166,7 +167,10 @@ production.devicesn.exception.not_found=SN号不存在 production.repair_record.validate.product_sn.not_null=SN号不能为空 production.repair_record.validate.mac.not_null=MAC地址不能为空 production.repair_record.validate.repair_status.not_null=维修状态不能为空 +production.repair_record.validate.repair_mark.not_null=返修记录不能为空 +production.repair_record.validate.identifier.not_null=SN号、MAC地址、序列号至少填写一个 production.repair_record.exception.not_found=维修记录不存在 +production.repair_record.exception.device_not_found=设备不存在 purchase.purchase_order.validate.id.not_null=订单ID不能为空 purchase.purchase_order.validate.vendor_name.not_blank=供应商名称不能为空 purchase.purchase_order.validate.vendor_name.not_null=供应商名称不能为空 diff --git a/src/main/resources/mapper/sale/DeviceMapper.xml b/src/main/resources/mapper/sale/DeviceMapper.xml index 30ceec6..a88441d 100644 --- a/src/main/resources/mapper/sale/DeviceMapper.xml +++ b/src/main/resources/mapper/sale/DeviceMapper.xml @@ -32,4 +32,33 @@ + + + diff --git a/src/main/resources/mapper/sale/RepairRecordMapper.xml b/src/main/resources/mapper/sale/RepairRecordMapper.xml index 9dfbb21..d79a702 100644 --- a/src/main/resources/mapper/sale/RepairRecordMapper.xml +++ b/src/main/resources/mapper/sale/RepairRecordMapper.xml @@ -27,4 +27,37 @@ + + + diff --git a/src/main/resources/sql/dev/permission-schema.sql b/src/main/resources/sql/dev/permission-schema.sql index 5c69924..fac6adc 100644 --- a/src/main/resources/sql/dev/permission-schema.sql +++ b/src/main/resources/sql/dev/permission-schema.sql @@ -17,7 +17,7 @@ CREATE TABLE IF NOT EXISTS sys_permission ( permission_code VARCHAR(50) DEFAULT NULL COMMENT '后端鉴权用的权限编码', event_name VARCHAR(50) DEFAULT NULL COMMENT '前端按钮绑定的方法名', class_name VARCHAR(30) DEFAULT NULL COMMENT '前端样式类名', - icon_name VARCHAR(30) DEFAULT NULL COMMENT '前端图标名称', + icon_name VARCHAR(100) DEFAULT NULL COMMENT '前端图标名称', sort INT NOT NULL DEFAULT 0 COMMENT '排序值,越小越靠前' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统权限表';