Commit 12350c4e by 杨浩

客户/供应商 对账

parent a9cea543
package cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.order;
import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpDeliveryStatus;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
......@@ -8,6 +9,7 @@ import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import java.util.List;
import static cn.iocoder.foodnexus.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
......@@ -80,4 +82,12 @@ public class ErpPurchaseOrderPageReqVO extends PageParam {
@Schema(description = "创建月份 yyyy-MM")
private String createMonth;
/**
*
*
* 枚举 {@link ErpDeliveryStatus}
*/
@Schema(description = "发货状态")
private List<String> deliveryStatus;
}
\ No newline at end of file
......@@ -3,6 +3,7 @@ package cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.order;
import cn.idev.excel.annotation.ExcelProperty;
import cn.iocoder.foodnexus.framework.excel.core.annotations.DictFormat;
import cn.iocoder.foodnexus.framework.excel.core.convert.DictConvert;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpDeliveryStatus;
import cn.iocoder.foodnexus.module.order.enums.DeliveryMode;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
......
......@@ -12,7 +12,7 @@ import lombok.Data;
@Data
public class SupplierMonthOrderPageReqVO extends PageParam {
@Schema(description = "月度")
@Schema(description = "月度(yyyy-MM)")
private String month;
}
......@@ -53,6 +53,7 @@ public interface ErpPurchaseOrderMapper extends BaseMapperX<ErpPurchaseOrderDO>
.eqIfPresent(ErpPurchaseOrderDO::getStatus, reqVO.getStatus())
.likeIfPresent(ErpPurchaseOrderDO::getRemark, reqVO.getRemark())
.eqIfPresent(ErpPurchaseOrderDO::getCreator, reqVO.getCreator())
.inIfPresent(ErpPurchaseOrderDO::getDeliveryStatus, reqVO.getDeliveryStatus())
.orderByDesc(ErpPurchaseOrderDO::getId);
// 入库状态。为什么需要 t. 的原因,是因为联表查询时,需要指定表名,不然会报 in_count 错误
if (Objects.equals(reqVO.getInStatus(), ErpPurchaseOrderPageReqVO.IN_STATUS_NONE)) {
......@@ -85,6 +86,19 @@ public interface ErpPurchaseOrderMapper extends BaseMapperX<ErpPurchaseOrderDO>
.eq(reqVO.getProductId() != null, ErpPurchaseOrderItemDO::getProductId, reqVO.getProductId())
.groupBy(ErpPurchaseOrderDO::getId); // 避免 1 对多查询,产生相同的 1
}
if (CommonUtil.isNotBlank(reqVO.getCreateMonth())) {
String createMonth = reqVO.getCreateMonth().trim();
String startOfMonth = createMonth + "-01 00:00:00";
String[] parts = createMonth.split("-");
int year = Integer.parseInt(parts[0]);
int nextMonth = Integer.parseInt(parts[1]) + 1;
String endOfMonth = nextMonth > 12 ?
(year + 1) + "-01-01 00:00:00" :
year + "-" + (nextMonth < 10 ? "0" + nextMonth : nextMonth) + "-01 00:00:00";
query.ge(ErpPurchaseOrderDO::getCreateTime, startOfMonth)
.lt(ErpPurchaseOrderDO::getCreateTime, endOfMonth);
}
return query;
}
......@@ -111,7 +125,7 @@ public interface ErpPurchaseOrderMapper extends BaseMapperX<ErpPurchaseOrderDO>
wrapper.in("t1.order_status", CommonUtil.asList(CustomerOrderStatus.SIGN_RECEIPT.getKey()), CustomerOrderStatus.FINISH.getKey());
wrapper.eq(CommonUtil.isNotBlank(pageReqVO.getMonth()), "DATE_FORMAT(t.create_time, '%Y-%m') ", pageReqVO.getMonth());
wrapper.orderByDesc("t.id");
return this.selectJoinPage(pageReqVO, SupplierMonthOrderRespVO.class, wrapper);
}
......
......@@ -29,6 +29,8 @@ public interface ErrorCodeConstants {
ErrorCode PURCHASE_ORDER_ITEM_RETURN_FAIL_IN_EXCEED = new ErrorCode(1_030_101_009, "采购订单项({})超过最大允许退货数量({})");
ErrorCode PURCHASE_ORDER_PROCESS_FAIL_EXISTS_RETURN = new ErrorCode(1_030_101_010, "反审核失败,已存在对应的采购退货单");
ErrorCode PURCHASE_DELIVERY_STATUS_ERROR = new ErrorCode(1_030_101_011, "采购订单发货状态异常");
ErrorCode PURCHASE_SUPPLIER_OWN_ERROR = new ErrorCode(1_030_101_012, "非本供应商订单");
ErrorCode PURHCASE_NO_EXISTS_ARRIVAL = new ErrorCode(1_030_101_013, "不存在未对账订单");
// ========== ERP 采购入库(1-030-102-000) ==========
ErrorCode PURCHASE_IN_NOT_EXISTS = new ErrorCode(1_030_102_000, "采购入库单不存在");
......
......@@ -121,4 +121,12 @@ public interface ErpPurchaseOrderService {
Map<String, Long> queryCountByDeliveryStatus(ErpPurchaseOrderPageReqVO pageReqVO);
PageResult<SupplierMonthOrderRespVO> pageMonth(SupplierMonthOrderPageReqVO pageReqVO, Long supplierId);
/**
* 确认对账
*
* @param purchaseOrderList 采购订单id集合
* @param supplierId 当前供应商id
*/
void reconciliation(List<ErpPurchaseOrderDO> purchaseOrderList, Long supplierId);
}
\ No newline at end of file
......@@ -43,6 +43,7 @@ import java.util.*;
import static cn.iocoder.foodnexus.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.foodnexus.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.foodnexus.module.erp.enums.ErrorCodeConstants.*;
// TODO 芋艿:记录操作日志
......@@ -415,6 +416,41 @@ public class ErpPurchaseOrderServiceImpl implements ErpPurchaseOrderService {
return purchaseOrderMapper.pageMonth(pageReqVO, supplierId);
}
/**
* 确认对账
*
* @param purchaseOrderList 采购订单id集合
* @param supplierId 当前供应商id
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void reconciliation(List<ErpPurchaseOrderDO> purchaseOrderList, Long supplierId) {
if (CommonUtil.isEmpty(purchaseOrderList)) {
throw exception(PURCHASE_ORDER_NOT_EXISTS);
}
Set<Long> validIds = new HashSet<>();
for (ErpPurchaseOrderDO order : purchaseOrderList) {
if (!supplierId.equals(order.getSupplierId())) {
throw exception(PURCHASE_SUPPLIER_OWN_ERROR);
}
if (ErpDeliveryStatus.ARRIVAL.getStatus().equals(order.getDeliveryStatus())) {
validIds.add(order.getId());
}
}
if (CommonUtil.isEmpty(validIds)) {
throw exception(PURHCASE_NO_EXISTS_ARRIVAL);
}
List<ErpPurchaseOrderDO> updateBatch = new ArrayList<>();
for (ErpPurchaseOrderDO item : purchaseOrderList) {
ErpPurchaseOrderDO updateInfo = new ErpPurchaseOrderDO();
updateInfo.setId(item.getId());
updateInfo.setDeliveryStatus(ErpDeliveryStatus.RECONCILIATION.getStatus());
updateBatch.add(updateInfo);
}
purchaseOrderMapper.updateBatch(updateBatch);
}
@Async
@TransactionalEventListener(classes = PurchaseOrderSplitEvent.class, phase = TransactionPhase.AFTER_COMMIT)
public void orderSplit(PurchaseOrderSplitEvent event) {
......
......@@ -105,6 +105,7 @@ public class DeliveryStaffController {
return success(BeanUtils.toBean(deliveryStaff, DeliveryStaffRespVO.class, item -> {
item.setCustomerList(deliveryStaffCustomerService.queryCustomerListByDeliveryStaffId(item.getId()));
item.setVehicleInfo(vehicleInfoService.queryByStaffId(item.getId()));
item.setCustomerDeptList(deliveryStaffCustomerService.queryDeptListByStaffId(item.getId()));
}));
}
......
......@@ -2,6 +2,7 @@ package cn.iocoder.foodnexus.module.operations.controller.admin.deliverystaff.vo
import cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.customer.ErpCustomerRespVO;
import cn.iocoder.foodnexus.module.operations.controller.admin.vehicleinfo.vo.VehicleInfoRespVO;
import cn.iocoder.foodnexus.module.system.controller.admin.dept.vo.dept.DeptSimpleRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
......@@ -86,4 +87,7 @@ public class DeliveryStaffRespVO {
@Schema(description = "绑定客户信息")
private List<ErpCustomerRespVO> customerList;
@Schema(description = "绑定灶点信息")
private List<DeptSimpleRespVO> customerDeptList;
}
\ No newline at end of file
......@@ -20,4 +20,8 @@ public class DeliveryStaffCustomerSaveReqVO {
@NotNull(message = "客户id不能为空")
private Long customerId;
@Schema(description = "客户灶点id")
@NotNull(message = "客户灶点id不能可空")
private Long customerDeptId;
}
\ No newline at end of file
......@@ -35,6 +35,10 @@ public class DeliveryStaffCustomerDO extends BaseDO {
* 客户id
*/
private Long customerId;
/**
* 客户灶点id
*/
private Long customerDeptId;
}
\ No newline at end of file
......@@ -3,6 +3,7 @@ package cn.iocoder.foodnexus.module.operations.service.deliverystaffcustomer;
import java.util.*;
import cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.customer.ErpCustomerRespVO;
import cn.iocoder.foodnexus.module.system.controller.admin.dept.vo.dept.DeptSimpleRespVO;
import jakarta.validation.*;
import cn.iocoder.foodnexus.module.operations.controller.admin.deliverystaffcustomer.vo.*;
import cn.iocoder.foodnexus.module.operations.dal.dataobject.deliverystaffcustomer.DeliveryStaffCustomerDO;
......@@ -55,4 +56,5 @@ public interface DeliveryStaffCustomerService {
List<ErpCustomerRespVO> queryCustomerListByDeliveryStaffId(Long id);
List<DeptSimpleRespVO> queryDeptListByStaffId(Long id);
}
\ No newline at end of file
package cn.iocoder.foodnexus.module.operations.service.deliverystaffcustomer;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.module.erp.controller.admin.sale.vo.customer.ErpCustomerRespVO;
import cn.iocoder.foodnexus.module.erp.service.sale.ErpCustomerService;
import cn.iocoder.foodnexus.module.system.controller.admin.dept.vo.dept.DeptSimpleRespVO;
import cn.iocoder.foodnexus.module.system.service.dept.DeptService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
......@@ -18,8 +23,6 @@ import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;
import cn.iocoder.foodnexus.module.operations.dal.mysql.deliverystaffcustomer.DeliveryStaffCustomerMapper;
import static cn.iocoder.foodnexus.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.foodnexus.module.operations.enums.ErrorCodeConstants.*;
/**
......@@ -37,6 +40,9 @@ public class DeliveryStaffCustomerServiceImpl implements DeliveryStaffCustomerSe
@Resource
private ErpCustomerService customerService;
@Autowired
private DeptService deptService;
@Override
public Long createDeliveryStaffCustomer(DeliveryStaffCustomerSaveReqVO createReqVO) {
// 插入
......@@ -84,9 +90,18 @@ public class DeliveryStaffCustomerServiceImpl implements DeliveryStaffCustomerSe
@Override
public List<ErpCustomerRespVO> queryCustomerListByDeliveryStaffId(Long staffId) {
List<DeliveryStaffCustomerDO> list = deliveryStaffCustomerMapper.selectList(DeliveryStaffCustomerDO::getDeliveryStaffId, staffId);
List<DeliveryStaffCustomerDO> list = deliveryStaffCustomerMapper.selectList(Wrappers.<DeliveryStaffCustomerDO>lambdaQuery()
.eq(DeliveryStaffCustomerDO::getDeliveryStaffId, staffId)
.groupBy(DeliveryStaffCustomerDO::getCustomerId));
return BeanUtils.toBean(customerService.getCustomerList(list.stream().map(DeliveryStaffCustomerDO::getCustomerId).toList()), ErpCustomerRespVO.class);
}
@Override
public List<DeptSimpleRespVO> queryDeptListByStaffId(Long staffId) {
List<DeliveryStaffCustomerDO> deliveryStaffCustomerDOS = deliveryStaffCustomerMapper.selectList(DeliveryStaffCustomerDO::getDeliveryStaffId, staffId);
return BeanUtils.toBean(deptService.getDeptList(CommonUtil.listConvertSet(deliveryStaffCustomerDOS, DeliveryStaffCustomerDO::getCustomerDeptId)),
DeptSimpleRespVO.class);
}
}
\ No newline at end of file
......@@ -151,11 +151,13 @@ public class InquireCustomerPushServiceImpl implements InquireCustomerPushServic
CustomerVisibleProductRespDTO dto = new CustomerVisibleProductRespDTO();
Map<Long, List<InquireSupplierPushDO>> supplierProductMap = CommonUtil.listConvertListMap(supplierPushList, InquireSupplierPushDO::getProductId);
Map<Long, InquirePriceItemDO> inquirePriceMap = CommonUtil.listConvertMap(inquirePriceItemDOS, InquirePriceItemDO::getId);
supplierProductMap.forEach((productId, list) -> {
// TODO 根据供应商评分排序等....
if (CommonUtil.isNotEmpty(list)) {
InquireSupplierPushDO push = list.get(0);
dto.put(push.getId(), push.getProductId(), push.getSupplierQuote());
InquirePriceItemDO inquirePriceItemDO = inquirePriceMap.get(push.getInquirePriceItemId());
dto.put(push.getId(), push.getProductId(), push.getSupplierQuote(), inquirePriceItemDO.getMarketPrice(), inquirePriceItemDO.getFloatingRate());
}
});
......
......@@ -75,4 +75,7 @@ public class CustomerOrderPageReqVO extends PageParam {
@Schema(hidden = true)
private Long creator;
@Schema(description = "创建月份(yyyy-MM)")
private String createYearMonth;
}
\ No newline at end of file
......@@ -42,6 +42,9 @@ public class CustomerOrderRespVO {
private String customerName;
@Schema(description = "灶点id")
private Long customerDeptId;
@Schema(description = "收获仓库id", requiredMode = Schema.RequiredMode.REQUIRED, example = "27065")
@ExcelProperty("收获仓库id")
private Long warehouseId;
......
......@@ -29,6 +29,9 @@ public class CustomerOrderSaveReqVO {
@NotNull(message = "客户id不能为空")
private Long customerId;
@Schema(description = "灶点id")
private Long customerDeptId;
@Schema(description = "收获仓库id", requiredMode = Schema.RequiredMode.REQUIRED, example = "27065")
@NotNull(message = "收获仓库id不能为空")
private Long warehouseId;
......
......@@ -5,6 +5,7 @@ import cn.iocoder.foodnexus.module.product.api.dto.ProductInfo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import cn.idev.excel.annotation.*;
......@@ -57,6 +58,12 @@ public class CustomerOrderItemRespVO {
@ExcelProperty("订单商品总价,单位:分")
private Integer orderItemTotal;
@Schema(description = "市场价,单位使用:分")
private Integer marketPrice;
@Schema(description = "下浮率(%)")
private BigDecimal discount;
@Schema(description = "订单商品数量", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("订单商品数量")
private Integer orderItemQuantity;
......
......@@ -5,6 +5,7 @@ import cn.iocoder.foodnexus.framework.common.pojo.CommonResult;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpDeliveryStatus;
import cn.iocoder.foodnexus.module.erp.api.service.ErpSupplierApi;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.order.*;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO;
......@@ -15,13 +16,12 @@ import cn.iocoder.foodnexus.module.order.service.customerorder.CustomerOrderServ
import cn.iocoder.foodnexus.module.order.service.customerorderitem.CustomerOrderItemService;
import cn.iocoder.foodnexus.module.system.annotations.AppSystemAuth;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
......@@ -71,11 +71,27 @@ public class SupplierPurchaseOrderController {
orderPageReqVo.setPageNo(pageReqVO.getPageNo());
orderPageReqVo.setSupplierId(supplierApi.querySupplierIdByUserId(getLoginUserId()));
orderPageReqVo.setCreateMonth(pageReqVO.getMonth());
orderPageReqVo.setDeliveryStatus(CommonUtil.asList(ErpDeliveryStatus.ARRIVAL.getStatus(), ErpDeliveryStatus.RECONCILIATION.getStatus()));
PageResult<ErpPurchaseOrderDO> pageResult = purchaseOrderService.getPurchaseOrderPage(orderPageReqVo);
return success(BeanUtils.toBean(pageResult, SupplierMonthOrderDetailsRespVO.class, this::accept));
return success(BeanUtils.toBean(pageResult, SupplierMonthOrderDetailsRespVO.class, this::transform));
}
private void accept(SupplierMonthOrderDetailsRespVO purchaseOrder) {
@PostMapping("reconciliation")
@Operation(summary = "确认对账")
@Parameter(name = "month", description = "月份(yyyy-MM)", required = true)
public CommonResult<Boolean> reconciliation(@RequestParam("month") String month) {
ErpPurchaseOrderPageReqVO orderPageReqVo = new ErpPurchaseOrderPageReqVO();
orderPageReqVo.setPageSize(-1);
orderPageReqVo.setPageNo(1);
orderPageReqVo.setSupplierId(supplierApi.querySupplierIdByUserId(getLoginUserId()));
orderPageReqVo.setCreateMonth(month);
orderPageReqVo.setDeliveryStatus(CommonUtil.asList(ErpDeliveryStatus.ARRIVAL.getStatus(), ErpDeliveryStatus.RECONCILIATION.getStatus()));
PageResult<ErpPurchaseOrderDO> pageResult = purchaseOrderService.getPurchaseOrderPage(orderPageReqVo);
purchaseOrderService.reconciliation(pageResult.getList(), orderPageReqVo.getSupplierId());
return success(Boolean.TRUE);
}
private void transform(SupplierMonthOrderDetailsRespVO purchaseOrder) {
CustomerOrderDO customerOrder = customerOrderService.getCustomerOrder(purchaseOrder.getCustomerOrderId());
List<CustomerOrderItemDO> customerOrderItemDOS = customerOrderItemService.queryByOrderId(purchaseOrder.getCustomerOrderId(), purchaseOrder.getSupplierId());
purchaseOrder.setDeliveryMode(customerOrder.getDeliveryMode());
......
package cn.iocoder.foodnexus.module.order.controller.app.customerOrder;
import cn.iocoder.foodnexus.framework.common.enums.UserSystemEnum;
import cn.iocoder.foodnexus.framework.common.pojo.CommonResult;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.module.order.controller.app.customerOrder.vo.AppCustomerMonthOrderRespVO;
import cn.iocoder.foodnexus.module.order.controller.app.customerOrder.vo.AppCustomerMonthOrderTotalRespVO;
import cn.iocoder.foodnexus.module.order.controller.app.customerOrder.vo.AppCustomerOrderReconciliationReqVO;
import cn.iocoder.foodnexus.module.order.controller.app.customerOrder.vo.AppCustomerYearOrderPageReqVO;
import cn.iocoder.foodnexus.module.order.service.customerorder.CustomerOrderService;
import cn.iocoder.foodnexus.module.system.annotations.AppSystemAuth;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import static cn.iocoder.foodnexus.framework.common.pojo.CommonResult.success;
/**
* @author : yanghao
* create at: 2025/10/13 14:13
* @description: APP - 订单对账
*/
@Tag(name = "APP - 对账")
@RestController
@RequestMapping("/order/reconciliation")
@Validated
@AppSystemAuth(UserSystemEnum.CUSTOMER)
public class AppCustomerOrderReconciliationController {
@Autowired
private CustomerOrderService customerOrderService;
@GetMapping("/page-year")
@Operation(summary = "分页获取月度账单(按年份)")
public CommonResult<AppCustomerMonthOrderRespVO> pageYear(@Valid AppCustomerYearOrderPageReqVO reqVO) {
return success(customerOrderService.reconciliationPageYear(reqVO));
}
@GetMapping("/month-total")
@Operation(summary = "分页获取客户订单(按月份)")
@Parameter(name = "yearMonth", description = "年月(yyyy-MM)", required = true)
public CommonResult<AppCustomerMonthOrderTotalRespVO> monthTotal(@RequestParam("yearMonth") String yearMonth) {
return success(customerOrderService.monthTotal(yearMonth));
}
@PostMapping("/confirm")
@Operation(summary = "确认账单")
public CommonResult<Boolean> confirm(@Valid AppCustomerOrderReconciliationReqVO reqVO) {
customerOrderService.reconciliationConfirm(reqVO);
return success(Boolean.TRUE);
}
}
package cn.iocoder.foodnexus.module.order.controller.app.customerOrder.vo;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
/**
* @author : yanghao
* create at: 2025/10/13 14:19
* @description: APP - 用户订单按月汇总
*/
@Data
public class AppCustomerMonthOrderRespVO {
@Schema(description = "订单总数")
private Long orderCount;
@Schema(description = "订单总金额")
private BigDecimal orderAmount;
@Schema(description = "月份对账信息分页")
private PageResult<MonthItems> pageResult;
@Data
public static class MonthItems {
@Schema(description = "月份(yyyy年xx月)")
private String yearMonth;
@Schema(description = "订单总数")
private Long orderCount;
@Schema(description = "总金额(分)")
private BigDecimal orderAmount;
@Schema(description = "应对账总金额(分)")
private BigDecimal payableAmount;
@Schema(description = "状态(是否对账)")
private Boolean status;
}
}
package cn.iocoder.foodnexus.module.order.controller.app.customerOrder.vo;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* @author : yanghao
* create at: 2025/10/13 14:19
* @description: APP - 用户订单按月汇总
*/
@Data
public class AppCustomerMonthOrderTotalRespVO {
@Schema(description = "订单总数")
private Long orderCount;
@Schema(description = "订单总金额")
private Double orderAmount;
}
......@@ -7,6 +7,8 @@ import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 客户订单-子订单新增/修改 Request VO")
@Data
public class AppCustomerOrderItemSaveReqVO {
......@@ -21,6 +23,12 @@ public class AppCustomerOrderItemSaveReqVO {
@Schema(description = "订单商品总价,单位:分", hidden = true)
private Integer orderItemTotal;
@Schema(description = "市场价,单位使用:分")
private Integer marketPrice;
@Schema(description = "下浮率(%)")
private BigDecimal discount;
@Schema(description = "订单商品数量", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "订单商品数量不能为空")
@Min(value = 1, message = "订单商品数量不能小于1")
......
package cn.iocoder.foodnexus.module.order.controller.app.customerOrder.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.util.List;
/**
* @author : yanghao
* create at: 2025/10/13 15:11
* @description: 客户对账确认订单
*/
@Data
public class AppCustomerOrderReconciliationReqVO {
@Schema(description = "ids", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,2]")
@NotNull(message = "ids不能为空")
@Size(min = 1, message = "ids不能为空")
private List<Long> ids;
}
package cn.iocoder.foodnexus.module.order.controller.app.customerOrder.vo;
import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* @author : yanghao
* create at: 2025/10/13 14:16
* @description:
*/
@Data
public class AppCustomerYearOrderPageReqVO extends PageParam {
@Schema(description = "年份(yyyy)")
@NotNull(message = "年份不能为空")
private String year;
/*@Schema(description = "月份(1-12)")
@Max(value = 12, message = "异常月份")
@Min(value = 1, message = "异常月份")
private Integer month;*/
}
......@@ -48,6 +48,10 @@ public class CustomerOrderDO extends BaseDO {
*/
private Long customerId;
/**
* 灶点id
*/
private Long customerDeptId;
/**
* 收获仓库id
*/
private Long warehouseId;
......
......@@ -7,6 +7,8 @@ import lombok.*;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.foodnexus.framework.mybatis.core.dataobject.BaseDO;
import java.math.BigDecimal;
/**
* 客户订单-子订单 DO
*
......@@ -65,6 +67,14 @@ public class CustomerOrderItemDO extends BaseDO {
*/
private Integer orderItemTotal;
/**
* 市场价,单位使用:分
*/
private Integer marketPrice;
/**
* 下浮率(%)
*/
private BigDecimal discount;
/**
* 订单商品数量
*/
private Integer orderItemQuantity;
......
......@@ -3,11 +3,18 @@ package cn.iocoder.foodnexus.module.order.dal.mysql.customerorder;
import java.util.*;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.foodnexus.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.foodnexus.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO;
import cn.iocoder.foodnexus.module.order.controller.app.customerOrder.vo.AppCustomerMonthOrderRespVO;
import cn.iocoder.foodnexus.module.order.controller.app.customerOrder.vo.AppCustomerMonthOrderTotalRespVO;
import cn.iocoder.foodnexus.module.order.controller.app.customerOrder.vo.AppCustomerYearOrderPageReqVO;
import cn.iocoder.foodnexus.module.order.dal.dataobject.customerorder.CustomerOrderDO;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.yulichang.query.MPJQueryWrapper;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.foodnexus.module.order.controller.admin.customerorder.vo.*;
......@@ -20,7 +27,7 @@ import cn.iocoder.foodnexus.module.order.controller.admin.customerorder.vo.*;
public interface CustomerOrderMapper extends BaseMapperX<CustomerOrderDO> {
default PageResult<CustomerOrderDO> selectPage(CustomerOrderPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<CustomerOrderDO>()
LambdaQueryWrapperX<CustomerOrderDO> queryWrapperX = new LambdaQueryWrapperX<CustomerOrderDO>()
.inIfPresent(CustomerOrderDO::getId, reqVO.getIds())
.eqIfPresent(CustomerOrderDO::getCode, reqVO.getCode())
.eqIfPresent(CustomerOrderDO::getOrderStatus, reqVO.getOrderStatus())
......@@ -39,7 +46,21 @@ public interface CustomerOrderMapper extends BaseMapperX<CustomerOrderDO> {
.eqIfPresent(CustomerOrderDO::getOperCompany, reqVO.getOperCompany())
.betweenIfPresent(CustomerOrderDO::getCreateTime, reqVO.getCreateTime())
.eqIfPresent(CustomerOrderDO::getCreator, reqVO.getCreator())
.orderByDesc(CustomerOrderDO::getId));
.orderByDesc(CustomerOrderDO::getId);
if (CommonUtil.isNotBlank(reqVO.getCreateYearMonth())) {
String createMonth = reqVO.getCreateYearMonth().trim();
String startOfMonth = createMonth + "-01 00:00:00";
String[] parts = createMonth.split("-");
int year = Integer.parseInt(parts[0]);
int nextMonth = Integer.parseInt(parts[1]) + 1;
String endOfMonth = nextMonth > 12 ?
(year + 1) + "-01-01 00:00:00" :
year + "-" + (nextMonth < 10 ? "0" + nextMonth : nextMonth) + "-01 00:00:00";
queryWrapperX.ge(CustomerOrderDO::getCreateTime, startOfMonth)
.lt(CustomerOrderDO::getCreateTime, endOfMonth);
}
return selectPage(reqVO, queryWrapperX);
}
default List<Map<String, Object>> queryStatusCount(Long loginUserId) {
......@@ -49,4 +70,51 @@ public interface CustomerOrderMapper extends BaseMapperX<CustomerOrderDO> {
queryWrapper.groupBy("order_status");
return this.selectMaps(queryWrapper);
}
default AppCustomerMonthOrderRespVO reconciliationPageYearTotal(String year) {
year = year.trim();
String begin = year + "-01-01 00:00:00";
String end = year + "-12-31 23:59:59";
MPJQueryWrapper<CustomerOrderDO> queryWrapperX = new MPJQueryWrapper<>();
queryWrapperX.select("count(*) as 'orderCount',SUM(order_amount) as 'orderAmount'");
queryWrapperX.between("create_time", begin, end);
queryWrapperX.in("order_status", CommonUtil.asList(CustomerOrderStatus.SIGN_RECEIPT.getKey(),
CustomerOrderStatus.FINISH.getKey()));
return this.selectJoinOne(AppCustomerMonthOrderRespVO.class, queryWrapperX);
}
default PageResult<AppCustomerMonthOrderRespVO.MonthItems> reconciliationPageYearPage(AppCustomerYearOrderPageReqVO reqVO) {
String year = reqVO.getYear();
String begin = year + "-01-01 00:00:00";
String end = year + "-12-31 23:59:59";
MPJQueryWrapper<CustomerOrderDO> queryWrapperX = new MPJQueryWrapper<>();
queryWrapperX.select("DATE_FORMAT(create_time, '%Y年%m月') as 'yearMonth',count(*) as 'orderCount',SUM(order_amount) as 'orderAmount',SUM(actual_amount) as 'payableAmount'");
queryWrapperX.select("CASE WHEN SUM(CASE WHEN order_status='SIGN_RECEIPT' THEN 1 ELSE 0 END)> 0 THEN 0 ELSE 1 END AS 'status'");
queryWrapperX.between("create_time", begin, end);
queryWrapperX.in("order_status", CommonUtil.asList(CustomerOrderStatus.SIGN_RECEIPT.getKey(),
CustomerOrderStatus.FINISH.getKey()));
queryWrapperX.groupBy("DATE_FORMAT(create_time, '%Y-%m') ");
queryWrapperX.orderByDesc("id");
return this.selectJoinPage(reqVO, AppCustomerMonthOrderRespVO.MonthItems.class, queryWrapperX);
}
default AppCustomerMonthOrderTotalRespVO reconciliationMonthTotal(String yearMonth) {
String createMonth = yearMonth.trim();
String startOfMonth = createMonth + "-01 00:00:00";
String[] parts = createMonth.split("-");
int year = Integer.parseInt(parts[0]);
int nextMonth = Integer.parseInt(parts[1]) + 1;
String endOfMonth = nextMonth > 12 ?
(year + 1) + "-01-01 00:00:00" :
year + "-" + (nextMonth < 10 ? "0" + nextMonth : nextMonth) + "-01 00:00:00";
MPJQueryWrapper<CustomerOrderDO> queryWrapperX = new MPJQueryWrapper<>();
queryWrapperX.select("count(*) as 'orderCount',SUM(order_amount) as 'orderAmount'");
queryWrapperX.between("create_time", startOfMonth, endOfMonth);
queryWrapperX.in("order_status", CommonUtil.asList(CustomerOrderStatus.SIGN_RECEIPT.getKey(),
CustomerOrderStatus.FINISH.getKey()));
queryWrapperX.orderByDesc("id");
return this.selectJoinOne(AppCustomerMonthOrderTotalRespVO.class, queryWrapperX);
}
}
\ No newline at end of file
......@@ -115,4 +115,20 @@ public interface CustomerOrderService {
void score(AppCustomerOrderScoreReqVO reqVO);
Map<String, Long> queryStatusCount(Long loginUserId);
/**
* 分页获取月度账单
* @param reqVO
* @return
*/
AppCustomerMonthOrderRespVO reconciliationPageYear(AppCustomerYearOrderPageReqVO reqVO);
/**
* 月订单汇总
* @param yearMonth
* @return
*/
AppCustomerMonthOrderTotalRespVO monthTotal(String yearMonth);
void reconciliationConfirm(AppCustomerOrderReconciliationReqVO reqVO);
}
\ No newline at end of file
......@@ -40,6 +40,8 @@ import cn.iocoder.foodnexus.module.product.api.InquireCustomerApi;
import cn.iocoder.foodnexus.module.product.api.dto.CustomerVisibleProductRespDTO;
import cn.iocoder.foodnexus.module.product.api.dto.ProductInfo;
import cn.iocoder.foodnexus.module.product.service.spu.ProductSpuService;
import cn.iocoder.foodnexus.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.foodnexus.module.system.service.user.AdminUserService;
import cn.iocoder.foodnexus.module.system.util.GenCodeUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -130,6 +132,9 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
private OrderScoreService orderScoreService;
@Autowired
private AdminUserService userService;
@Autowired
private GenCodeUtils genCodeUtils;
@Override
......@@ -204,6 +209,8 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
CustomerVisibleProductRespDTO.CustomerProduct customerProduct = customerProductMap.get(item.getProductId());
item.setOrderItemPrice(customerProduct.getSupplierQuote());
item.setOrderItemTotal(customerProduct.getSupplierQuote() * item.getOrderItemQuantity());
item.setMarketPrice(customerProduct.getMarketPrice());
item.setDiscount(customerProduct.getFloatingRate());
InquireSupplierPushDO inquireSupplierPush = inquireSupplierPushService.getInquireSupplierPush(customerProduct.getInquireSupplierId());
procuctSet.add(inquireSupplierPush.getProductId());
......@@ -218,6 +225,8 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
createOrder.setCode(genCodeUtils.createAmBatch("XS"));
createOrder.setOrderStatus(CustomerOrderStatus.ORDER_SUCCESS);
createOrder.setCustomerId(customerId);
AdminUserDO user = userService.getUser(loginUser.getId());
createOrder.setCustomerDeptId(user.getDeptId());
createOrder.setWarehouseInfo(warehouseApi.getInfoByWarehouseAreaId(createOrder.getWarehouseAreaId()));
createOrder.setAddressInfo(BeanUtils.toBean(addressService.getCustomerAddress(createReqVO.getAddressId()), CustomerAddressInfo.class));
createOrder.setSupplierCount(supplierSet.size());
......@@ -336,6 +345,7 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
Map<Long, ErpSaleOutItemDO> productMap = CommonUtil.listConvertMap(saleOutItems, ErpSaleOutItemDO::getProductId);
List<CustomerOrderItemDO> updateBatch = new ArrayList<>();
AtomicReference<Integer> actualAmount = new AtomicReference<>(0);
customerOrderItems.forEach(customerOrderItem -> {
CustomerOrderItemDO updateItem = new CustomerOrderItemDO();
updateItem.setId(customerOrderItem.getId());
......@@ -353,10 +363,16 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
updateItem.setSignedQuantity(customerOrderItem.getOrderItemQuantity());
}
updateItem.setSignedTotal(updateItem.getSignedQuantity() * customerOrderItem.getOrderItemPrice());
actualAmount.updateAndGet(v -> v + updateItem.getSignedTotal());
updateBatch.add(updateItem);
});
customerOrderItemMapper.updateBatch(updateBatch);
// 更新实际支付金额
CustomerOrderDO updateOrder = new CustomerOrderDO();
updateOrder.setId(customerOrder.getId());
updateOrder.setActualAmount(actualAmount.get());
customerOrderMapper.updateById(updateOrder);
// 订单记录
CustomerOrderRecordEvent event = new CustomerOrderRecordEvent();
......@@ -529,7 +545,7 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
.set(CustomerOrderDO::getOrderRemark, reqVO.getOrderRemark()));
}
// 订单记录
// TODO 待替换 订单记录
CustomerOrderRecordEvent event = new CustomerOrderRecordEvent();
event.setOrderStatus(CustomerOrderStatus.FINISH);
event.setCustomerOrderId(id);
......@@ -549,6 +565,50 @@ public class CustomerOrderServiceImpl implements CustomerOrderService, CustomerO
}
/**
* 分页获取月度账单
*
* @param reqVO
* @return
*/
@Override
public AppCustomerMonthOrderRespVO reconciliationPageYear(AppCustomerYearOrderPageReqVO reqVO) {
AppCustomerMonthOrderRespVO respVO = customerOrderMapper.reconciliationPageYearTotal(reqVO.getYear());
if (CommonUtil.isNotEmpty(respVO)) {
respVO.setPageResult(customerOrderMapper.reconciliationPageYearPage(reqVO));
}
return respVO;
}
/**
* 月订单汇总
*
* @param yearMonth
* @return
*/
@Override
public AppCustomerMonthOrderTotalRespVO monthTotal(String yearMonth) {
return customerOrderMapper.reconciliationMonthTotal(yearMonth);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void reconciliationConfirm(AppCustomerOrderReconciliationReqVO reqVO) {
reqVO.getIds().forEach(id -> {
CustomerOrderDO customerOrder = getCustomerOrder(id);
if (CommonUtil.isEmpty(customerOrder)) {
throw exception(CUSTOMER_ORDER_NOT_EXISTS);
}
if (CustomerOrderStatus.SIGN_RECEIPT.equals(customerOrder.getOrderStatus())) {
// 订单记录
CustomerOrderRecordEvent event = new CustomerOrderRecordEvent();
event.setOrderStatus(CustomerOrderStatus.FINISH);
event.setCustomerOrderId(id);
orderRecordApi.recordEvent(event);
}
});
}
/**
* {@link ErpPurchaseOrderServiceImpl#orderSplit(PurchaseOrderSplitEvent)}
*/
private void orderSplitPurchase(Long customerOrderId) {
......
......@@ -5,6 +5,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
......@@ -42,10 +43,19 @@ public class CustomerVisibleProductRespDTO implements Serializable {
*/
private Integer supplierQuote;
/**
* 市场价,单位使用:分
*/
private Integer marketPrice;
/**
* 下浮率(%)
*/
private BigDecimal floatingRate;
}
public void put(Long inquireSupplierId, Long productId, Integer supplierQuote) {
this.items.add(new CustomerProduct(inquireSupplierId, productId, supplierQuote));
public void put(Long inquireSupplierId, Long productId, Integer supplierQuote, Integer marketPrice, BigDecimal floatingRate) {
this.items.add(new CustomerProduct(inquireSupplierId, productId, supplierQuote, marketPrice, floatingRate));
}
}
......@@ -112,6 +112,6 @@ public interface RedisKeyConstants {
* KEY:{customerId}
* VALUE 客户id
*/
String CUSTOMER_VISIBLE_PRODUCT = "customer_visible_product";
String CUSTOMER_VISIBLE_PRODUCT = "customer_visible_products";
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment