From e409437714663a35aa186ee2be204c217cbbb9ea Mon Sep 17 00:00:00 2001 From: "zangch@mesnac.com" Date: Tue, 28 Oct 2025 16:57:41 +0800 Subject: [PATCH] =?UTF-8?q?feat(oa/crm):=20=E6=96=B0=E5=A2=9E=E6=8A=A5?= =?UTF-8?q?=E4=BB=B7=E5=8D=95=E4=BF=A1=E6=81=AF=E7=AE=A1=E7=90=86=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增报价单信息实体类 CrmQuoteInfo 及其业务对象 CrmQuoteInfoBo - 新增报价单信息控制器 CrmQuoteInfoController,支持增删改查及导出功能 - 新增报价单信息 Mapper 接口及 XML 映射文件,实现数据持久化操作 - 新增报价单信息服务实现类 CrmQuoteInfoServiceImpl,包含完整的业务逻辑处理- 支持报价单分页查询、详情查看、多轮报价查询及金额汇总计算功能 - 提供报价单子表物料明细的关联保存与更新逻辑 - 实现客户方与供货方联系人的关联查询展示- 添加权限控制注解,确保接口访问安全 - 支持报价单导出为 Excel 文件功能 - 支持根据报价单 ID 进行删除及批量删除操作 - 添加重复提交限制注解,防止重复新增或修改 - 新增报价单打印模板及附件存储字段支持 - 实现报价单状态及流程状态字段管理 - 添加报价单编号、名称、类别等基础信息维护功能 - 支持币种、税率、含税信息配置及相关金额字段计算- 实现报价有效期、交付方式、付款方式等相关业务字段管理- 提供客户及供应商联系人信息快速录入与展示功能- 新增报价单备注信息及创建/更新时间追踪功能 - 使用 MyBatis Plus 实现高效的数据访问层封装 - 利用 MapStruct 实现实体与 BO 对象之间的转换 - 添加事务管理以确保主子表数据一致性- 引入参数校验机制保障数据合法性 - 支持通过报价单号或名称进行模糊搜索查询 - 新增报价单轮次管理和相同报价历史追溯功能 --- .../controller/CrmQuoteInfoController.java | 133 ++++++ .../CrmQuoteMaterialController.java | 117 ++++++ .../dromara/oa/crm/domain/CrmQuoteInfo.java | 235 +++++++++++ .../oa/crm/domain/CrmQuoteMaterial.java | 116 ++++++ .../oa/crm/domain/bo/CrmQuoteInfoBo.java | 212 ++++++++++ .../oa/crm/domain/bo/CrmQuoteMaterialBo.java | 105 +++++ .../oa/crm/domain/vo/CrmQuoteInfoVo.java | 274 +++++++++++++ .../oa/crm/domain/vo/CrmQuoteMaterialVo.java | 141 +++++++ .../oa/crm/mapper/CrmQuoteInfoMapper.java | 114 ++++++ .../oa/crm/mapper/CrmQuoteMaterialMapper.java | 114 ++++++ .../oa/crm/service/ICrmQuoteInfoService.java | 78 ++++ .../crm/service/ICrmQuoteMaterialService.java | 68 ++++ .../service/impl/CrmQuoteInfoServiceImpl.java | 324 +++++++++++++++ .../impl/CrmQuoteMaterialServiceImpl.java | 151 +++++++ .../mapper/oa/crm/CrmQuoteInfoMapper.xml | 381 ++++++++++++++++++ .../mapper/oa/crm/CrmQuoteMaterialMapper.xml | 241 +++++++++++ 16 files changed, 2804 insertions(+) create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/controller/CrmQuoteInfoController.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/controller/CrmQuoteMaterialController.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/CrmQuoteInfo.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/CrmQuoteMaterial.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/bo/CrmQuoteInfoBo.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/bo/CrmQuoteMaterialBo.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/vo/CrmQuoteInfoVo.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/vo/CrmQuoteMaterialVo.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/mapper/CrmQuoteInfoMapper.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/mapper/CrmQuoteMaterialMapper.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/ICrmQuoteInfoService.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/ICrmQuoteMaterialService.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/impl/CrmQuoteInfoServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/impl/CrmQuoteMaterialServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/crm/CrmQuoteInfoMapper.xml create mode 100644 ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/crm/CrmQuoteMaterialMapper.xml diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/controller/CrmQuoteInfoController.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/controller/CrmQuoteInfoController.java new file mode 100644 index 00000000..2a81e939 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/controller/CrmQuoteInfoController.java @@ -0,0 +1,133 @@ +package org.dromara.oa.crm.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.oa.crm.domain.bo.CrmQuoteInfoBo; +import org.dromara.oa.crm.domain.vo.CrmQuoteInfoVo; +import org.dromara.oa.crm.service.ICrmQuoteInfoService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 报价单信息 + * 前端访问路由地址为:/oa/crm/crmQuoteInfo + * + * @author Yinq + * @date 2025-10-28 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/crm/crmQuoteInfo") +public class CrmQuoteInfoController extends BaseController { + + private final ICrmQuoteInfoService crmQuoteInfoService; + + /** + * 查询报价单信息列表 + */ + @SaCheckPermission("oa/crm:crmQuoteInfo:list") + @GetMapping("/list") + public TableDataInfo list(CrmQuoteInfoBo bo, PageQuery pageQuery) { + return crmQuoteInfoService.queryPageList(bo, pageQuery); + } + + /** + * 导出报价单信息列表 + */ + @SaCheckPermission("oa/crm:crmQuoteInfo:export") + @Log(title = "报价单信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(CrmQuoteInfoBo bo, HttpServletResponse response) { + List list = crmQuoteInfoService.queryList(bo); + ExcelUtil.exportExcel(list, "报价单信息", CrmQuoteInfoVo.class, response); + } + + /** + * 获取报价单信息详细信息 + * + * @param quoteId 主键 + */ + @SaCheckPermission("oa/crm:crmQuoteInfo:query") + @GetMapping("/{quoteId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable("quoteId") Long quoteId) { + return R.ok(crmQuoteInfoService.queryById(quoteId)); + } + + /** + * 新增报价单信息 + */ + @SaCheckPermission("oa/crm:crmQuoteInfo:add") + @Log(title = "报价单信息", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody CrmQuoteInfoBo bo) { + return toAjax(crmQuoteInfoService.insertByBo(bo)); + } + + /** + * 修改报价单信息 + */ + @SaCheckPermission("oa/crm:crmQuoteInfo:edit") + @Log(title = "报价单信息", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody CrmQuoteInfoBo bo) { + return toAjax(crmQuoteInfoService.updateByBo(bo)); + } + + /** + * 删除报价单信息 + * + * @param quoteIds 主键串 + */ + @SaCheckPermission("oa/crm:crmQuoteInfo:remove") + @Log(title = "报价单信息", businessType = BusinessType.DELETE) + @DeleteMapping("/{quoteIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable("quoteIds") Long[] quoteIds) { + return toAjax(crmQuoteInfoService.deleteWithValidByIds(List.of(quoteIds), true)); + } + + /** + * 下拉框查询报价单信息列表 + */ + @GetMapping("/getCrmQuoteInfoList") + public R> getCrmQuoteInfoList(CrmQuoteInfoBo bo) { + List list = crmQuoteInfoService.queryList(bo); + return R.ok(list); + } + + /** + * 查看同一次的多轮报价集合(同一客户 + 相同报价单名称) + */ + @GetMapping("/rounds/{quoteId}") + public R> listRounds(@PathVariable("quoteId") Long quoteId) { + return R.ok(crmQuoteInfoService.listRoundsByQuoteId(quoteId)); + } + + /** + * 根据报价明细回写主表金额汇总 + */ + @PostMapping("/recalc/{quoteId}") + public R recalcTotals(@PathVariable("quoteId") Long quoteId) { + return R.ok(crmQuoteInfoService.recalcTotals(quoteId)); + } + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/controller/CrmQuoteMaterialController.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/controller/CrmQuoteMaterialController.java new file mode 100644 index 00000000..cf6696e9 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/controller/CrmQuoteMaterialController.java @@ -0,0 +1,117 @@ +package org.dromara.oa.crm.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.oa.crm.domain.bo.CrmQuoteMaterialBo; +import org.dromara.oa.crm.domain.vo.CrmQuoteMaterialVo; +import org.dromara.oa.crm.service.ICrmQuoteMaterialService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 报价单物料明细 + * 前端访问路由地址为:/oa/crm/crmQuoteMaterial + * + * @author Yinq + * @date 2025-10-28 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/crm/crmQuoteMaterial") +public class CrmQuoteMaterialController extends BaseController { + + private final ICrmQuoteMaterialService crmQuoteMaterialService; + + /** + * 查询报价单物料明细列表 + */ + @SaCheckPermission("oa/crm:crmQuoteMaterial:list") + @GetMapping("/list") + public TableDataInfo list(CrmQuoteMaterialBo bo, PageQuery pageQuery) { + return crmQuoteMaterialService.queryPageList(bo, pageQuery); + } + + /** + * 导出报价单物料明细列表 + */ + @SaCheckPermission("oa/crm:crmQuoteMaterial:export") + @Log(title = "报价单物料明细", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(CrmQuoteMaterialBo bo, HttpServletResponse response) { + List list = crmQuoteMaterialService.queryList(bo); + ExcelUtil.exportExcel(list, "报价单物料明细", CrmQuoteMaterialVo.class, response); + } + + /** + * 获取报价单物料明细详细信息 + * + * @param quoteMaterialId 主键 + */ + @SaCheckPermission("oa/crm:crmQuoteMaterial:query") + @GetMapping("/{quoteMaterialId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable("quoteMaterialId") Long quoteMaterialId) { + return R.ok(crmQuoteMaterialService.queryById(quoteMaterialId)); + } + + /** + * 新增报价单物料明细 + */ + @SaCheckPermission("oa/crm:crmQuoteMaterial:add") + @Log(title = "报价单物料明细", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody CrmQuoteMaterialBo bo) { + return toAjax(crmQuoteMaterialService.insertByBo(bo)); + } + + /** + * 修改报价单物料明细 + */ + @SaCheckPermission("oa/crm:crmQuoteMaterial:edit") + @Log(title = "报价单物料明细", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody CrmQuoteMaterialBo bo) { + return toAjax(crmQuoteMaterialService.updateByBo(bo)); + } + + /** + * 删除报价单物料明细 + * + * @param quoteMaterialIds 主键串 + */ + @SaCheckPermission("oa/crm:crmQuoteMaterial:remove") + @Log(title = "报价单物料明细", businessType = BusinessType.DELETE) + @DeleteMapping("/{quoteMaterialIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable("quoteMaterialIds") Long[] quoteMaterialIds) { + return toAjax(crmQuoteMaterialService.deleteWithValidByIds(List.of(quoteMaterialIds), true)); + } + + /** + * 下拉框查询报价单物料明细列表 + */ + @GetMapping("/getCrmQuoteMaterialList") + public R> getCrmQuoteMaterialList(CrmQuoteMaterialBo bo) { + List list = crmQuoteMaterialService.queryList(bo); + return R.ok(list); + } + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/CrmQuoteInfo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/CrmQuoteInfo.java new file mode 100644 index 00000000..b8d5e983 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/CrmQuoteInfo.java @@ -0,0 +1,235 @@ +package org.dromara.oa.crm.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.tenant.core.TenantEntity; + +import java.io.Serial; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * 报价单信息对象 crm_quote_info + * + * @author Yinq + * @date 2025-10-28 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("crm_quote_info") +public class CrmQuoteInfo extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 报价ID + */ + @TableId(value = "quote_id", type = IdType.ASSIGN_ID) + private Long quoteId; + + /** + * 报价单号 + */ + private String quoteCode; + + /** + * 报价单名称 + */ + private String quoteName; + + /** + * 报价轮次 + */ + private Long quoteRound; + + /** + * 报价大类(1橡机板块 2非橡机板块) + */ + private String quoteCategory; + + /** + * 报价类型(1对内 2对外) + */ + private String quoteType; + + /** + * 业务方向(1智能轮胎 2轮胎工厂 3快递物流 4锂电 5工业软件 6智能制造 7新行业及零售) + */ + private String businessDirection; + + /** + * 部门 + */ + private Long quoteDeptId; + + /** + * 报价日期 + */ + private Date quoteDate; + + /** + * 报价有效期起 + */ + private Date validFrom; + + /** + * 报价有效期(天) + */ + private Long validDays; + + /** + * 报价有效期止 + */ + private Date validTo; + + /** + * 交货期(天) + */ + private Long deliveryPeriod; + + /** + * 交付/交货方式 + */ + private String deliveryMethod; + + /** + * 付款方式(1电汇 2承兑) + */ + private String paymentMethod; + + /** + * 币种(字典类型) + */ + private String currencyType; + + /** + * 含税信息(如:含13%增值税) + */ + private String taxIncludedInfo; + + /** + * 税率(默认按明细可覆盖) + */ + private BigDecimal taxRate; + + /** + * 总报价 + */ + private BigDecimal totalPrice; + + /** + * 未税总价 + */ + private BigDecimal totalBeforeTax; + + /** + * 税额 + */ + private BigDecimal totalTax; + + /** + * 含税总价 + */ + private BigDecimal totalIncludingTax; + + /** + * 客户方联系人ID + */ + private Long customerContactId; + + /** + * 客户方联系人 + */ + private String customerContactName; + + /** + * 客户方联系电话 + */ + private String customerContactPhone; + + /** + * 客户方电子邮箱 + */ + private String customerContactEmail; + + /** + * 供货方联系人ID + */ + private Long supplierContactId; + + /** + * 供货方联系人 + */ + private String supplierContactName; + + /** + * 供货方联系电话 + */ + private String supplierContactPhone; + + /** + * 供货方电子邮箱 + */ + private String supplierContactEmail; + + /** + * 项目ID(可选) + */ + private Long projectId; + + /** + * 打印模板ID(可选) + */ + private Long templateId; + + /** + * 附件ID + */ + private String ossId; + + /** + * 报价单状态(1暂存 2审批中 3可用) + */ + private String quoteStatus; + + /** + * 流程状态 + */ + private String flowStatus; + + /** + * 备注 + */ + private String remark; + + /** + * 删除标志(0存在 1删除) + */ + @TableLogic + private String delFlag; + + + /** + * 客户方联系人真实名称(从 CrmCustomerContact 关联得到,不落库) + */ + @TableField(exist = false) + private String customerContactRealName; + + /** + * 供货方联系人真实名称(从 CrmCustomerContact 关联得到,不落库) + */ + @TableField(exist = false) + private String supplierContactRealName; + + + /** + * 报价单子表-物料明细 + */ + @TableField(exist = false) + private List items; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/CrmQuoteMaterial.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/CrmQuoteMaterial.java new file mode 100644 index 00000000..8730cf1e --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/CrmQuoteMaterial.java @@ -0,0 +1,116 @@ +package org.dromara.oa.crm.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.tenant.core.TenantEntity; + +import java.io.Serial; +import java.math.BigDecimal; + +/** + * 报价单物料明细对象 crm_quote_material + * + * @author Yinq + * @date 2025-10-28 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("crm_quote_material") +public class CrmQuoteMaterial extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 报价物料ID + */ + @TableId(value = "quote_material_id", type = IdType.AUTO) + private Long quoteMaterialId; + + /** + * 报价ID + */ + private Long quoteId; + + /** + * 序号(ERP风格) + */ + private Long itemNo; + + /** + * 产品/服务名称 + */ + private String productName; + + /** + * 规格描述 + */ + private String specificationDescription; + + /** + * 物料ID(SAP) + */ + private Long materialId; + + /** + * 销售物料ID(关联名) + */ + private Long relationMaterialId; + + /** + * 数量 + */ + private BigDecimal amount; + + /** + * 单位ID + */ + private Long unitId; + + /** + * 单位名称 + */ + private String unitName; + + /** + * 未税单价 + */ + private BigDecimal beforePrice; + + /** + * 税率 + */ + private BigDecimal taxRate; + + /** + * 含税单价 + */ + private BigDecimal includingPrice; + + /** + * 小计(含税) + */ + private BigDecimal subtotal; + + /** + * 备注 + */ + private String remark; + + /** + * 激活标识(1是 0否) + */ + private String activeFlag; + + /** + * 删除标志(0存在 1删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/bo/CrmQuoteInfoBo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/bo/CrmQuoteInfoBo.java new file mode 100644 index 00000000..2990d802 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/bo/CrmQuoteInfoBo.java @@ -0,0 +1,212 @@ +package org.dromara.oa.crm.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.oa.crm.domain.CrmQuoteInfo; + +import java.util.Date; +import java.math.BigDecimal; +import java.util.List; + +/** + * 报价单信息业务对象 crm_quote_info + * + * @author Yinq + * @date 2025-10-28 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = CrmQuoteInfo.class, reverseConvertGenerate = false) +public class CrmQuoteInfoBo extends BaseEntity { + + /** + * 报价ID + */ + @NotNull(message = "报价ID不能为空", groups = { EditGroup.class }) + private Long quoteId; + + /** + * 报价单号 + */ + private String quoteCode; + + /** + * 报价单名称 + */ + private String quoteName; + + /** + * 报价轮次 + */ + private Long quoteRound; + + /** + * 报价大类(1橡机板块 2非橡机板块) + */ + private String quoteCategory; + + /** + * 报价类型(1对内 2对外) + */ + private String quoteType; + + /** + * 业务方向(1智能轮胎 2轮胎工厂 3快递物流 4锂电 5工业软件 6智能制造 7新行业及零售) + */ + private String businessDirection; + + /** + * 部门 + */ + private Long quoteDeptId; + + /** + * 报价日期 + */ + private Date quoteDate; + + /** + * 报价有效期起 + */ + private Date validFrom; + + /** + * 报价有效期(天) + */ + private Long validDays; + + /** + * 报价有效期止 + */ + private Date validTo; + + /** + * 交货期(天) + */ + private Long deliveryPeriod; + + /** + * 交付/交货方式 + */ + private String deliveryMethod; + + /** + * 付款方式(1电汇 2承兑) + */ + private String paymentMethod; + + /** + * 币种(字典类型) + */ + private String currencyType; + + /** + * 含税信息(如:含13%增值税) + */ + private String taxIncludedInfo; + + /** + * 税率(默认按明细可覆盖) + */ + private BigDecimal taxRate; + + /** + * 总报价 + */ + private BigDecimal totalPrice; + + /** + * 未税总价 + */ + private BigDecimal totalBeforeTax; + + /** + * 税额 + */ + private BigDecimal totalTax; + + /** + * 含税总价 + */ + private BigDecimal totalIncludingTax; + + /** + * 客户方联系人ID + */ + private Long customerContactId; + + /** + * 客户方联系人 + */ + private String customerContactName; + + /** + * 客户方联系电话 + */ + private String customerContactPhone; + + /** + * 客户方电子邮箱 + */ + private String customerContactEmail; + + /** + * 供货方联系人ID + */ + private Long supplierContactId; + + /** + * 供货方联系人 + */ + private String supplierContactName; + + /** + * 供货方联系电话 + */ + private String supplierContactPhone; + + /** + * 供货方电子邮箱 + */ + private String supplierContactEmail; + + /** + * 项目ID(可选) + */ + private Long projectId; + + /** + * 打印模板ID(可选) + */ + private Long templateId; + + /** + * 附件ID + */ + private String ossId; + + /** + * 报价单状态(1暂存 2审批中 3可用) + */ + private String quoteStatus; + + /** + * 流程状态 + */ + private String flowStatus; + + /** + * 备注 + */ + private String remark; + + /** + * 报价单子表-物料明细 + */ + private List itemsBo; + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/bo/CrmQuoteMaterialBo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/bo/CrmQuoteMaterialBo.java new file mode 100644 index 00000000..89e9b33a --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/bo/CrmQuoteMaterialBo.java @@ -0,0 +1,105 @@ +package org.dromara.oa.crm.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.oa.crm.domain.CrmQuoteMaterial; +import java.math.BigDecimal; + +/** + * 报价单物料明细业务对象 crm_quote_material + * + * @author Yinq + * @date 2025-10-28 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = CrmQuoteMaterial.class, reverseConvertGenerate = false) +public class CrmQuoteMaterialBo extends BaseEntity { + + /** + * 报价物料ID + */ + @NotNull(message = "报价物料ID不能为空", groups = { EditGroup.class }) + private Long quoteMaterialId; + + /** + * 报价ID + */ + private Long quoteId; + + /** + * 序号(ERP风格) + */ + private Long itemNo; + + /** + * 产品/服务名称 + */ + private String productName; + + /** + * 规格描述 + */ + private String specificationDescription; + + /** + * 物料ID(SAP) + */ + private Long materialId; + + /** + * 销售物料ID(关联名) + */ + private Long relationMaterialId; + + /** + * 数量 + */ + private BigDecimal amount; + + /** + * 单位ID + */ + private Long unitId; + + /** + * 单位名称 + */ + private String unitName; + + /** + * 未税单价 + */ + private BigDecimal beforePrice; + + /** + * 税率 + */ + private BigDecimal taxRate; + + /** + * 含税单价 + */ + private BigDecimal includingPrice; + + /** + * 小计(含税) + */ + private BigDecimal subtotal; + + /** + * 备注 + */ + private String remark; + + /** + * 激活标识(1是 0否) + */ + private String activeFlag; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/vo/CrmQuoteInfoVo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/vo/CrmQuoteInfoVo.java new file mode 100644 index 00000000..fefe3fd9 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/vo/CrmQuoteInfoVo.java @@ -0,0 +1,274 @@ +package org.dromara.oa.crm.domain.vo; + +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.oa.crm.domain.CrmQuoteInfo; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + + + +/** + * 报价单信息视图对象 crm_quote_info + * + * @author Yinq + * @date 2025-10-28 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = CrmQuoteInfo.class) +public class CrmQuoteInfoVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 报价ID + */ + @ExcelProperty(value = "报价ID") + private Long quoteId; + + /** + * 报价单号 + */ + @ExcelProperty(value = "报价单号") + private String quoteCode; + + /** + * 报价单名称 + */ + @ExcelProperty(value = "报价单名称") + private String quoteName; + + /** + * 报价轮次 + */ + @ExcelProperty(value = "报价轮次") + private Long quoteRound; + + /** + * 报价大类(1橡机板块 2非橡机板块) + */ + @ExcelProperty(value = "报价大类(1橡机板块 2非橡机板块)", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "quote_category") + private String quoteCategory; + + /** + * 报价类型(1对内 2对外) + */ + @ExcelProperty(value = "报价类型(1对内 2对外)", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "contract_type") + private String quoteType; + + /** + * 业务方向(1智能轮胎 2轮胎工厂 3快递物流 4锂电 5工业软件 6智能制造 7新行业及零售) + */ + @ExcelProperty(value = "业务方向", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "business_direction") + private String businessDirection; + + /** + * 部门 + */ + @ExcelProperty(value = "部门") + private Long quoteDeptId; + + /** + * 报价日期 + */ + @ExcelProperty(value = "报价日期") + private Date quoteDate; + + /** + * 报价有效期起 + */ + @ExcelProperty(value = "报价有效期起") + private Date validFrom; + + /** + * 报价有效期(天) + */ + @ExcelProperty(value = "报价有效期", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "天=") + private Long validDays; + + /** + * 报价有效期止 + */ + @ExcelProperty(value = "报价有效期止") + private Date validTo; + + /** + * 交货期(天) + */ + @ExcelProperty(value = "交货期", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "天=") + private Long deliveryPeriod; + + /** + * 交付/交货方式 + */ + @ExcelProperty(value = "交付/交货方式") + private String deliveryMethod; + + /** + * 付款方式(1电汇 2承兑) + */ + @ExcelProperty(value = "付款方式(1电汇 2承兑)", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "payment_method") + private String paymentMethod; + + /** + * 币种(字典类型) + */ + @ExcelProperty(value = "币种", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "currency_type") + private String currencyType; + + /** + * 含税信息(如:含13%增值税) + */ + @ExcelProperty(value = "含税信息", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "如=:含13%增值税") + private String taxIncludedInfo; + + /** + * 税率(默认按明细可覆盖) + */ + @ExcelProperty(value = "税率(默认按明细可覆盖)") + private BigDecimal taxRate; + + /** + * 总报价 + */ + @ExcelProperty(value = "总报价") + private BigDecimal totalPrice; + + /** + * 未税总价 + */ + @ExcelProperty(value = "未税总价") + private BigDecimal totalBeforeTax; + + /** + * 税额 + */ + @ExcelProperty(value = "税额") + private BigDecimal totalTax; + + /** + * 含税总价 + */ + @ExcelProperty(value = "含税总价") + private BigDecimal totalIncludingTax; + + /** + * 客户方联系人ID + */ + @ExcelProperty(value = "客户方联系人ID") + private Long customerContactId; + + /** + * 客户方联系人 + */ + @ExcelProperty(value = "客户方联系人") + private String customerContactName; + + /** + * 客户方联系电话 + */ + @ExcelProperty(value = "客户方联系电话") + private String customerContactPhone; + + /** + * 客户方电子邮箱 + */ + @ExcelProperty(value = "客户方电子邮箱") + private String customerContactEmail; + + /** + * 供货方联系人ID + */ + @ExcelProperty(value = "供货方联系人ID") + private Long supplierContactId; + + /** + * 供货方联系人 + */ + @ExcelProperty(value = "供货方联系人") + private String supplierContactName; + + /** + * 供货方联系电话 + */ + @ExcelProperty(value = "供货方联系电话") + private String supplierContactPhone; + + /** + * 供货方电子邮箱 + */ + @ExcelProperty(value = "供货方电子邮箱") + private String supplierContactEmail; + + /** + * 项目ID(可选) + */ + @ExcelProperty(value = "项目ID(可选)") + private Long projectId; + + /** + * 打印模板ID(可选) + */ + @ExcelProperty(value = "打印模板ID(可选)") + private Long templateId; + + /** + * 附件ID + */ + @ExcelProperty(value = "附件ID") + private String ossId; + + /** + * 报价单状态(1暂存 2审批中 3可用) + */ + @ExcelProperty(value = "报价单状态(1暂存 2审批中 3可用)", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "quote_status") + private String quoteStatus; + + /** + * 流程状态 + */ + @ExcelProperty(value = "流程状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "flow_status") + private String flowStatus; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** 派生:客户方联系人真实名称(CrmCustomerContact) */ + @ExcelProperty(value = "客户方联系人(实时)") + private String customerContactRealName; + + /** 派生:供货方联系人真实名称(CrmCustomerContact) */ + @ExcelProperty(value = "供货方联系人(实时)") + private String supplierContactRealName; + + + /** + * 报价单子表-物料明细 + */ + @ExcelProperty(value = "报价单子表-物料明细") + private List itemsVo; + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/vo/CrmQuoteMaterialVo.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/vo/CrmQuoteMaterialVo.java new file mode 100644 index 00000000..60b3b220 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/domain/vo/CrmQuoteMaterialVo.java @@ -0,0 +1,141 @@ +package org.dromara.oa.crm.domain.vo; + +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.oa.crm.domain.CrmQuoteMaterial; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + + + +/** + * 报价单物料明细视图对象 crm_quote_material + * + * @author Yinq + * @date 2025-10-28 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = CrmQuoteMaterial.class) +public class CrmQuoteMaterialVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 报价物料ID + */ + @ExcelProperty(value = "报价物料ID") + private Long quoteMaterialId; + + /** + * 报价ID + */ + @ExcelProperty(value = "报价ID") + private Long quoteId; + + /** + * 序号(ERP风格) + */ + @ExcelProperty(value = "序号(ERP风格)") + private Long itemNo; + + /** + * 产品/服务名称 + */ + @ExcelProperty(value = "产品/服务名称") + private String productName; + + /** + * 规格描述 + */ + @ExcelProperty(value = "规格描述") + private String specificationDescription; + + /** + * 物料ID(SAP) + */ + @ExcelProperty(value = "物料ID(SAP)") + private Long materialId; + + /** + * 销售物料ID(关联名) + */ + @ExcelProperty(value = "销售物料ID(关联名)") + private Long relationMaterialId; + + /** + * SAP物料名称(联表得到) + */ + @ExcelProperty(value = "SAP物料名称") + private String materialName; + + /** + * 销售物料名称(联表得到) + */ + @ExcelProperty(value = "销售物料名称") + private String saleMaterialName; + + /** + * 数量 + */ + @ExcelProperty(value = "数量") + private BigDecimal amount; + + /** + * 单位ID + */ + @ExcelProperty(value = "单位ID") + private Long unitId; + + /** + * 单位名称 + */ + @ExcelProperty(value = "单位名称") + private String unitName; + + /** + * 未税单价 + */ + @ExcelProperty(value = "未税单价") + private BigDecimal beforePrice; + + /** + * 税率 + */ + @ExcelProperty(value = "税率") + private BigDecimal taxRate; + + /** + * 含税单价 + */ + @ExcelProperty(value = "含税单价") + private BigDecimal includingPrice; + + /** + * 小计(含税) + */ + @ExcelProperty(value = "小计(含税)") + private BigDecimal subtotal; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 激活标识(1是 0否) + */ + @ExcelProperty(value = "激活标识", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "active_flag") + private String activeFlag; + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/mapper/CrmQuoteInfoMapper.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/mapper/CrmQuoteInfoMapper.java new file mode 100644 index 00000000..f5d9ac4d --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/mapper/CrmQuoteInfoMapper.java @@ -0,0 +1,114 @@ +package org.dromara.oa.crm.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.oa.crm.domain.CrmQuoteInfo; +import org.dromara.oa.crm.domain.vo.CrmQuoteInfoVo; + +import java.util.Collection; +import java.util.List; + +/** + * 报价单信息Mapper接口 + * + * @author Yinq + * @date 2025-10-28 + */ +public interface CrmQuoteInfoMapper extends BaseMapperPlus { + + /** + * 查询报价单信息列表 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 报价单信息集合 + */ + public Page selectCustomCrmQuoteInfoVoList(@Param("page") Page page, @Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 查询报价单信息列表 + * + * @param queryWrapper 条件 + * @return 报价单信息集合 + */ + public List selectCustomCrmQuoteInfoVoList(@Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 根据ID查询报价单信息详情 + * + * @param quoteId 主键ID + * @return 报价单信息对象 + */ + CrmQuoteInfoVo selectCustomCrmQuoteInfoVoById(@Param("quoteId") Long quoteId); + + /** + * 根据ID列表批量查询报价单信息 + * + * @param ids ID集合 + * @return 报价单信息集合 + */ + List selectCustomCrmQuoteInfoVoByIds(@Param("ids") Collection ids); + + /** + * 统计报价单信息记录数 + * + * @param queryWrapper 查询条件 + * @return 记录总数 + */ + Long countCustomCrmQuoteInfo(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 分页查询报价单信息(自定义条件) + * + * @param page 分页对象 + * @param queryWrapper 查询条件 + * @return 分页结果 + */ + Page selectCustomCrmQuoteInfoVoPage(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 批量插入报价单信息 + * + * @param list 报价单信息对象集合 + * @return 影响行数 + */ + int batchInsertCrmQuoteInfo(@Param("list") List list); + + /** + * 批量更新报价单信息 + * + * @param list 报价单信息对象集合 + * @return 影响行数 + */ + int batchUpdateCrmQuoteInfo(@Param("list") List list); + + /** + * 根据自定义条件删除报价单信息 + * + * @param queryWrapper 删除条件 + * @return 影响行数 + */ + int deleteCustomCrmQuoteInfo(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据ID列表批量删除报价单信息 + * + * @param ids ID集合 + * @return 影响行数 + */ + int deleteCustomCrmQuoteInfoByIds(@Param("ids") Collection ids); + + /** + * 检查报价单信息是否存在 + * + * @param queryWrapper 查询条件 + * @return 是否存在 + */ + Boolean existsCrmQuoteInfo(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/mapper/CrmQuoteMaterialMapper.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/mapper/CrmQuoteMaterialMapper.java new file mode 100644 index 00000000..8542acc6 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/mapper/CrmQuoteMaterialMapper.java @@ -0,0 +1,114 @@ +package org.dromara.oa.crm.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.oa.crm.domain.CrmQuoteMaterial; +import org.dromara.oa.crm.domain.vo.CrmQuoteMaterialVo; + +import java.util.Collection; +import java.util.List; + +/** + * 报价单物料明细Mapper接口 + * + * @author Yinq + * @date 2025-10-28 + */ +public interface CrmQuoteMaterialMapper extends BaseMapperPlus { + + /** + * 查询报价单物料明细列表 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 报价单物料明细集合 + */ + public Page selectCustomCrmQuoteMaterialVoList(@Param("page") Page page, @Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 查询报价单物料明细列表 + * + * @param queryWrapper 条件 + * @return 报价单物料明细集合 + */ + public List selectCustomCrmQuoteMaterialVoList(@Param(Constants.WRAPPER) MPJLambdaWrapper queryWrapper); + + /** + * 根据ID查询报价单物料明细详情 + * + * @param quoteMaterialId 主键ID + * @return 报价单物料明细对象 + */ + CrmQuoteMaterialVo selectCustomCrmQuoteMaterialVoById(@Param("quoteMaterialId") Long quoteMaterialId); + + /** + * 根据ID列表批量查询报价单物料明细 + * + * @param ids ID集合 + * @return 报价单物料明细集合 + */ + List selectCustomCrmQuoteMaterialVoByIds(@Param("ids") Collection ids); + + /** + * 统计报价单物料明细记录数 + * + * @param queryWrapper 查询条件 + * @return 记录总数 + */ + Long countCustomCrmQuoteMaterial(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 分页查询报价单物料明细(自定义条件) + * + * @param page 分页对象 + * @param queryWrapper 查询条件 + * @return 分页结果 + */ + Page selectCustomCrmQuoteMaterialVoPage(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 批量插入报价单物料明细 + * + * @param list 报价单物料明细对象集合 + * @return 影响行数 + */ + int batchInsertCrmQuoteMaterial(@Param("list") List list); + + /** + * 批量更新报价单物料明细 + * + * @param list 报价单物料明细对象集合 + * @return 影响行数 + */ + int batchUpdateCrmQuoteMaterial(@Param("list") List list); + + /** + * 根据自定义条件删除报价单物料明细 + * + * @param queryWrapper 删除条件 + * @return 影响行数 + */ + int deleteCustomCrmQuoteMaterial(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据ID列表批量删除报价单物料明细 + * + * @param ids ID集合 + * @return 影响行数 + */ + int deleteCustomCrmQuoteMaterialByIds(@Param("ids") Collection ids); + + /** + * 检查报价单物料明细是否存在 + * + * @param queryWrapper 查询条件 + * @return 是否存在 + */ + Boolean existsCrmQuoteMaterial(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/ICrmQuoteInfoService.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/ICrmQuoteInfoService.java new file mode 100644 index 00000000..d6828ab1 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/ICrmQuoteInfoService.java @@ -0,0 +1,78 @@ +package org.dromara.oa.crm.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.oa.crm.domain.bo.CrmQuoteInfoBo; +import org.dromara.oa.crm.domain.vo.CrmQuoteInfoVo; + +import java.util.Collection; +import java.util.List; + +/** + * 报价单信息Service接口 + * + * @author Yinq + * @date 2025-10-28 + */ +public interface ICrmQuoteInfoService { + + /** + * 查询报价单信息 + * + * @param quoteId 主键 + * @return 报价单信息 + */ + CrmQuoteInfoVo queryById(Long quoteId); + + /** + * 分页查询报价单信息列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 报价单信息分页列表 + */ + TableDataInfo queryPageList(CrmQuoteInfoBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的报价单信息列表 + * + * @param bo 查询条件 + * @return 报价单信息列表 + */ + List queryList(CrmQuoteInfoBo bo); + + /** + * 新增报价单信息 + * + * @param bo 报价单信息 + * @return 是否新增成功 + */ + Boolean insertByBo(CrmQuoteInfoBo bo); + + /** + * 修改报价单信息 + * + * @param bo 报价单信息 + * @return 是否修改成功 + */ + Boolean updateByBo(CrmQuoteInfoBo bo); + + /** + * 校验并批量删除报价单信息信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 查询同一次的多轮报价集合(按同一客户+相同报价单名称) + */ + List listRoundsByQuoteId(Long quoteId); + + /** + * 按报价明细自动汇总主表金额 + */ + Boolean recalcTotals(Long quoteId); +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/ICrmQuoteMaterialService.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/ICrmQuoteMaterialService.java new file mode 100644 index 00000000..55cd6cbb --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/ICrmQuoteMaterialService.java @@ -0,0 +1,68 @@ +package org.dromara.oa.crm.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.oa.crm.domain.bo.CrmQuoteMaterialBo; +import org.dromara.oa.crm.domain.vo.CrmQuoteMaterialVo; + +import java.util.Collection; +import java.util.List; + +/** + * 报价单物料明细Service接口 + * + * @author Yinq + * @date 2025-10-28 + */ +public interface ICrmQuoteMaterialService { + + /** + * 查询报价单物料明细 + * + * @param quoteMaterialId 主键 + * @return 报价单物料明细 + */ + CrmQuoteMaterialVo queryById(Long quoteMaterialId); + + /** + * 分页查询报价单物料明细列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 报价单物料明细分页列表 + */ + TableDataInfo queryPageList(CrmQuoteMaterialBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的报价单物料明细列表 + * + * @param bo 查询条件 + * @return 报价单物料明细列表 + */ + List queryList(CrmQuoteMaterialBo bo); + + /** + * 新增报价单物料明细 + * + * @param bo 报价单物料明细 + * @return 是否新增成功 + */ + Boolean insertByBo(CrmQuoteMaterialBo bo); + + /** + * 修改报价单物料明细 + * + * @param bo 报价单物料明细 + * @return 是否修改成功 + */ + Boolean updateByBo(CrmQuoteMaterialBo bo); + + /** + * 校验并批量删除报价单物料明细信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/impl/CrmQuoteInfoServiceImpl.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/impl/CrmQuoteInfoServiceImpl.java new file mode 100644 index 00000000..62301fa3 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/impl/CrmQuoteInfoServiceImpl.java @@ -0,0 +1,324 @@ +package org.dromara.oa.crm.service.impl; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.yulichang.toolkit.JoinWrappers; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.oa.crm.domain.CrmCustomerContact; +import org.dromara.oa.crm.domain.CrmCustomerInfo; +import org.dromara.oa.crm.domain.CrmQuoteInfo; +import org.dromara.oa.crm.domain.CrmQuoteMaterial; +import org.dromara.oa.crm.domain.bo.CrmQuoteInfoBo; +import org.dromara.oa.crm.domain.bo.CrmQuoteMaterialBo; +import org.dromara.oa.crm.domain.vo.CrmCustomerContactVo; +import org.dromara.oa.crm.domain.vo.CrmQuoteInfoVo; +import org.dromara.oa.crm.domain.vo.CrmQuoteMaterialVo; +import org.dromara.oa.crm.mapper.CrmQuoteInfoMapper; +import org.dromara.oa.crm.mapper.CrmQuoteMaterialMapper; +import org.dromara.oa.crm.service.ICrmCustomerContactService; +import org.dromara.oa.crm.service.ICrmQuoteInfoService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; +import java.util.Map; + +/** + * 报价单信息Service业务层处理 + * + * @author Yinq + * @date 2025-10-28 + */ +@RequiredArgsConstructor +@Service +public class CrmQuoteInfoServiceImpl implements ICrmQuoteInfoService { + + private final CrmQuoteInfoMapper baseMapper; + private final CrmQuoteMaterialMapper quoteMaterialMapper; + private final ICrmCustomerContactService customerContactService; + + /** + * 查询报价单信息 + * + * @param quoteId 主键 + * @return 报价单信息 + */ + @Override + public CrmQuoteInfoVo queryById(Long quoteId){ + CrmQuoteInfoVo vo = baseMapper.selectVoById(quoteId); + if (vo != null) { + // 关联查询子表明细 + List items = quoteMaterialMapper.selectVoList( + JoinWrappers.lambda(CrmQuoteMaterial.class) + .selectAll(CrmQuoteMaterial.class) + .eq(CrmQuoteMaterial::getQuoteId, quoteId) + .orderByAsc(CrmQuoteMaterial::getItemNo) + ); + vo.setItemsVo(items); + } + return vo; + } + + /** + * 分页查询报价单信息列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 报价单信息分页列表 + */ + @Override + public TableDataInfo queryPageList(CrmQuoteInfoBo bo, PageQuery pageQuery) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的报价单信息列表 + * + * @param bo 查询条件 + * @return 报价单信息列表 + */ + @Override + public List queryList(CrmQuoteInfoBo bo) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private MPJLambdaWrapper buildQueryWrapper(CrmQuoteInfoBo bo) { + Map params = bo.getParams(); + MPJLambdaWrapper lqw = JoinWrappers.lambda(CrmQuoteInfo.class) + // 主表全部字段 + .selectAll(CrmQuoteInfo.class) + // 客户方联系人(CrmCustomerContact,别名:CustomerContact) + .selectAs("CustomerContact", CrmCustomerContact::getContactName, CrmQuoteInfo::getCustomerContactRealName) + .leftJoin(CrmCustomerContact.class, "CustomerContact", CrmCustomerContact::getContactId, CrmQuoteInfo::getCustomerContactId) + + // 供货方联系人(CrmCustomerContact,别名:SupplierContact) + .selectAs("SupplierContact", CrmCustomerContact::getContactName, CrmQuoteInfo::getSupplierContactRealName) + .leftJoin(CrmCustomerContact.class, "SupplierContact", CrmCustomerContact::getContactId, CrmQuoteInfo::getSupplierContactId) + + + .eq(StringUtils.isNotBlank(bo.getQuoteCode()), CrmQuoteInfo::getQuoteCode, bo.getQuoteCode()) + .like(StringUtils.isNotBlank(bo.getQuoteName()), CrmQuoteInfo::getQuoteName, bo.getQuoteName()) + .eq(bo.getQuoteRound() != null, CrmQuoteInfo::getQuoteRound, bo.getQuoteRound()) + .eq(StringUtils.isNotBlank(bo.getQuoteCategory()), CrmQuoteInfo::getQuoteCategory, bo.getQuoteCategory()) + .eq(StringUtils.isNotBlank(bo.getQuoteType()), CrmQuoteInfo::getQuoteType, bo.getQuoteType()) + .eq(StringUtils.isNotBlank(bo.getBusinessDirection()), CrmQuoteInfo::getBusinessDirection, bo.getBusinessDirection()) + .eq(bo.getQuoteDeptId() != null, CrmQuoteInfo::getQuoteDeptId, bo.getQuoteDeptId()) + .eq(bo.getQuoteDate() != null, CrmQuoteInfo::getQuoteDate, bo.getQuoteDate()) + .eq(bo.getValidFrom() != null, CrmQuoteInfo::getValidFrom, bo.getValidFrom()) + .eq(bo.getValidDays() != null, CrmQuoteInfo::getValidDays, bo.getValidDays()) + .eq(bo.getValidTo() != null, CrmQuoteInfo::getValidTo, bo.getValidTo()) + .eq(bo.getDeliveryPeriod() != null, CrmQuoteInfo::getDeliveryPeriod, bo.getDeliveryPeriod()) + .eq(StringUtils.isNotBlank(bo.getDeliveryMethod()), CrmQuoteInfo::getDeliveryMethod, bo.getDeliveryMethod()) + .eq(StringUtils.isNotBlank(bo.getPaymentMethod()), CrmQuoteInfo::getPaymentMethod, bo.getPaymentMethod()) + .eq(StringUtils.isNotBlank(bo.getCurrencyType()), CrmQuoteInfo::getCurrencyType, bo.getCurrencyType()) + .eq(StringUtils.isNotBlank(bo.getTaxIncludedInfo()), CrmQuoteInfo::getTaxIncludedInfo, bo.getTaxIncludedInfo()) + .eq(bo.getTaxRate() != null, CrmQuoteInfo::getTaxRate, bo.getTaxRate()) + .eq(bo.getTotalPrice() != null, CrmQuoteInfo::getTotalPrice, bo.getTotalPrice()) + .eq(bo.getTotalBeforeTax() != null, CrmQuoteInfo::getTotalBeforeTax, bo.getTotalBeforeTax()) + .eq(bo.getTotalTax() != null, CrmQuoteInfo::getTotalTax, bo.getTotalTax()) + .eq(bo.getTotalIncludingTax() != null, CrmQuoteInfo::getTotalIncludingTax, bo.getTotalIncludingTax()) + .eq(bo.getCustomerContactId() != null, CrmQuoteInfo::getCustomerContactId, bo.getCustomerContactId()) + .like(StringUtils.isNotBlank(bo.getCustomerContactName()), CrmQuoteInfo::getCustomerContactName, bo.getCustomerContactName()) + .eq(StringUtils.isNotBlank(bo.getCustomerContactPhone()), CrmQuoteInfo::getCustomerContactPhone, bo.getCustomerContactPhone()) + .eq(StringUtils.isNotBlank(bo.getCustomerContactEmail()), CrmQuoteInfo::getCustomerContactEmail, bo.getCustomerContactEmail()) + .eq(bo.getSupplierContactId() != null, CrmQuoteInfo::getSupplierContactId, bo.getSupplierContactId()) + .like(StringUtils.isNotBlank(bo.getSupplierContactName()), CrmQuoteInfo::getSupplierContactName, bo.getSupplierContactName()) + .eq(StringUtils.isNotBlank(bo.getSupplierContactPhone()), CrmQuoteInfo::getSupplierContactPhone, bo.getSupplierContactPhone()) + .eq(StringUtils.isNotBlank(bo.getSupplierContactEmail()), CrmQuoteInfo::getSupplierContactEmail, bo.getSupplierContactEmail()) + .eq(bo.getProjectId() != null, CrmQuoteInfo::getProjectId, bo.getProjectId()) + .eq(bo.getTemplateId() != null, CrmQuoteInfo::getTemplateId, bo.getTemplateId()) + .eq(StringUtils.isNotBlank(bo.getOssId()), CrmQuoteInfo::getOssId, bo.getOssId()) + .eq(StringUtils.isNotBlank(bo.getQuoteStatus()), CrmQuoteInfo::getQuoteStatus, bo.getQuoteStatus()) + .eq(StringUtils.isNotBlank(bo.getFlowStatus()), CrmQuoteInfo::getFlowStatus, bo.getFlowStatus()) +; + return lqw; + } + + /** + * 新增报价单信息 + * + * @param bo 报价单信息 + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByBo(CrmQuoteInfoBo bo) { + CrmQuoteInfo add = MapstructUtils.convert(bo, CrmQuoteInfo.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setQuoteId(add.getQuoteId()); + // 保存子表 + List itemsBo = bo.getItemsBo(); + if (itemsBo != null && !itemsBo.isEmpty()) { + for (int i = 0; i < itemsBo.size(); i++) { + CrmQuoteMaterialBo itemBo = itemsBo.get(i); + CrmQuoteMaterial entity = MapstructUtils.convert(itemBo, CrmQuoteMaterial.class); + // 避免主键冲突:子表使用自增主键,插入前显式置空 + entity.setQuoteMaterialId(null); + entity.setQuoteId(add.getQuoteId()); + // 若未指定序号则按顺序回填 + if (entity.getItemNo() == null) { + entity.setItemNo((long) (i + 1)); + } + quoteMaterialMapper.insert(entity); + } + // 回写主表金额汇总 + this.recalcTotals(add.getQuoteId()); + } + } + return flag; + } + + /** + * 修改报价单信息 + * + * @param bo 报价单信息 + * @return 是否修改成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(CrmQuoteInfoBo bo) { + CrmQuoteInfo update = MapstructUtils.convert(bo, CrmQuoteInfo.class); + validEntityBeforeSave(update); + boolean ok = baseMapper.updateById(update) > 0; + if (!ok) return false; + // 全量覆盖子表:先删后增(保持简单一致性) + Long qid = bo.getQuoteId(); + quoteMaterialMapper.delete(Wrappers.lambdaQuery().eq(CrmQuoteMaterial::getQuoteId, qid)); + List itemsBo = bo.getItemsBo(); + if (itemsBo != null && !itemsBo.isEmpty()) { + for (int i = 0; i < itemsBo.size(); i++) { + CrmQuoteMaterialBo itemBo = itemsBo.get(i); + CrmQuoteMaterial entity = MapstructUtils.convert(itemBo, CrmQuoteMaterial.class); + // 避免主键冲突:子表使用自增主键,插入前显式置空 + entity.setQuoteMaterialId(null); + entity.setQuoteId(qid); + if (entity.getItemNo() == null) { + entity.setItemNo((long) (i + 1)); + } + quoteMaterialMapper.insert(entity); + } + } + // 回写主表金额汇总 + this.recalcTotals(qid); + return true; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(CrmQuoteInfo entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除报价单信息信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + // 先删除子表 + int delete = quoteMaterialMapper.delete(Wrappers.lambdaQuery().in(CrmQuoteMaterial::getQuoteId, ids)); + int i = baseMapper.deleteByIds(ids); + return i > 0; + } + + /** + * 查询同一次的多轮报价集合(同一客户 + 相同报价单名称) + * 不修改库结构,依据联系人ID反查客户ID做分组。 + */ + public List listRoundsByQuoteId(Long quoteId) { + CrmQuoteInfoVo base = baseMapper.selectVoById(quoteId); + if (base == null) { + return List.of(); + } + // 通过联系人拿客户ID + Long contactId = base.getCustomerContactId(); + Long customerId = null; + if (contactId != null) { + CrmCustomerContactVo contactVo = customerContactService.queryById(contactId); + if (contactVo != null) { + customerId = contactVo.getCustomerId(); + } + } + + MPJLambdaWrapper lqw = JoinWrappers.lambda(CrmQuoteInfo.class) + .selectAll(CrmQuoteInfo.class) + // 别名连接与派生字段选择 + .leftJoin(CrmCustomerContact.class, "CustomerContact", CrmCustomerContact::getContactId, CrmQuoteInfo::getCustomerContactId) + .leftJoin(CrmCustomerContact.class, "SupplierContact", CrmCustomerContact::getContactId, CrmQuoteInfo::getSupplierContactId) + .leftJoin(CrmCustomerInfo.class, "Customer", CrmCustomerInfo::getCustomerId, CrmCustomerContact::getCustomerId) + .selectAs("CustomerContact", CrmCustomerContact::getContactName, CrmQuoteInfo::getCustomerContactRealName) + .selectAs("SupplierContact", CrmCustomerContact::getContactName, CrmQuoteInfo::getSupplierContactRealName) + .eq(CrmQuoteInfo::getQuoteName, base.getQuoteName()) + // 使用客户方联系人别名的 customer_id 过滤同一客户 + .eq(customerId != null, CrmCustomerContact::getCustomerId, customerId) + .orderByAsc(CrmQuoteInfo::getQuoteDate); + + return baseMapper.selectVoList(lqw); + } + + /** + * 按报价明细自动汇总主表金额(未税/税额/含税/总报价) + */ + public Boolean recalcTotals(Long quoteId) { + if (quoteId == null) return false; + // 查询该报价的所有明细 + MPJLambdaWrapper lqw = JoinWrappers.lambda(CrmQuoteMaterial.class) + .selectAll(CrmQuoteMaterial.class) + .eq(CrmQuoteMaterial::getQuoteId, quoteId); + List items = quoteMaterialMapper.selectVoList(lqw); + if (items == null || items.isEmpty()) { + return true; // 无明细则不处理 + } + // 汇总金额(统一两位小数,四舍五入) + BigDecimal totalIncluding = BigDecimal.ZERO; + BigDecimal totalBefore = BigDecimal.ZERO; + BigDecimal totalTax = BigDecimal.ZERO; + for (CrmQuoteMaterialVo m : items) { + BigDecimal amt = m.getAmount() == null ? BigDecimal.ZERO : m.getAmount(); + BigDecimal before = m.getBeforePrice() == null ? BigDecimal.ZERO : m.getBeforePrice(); + BigDecimal rate = m.getTaxRate() == null ? BigDecimal.ZERO : m.getTaxRate(); + BigDecimal including = m.getIncludingPrice(); + if (including == null) { + // 含税单价 = 未税单价 × (1 + 税率/100) + including = before.multiply(BigDecimal.ONE.add(rate.movePointLeft(2))).setScale(2, RoundingMode.HALF_UP); + } + BigDecimal subtotal = m.getSubtotal(); + if (subtotal == null) { + subtotal = including.multiply(amt).setScale(2, RoundingMode.HALF_UP); + } + totalIncluding = totalIncluding.add(subtotal); + totalBefore = totalBefore.add(before.multiply(amt)); + totalTax = totalTax.add(including.subtract(before).multiply(amt)); + } + // 总报价与含税总价保持一致 + BigDecimal totalPrice = totalIncluding; + CrmQuoteInfo update = new CrmQuoteInfo(); + update.setQuoteId(quoteId); + update.setTotalIncludingTax(totalIncluding.setScale(2, RoundingMode.HALF_UP)); + update.setTotalBeforeTax(totalBefore.setScale(2, RoundingMode.HALF_UP)); + update.setTotalTax(totalTax.setScale(2, RoundingMode.HALF_UP)); + update.setTotalPrice(totalPrice.setScale(2, RoundingMode.HALF_UP)); + return baseMapper.updateById(update) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/impl/CrmQuoteMaterialServiceImpl.java b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/impl/CrmQuoteMaterialServiceImpl.java new file mode 100644 index 00000000..0d8754e4 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/java/org/dromara/oa/crm/service/impl/CrmQuoteMaterialServiceImpl.java @@ -0,0 +1,151 @@ +package org.dromara.oa.crm.service.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.github.yulichang.toolkit.JoinWrappers; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.oa.base.domain.BaseMaterialInfo; +import org.dromara.oa.base.domain.BaseRelationMaterial; +import org.dromara.oa.crm.domain.CrmQuoteMaterial; +import org.dromara.oa.crm.domain.bo.CrmQuoteMaterialBo; +import org.dromara.oa.crm.domain.vo.CrmQuoteMaterialVo; +import org.dromara.oa.crm.mapper.CrmQuoteMaterialMapper; +import org.dromara.oa.crm.service.ICrmQuoteMaterialService; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 报价单物料明细Service业务层处理 + * + * @author Yinq + * @date 2025-10-28 + */ +@RequiredArgsConstructor +@Service +public class CrmQuoteMaterialServiceImpl implements ICrmQuoteMaterialService { + + private final CrmQuoteMaterialMapper baseMapper; + + /** + * 查询报价单物料明细 + * + * @param quoteMaterialId 主键 + * @return 报价单物料明细 + */ + @Override + public CrmQuoteMaterialVo queryById(Long quoteMaterialId){ + return baseMapper.selectVoById(quoteMaterialId); + } + + /** + * 分页查询报价单物料明细列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 报价单物料明细分页列表 + */ + @Override + public TableDataInfo queryPageList(CrmQuoteMaterialBo bo, PageQuery pageQuery) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的报价单物料明细列表 + * + * @param bo 查询条件 + * @return 报价单物料明细列表 + */ + @Override + public List queryList(CrmQuoteMaterialBo bo) { + MPJLambdaWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private MPJLambdaWrapper buildQueryWrapper(CrmQuoteMaterialBo bo) { + Map params = bo.getParams(); + MPJLambdaWrapper lqw = JoinWrappers.lambda(CrmQuoteMaterial.class) + .selectAll(CrmQuoteMaterial.class) + // 联表选择:SAP物料名称 & 销售物料名称 + .select(BaseMaterialInfo::getMaterialName) + .select(BaseRelationMaterial::getSaleMaterialName) + .leftJoin(BaseMaterialInfo.class, BaseMaterialInfo::getMaterialId, CrmQuoteMaterial::getMaterialId) + .leftJoin(BaseRelationMaterial.class, BaseRelationMaterial::getRelationMaterialId, CrmQuoteMaterial::getRelationMaterialId) + .eq(bo.getQuoteId() != null, CrmQuoteMaterial::getQuoteId, bo.getQuoteId()) + .eq(bo.getItemNo() != null, CrmQuoteMaterial::getItemNo, bo.getItemNo()) + .like(StringUtils.isNotBlank(bo.getProductName()), CrmQuoteMaterial::getProductName, bo.getProductName()) + .eq(StringUtils.isNotBlank(bo.getSpecificationDescription()), CrmQuoteMaterial::getSpecificationDescription, bo.getSpecificationDescription()) + .eq(bo.getMaterialId() != null, CrmQuoteMaterial::getMaterialId, bo.getMaterialId()) + .eq(bo.getRelationMaterialId() != null, CrmQuoteMaterial::getRelationMaterialId, bo.getRelationMaterialId()) + .eq(bo.getAmount() != null, CrmQuoteMaterial::getAmount, bo.getAmount()) + .eq(bo.getUnitId() != null, CrmQuoteMaterial::getUnitId, bo.getUnitId()) + .like(StringUtils.isNotBlank(bo.getUnitName()), CrmQuoteMaterial::getUnitName, bo.getUnitName()) + .eq(bo.getBeforePrice() != null, CrmQuoteMaterial::getBeforePrice, bo.getBeforePrice()) + .eq(bo.getTaxRate() != null, CrmQuoteMaterial::getTaxRate, bo.getTaxRate()) + .eq(bo.getIncludingPrice() != null, CrmQuoteMaterial::getIncludingPrice, bo.getIncludingPrice()) + .eq(bo.getSubtotal() != null, CrmQuoteMaterial::getSubtotal, bo.getSubtotal()) + .eq(StringUtils.isNotBlank(bo.getActiveFlag()), CrmQuoteMaterial::getActiveFlag, bo.getActiveFlag()) +; + return lqw; + } + + /** + * 新增报价单物料明细 + * + * @param bo 报价单物料明细 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(CrmQuoteMaterialBo bo) { + CrmQuoteMaterial add = MapstructUtils.convert(bo, CrmQuoteMaterial.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setQuoteMaterialId(add.getQuoteMaterialId()); + } + return flag; + } + + /** + * 修改报价单物料明细 + * + * @param bo 报价单物料明细 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(CrmQuoteMaterialBo bo) { + CrmQuoteMaterial update = MapstructUtils.convert(bo, CrmQuoteMaterial.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(CrmQuoteMaterial entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除报价单物料明细信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/crm/CrmQuoteInfoMapper.xml b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/crm/CrmQuoteInfoMapper.xml new file mode 100644 index 00000000..01a663b7 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/crm/CrmQuoteInfoMapper.xml @@ -0,0 +1,381 @@ + + + + + + + + + + + + + + + + + + + + + + + insert into crm_quote_info( + tenant_id, + + quote_code, + + quote_name, + + quote_round, + + quote_category, + + quote_type, + + business_direction, + + quote_dept_id, + + quote_date, + + valid_from, + + valid_days, + + valid_to, + + delivery_period, + + delivery_method, + + payment_method, + + currency_type, + + tax_included_info, + + tax_rate, + + total_price, + + total_before_tax, + + total_tax, + + total_including_tax, + + customer_contact_id, + + customer_contact_name, + + customer_contact_phone, + + customer_contact_email, + + supplier_contact_id, + + supplier_contact_name, + + supplier_contact_phone, + + supplier_contact_email, + + project_id, + + template_id, + + oss_id, + + quote_status, + + flow_status, + + remark, + + del_flag, + + create_dept, + + create_by, + + create_time, + + update_by, + + update_time + + ) + values + + ( + #{item.tenantId}, + + #{item.quoteCode}, + + #{item.quoteName}, + + #{item.quoteRound}, + + #{item.quoteCategory}, + + #{item.quoteType}, + + #{item.businessDirection}, + + #{item.quoteDeptId}, + + #{item.quoteDate}, + + #{item.validFrom}, + + #{item.validDays}, + + #{item.validTo}, + + #{item.deliveryPeriod}, + + #{item.deliveryMethod}, + + #{item.paymentMethod}, + + #{item.currencyType}, + + #{item.taxIncludedInfo}, + + #{item.taxRate}, + + #{item.totalPrice}, + + #{item.totalBeforeTax}, + + #{item.totalTax}, + + #{item.totalIncludingTax}, + + #{item.customerContactId}, + + #{item.customerContactName}, + + #{item.customerContactPhone}, + + #{item.customerContactEmail}, + + #{item.supplierContactId}, + + #{item.supplierContactName}, + + #{item.supplierContactPhone}, + + #{item.supplierContactEmail}, + + #{item.projectId}, + + #{item.templateId}, + + #{item.ossId}, + + #{item.quoteStatus}, + + #{item.flowStatus}, + + #{item.remark}, + + #{item.delFlag}, + + #{item.createDept}, + + #{item.createBy}, + + #{item.createTime}, + + #{item.updateBy}, + + #{item.updateTime} + + ) + + + + + + + update crm_quote_info + + + tenant_id = #{item.tenantId}, + + + quote_code = #{item.quoteCode}, + + + quote_name = #{item.quoteName}, + + + quote_round = #{item.quoteRound}, + + + quote_category = #{item.quoteCategory}, + + + quote_type = #{item.quoteType}, + + + business_direction = #{item.businessDirection}, + + + quote_dept_id = #{item.quoteDeptId}, + + + quote_date = #{item.quoteDate}, + + + valid_from = #{item.validFrom}, + + + valid_days = #{item.validDays}, + + + valid_to = #{item.validTo}, + + + delivery_period = #{item.deliveryPeriod}, + + + delivery_method = #{item.deliveryMethod}, + + + payment_method = #{item.paymentMethod}, + + + currency_type = #{item.currencyType}, + + + tax_included_info = #{item.taxIncludedInfo}, + + + tax_rate = #{item.taxRate}, + + + total_price = #{item.totalPrice}, + + + total_before_tax = #{item.totalBeforeTax}, + + + total_tax = #{item.totalTax}, + + + total_including_tax = #{item.totalIncludingTax}, + + + customer_contact_id = #{item.customerContactId}, + + + customer_contact_name = #{item.customerContactName}, + + + customer_contact_phone = #{item.customerContactPhone}, + + + customer_contact_email = #{item.customerContactEmail}, + + + supplier_contact_id = #{item.supplierContactId}, + + + supplier_contact_name = #{item.supplierContactName}, + + + supplier_contact_phone = #{item.supplierContactPhone}, + + + supplier_contact_email = #{item.supplierContactEmail}, + + + project_id = #{item.projectId}, + + + template_id = #{item.templateId}, + + + oss_id = #{item.ossId}, + + + quote_status = #{item.quoteStatus}, + + + flow_status = #{item.flowStatus}, + + + remark = #{item.remark}, + + + del_flag = #{item.delFlag}, + + + create_dept = #{item.createDept}, + + + create_by = #{item.createBy}, + + + create_time = #{item.createTime}, + + + update_by = #{item.updateBy}, + + + update_time = #{item.updateTime} + + + where quote_id = #{item.quoteId} + + + + + + delete from crm_quote_info + ${ew.getCustomSqlSegment} + + + + + delete from crm_quote_info + where quote_id in + + #{id} + + + + + + + + diff --git a/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/crm/CrmQuoteMaterialMapper.xml b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/crm/CrmQuoteMaterialMapper.xml new file mode 100644 index 00000000..c76a2b86 --- /dev/null +++ b/ruoyi-modules/ruoyi-oa/src/main/resources/mapper/oa/crm/CrmQuoteMaterialMapper.xml @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + + + + + + + + insert into crm_quote_material( + tenant_id, + + quote_id, + + item_no, + + product_name, + + specification_description, + + material_id, + + relation_material_id, + + amount, + + unit_id, + + unit_name, + + before_price, + + tax_rate, + + including_price, + + subtotal, + + remark, + + active_flag, + + del_flag, + + create_dept, + + create_by, + + create_time, + + update_by, + + update_time + + ) + values + + ( + #{item.tenantId}, + + #{item.quoteId}, + + #{item.itemNo}, + + #{item.productName}, + + #{item.specificationDescription}, + + #{item.materialId}, + + #{item.relationMaterialId}, + + #{item.amount}, + + #{item.unitId}, + + #{item.unitName}, + + #{item.beforePrice}, + + #{item.taxRate}, + + #{item.includingPrice}, + + #{item.subtotal}, + + #{item.remark}, + + #{item.activeFlag}, + + #{item.delFlag}, + + #{item.createDept}, + + #{item.createBy}, + + #{item.createTime}, + + #{item.updateBy}, + + #{item.updateTime} + + ) + + + + + + + update crm_quote_material + + + tenant_id = #{item.tenantId}, + + + quote_id = #{item.quoteId}, + + + item_no = #{item.itemNo}, + + + product_name = #{item.productName}, + + + specification_description = #{item.specificationDescription}, + + + material_id = #{item.materialId}, + + + relation_material_id = #{item.relationMaterialId}, + + + amount = #{item.amount}, + + + unit_id = #{item.unitId}, + + + unit_name = #{item.unitName}, + + + before_price = #{item.beforePrice}, + + + tax_rate = #{item.taxRate}, + + + including_price = #{item.includingPrice}, + + + subtotal = #{item.subtotal}, + + + remark = #{item.remark}, + + + active_flag = #{item.activeFlag}, + + + del_flag = #{item.delFlag}, + + + create_dept = #{item.createDept}, + + + create_by = #{item.createBy}, + + + create_time = #{item.createTime}, + + + update_by = #{item.updateBy}, + + + update_time = #{item.updateTime} + + + where quote_material_id = #{item.quoteMaterialId} + + + + + + delete from crm_quote_material + ${ew.getCustomSqlSegment} + + + + + delete from crm_quote_material + where quote_material_id in + + #{id} + + + + + + + +